17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5447e4a63Spetede * Common Development and Distribution License (the "License").
6447e4a63Spetede * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
220dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * SunOS MT STREAMS ERI(PCI) 10/100 Mb Ethernet Device Driver
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/debug.h>
327c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
337c478bd9Sstevel@tonic-gate #include <sys/stream.h>
347c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
357c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include <sys/crc32.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include <sys/stat.h>
417c478bd9Sstevel@tonic-gate #include <sys/cpu.h>
427c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
437c478bd9Sstevel@tonic-gate #include <inet/common.h>
447c478bd9Sstevel@tonic-gate #include <sys/pattr.h>
457c478bd9Sstevel@tonic-gate #include <inet/mi.h>
467c478bd9Sstevel@tonic-gate #include <inet/nd.h>
477c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
48d62bc4baSyz #include <sys/vlan.h>
497c478bd9Sstevel@tonic-gate #include <sys/policy.h>
50da14cebeSEric Cheng #include <sys/mac_provider.h>
51d64540e3Sgd #include <sys/mac_ether.h>
52d64540e3Sgd #include <sys/dlpi.h>
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate #include <sys/pci.h>
557c478bd9Sstevel@tonic-gate
56297a64e7Sgd #include "eri_phy.h"
57297a64e7Sgd #include "eri_mac.h"
58297a64e7Sgd #include "eri.h"
59297a64e7Sgd #include "eri_common.h"
607c478bd9Sstevel@tonic-gate
61297a64e7Sgd #include "eri_msg.h"
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate * **** Function Prototypes *****
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate * Entry points (man9e)
687c478bd9Sstevel@tonic-gate */
697c478bd9Sstevel@tonic-gate static int eri_attach(dev_info_t *, ddi_attach_cmd_t);
707c478bd9Sstevel@tonic-gate static int eri_detach(dev_info_t *, ddi_detach_cmd_t);
71d64540e3Sgd static uint_t eri_intr(caddr_t);
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate * I/O (Input/Output) Functions
757c478bd9Sstevel@tonic-gate */
76d64540e3Sgd static boolean_t eri_send_msg(struct eri *, mblk_t *);
77d64540e3Sgd static mblk_t *eri_read_dma(struct eri *, volatile struct rmd *,
78d64540e3Sgd volatile int, uint64_t flags);
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * Initialization Functions
827c478bd9Sstevel@tonic-gate */
83d64540e3Sgd static boolean_t eri_init(struct eri *);
847c478bd9Sstevel@tonic-gate static int eri_allocthings(struct eri *);
857c478bd9Sstevel@tonic-gate static int eri_init_xfer_params(struct eri *);
867c478bd9Sstevel@tonic-gate static void eri_statinit(struct eri *);
877c478bd9Sstevel@tonic-gate static int eri_burstsize(struct eri *);
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate static void eri_setup_mac_address(struct eri *, dev_info_t *);
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate static uint32_t eri_init_rx_channel(struct eri *);
927c478bd9Sstevel@tonic-gate static void eri_init_rx(struct eri *);
937c478bd9Sstevel@tonic-gate static void eri_init_txmac(struct eri *);
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate * Un-init Functions
977c478bd9Sstevel@tonic-gate */
987c478bd9Sstevel@tonic-gate static uint32_t eri_txmac_disable(struct eri *);
997c478bd9Sstevel@tonic-gate static uint32_t eri_rxmac_disable(struct eri *);
1007c478bd9Sstevel@tonic-gate static int eri_stop(struct eri *);
1017c478bd9Sstevel@tonic-gate static void eri_uninit(struct eri *erip);
1027c478bd9Sstevel@tonic-gate static int eri_freebufs(struct eri *);
103d64540e3Sgd static boolean_t eri_reclaim(struct eri *, uint32_t);
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate * Transceiver (xcvr) Functions
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate static int eri_new_xcvr(struct eri *); /* Initializes & detects xcvrs */
1097c478bd9Sstevel@tonic-gate static int eri_reset_xcvr(struct eri *);
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND
1127c478bd9Sstevel@tonic-gate static void eri_xcvr_force_mode(struct eri *, uint32_t *);
1137c478bd9Sstevel@tonic-gate #endif
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate static void eri_mif_poll(struct eri *, soft_mif_enable_t);
1167c478bd9Sstevel@tonic-gate static void eri_check_link(struct eri *);
117860c4cd4Scarlsonj static uint32_t eri_check_link_noind(struct eri *);
118d64540e3Sgd static link_state_t eri_mif_check(struct eri *, uint16_t, uint16_t);
1197c478bd9Sstevel@tonic-gate static void eri_mii_write(struct eri *, uint8_t, uint16_t);
1207c478bd9Sstevel@tonic-gate static uint32_t eri_mii_read(struct eri *, uint8_t, uint16_t *);
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate * Reset Functions
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate static uint32_t eri_etx_reset(struct eri *);
1267c478bd9Sstevel@tonic-gate static uint32_t eri_erx_reset(struct eri *);
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate * Error Functions
1307c478bd9Sstevel@tonic-gate */
1317c478bd9Sstevel@tonic-gate static void eri_fatal_err(struct eri *, uint32_t);
1327c478bd9Sstevel@tonic-gate static void eri_nonfatal_err(struct eri *, uint32_t);
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate #ifdef ERI_TX_HUNG
1357c478bd9Sstevel@tonic-gate static int eri_check_txhung(struct eri *);
1367c478bd9Sstevel@tonic-gate #endif
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate * Hardening Functions
1407c478bd9Sstevel@tonic-gate */
141d64540e3Sgd static void eri_fault_msg(struct eri *, uint_t, msg_t, const char *, ...);
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate * Misc Functions
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate static void eri_savecntrs(struct eri *);
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate static void eri_stop_timer(struct eri *erip);
1497c478bd9Sstevel@tonic-gate static void eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec);
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate static void eri_bb_force_idle(struct eri *);
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate * Utility Functions
1557c478bd9Sstevel@tonic-gate */
1567c478bd9Sstevel@tonic-gate static mblk_t *eri_allocb(size_t size);
1577c478bd9Sstevel@tonic-gate static mblk_t *eri_allocb_sp(size_t size);
1587c478bd9Sstevel@tonic-gate static int eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp);
1597c478bd9Sstevel@tonic-gate static int eri_param_set(queue_t *, mblk_t *, char *, caddr_t);
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate * Functions to support ndd
1637c478bd9Sstevel@tonic-gate */
1647c478bd9Sstevel@tonic-gate static void eri_nd_free(caddr_t *nd_pparam);
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate static boolean_t eri_nd_load(caddr_t *nd_pparam, char *name,
1677c478bd9Sstevel@tonic-gate pfi_t get_pfi, pfi_t set_pfi, caddr_t data);
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate static int eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp);
1707c478bd9Sstevel@tonic-gate static void eri_param_cleanup(struct eri *);
1717c478bd9Sstevel@tonic-gate static int eri_param_register(struct eri *, param_t *, int);
172d64540e3Sgd static void eri_process_ndd_ioctl(struct eri *, queue_t *, mblk_t *, int);
173d64540e3Sgd static int eri_mk_mblk_tail_space(mblk_t *, mblk_t **, size_t);
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate
176d64540e3Sgd static void eri_loopback(struct eri *, queue_t *, mblk_t *);
1777c478bd9Sstevel@tonic-gate
178d64540e3Sgd static uint32_t eri_ladrf_bit(const uint8_t *);
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate
181d64540e3Sgd /*
182d64540e3Sgd * Nemo (GLDv3) Functions.
183d64540e3Sgd */
184d64540e3Sgd static int eri_m_stat(void *, uint_t, uint64_t *);
185d64540e3Sgd static int eri_m_start(void *);
186d64540e3Sgd static void eri_m_stop(void *);
187d64540e3Sgd static int eri_m_promisc(void *, boolean_t);
188d64540e3Sgd static int eri_m_multicst(void *, boolean_t, const uint8_t *);
189d64540e3Sgd static int eri_m_unicst(void *, const uint8_t *);
190d64540e3Sgd static void eri_m_ioctl(void *, queue_t *, mblk_t *);
191d64540e3Sgd static boolean_t eri_m_getcapab(void *, mac_capab_t, void *);
192d64540e3Sgd static mblk_t *eri_m_tx(void *, mblk_t *);
193d64540e3Sgd
194d64540e3Sgd static mac_callbacks_t eri_m_callbacks = {
195d64540e3Sgd MC_IOCTL | MC_GETCAPAB,
196d64540e3Sgd eri_m_stat,
197d64540e3Sgd eri_m_start,
198d64540e3Sgd eri_m_stop,
199d64540e3Sgd eri_m_promisc,
200d64540e3Sgd eri_m_multicst,
201d64540e3Sgd eri_m_unicst,
202d64540e3Sgd eri_m_tx,
2030dc2366fSVenugopal Iyer NULL,
204d64540e3Sgd eri_m_ioctl,
205d64540e3Sgd eri_m_getcapab
206d64540e3Sgd };
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate * Define PHY Vendors: Matches to IEEE
2107c478bd9Sstevel@tonic-gate * Organizationally Unique Identifier (OUI)
2117c478bd9Sstevel@tonic-gate */
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate * The first two are supported as Internal XCVRs
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate #define PHY_VENDOR_LUCENT 0x601d
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate #define PHY_LINK_NONE 0 /* Not attempted yet or retry */
2187c478bd9Sstevel@tonic-gate #define PHY_LINK_DOWN 1 /* Not being used */
2197c478bd9Sstevel@tonic-gate #define PHY_LINK_UP 2 /* Not being used */
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate #define AUTO_SPEED 0
2227c478bd9Sstevel@tonic-gate #define FORCE_SPEED 1
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate /*
225d64540e3Sgd * MIB II broadcast/multicast packets
2267c478bd9Sstevel@tonic-gate */
2277c478bd9Sstevel@tonic-gate
228d64540e3Sgd #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0)
229d64540e3Sgd #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
2307c478bd9Sstevel@tonic-gate
231d64540e3Sgd #define BUMP_InNUcast(erip, pkt) \
232d64540e3Sgd if (IS_BROADCAST(pkt)) { \
2337c478bd9Sstevel@tonic-gate HSTAT(erip, brdcstrcv); \
234d64540e3Sgd } else if (IS_MULTICAST(pkt)) { \
2357c478bd9Sstevel@tonic-gate HSTAT(erip, multircv); \
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate
238d64540e3Sgd #define BUMP_OutNUcast(erip, pkt) \
239d64540e3Sgd if (IS_BROADCAST(pkt)) { \
2407c478bd9Sstevel@tonic-gate HSTAT(erip, brdcstxmt); \
241d64540e3Sgd } else if (IS_MULTICAST(pkt)) { \
2427c478bd9Sstevel@tonic-gate HSTAT(erip, multixmt); \
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate #define NEXTTMDP(tbasep, tmdlimp, tmdp) (((tmdp) + 1) == tmdlimp \
2467c478bd9Sstevel@tonic-gate ? tbasep : ((tmdp) + 1))
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate #define ETHERHEADER_SIZE (sizeof (struct ether_header))
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
2517c478bd9Sstevel@tonic-gate #define ERI_PROCESS_READ(erip, bp, sum) \
2527c478bd9Sstevel@tonic-gate { \
2537c478bd9Sstevel@tonic-gate t_uscalar_t type; \
2547c478bd9Sstevel@tonic-gate uint_t start_offset, end_offset; \
2557c478bd9Sstevel@tonic-gate \
2567c478bd9Sstevel@tonic-gate *(bp->b_wptr) = 0; /* pad byte */ \
2577c478bd9Sstevel@tonic-gate \
2587c478bd9Sstevel@tonic-gate /* \
2597c478bd9Sstevel@tonic-gate * update MIB II statistics \
2607c478bd9Sstevel@tonic-gate */ \
2617c478bd9Sstevel@tonic-gate HSTAT(erip, ipackets64); \
2627c478bd9Sstevel@tonic-gate HSTATN(erip, rbytes64, len); \
263d64540e3Sgd BUMP_InNUcast(erip, bp->b_rptr); \
264d64540e3Sgd type = get_ether_type(bp->b_rptr); \
265d64540e3Sgd if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) { \
2667c478bd9Sstevel@tonic-gate start_offset = 0; \
26722eb7cb5Sgd end_offset = MBLKL(bp) - ETHERHEADER_SIZE; \
2680dc2366fSVenugopal Iyer mac_hcksum_set(bp, \
269*7e996435SToomas Soome start_offset, 0, end_offset, sum, \
2700dc2366fSVenugopal Iyer HCK_PARTIALCKSUM); \
2717c478bd9Sstevel@tonic-gate } else { \
2727c478bd9Sstevel@tonic-gate /* \
2737c478bd9Sstevel@tonic-gate * Strip the PADS for 802.3 \
2747c478bd9Sstevel@tonic-gate */ \
2757c478bd9Sstevel@tonic-gate if (type <= ETHERMTU) \
2767c478bd9Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + \
2777c478bd9Sstevel@tonic-gate ETHERHEADER_SIZE + type; \
2787c478bd9Sstevel@tonic-gate } \
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate #else
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate #define ERI_PROCESS_READ(erip, bp) \
2837c478bd9Sstevel@tonic-gate { \
2847c478bd9Sstevel@tonic-gate t_uscalar_t type; \
285d64540e3Sgd type = get_ether_type(bp->b_rptr); \
286d64540e3Sgd \
287d64540e3Sgd /* \
288d64540e3Sgd * update MIB II statistics \
289d64540e3Sgd */ \
290d64540e3Sgd HSTAT(erip, ipackets64); \
291d64540e3Sgd HSTATN(erip, rbytes64, len); \
292d64540e3Sgd BUMP_InNUcast(erip, bp->b_rptr); \
293d64540e3Sgd /* \
294d64540e3Sgd * Strip the PADS for 802.3 \
295d64540e3Sgd */ \
296d64540e3Sgd if (type <= ETHERMTU) \
297*7e996435SToomas Soome bp->b_wptr = bp->b_rptr + ETHERHEADER_SIZE + \
298*7e996435SToomas Soome type; \
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate #endif /* ERI_RCV_CKSUM */
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate * TX Interrupt Rate
3047c478bd9Sstevel@tonic-gate */
3057c478bd9Sstevel@tonic-gate static int tx_interrupt_rate = 16;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * Ethernet broadcast address definition.
3097c478bd9Sstevel@tonic-gate */
310d64540e3Sgd static uint8_t etherbroadcastaddr[] = {
3117c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
3127c478bd9Sstevel@tonic-gate };
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate * The following variables are used for configuring various features
3167c478bd9Sstevel@tonic-gate */
3177c478bd9Sstevel@tonic-gate #define ERI_DESC_HANDLE_ALLOC 0x0001
3187c478bd9Sstevel@tonic-gate #define ERI_DESC_MEM_ALLOC 0x0002
3197c478bd9Sstevel@tonic-gate #define ERI_DESC_MEM_MAP 0x0004
3207c478bd9Sstevel@tonic-gate #define ERI_RCV_HANDLE_ALLOC 0x0020
3217c478bd9Sstevel@tonic-gate #define ERI_RCV_HANDLE_BIND 0x0040
3227c478bd9Sstevel@tonic-gate #define ERI_XMIT_DVMA_ALLOC 0x0100
3237c478bd9Sstevel@tonic-gate #define ERI_RCV_DVMA_ALLOC 0x0200
3247c478bd9Sstevel@tonic-gate #define ERI_XBUFS_HANDLE_ALLOC 0x0400
3257c478bd9Sstevel@tonic-gate #define ERI_XBUFS_KMEM_ALLOC 0x0800
3267c478bd9Sstevel@tonic-gate #define ERI_XBUFS_KMEM_DMABIND 0x1000
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate #define ERI_DONT_STRIP_CRC
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate * Translate a kernel virtual address to i/o address.
3327c478bd9Sstevel@tonic-gate */
3337c478bd9Sstevel@tonic-gate #define ERI_IOPBIOADDR(erip, a) \
3347c478bd9Sstevel@tonic-gate ((erip)->iopbiobase + ((uintptr_t)a - (erip)->iopbkbase))
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate * ERI Configuration Register Value
3387c478bd9Sstevel@tonic-gate * Used to configure parameters that define DMA burst
3397c478bd9Sstevel@tonic-gate * and internal arbitration behavior.
3407c478bd9Sstevel@tonic-gate * for equal TX and RX bursts, set the following in global
3417c478bd9Sstevel@tonic-gate * configuration register.
3427c478bd9Sstevel@tonic-gate * static int global_config = 0x42;
3437c478bd9Sstevel@tonic-gate */
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate * ERI ERX Interrupt Blanking Time
3477c478bd9Sstevel@tonic-gate * Each count is about 16 us (2048 clocks) for 66 MHz PCI.
3487c478bd9Sstevel@tonic-gate */
3497c478bd9Sstevel@tonic-gate static int intr_blank_time = 6; /* for about 96 us */
3507c478bd9Sstevel@tonic-gate static int intr_blank_packets = 8; /* */
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate * ERX PAUSE Threshold Register value
3547c478bd9Sstevel@tonic-gate * The following value is for an OFF Threshold of about 15.5 Kbytes
3557c478bd9Sstevel@tonic-gate * and an ON Threshold of 4K bytes.
3567c478bd9Sstevel@tonic-gate */
3577c478bd9Sstevel@tonic-gate static int rx_pause_threshold = 0xf8 | (0x40 << 12);
3587c478bd9Sstevel@tonic-gate static int eri_reinit_fatal = 0;
3597c478bd9Sstevel@tonic-gate #ifdef DEBUG
3607c478bd9Sstevel@tonic-gate static int noteri = 0;
3617c478bd9Sstevel@tonic-gate #endif
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate #ifdef ERI_TX_HUNG
3647c478bd9Sstevel@tonic-gate static int eri_reinit_txhung = 0;
3657c478bd9Sstevel@tonic-gate #endif
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate #ifdef ERI_HDX_BUG_WORKAROUND
3687c478bd9Sstevel@tonic-gate /*
3697c478bd9Sstevel@tonic-gate * By default enable padding in hdx mode to 97 bytes.
3707c478bd9Sstevel@tonic-gate * To disabled, in /etc/system:
3717c478bd9Sstevel@tonic-gate * set eri:eri_hdx_pad_enable=0
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate static uchar_t eri_hdx_pad_enable = 1;
3747c478bd9Sstevel@tonic-gate #endif
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate * Default values to initialize the cache line size and latency timer
3787c478bd9Sstevel@tonic-gate * registers in the PCI configuration space.
3797c478bd9Sstevel@tonic-gate * ERI_G_CACHE_LINE_SIZE_16 is defined as 16 since RIO expects in units
3807c478bd9Sstevel@tonic-gate * of 4 bytes.
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate #ifdef ERI_PM_WORKAROUND_PCI
3837c478bd9Sstevel@tonic-gate static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_32; /* 128 bytes */
3847c478bd9Sstevel@tonic-gate static int eri_pci_latency_timer = 0xff; /* 255 PCI cycles */
3857c478bd9Sstevel@tonic-gate #else
3867c478bd9Sstevel@tonic-gate static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_16; /* 64 bytes */
3877c478bd9Sstevel@tonic-gate static int eri_pci_latency_timer = 0x40; /* 64 PCI cycles */
3887c478bd9Sstevel@tonic-gate #endif
3897c478bd9Sstevel@tonic-gate #define ERI_CACHE_LINE_SIZE (eri_pci_cache_line << ERI_G_CACHE_BIT)
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate * Claim the device is ultra-capable of burst in the beginning. Use
3937c478bd9Sstevel@tonic-gate * the value returned by ddi_dma_burstsizes() to actually set the ERI
3947c478bd9Sstevel@tonic-gate * global configuration register later.
3957c478bd9Sstevel@tonic-gate *
3967c478bd9Sstevel@tonic-gate * PCI_ERI supports Infinite burst or 64-byte-multiple bursts.
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate #define ERI_LIMADDRLO ((uint64_t)0x00000000)
3997c478bd9Sstevel@tonic-gate #define ERI_LIMADDRHI ((uint64_t)0xffffffff)
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_attr = {
4027c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version number. */
4037c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRLO, /* low address */
4047c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRHI, /* high address */
4057c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* address counter max */
4067c478bd9Sstevel@tonic-gate (uint64_t)1, /* alignment */
4077c478bd9Sstevel@tonic-gate (uint_t)0xe000e0, /* dlim_burstsizes for 32 4 bit xfers */
4087c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* minimum transfer size */
4097c478bd9Sstevel@tonic-gate (uint64_t)0x7fffffff, /* maximum transfer size */
4107c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* maximum segment size */
4117c478bd9Sstevel@tonic-gate 1, /* scatter/gather list length */
4127c478bd9Sstevel@tonic-gate (uint32_t)1, /* granularity */
4137c478bd9Sstevel@tonic-gate (uint_t)0 /* attribute flags */
4147c478bd9Sstevel@tonic-gate };
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate static ddi_dma_attr_t desc_dma_attr = {
4177c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version number. */
4187c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRLO, /* low address */
4197c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRHI, /* high address */
4207c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* address counter max */
4217c478bd9Sstevel@tonic-gate (uint64_t)8, /* alignment */
4227c478bd9Sstevel@tonic-gate (uint_t)0xe000e0, /* dlim_burstsizes for 32 4 bit xfers */
4237c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* minimum transfer size */
4247c478bd9Sstevel@tonic-gate (uint64_t)0x7fffffff, /* maximum transfer size */
4257c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* maximum segment size */
4267c478bd9Sstevel@tonic-gate 1, /* scatter/gather list length */
4277c478bd9Sstevel@tonic-gate 16, /* granularity */
4287c478bd9Sstevel@tonic-gate 0 /* attribute flags */
4297c478bd9Sstevel@tonic-gate };
4307c478bd9Sstevel@tonic-gate
431bd78278bSGarrett D'Amore static ddi_device_acc_attr_t buf_attr = {
432bd78278bSGarrett D'Amore DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
433bd78278bSGarrett D'Amore DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
434bd78278bSGarrett D'Amore DDI_STRICTORDER_ACC, /* devacc_attr_dataorder */
435bd78278bSGarrett D'Amore DDI_DEFAULT_ACC, /* devacc_attr_access */
436bd78278bSGarrett D'Amore };
437bd78278bSGarrett D'Amore
4387c478bd9Sstevel@tonic-gate ddi_dma_lim_t eri_dma_limits = {
4397c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRLO, /* dlim_addr_lo */
4407c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRHI, /* dlim_addr_hi */
4417c478bd9Sstevel@tonic-gate (uint64_t)ERI_LIMADDRHI, /* dlim_cntr_max */
4427c478bd9Sstevel@tonic-gate (uint_t)0x00e000e0, /* dlim_burstsizes for 32 and 64 bit xfers */
4437c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* dlim_minxfer */
4447c478bd9Sstevel@tonic-gate 1024 /* dlim_speed */
4457c478bd9Sstevel@tonic-gate };
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate * Link Configuration variables
4497c478bd9Sstevel@tonic-gate *
4507c478bd9Sstevel@tonic-gate * On Motherboard implementations, 10/100 Mbps speeds may be supported
4517c478bd9Sstevel@tonic-gate * by using both the Serial Link and the MII on Non-serial-link interface.
4527c478bd9Sstevel@tonic-gate * When both links are present, the driver automatically tries to bring up
4537c478bd9Sstevel@tonic-gate * both. If both are up, the Gigabit Serial Link is selected for use, by
4547c478bd9Sstevel@tonic-gate * default. The following configuration variable is used to force the selection
4557c478bd9Sstevel@tonic-gate * of one of the links when both are up.
4567c478bd9Sstevel@tonic-gate * To change the default selection to the MII link when both the Serial
4577c478bd9Sstevel@tonic-gate * Link and the MII link are up, change eri_default_link to 1.
4587c478bd9Sstevel@tonic-gate *
4597c478bd9Sstevel@tonic-gate * Once a link is in use, the driver will continue to use that link till it
4607c478bd9Sstevel@tonic-gate * goes down. When it goes down, the driver will look at the status of both the
4617c478bd9Sstevel@tonic-gate * links again for link selection.
4627c478bd9Sstevel@tonic-gate *
4637c478bd9Sstevel@tonic-gate * Currently the standard is not stable w.r.t. gigabit link configuration
4647c478bd9Sstevel@tonic-gate * using auto-negotiation procedures. Meanwhile, the link may be configured
4657c478bd9Sstevel@tonic-gate * in "forced" mode using the "autonegotiation enable" bit (bit-12) in the
4667c478bd9Sstevel@tonic-gate * PCS MII Command Register. In this mode the PCS sends "idles" until sees
4677c478bd9Sstevel@tonic-gate * "idles" as initialization instead of the Link Configuration protocol
4687c478bd9Sstevel@tonic-gate * where a Config register is exchanged. In this mode, the ERI is programmed
4697c478bd9Sstevel@tonic-gate * for full-duplex operation with both pauseTX and pauseRX (for flow control)
4707c478bd9Sstevel@tonic-gate * enabled.
4717c478bd9Sstevel@tonic-gate */
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate static int select_link = 0; /* automatic selection */
4747c478bd9Sstevel@tonic-gate static int default_link = 0; /* Select Serial link if both are up */
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate * The following variables are used for configuring link-operation
4787c478bd9Sstevel@tonic-gate * for all the "eri" interfaces in the system.
4797c478bd9Sstevel@tonic-gate * Later these parameters may be changed per interface using "ndd" command
4807c478bd9Sstevel@tonic-gate * These parameters may also be specified as properties using the .conf
4817c478bd9Sstevel@tonic-gate * file mechanism for each interface.
4827c478bd9Sstevel@tonic-gate */
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate * The following variable value will be overridden by "link-pulse-disabled"
4867c478bd9Sstevel@tonic-gate * property which may be created by OBP or eri.conf file. This property is
4877c478bd9Sstevel@tonic-gate * applicable only for 10 Mbps links.
4887c478bd9Sstevel@tonic-gate */
4897c478bd9Sstevel@tonic-gate static int link_pulse_disabled = 0; /* link pulse disabled */
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate /* For MII-based FastEthernet links */
4927c478bd9Sstevel@tonic-gate static int adv_autoneg_cap = 1;
4937c478bd9Sstevel@tonic-gate static int adv_100T4_cap = 0;
4947c478bd9Sstevel@tonic-gate static int adv_100fdx_cap = 1;
4957c478bd9Sstevel@tonic-gate static int adv_100hdx_cap = 1;
4967c478bd9Sstevel@tonic-gate static int adv_10fdx_cap = 1;
4977c478bd9Sstevel@tonic-gate static int adv_10hdx_cap = 1;
4987c478bd9Sstevel@tonic-gate static int adv_pauseTX_cap = 0;
4997c478bd9Sstevel@tonic-gate static int adv_pauseRX_cap = 0;
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate * The following gap parameters are in terms of byte times.
5037c478bd9Sstevel@tonic-gate */
5047c478bd9Sstevel@tonic-gate static int ipg0 = 8;
5057c478bd9Sstevel@tonic-gate static int ipg1 = 8;
5067c478bd9Sstevel@tonic-gate static int ipg2 = 4;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate static int lance_mode = 1; /* to enable LANCE mode */
5097c478bd9Sstevel@tonic-gate static int mifpoll_enable = 0; /* to enable mif poll */
5107c478bd9Sstevel@tonic-gate static int ngu_enable = 0; /* to enable Never Give Up mode */
5117c478bd9Sstevel@tonic-gate
512*7e996435SToomas Soome static int eri_force_mlf = 0; /* to enable mif poll */
5137c478bd9Sstevel@tonic-gate static int eri_phy_mintrans = 1; /* Lu3X31T mintrans algorithm */
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate * For the MII interface, the External Transceiver is selected when present.
5167c478bd9Sstevel@tonic-gate * The following variable is used to select the Internal Transceiver even
5177c478bd9Sstevel@tonic-gate * when the External Transceiver is present.
5187c478bd9Sstevel@tonic-gate */
5197c478bd9Sstevel@tonic-gate static int use_int_xcvr = 0;
5207c478bd9Sstevel@tonic-gate static int pace_size = 0; /* Do not use pacing for now */
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate static int eri_use_dvma_rx = 0; /* =1:use dvma */
5237c478bd9Sstevel@tonic-gate static int eri_rx_bcopy_max = RX_BCOPY_MAX; /* =1:use bcopy() */
5247c478bd9Sstevel@tonic-gate static int eri_overflow_reset = 1; /* global reset if rx_fifo_overflow */
5257c478bd9Sstevel@tonic-gate static int eri_tx_ring_size = 2048; /* number of entries in tx ring */
5267c478bd9Sstevel@tonic-gate static int eri_rx_ring_size = 1024; /* number of entries in rx ring */
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate * The following parameters may be configured by the user. If they are not
5297c478bd9Sstevel@tonic-gate * configured by the user, the values will be based on the capabilities of
5307c478bd9Sstevel@tonic-gate * the transceiver.
5317c478bd9Sstevel@tonic-gate * The value "ERI_NOTUSR" is ORed with the parameter value to indicate values
5327c478bd9Sstevel@tonic-gate * which are NOT configured by the user.
5337c478bd9Sstevel@tonic-gate */
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate #define ERI_NOTUSR 0x0f000000
5367c478bd9Sstevel@tonic-gate #define ERI_MASK_1BIT 0x1
5377c478bd9Sstevel@tonic-gate #define ERI_MASK_2BIT 0x3
5387c478bd9Sstevel@tonic-gate #define ERI_MASK_8BIT 0xff
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate * Note:
5437c478bd9Sstevel@tonic-gate * ERI has all of the above capabilities.
5447c478bd9Sstevel@tonic-gate * Only when an External Transceiver is selected for MII-based FastEthernet
5457c478bd9Sstevel@tonic-gate * link operation, the capabilities depend upon the capabilities of the
5467c478bd9Sstevel@tonic-gate * External Transceiver.
5477c478bd9Sstevel@tonic-gate */
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------- */
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate static param_t param_arr[] = {
552d64540e3Sgd /* min max value r/w/hidden+name */
553d64540e3Sgd { 0, 2, 2, "-transceiver_inuse"},
554d64540e3Sgd { 0, 1, 0, "-link_status"},
555d64540e3Sgd { 0, 1, 0, "-link_speed"},
556d64540e3Sgd { 0, 1, 0, "-link_mode"},
557d64540e3Sgd { 0, 255, 8, "+ipg1"},
558d64540e3Sgd { 0, 255, 4, "+ipg2"},
559d64540e3Sgd { 0, 1, 0, "+use_int_xcvr"},
560d64540e3Sgd { 0, 255, 0, "+pace_size"},
561d64540e3Sgd { 0, 1, 1, "+adv_autoneg_cap"},
562d64540e3Sgd { 0, 1, 1, "+adv_100T4_cap"},
563d64540e3Sgd { 0, 1, 1, "+adv_100fdx_cap"},
564d64540e3Sgd { 0, 1, 1, "+adv_100hdx_cap"},
565d64540e3Sgd { 0, 1, 1, "+adv_10fdx_cap"},
566d64540e3Sgd { 0, 1, 1, "+adv_10hdx_cap"},
567d64540e3Sgd { 0, 1, 1, "-autoneg_cap"},
568d64540e3Sgd { 0, 1, 1, "-100T4_cap"},
569d64540e3Sgd { 0, 1, 1, "-100fdx_cap"},
570d64540e3Sgd { 0, 1, 1, "-100hdx_cap"},
571d64540e3Sgd { 0, 1, 1, "-10fdx_cap"},
572d64540e3Sgd { 0, 1, 1, "-10hdx_cap"},
573d64540e3Sgd { 0, 1, 0, "-lp_autoneg_cap"},
574d64540e3Sgd { 0, 1, 0, "-lp_100T4_cap"},
575d64540e3Sgd { 0, 1, 0, "-lp_100fdx_cap"},
576d64540e3Sgd { 0, 1, 0, "-lp_100hdx_cap"},
577d64540e3Sgd { 0, 1, 0, "-lp_10fdx_cap"},
578d64540e3Sgd { 0, 1, 0, "-lp_10hdx_cap"},
579d64540e3Sgd { 0, 1, 1, "+lance_mode"},
580d64540e3Sgd { 0, 31, 8, "+ipg0"},
581d64540e3Sgd { 0, 127, 6, "+intr_blank_time"},
582d64540e3Sgd { 0, 255, 8, "+intr_blank_packets"},
583d64540e3Sgd { 0, 1, 1, "!serial-link"},
584d64540e3Sgd { 0, 2, 1, "!non-serial-link"},
585d64540e3Sgd { 0, 1, 0, "%select-link"},
586d64540e3Sgd { 0, 1, 0, "%default-link"},
587d64540e3Sgd { 0, 2, 0, "!link-in-use"},
588d64540e3Sgd { 0, 1, 1, "%adv_asm_dir_cap"},
589d64540e3Sgd { 0, 1, 1, "%adv_pause_cap"},
590d64540e3Sgd { 0, 1, 0, "!asm_dir_cap"},
591d64540e3Sgd { 0, 1, 0, "!pause_cap"},
592d64540e3Sgd { 0, 1, 0, "!lp_asm_dir_cap"},
593d64540e3Sgd { 0, 1, 0, "!lp_pause_cap"},
5947c478bd9Sstevel@tonic-gate };
5957c478bd9Sstevel@tonic-gate
596d64540e3Sgd DDI_DEFINE_STREAM_OPS(eri_dev_ops, nulldev, nulldev, eri_attach, eri_detach,
597*7e996435SToomas Soome nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported);
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate * This is the loadable module wrapper.
6017c478bd9Sstevel@tonic-gate */
6027c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
6067c478bd9Sstevel@tonic-gate */
6077c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
6087c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
609d64540e3Sgd "Sun RIO 10/100 Mb Ethernet",
610d64540e3Sgd &eri_dev_ops, /* driver ops */
6117c478bd9Sstevel@tonic-gate };
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
6147c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL
6157c478bd9Sstevel@tonic-gate };
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate * Hardware Independent Functions
6197c478bd9Sstevel@tonic-gate * New Section
6207c478bd9Sstevel@tonic-gate */
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate int
_init(void)6237c478bd9Sstevel@tonic-gate _init(void)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate int status;
6267c478bd9Sstevel@tonic-gate
627d64540e3Sgd mac_init_ops(&eri_dev_ops, "eri");
628d64540e3Sgd if ((status = mod_install(&modlinkage)) != 0) {
629d64540e3Sgd mac_fini_ops(&eri_dev_ops);
630d64540e3Sgd }
6317c478bd9Sstevel@tonic-gate return (status);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate int
_fini(void)6357c478bd9Sstevel@tonic-gate _fini(void)
6367c478bd9Sstevel@tonic-gate {
637d64540e3Sgd int status;
6387c478bd9Sstevel@tonic-gate
6397c478bd9Sstevel@tonic-gate status = mod_remove(&modlinkage);
640d64540e3Sgd if (status == 0) {
641d64540e3Sgd mac_fini_ops(&eri_dev_ops);
642d64540e3Sgd }
6437c478bd9Sstevel@tonic-gate return (status);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)6477c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
6487c478bd9Sstevel@tonic-gate {
649d64540e3Sgd return (mod_info(&modlinkage, modinfop));
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate * Interface exists: make available by filling in network interface
6557c478bd9Sstevel@tonic-gate * record. System will initialize the interface when it is ready
6567c478bd9Sstevel@tonic-gate * to accept packets.
6577c478bd9Sstevel@tonic-gate */
6587c478bd9Sstevel@tonic-gate static int
eri_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6597c478bd9Sstevel@tonic-gate eri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6607c478bd9Sstevel@tonic-gate {
661d64540e3Sgd struct eri *erip = NULL;
662d64540e3Sgd mac_register_t *macp = NULL;
6637c478bd9Sstevel@tonic-gate int regno;
664d64540e3Sgd boolean_t doinit;
665d64540e3Sgd boolean_t mutex_inited = B_FALSE;
666d64540e3Sgd boolean_t intr_add = B_FALSE;
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate switch (cmd) {
6697c478bd9Sstevel@tonic-gate case DDI_ATTACH:
6707c478bd9Sstevel@tonic-gate break;
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate case DDI_RESUME:
6737c478bd9Sstevel@tonic-gate if ((erip = ddi_get_driver_private(dip)) == NULL)
6747c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6757c478bd9Sstevel@tonic-gate
676d64540e3Sgd mutex_enter(&erip->intrlock);
6777c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_SUSPENDED;
6787c478bd9Sstevel@tonic-gate erip->init_macregs = 1;
6797c478bd9Sstevel@tonic-gate param_linkup = 0;
680d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
6817c478bd9Sstevel@tonic-gate erip->linkcheck = 0;
6827c478bd9Sstevel@tonic-gate
683d64540e3Sgd doinit = (erip->flags & ERI_STARTED) ? B_TRUE : B_FALSE;
684d64540e3Sgd mutex_exit(&erip->intrlock);
685d64540e3Sgd
686d64540e3Sgd if (doinit && !eri_init(erip)) {
687d64540e3Sgd return (DDI_FAILURE);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate default:
6927c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate /*
6967c478bd9Sstevel@tonic-gate * Allocate soft device data structure
6977c478bd9Sstevel@tonic-gate */
698d64540e3Sgd erip = kmem_zalloc(sizeof (struct eri), KM_SLEEP);
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate /*
7017c478bd9Sstevel@tonic-gate * Initialize as many elements as possible.
7027c478bd9Sstevel@tonic-gate */
7037c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, erip);
7047c478bd9Sstevel@tonic-gate erip->dip = dip; /* dip */
7057c478bd9Sstevel@tonic-gate erip->instance = ddi_get_instance(dip); /* instance */
7067c478bd9Sstevel@tonic-gate erip->flags = 0;
707d64540e3Sgd erip->multi_refcnt = 0;
708d64540e3Sgd erip->promisc = B_FALSE;
709d64540e3Sgd
710d64540e3Sgd if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
711d64540e3Sgd ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
712d64540e3Sgd "mac_alloc failed");
713d64540e3Sgd goto attach_fail;
714d64540e3Sgd }
715d64540e3Sgd macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
716d64540e3Sgd macp->m_driver = erip;
717d64540e3Sgd macp->m_dip = dip;
718d64540e3Sgd macp->m_src_addr = erip->ouraddr;
719d64540e3Sgd macp->m_callbacks = &eri_m_callbacks;
720d64540e3Sgd macp->m_min_sdu = 0;
721d64540e3Sgd macp->m_max_sdu = ETHERMTU;
722d62bc4baSyz macp->m_margin = VLAN_TAGSZ;
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate /*
7257c478bd9Sstevel@tonic-gate * Map in the device registers.
7267c478bd9Sstevel@tonic-gate * Separate pointers will be set up for the following
7277c478bd9Sstevel@tonic-gate * register groups within the GEM Register Space:
728*7e996435SToomas Soome * Global register set
729*7e996435SToomas Soome * ETX register set
730*7e996435SToomas Soome * ERX register set
731*7e996435SToomas Soome * BigMAC register set.
732*7e996435SToomas Soome * MIF register set
7337c478bd9Sstevel@tonic-gate */
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) {
7367c478bd9Sstevel@tonic-gate ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
737d64540e3Sgd "ddi_dev_nregs failed, returned %d", regno);
7387c478bd9Sstevel@tonic-gate goto attach_fail;
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate /*
7427c478bd9Sstevel@tonic-gate * Map the PCI config space
7437c478bd9Sstevel@tonic-gate */
744d64540e3Sgd if (pci_config_setup(dip, &erip->pci_config_handle) != DDI_SUCCESS) {
7457c478bd9Sstevel@tonic-gate ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
746d64540e3Sgd "%s pci_config_setup()", config_space_fatal_msg);
7477c478bd9Sstevel@tonic-gate goto attach_fail;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate /*
7517c478bd9Sstevel@tonic-gate * Initialize device attributes structure
7527c478bd9Sstevel@tonic-gate */
7537c478bd9Sstevel@tonic-gate erip->dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
7547c478bd9Sstevel@tonic-gate erip->dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
7557c478bd9Sstevel@tonic-gate erip->dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
7567c478bd9Sstevel@tonic-gate
757d64540e3Sgd if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->globregp), 0, 0,
758d64540e3Sgd &erip->dev_attr, &erip->globregh)) {
759d64540e3Sgd goto attach_fail;
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate erip->etxregh = erip->globregh;
7627c478bd9Sstevel@tonic-gate erip->erxregh = erip->globregh;
7637c478bd9Sstevel@tonic-gate erip->bmacregh = erip->globregh;
7647c478bd9Sstevel@tonic-gate erip->mifregh = erip->globregh;
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate erip->etxregp = (void *)(((caddr_t)erip->globregp) + 0x2000);
7677c478bd9Sstevel@tonic-gate erip->erxregp = (void *)(((caddr_t)erip->globregp) + 0x4000);
7687c478bd9Sstevel@tonic-gate erip->bmacregp = (void *)(((caddr_t)erip->globregp) + 0x6000);
7697c478bd9Sstevel@tonic-gate erip->mifregp = (void *)(((caddr_t)erip->globregp) + 0x6200);
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate * Map the software reset register.
7737c478bd9Sstevel@tonic-gate */
774d64540e3Sgd if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->sw_reset_reg),
775d64540e3Sgd 0x1010, 4, &erip->dev_attr, &erip->sw_reset_regh)) {
7767c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG,
777d64540e3Sgd mregs_4soft_reset_fail_msg);
778d64540e3Sgd goto attach_fail;
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate /*
7827c478bd9Sstevel@tonic-gate * Try and stop the device.
7837c478bd9Sstevel@tonic-gate * This is done until we want to handle interrupts.
7847c478bd9Sstevel@tonic-gate */
7857c478bd9Sstevel@tonic-gate if (eri_stop(erip))
7867c478bd9Sstevel@tonic-gate goto attach_fail;
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate * set PCI latency timer register.
7907c478bd9Sstevel@tonic-gate */
7917c478bd9Sstevel@tonic-gate pci_config_put8(erip->pci_config_handle, PCI_CONF_LATENCY_TIMER,
792d64540e3Sgd (uchar_t)eri_pci_latency_timer);
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) {
7957c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
7967c478bd9Sstevel@tonic-gate " high-level interrupts are not supported");
7977c478bd9Sstevel@tonic-gate goto attach_fail;
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate * Get the interrupt cookie so the mutexes can be
8027c478bd9Sstevel@tonic-gate * Initialized.
8037c478bd9Sstevel@tonic-gate */
8047c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &erip->cookie) != DDI_SUCCESS)
8057c478bd9Sstevel@tonic-gate goto attach_fail;
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate * Initialize mutex's for this device.
8097c478bd9Sstevel@tonic-gate */
8107c478bd9Sstevel@tonic-gate mutex_init(&erip->xmitlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8117c478bd9Sstevel@tonic-gate mutex_init(&erip->intrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8127c478bd9Sstevel@tonic-gate mutex_init(&erip->linklock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8137c478bd9Sstevel@tonic-gate mutex_init(&erip->xcvrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8147c478bd9Sstevel@tonic-gate
815d64540e3Sgd mutex_inited = B_TRUE;
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate /*
8187c478bd9Sstevel@tonic-gate * Add interrupt to system
8197c478bd9Sstevel@tonic-gate */
820d64540e3Sgd if (ddi_add_intr(dip, 0, &erip->cookie, 0, eri_intr, (caddr_t)erip) ==
821d64540e3Sgd DDI_SUCCESS)
822d64540e3Sgd intr_add = B_TRUE;
8237c478bd9Sstevel@tonic-gate else {
8247c478bd9Sstevel@tonic-gate goto attach_fail;
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * Set up the ethernet mac address.
8297c478bd9Sstevel@tonic-gate */
8307c478bd9Sstevel@tonic-gate (void) eri_setup_mac_address(erip, dip);
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate if (eri_init_xfer_params(erip))
8337c478bd9Sstevel@tonic-gate goto attach_fail;
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate if (eri_burstsize(erip) == DDI_FAILURE) {
8367c478bd9Sstevel@tonic-gate goto attach_fail;
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate /*
8407c478bd9Sstevel@tonic-gate * Setup fewer receive bufers.
8417c478bd9Sstevel@tonic-gate */
8427c478bd9Sstevel@tonic-gate ERI_RPENDING = eri_rx_ring_size;
8437c478bd9Sstevel@tonic-gate ERI_TPENDING = eri_tx_ring_size;
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate erip->rpending_mask = ERI_RPENDING - 1;
8467c478bd9Sstevel@tonic-gate erip->rmdmax_mask = ERI_RPENDING - 1;
8477c478bd9Sstevel@tonic-gate erip->mif_config = (ERI_PHY_BMSR << ERI_MIF_CFGPR_SHIFT);
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate erip->stats.pmcap = ERI_PMCAP_NONE;
8507c478bd9Sstevel@tonic-gate if (pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000) ==
851d64540e3Sgd DDI_SUCCESS)
8527c478bd9Sstevel@tonic-gate erip->stats.pmcap = ERI_PMCAP_4MHZ;
8537c478bd9Sstevel@tonic-gate
854d64540e3Sgd if (mac_register(macp, &erip->mh) != 0)
855d64540e3Sgd goto attach_fail;
8567c478bd9Sstevel@tonic-gate
857d64540e3Sgd mac_free(macp);
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate attach_fail:
8627c478bd9Sstevel@tonic-gate if (erip->pci_config_handle)
8637c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&erip->pci_config_handle);
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate if (mutex_inited) {
8667c478bd9Sstevel@tonic-gate mutex_destroy(&erip->xmitlock);
8677c478bd9Sstevel@tonic-gate mutex_destroy(&erip->intrlock);
8687c478bd9Sstevel@tonic-gate mutex_destroy(&erip->linklock);
8697c478bd9Sstevel@tonic-gate mutex_destroy(&erip->xcvrlock);
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate
872d64540e3Sgd ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, attach_fail_msg);
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate if (intr_add)
8757c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, erip->cookie);
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate if (erip->globregh)
8787c478bd9Sstevel@tonic-gate ddi_regs_map_free(&erip->globregh);
8797c478bd9Sstevel@tonic-gate
880d64540e3Sgd if (macp != NULL)
881d64540e3Sgd mac_free(macp);
882d64540e3Sgd if (erip != NULL)
883d64540e3Sgd kmem_free(erip, sizeof (*erip));
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate static int
eri_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)8897c478bd9Sstevel@tonic-gate eri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8907c478bd9Sstevel@tonic-gate {
891*7e996435SToomas Soome struct eri *erip;
8927c478bd9Sstevel@tonic-gate int i;
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate if ((erip = ddi_get_driver_private(dip)) == NULL) {
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate * No resources allocated.
8977c478bd9Sstevel@tonic-gate */
8987c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate switch (cmd) {
9027c478bd9Sstevel@tonic-gate case DDI_DETACH:
9037c478bd9Sstevel@tonic-gate break;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate case DDI_SUSPEND:
9067c478bd9Sstevel@tonic-gate erip->flags |= ERI_SUSPENDED;
9077c478bd9Sstevel@tonic-gate eri_uninit(erip);
9087c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
9097c478bd9Sstevel@tonic-gate
9107c478bd9Sstevel@tonic-gate default:
9117c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate if (erip->flags & (ERI_RUNNING | ERI_SUSPENDED)) {
9157c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, busy_msg);
9167c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
919d64540e3Sgd if (mac_unregister(erip->mh) != 0) {
920d64540e3Sgd return (DDI_FAILURE);
921d64540e3Sgd }
922d64540e3Sgd
9237c478bd9Sstevel@tonic-gate /*
9247c478bd9Sstevel@tonic-gate * Make the device quiescent
9257c478bd9Sstevel@tonic-gate */
9267c478bd9Sstevel@tonic-gate (void) eri_stop(erip);
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate /*
9297c478bd9Sstevel@tonic-gate * Remove instance of the intr
9307c478bd9Sstevel@tonic-gate */
9317c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, erip->cookie);
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate if (erip->pci_config_handle)
9347c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&erip->pci_config_handle);
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate * Destroy all mutexes and data structures allocated during
9387c478bd9Sstevel@tonic-gate * attach time.
9397c478bd9Sstevel@tonic-gate */
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate if (erip->globregh)
9427c478bd9Sstevel@tonic-gate ddi_regs_map_free(&erip->globregh);
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate erip->etxregh = NULL;
9457c478bd9Sstevel@tonic-gate erip->erxregh = NULL;
9467c478bd9Sstevel@tonic-gate erip->bmacregh = NULL;
9477c478bd9Sstevel@tonic-gate erip->mifregh = NULL;
9487c478bd9Sstevel@tonic-gate erip->globregh = NULL;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate if (erip->sw_reset_regh)
9517c478bd9Sstevel@tonic-gate ddi_regs_map_free(&erip->sw_reset_regh);
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate if (erip->ksp)
9547c478bd9Sstevel@tonic-gate kstat_delete(erip->ksp);
9557c478bd9Sstevel@tonic-gate
9567c478bd9Sstevel@tonic-gate eri_stop_timer(erip); /* acquire linklock */
9577c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, 0);
9587c478bd9Sstevel@tonic-gate mutex_destroy(&erip->xmitlock);
9597c478bd9Sstevel@tonic-gate mutex_destroy(&erip->intrlock);
9607c478bd9Sstevel@tonic-gate mutex_destroy(&erip->linklock);
9617c478bd9Sstevel@tonic-gate mutex_destroy(&erip->xcvrlock);
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate if (erip->md_h) {
9647c478bd9Sstevel@tonic-gate if (ddi_dma_unbind_handle(erip->md_h) ==
9657c478bd9Sstevel@tonic-gate DDI_FAILURE)
9667c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
9677c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&erip->mdm_h);
9687c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&erip->md_h);
9697c478bd9Sstevel@tonic-gate }
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate if (eri_freebufs(erip))
9727c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate /* dvma handle case */
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate if (erip->eri_dvmarh) {
9777c478bd9Sstevel@tonic-gate (void) dvma_release(erip->eri_dvmarh);
9787c478bd9Sstevel@tonic-gate erip->eri_dvmarh = NULL;
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate /*
9817c478bd9Sstevel@tonic-gate * xmit_dma_mode, erip->ndmaxh[i]=NULL for dvma
9827c478bd9Sstevel@tonic-gate */
9837c478bd9Sstevel@tonic-gate else {
9847c478bd9Sstevel@tonic-gate for (i = 0; i < ERI_RPENDING; i++)
9857c478bd9Sstevel@tonic-gate if (erip->ndmarh[i])
9867c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&erip->ndmarh[i]);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate /*
989bd78278bSGarrett D'Amore * Release TX buffer
9907c478bd9Sstevel@tonic-gate */
9917c478bd9Sstevel@tonic-gate if (erip->tbuf_ioaddr != 0) {
9927c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(erip->tbuf_handle);
9937c478bd9Sstevel@tonic-gate erip->tbuf_ioaddr = 0;
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate if (erip->tbuf_kaddr != NULL) {
996bd78278bSGarrett D'Amore ddi_dma_mem_free(&erip->tbuf_acch);
9977c478bd9Sstevel@tonic-gate erip->tbuf_kaddr = NULL;
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate if (erip->tbuf_handle != NULL) {
10007c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&erip->tbuf_handle);
10017c478bd9Sstevel@tonic-gate erip->tbuf_handle = NULL;
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate eri_param_cleanup(erip);
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, NULL);
10077c478bd9Sstevel@tonic-gate kmem_free((caddr_t)erip, sizeof (struct eri));
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate /*
10137c478bd9Sstevel@tonic-gate * To set up the mac address for the network interface:
10147c478bd9Sstevel@tonic-gate * The adapter card may support a local mac address which is published
10157c478bd9Sstevel@tonic-gate * in a device node property "local-mac-address". This mac address is
10167c478bd9Sstevel@tonic-gate * treated as the factory-installed mac address for DLPI interface.
10177c478bd9Sstevel@tonic-gate * If the adapter firmware has used the device for diskless boot
10187c478bd9Sstevel@tonic-gate * operation it publishes a property called "mac-address" for use by
10197c478bd9Sstevel@tonic-gate * inetboot and the device driver.
10207c478bd9Sstevel@tonic-gate * If "mac-address" is not found, the system options property
10217c478bd9Sstevel@tonic-gate * "local-mac-address" is used to select the mac-address. If this option
10227c478bd9Sstevel@tonic-gate * is set to "true", and "local-mac-address" has been found, then
10237c478bd9Sstevel@tonic-gate * local-mac-address is used; otherwise the system mac address is used
10247c478bd9Sstevel@tonic-gate * by calling the "localetheraddr()" function.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate static void
eri_setup_mac_address(struct eri * erip,dev_info_t * dip)10287c478bd9Sstevel@tonic-gate eri_setup_mac_address(struct eri *erip, dev_info_t *dip)
10297c478bd9Sstevel@tonic-gate {
1030d64540e3Sgd uchar_t *prop;
1031d64540e3Sgd char *uselocal;
1032d64540e3Sgd unsigned prop_len;
1033d64540e3Sgd uint32_t addrflags = 0;
1034d64540e3Sgd struct ether_addr factaddr;
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate * Check if it is an adapter with its own local mac address
10387c478bd9Sstevel@tonic-gate * If it is present, save it as the "factory-address"
10397c478bd9Sstevel@tonic-gate * for this adapter.
10407c478bd9Sstevel@tonic-gate */
1041d64540e3Sgd if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1042d64540e3Sgd "local-mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) {
10437c478bd9Sstevel@tonic-gate if (prop_len == ETHERADDRL) {
1044d64540e3Sgd addrflags = ERI_FACTADDR_PRESENT;
1045d64540e3Sgd bcopy(prop, &factaddr, ETHERADDRL);
10467c478bd9Sstevel@tonic-gate ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG,
1047d64540e3Sgd lether_addr_msg, ether_sprintf(&factaddr));
10487c478bd9Sstevel@tonic-gate }
1049d64540e3Sgd ddi_prop_free(prop);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate * Check if the adapter has published "mac-address" property.
10537c478bd9Sstevel@tonic-gate * If it is present, use it as the mac address for this device.
10547c478bd9Sstevel@tonic-gate */
1055d64540e3Sgd if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1056d64540e3Sgd "mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) {
10577c478bd9Sstevel@tonic-gate if (prop_len >= ETHERADDRL) {
1058d64540e3Sgd bcopy(prop, erip->ouraddr, ETHERADDRL);
10594c27844fSgd ddi_prop_free(prop);
10607c478bd9Sstevel@tonic-gate return;
10617c478bd9Sstevel@tonic-gate }
1062d64540e3Sgd ddi_prop_free(prop);
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate
1065d64540e3Sgd if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "local-mac-address?",
1066d64540e3Sgd &uselocal) == DDI_PROP_SUCCESS) {
1067d64540e3Sgd if ((strcmp("true", uselocal) == 0) &&
1068d64540e3Sgd (addrflags & ERI_FACTADDR_PRESENT)) {
1069d64540e3Sgd addrflags |= ERI_FACTADDR_USE;
1070d64540e3Sgd bcopy(&factaddr, erip->ouraddr, ETHERADDRL);
1071d64540e3Sgd ddi_prop_free(uselocal);
10727c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
1073d64540e3Sgd lmac_addr_msg);
10747c478bd9Sstevel@tonic-gate return;
10757c478bd9Sstevel@tonic-gate }
1076d64540e3Sgd ddi_prop_free(uselocal);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate * Get the system ethernet address.
10817c478bd9Sstevel@tonic-gate */
1082d64540e3Sgd (void) localetheraddr(NULL, &factaddr);
1083d64540e3Sgd bcopy(&factaddr, erip->ouraddr, ETHERADDRL);
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate * Calculate the bit in the multicast address filter that selects the given
10897c478bd9Sstevel@tonic-gate * address.
10907c478bd9Sstevel@tonic-gate * Note: For ERI, the last 8-bits are used.
10917c478bd9Sstevel@tonic-gate */
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate static uint32_t
eri_ladrf_bit(const uint8_t * addr)1094d64540e3Sgd eri_ladrf_bit(const uint8_t *addr)
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate uint32_t crc;
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate * Just want the 8 most significant bits.
11027c478bd9Sstevel@tonic-gate */
11037c478bd9Sstevel@tonic-gate return ((~crc) >> 24);
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate static void
eri_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)1107d64540e3Sgd eri_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
11087c478bd9Sstevel@tonic-gate {
1109d64540e3Sgd struct eri *erip = arg;
1110d64540e3Sgd struct iocblk *iocp = (void *)mp->b_rptr;
1111d64540e3Sgd int err;
11127c478bd9Sstevel@tonic-gate
1113d64540e3Sgd ASSERT(erip != NULL);
11147c478bd9Sstevel@tonic-gate
1115d64540e3Sgd /*
1116d64540e3Sgd * Privilege checks.
1117d64540e3Sgd */
1118d64540e3Sgd switch (iocp->ioc_cmd) {
1119d64540e3Sgd case ERI_SET_LOOP_MODE:
1120d64540e3Sgd case ERI_ND_SET:
1121d64540e3Sgd err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1122d64540e3Sgd if (err != 0) {
1123d64540e3Sgd miocnak(wq, mp, 0, err);
1124d64540e3Sgd return;
1125d64540e3Sgd }
11267c478bd9Sstevel@tonic-gate break;
1127d64540e3Sgd default:
11287c478bd9Sstevel@tonic-gate break;
1129d64540e3Sgd }
11307c478bd9Sstevel@tonic-gate
1131d64540e3Sgd switch (iocp->ioc_cmd) {
1132d64540e3Sgd case ERI_ND_GET:
1133d64540e3Sgd case ERI_ND_SET:
1134d64540e3Sgd eri_process_ndd_ioctl(erip, wq, mp, iocp->ioc_cmd);
11357c478bd9Sstevel@tonic-gate break;
11367c478bd9Sstevel@tonic-gate
1137d64540e3Sgd case ERI_SET_LOOP_MODE:
1138d64540e3Sgd case ERI_GET_LOOP_MODE:
1139d64540e3Sgd /*
1140d64540e3Sgd * XXX: Consider updating this to the new netlb ioctls.
1141d64540e3Sgd */
1142d64540e3Sgd eri_loopback(erip, wq, mp);
11437c478bd9Sstevel@tonic-gate break;
11447c478bd9Sstevel@tonic-gate
1145d64540e3Sgd default:
1146d64540e3Sgd miocnak(wq, mp, 0, EINVAL);
11477c478bd9Sstevel@tonic-gate break;
1148d64540e3Sgd }
11497c478bd9Sstevel@tonic-gate
1150d64540e3Sgd ASSERT(!MUTEX_HELD(&erip->linklock));
1151d64540e3Sgd }
11527c478bd9Sstevel@tonic-gate
1153d64540e3Sgd static void
eri_loopback(struct eri * erip,queue_t * wq,mblk_t * mp)1154d64540e3Sgd eri_loopback(struct eri *erip, queue_t *wq, mblk_t *mp)
1155d64540e3Sgd {
1156d64540e3Sgd struct iocblk *iocp = (void *)mp->b_rptr;
1157d64540e3Sgd loopback_t *al;
11587c478bd9Sstevel@tonic-gate
1159d64540e3Sgd if (mp->b_cont == NULL || MBLKL(mp->b_cont) < sizeof (loopback_t)) {
1160d64540e3Sgd miocnak(wq, mp, 0, EINVAL);
1161d64540e3Sgd return;
1162d64540e3Sgd }
11637c478bd9Sstevel@tonic-gate
1164d64540e3Sgd al = (void *)mp->b_cont->b_rptr;
11657c478bd9Sstevel@tonic-gate
1166d64540e3Sgd switch (iocp->ioc_cmd) {
1167d64540e3Sgd case ERI_SET_LOOP_MODE:
1168d64540e3Sgd switch (al->loopback) {
1169d64540e3Sgd case ERI_LOOPBACK_OFF:
1170d64540e3Sgd erip->flags &= (~ERI_MACLOOPBACK & ~ERI_SERLOOPBACK);
1171d64540e3Sgd /* force link status to go down */
1172d64540e3Sgd param_linkup = 0;
1173d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
1174d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1175d64540e3Sgd (void) eri_init(erip);
1176d64540e3Sgd break;
11777c478bd9Sstevel@tonic-gate
1178d64540e3Sgd case ERI_MAC_LOOPBACK_ON:
1179d64540e3Sgd erip->flags |= ERI_MACLOOPBACK;
1180d64540e3Sgd erip->flags &= ~ERI_SERLOOPBACK;
1181d64540e3Sgd param_linkup = 0;
1182d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
1183d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1184d64540e3Sgd (void) eri_init(erip);
1185d64540e3Sgd break;
11867c478bd9Sstevel@tonic-gate
1187d64540e3Sgd case ERI_PCS_LOOPBACK_ON:
1188d64540e3Sgd break;
1189d64540e3Sgd
1190d64540e3Sgd case ERI_SER_LOOPBACK_ON:
1191d64540e3Sgd erip->flags |= ERI_SERLOOPBACK;
1192d64540e3Sgd erip->flags &= ~ERI_MACLOOPBACK;
1193d64540e3Sgd /* force link status to go down */
1194d64540e3Sgd param_linkup = 0;
1195d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
1196d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1197d64540e3Sgd (void) eri_init(erip);
1198d64540e3Sgd break;
11997c478bd9Sstevel@tonic-gate
1200d64540e3Sgd default:
1201d64540e3Sgd ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
1202d64540e3Sgd loopback_val_default);
1203d64540e3Sgd miocnak(wq, mp, 0, EINVAL);
1204d64540e3Sgd return;
1205d64540e3Sgd }
1206d64540e3Sgd miocnak(wq, mp, 0, 0);
12077c478bd9Sstevel@tonic-gate break;
12087c478bd9Sstevel@tonic-gate
1209d64540e3Sgd case ERI_GET_LOOP_MODE:
1210d64540e3Sgd al->loopback = ERI_MAC_LOOPBACK_ON | ERI_PCS_LOOPBACK_ON |
1211d64540e3Sgd ERI_SER_LOOPBACK_ON;
1212d64540e3Sgd miocack(wq, mp, sizeof (loopback_t), 0);
12137c478bd9Sstevel@tonic-gate break;
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate default:
1216d64540e3Sgd ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1217d64540e3Sgd loopback_cmd_default);
12187c478bd9Sstevel@tonic-gate }
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate
12217c478bd9Sstevel@tonic-gate static int
eri_m_promisc(void * arg,boolean_t on)1222d64540e3Sgd eri_m_promisc(void *arg, boolean_t on)
12237c478bd9Sstevel@tonic-gate {
1224d64540e3Sgd struct eri *erip = arg;
12257c478bd9Sstevel@tonic-gate
1226d64540e3Sgd mutex_enter(&erip->intrlock);
1227d64540e3Sgd erip->promisc = on;
1228d64540e3Sgd eri_init_rx(erip);
1229d64540e3Sgd mutex_exit(&erip->intrlock);
1230d64540e3Sgd return (0);
1231d64540e3Sgd }
12327c478bd9Sstevel@tonic-gate
1233d64540e3Sgd /*
1234d64540e3Sgd * This is to support unlimited number of members
1235d64540e3Sgd * in Multicast.
1236d64540e3Sgd */
1237d64540e3Sgd static int
eri_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1238d64540e3Sgd eri_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1239d64540e3Sgd {
1240d64540e3Sgd struct eri *erip = arg;
1241*7e996435SToomas Soome uint32_t ladrf_bit;
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate /*
1244d64540e3Sgd * If this address's bit was not already set in the local address
1245d64540e3Sgd * filter, add it and re-initialize the Hardware.
12467c478bd9Sstevel@tonic-gate */
1247d64540e3Sgd ladrf_bit = eri_ladrf_bit(mca);
12487c478bd9Sstevel@tonic-gate
1249d64540e3Sgd mutex_enter(&erip->intrlock);
1250d64540e3Sgd if (add) {
1251d64540e3Sgd erip->ladrf_refcnt[ladrf_bit]++;
1252d64540e3Sgd if (erip->ladrf_refcnt[ladrf_bit] == 1) {
1253d64540e3Sgd LADRF_SET(erip, ladrf_bit);
1254d64540e3Sgd erip->multi_refcnt++;
1255d64540e3Sgd eri_init_rx(erip);
1256d64540e3Sgd }
1257d64540e3Sgd } else {
1258d64540e3Sgd erip->ladrf_refcnt[ladrf_bit]--;
1259d64540e3Sgd if (erip->ladrf_refcnt[ladrf_bit] == 0) {
1260d64540e3Sgd LADRF_CLR(erip, ladrf_bit);
1261d64540e3Sgd erip->multi_refcnt--;
12627c478bd9Sstevel@tonic-gate eri_init_rx(erip);
12637c478bd9Sstevel@tonic-gate }
12647c478bd9Sstevel@tonic-gate }
1265d64540e3Sgd mutex_exit(&erip->intrlock);
1266d64540e3Sgd return (0);
1267d64540e3Sgd }
1268d64540e3Sgd
1269d64540e3Sgd static int
eri_m_unicst(void * arg,const uint8_t * macaddr)1270d64540e3Sgd eri_m_unicst(void *arg, const uint8_t *macaddr)
1271d64540e3Sgd {
1272d64540e3Sgd struct eri *erip = arg;
12737c478bd9Sstevel@tonic-gate
12747c478bd9Sstevel@tonic-gate /*
12757c478bd9Sstevel@tonic-gate * Set new interface local address and re-init device.
12767c478bd9Sstevel@tonic-gate * This is destructive to any other streams attached
12777c478bd9Sstevel@tonic-gate * to this device.
12787c478bd9Sstevel@tonic-gate */
12797c478bd9Sstevel@tonic-gate mutex_enter(&erip->intrlock);
1280d64540e3Sgd bcopy(macaddr, &erip->ouraddr, ETHERADDRL);
1281d64540e3Sgd eri_init_rx(erip);
12827c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
1283d64540e3Sgd return (0);
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate
1286d64540e3Sgd /*ARGSUSED*/
1287d64540e3Sgd static boolean_t
eri_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)1288d64540e3Sgd eri_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
12897c478bd9Sstevel@tonic-gate {
1290d64540e3Sgd switch (cap) {
1291d64540e3Sgd case MAC_CAPAB_HCKSUM: {
1292d64540e3Sgd uint32_t *hcksum_txflags = cap_data;
1293d64540e3Sgd *hcksum_txflags = HCKSUM_INET_PARTIAL;
1294d64540e3Sgd return (B_TRUE);
12957c478bd9Sstevel@tonic-gate }
1296d64540e3Sgd default:
1297d64540e3Sgd return (B_FALSE);
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate
1301d64540e3Sgd static int
eri_m_start(void * arg)1302d64540e3Sgd eri_m_start(void *arg)
13037c478bd9Sstevel@tonic-gate {
1304d64540e3Sgd struct eri *erip = arg;
13057c478bd9Sstevel@tonic-gate
1306d64540e3Sgd mutex_enter(&erip->intrlock);
1307d64540e3Sgd erip->flags |= ERI_STARTED;
1308d64540e3Sgd mutex_exit(&erip->intrlock);
13097c478bd9Sstevel@tonic-gate
1310d64540e3Sgd if (!eri_init(erip)) {
1311d64540e3Sgd mutex_enter(&erip->intrlock);
1312d64540e3Sgd erip->flags &= ~ERI_STARTED;
1313d64540e3Sgd mutex_exit(&erip->intrlock);
1314d64540e3Sgd return (EIO);
13157c478bd9Sstevel@tonic-gate }
1316d64540e3Sgd return (0);
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate
13197c478bd9Sstevel@tonic-gate static void
eri_m_stop(void * arg)1320d64540e3Sgd eri_m_stop(void *arg)
13217c478bd9Sstevel@tonic-gate {
1322d64540e3Sgd struct eri *erip = arg;
13237c478bd9Sstevel@tonic-gate
1324d64540e3Sgd mutex_enter(&erip->intrlock);
1325d64540e3Sgd erip->flags &= ~ERI_STARTED;
1326d64540e3Sgd mutex_exit(&erip->intrlock);
1327d64540e3Sgd eri_uninit(erip);
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate
1330d64540e3Sgd static int
eri_m_stat(void * arg,uint_t stat,uint64_t * val)1331d64540e3Sgd eri_m_stat(void *arg, uint_t stat, uint64_t *val)
1332860c4cd4Scarlsonj {
1333d64540e3Sgd struct eri *erip = arg;
1334d64540e3Sgd struct stats *esp;
1335d64540e3Sgd boolean_t macupdate = B_FALSE;
1336860c4cd4Scarlsonj
1337d64540e3Sgd esp = &erip->stats;
1338d64540e3Sgd
1339d64540e3Sgd mutex_enter(&erip->xmitlock);
1340d64540e3Sgd if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) {
1341d64540e3Sgd erip->tx_completion =
1342d64540e3Sgd GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK;
1343d64540e3Sgd macupdate |= eri_reclaim(erip, erip->tx_completion);
13447c478bd9Sstevel@tonic-gate }
1345d64540e3Sgd mutex_exit(&erip->xmitlock);
1346d64540e3Sgd if (macupdate)
1347d64540e3Sgd mac_tx_update(erip->mh);
13487c478bd9Sstevel@tonic-gate
1349d64540e3Sgd eri_savecntrs(erip);
13507c478bd9Sstevel@tonic-gate
1351d64540e3Sgd switch (stat) {
1352d64540e3Sgd case MAC_STAT_IFSPEED:
1353d64540e3Sgd *val = esp->ifspeed * 1000000ULL;
1354d64540e3Sgd break;
1355d64540e3Sgd case MAC_STAT_MULTIRCV:
1356d64540e3Sgd *val = esp->multircv;
1357d64540e3Sgd break;
1358d64540e3Sgd case MAC_STAT_BRDCSTRCV:
1359d64540e3Sgd *val = esp->brdcstrcv;
1360d64540e3Sgd break;
1361d64540e3Sgd case MAC_STAT_IPACKETS:
1362d64540e3Sgd *val = esp->ipackets64;
1363d64540e3Sgd break;
1364d64540e3Sgd case MAC_STAT_RBYTES:
1365d64540e3Sgd *val = esp->rbytes64;
1366d64540e3Sgd break;
1367d64540e3Sgd case MAC_STAT_OBYTES:
1368d64540e3Sgd *val = esp->obytes64;
1369d64540e3Sgd break;
1370d64540e3Sgd case MAC_STAT_OPACKETS:
1371d64540e3Sgd *val = esp->opackets64;
1372d64540e3Sgd break;
1373d64540e3Sgd case MAC_STAT_IERRORS:
1374d64540e3Sgd *val = esp->ierrors;
1375d64540e3Sgd break;
1376d64540e3Sgd case MAC_STAT_OERRORS:
1377d64540e3Sgd *val = esp->oerrors;
1378d64540e3Sgd break;
1379d64540e3Sgd case MAC_STAT_MULTIXMT:
1380d64540e3Sgd *val = esp->multixmt;
1381d64540e3Sgd break;
1382d64540e3Sgd case MAC_STAT_BRDCSTXMT:
1383d64540e3Sgd *val = esp->brdcstxmt;
1384d64540e3Sgd break;
1385d64540e3Sgd case MAC_STAT_NORCVBUF:
1386d64540e3Sgd *val = esp->norcvbuf;
1387d64540e3Sgd break;
1388d64540e3Sgd case MAC_STAT_NOXMTBUF:
1389d64540e3Sgd *val = esp->noxmtbuf;
1390d64540e3Sgd break;
1391d64540e3Sgd case MAC_STAT_UNDERFLOWS:
1392d64540e3Sgd *val = esp->txmac_urun;
1393d64540e3Sgd break;
1394d64540e3Sgd case MAC_STAT_OVERFLOWS:
1395d64540e3Sgd *val = esp->rx_overflow;
1396d64540e3Sgd break;
1397d64540e3Sgd case MAC_STAT_COLLISIONS:
1398d64540e3Sgd *val = esp->collisions;
1399d64540e3Sgd break;
1400d64540e3Sgd case ETHER_STAT_ALIGN_ERRORS:
1401d64540e3Sgd *val = esp->rx_align_err;
1402d64540e3Sgd break;
1403d64540e3Sgd case ETHER_STAT_FCS_ERRORS:
1404d64540e3Sgd *val = esp->rx_crc_err;
1405d64540e3Sgd break;
1406d64540e3Sgd case ETHER_STAT_EX_COLLISIONS:
1407d64540e3Sgd *val = esp->excessive_coll;
1408d64540e3Sgd break;
1409d64540e3Sgd case ETHER_STAT_TX_LATE_COLLISIONS:
1410d64540e3Sgd *val = esp->late_coll;
1411d64540e3Sgd break;
1412d64540e3Sgd case ETHER_STAT_FIRST_COLLISIONS:
1413d64540e3Sgd *val = esp->first_coll;
1414d64540e3Sgd break;
1415d64540e3Sgd case ETHER_STAT_LINK_DUPLEX:
1416d64540e3Sgd *val = esp->link_duplex;
1417d64540e3Sgd break;
1418d64540e3Sgd case ETHER_STAT_TOOLONG_ERRORS:
1419d64540e3Sgd *val = esp->rx_toolong_pkts;
1420d64540e3Sgd break;
1421d64540e3Sgd case ETHER_STAT_TOOSHORT_ERRORS:
1422d64540e3Sgd *val = esp->rx_runt;
1423d64540e3Sgd break;
14247c478bd9Sstevel@tonic-gate
1425d64540e3Sgd case ETHER_STAT_XCVR_ADDR:
1426d64540e3Sgd *val = erip->phyad;
1427d64540e3Sgd break;
1428d64540e3Sgd
1429d64540e3Sgd case ETHER_STAT_XCVR_INUSE:
1430d64540e3Sgd *val = XCVR_100X; /* should always be 100X for now */
1431d64540e3Sgd break;
14327c478bd9Sstevel@tonic-gate
1433d64540e3Sgd case ETHER_STAT_CAP_100FDX:
1434d64540e3Sgd *val = param_bmsr_100fdx;
1435d64540e3Sgd break;
1436d64540e3Sgd case ETHER_STAT_CAP_100HDX:
1437d64540e3Sgd *val = param_bmsr_100hdx;
1438d64540e3Sgd break;
1439d64540e3Sgd case ETHER_STAT_CAP_10FDX:
1440d64540e3Sgd *val = param_bmsr_10fdx;
1441d64540e3Sgd break;
1442d64540e3Sgd case ETHER_STAT_CAP_10HDX:
1443d64540e3Sgd *val = param_bmsr_10hdx;
1444d64540e3Sgd break;
1445d64540e3Sgd case ETHER_STAT_CAP_AUTONEG:
1446d64540e3Sgd *val = param_bmsr_ancap;
1447d64540e3Sgd break;
1448d64540e3Sgd case ETHER_STAT_CAP_ASMPAUSE:
1449d64540e3Sgd *val = param_bmsr_asm_dir;
1450d64540e3Sgd break;
1451d64540e3Sgd case ETHER_STAT_CAP_PAUSE:
1452d64540e3Sgd *val = param_bmsr_pause;
1453d64540e3Sgd break;
1454d64540e3Sgd case ETHER_STAT_ADV_CAP_100FDX:
1455d64540e3Sgd *val = param_anar_100fdx;
1456d64540e3Sgd break;
1457d64540e3Sgd case ETHER_STAT_ADV_CAP_100HDX:
1458d64540e3Sgd *val = param_anar_100hdx;
1459d64540e3Sgd break;
1460d64540e3Sgd case ETHER_STAT_ADV_CAP_10FDX:
1461d64540e3Sgd *val = param_anar_10fdx;
1462d64540e3Sgd break;
1463d64540e3Sgd case ETHER_STAT_ADV_CAP_10HDX:
1464d64540e3Sgd *val = param_anar_10hdx;
1465d64540e3Sgd break;
1466d64540e3Sgd case ETHER_STAT_ADV_CAP_AUTONEG:
1467d64540e3Sgd *val = param_autoneg;
1468d64540e3Sgd break;
1469d64540e3Sgd case ETHER_STAT_ADV_CAP_ASMPAUSE:
1470d64540e3Sgd *val = param_anar_asm_dir;
1471d64540e3Sgd break;
1472d64540e3Sgd case ETHER_STAT_ADV_CAP_PAUSE:
1473d64540e3Sgd *val = param_anar_pause;
1474d64540e3Sgd break;
1475d64540e3Sgd case ETHER_STAT_LP_CAP_100FDX:
1476d64540e3Sgd *val = param_anlpar_100fdx;
1477d64540e3Sgd break;
1478d64540e3Sgd case ETHER_STAT_LP_CAP_100HDX:
1479d64540e3Sgd *val = param_anlpar_100hdx;
1480d64540e3Sgd break;
1481d64540e3Sgd case ETHER_STAT_LP_CAP_10FDX:
1482d64540e3Sgd *val = param_anlpar_10fdx;
1483d64540e3Sgd break;
1484d64540e3Sgd case ETHER_STAT_LP_CAP_10HDX:
1485d64540e3Sgd *val = param_anlpar_10hdx;
1486d64540e3Sgd break;
1487d64540e3Sgd case ETHER_STAT_LP_CAP_AUTONEG:
1488d64540e3Sgd *val = param_aner_lpancap;
1489d64540e3Sgd break;
1490d64540e3Sgd case ETHER_STAT_LP_CAP_ASMPAUSE:
1491d64540e3Sgd *val = param_anlpar_pauseTX;
1492d64540e3Sgd break;
1493d64540e3Sgd case ETHER_STAT_LP_CAP_PAUSE:
1494d64540e3Sgd *val = param_anlpar_pauseRX;
1495d64540e3Sgd break;
1496d64540e3Sgd case ETHER_STAT_LINK_PAUSE:
1497d64540e3Sgd *val = esp->pausing;
1498d64540e3Sgd break;
1499d64540e3Sgd case ETHER_STAT_LINK_ASMPAUSE:
1500d64540e3Sgd *val = param_anar_asm_dir &&
1501d64540e3Sgd param_anlpar_pauseTX &&
1502d64540e3Sgd (param_anar_pause != param_anlpar_pauseRX);
1503d64540e3Sgd break;
1504d64540e3Sgd case ETHER_STAT_LINK_AUTONEG:
1505d64540e3Sgd *val = param_autoneg && param_aner_lpancap;
1506d64540e3Sgd break;
1507d64540e3Sgd }
1508d64540e3Sgd return (0);
1509d64540e3Sgd }
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate /*
15127c478bd9Sstevel@tonic-gate * Hardware Functions
15137c478bd9Sstevel@tonic-gate * New Section
15147c478bd9Sstevel@tonic-gate */
15157c478bd9Sstevel@tonic-gate
15167c478bd9Sstevel@tonic-gate /*
15177c478bd9Sstevel@tonic-gate * Initialize the MAC registers. Some of of the MAC registers are initialized
15187c478bd9Sstevel@tonic-gate * just once since Global Reset or MAC reset doesn't clear them. Others (like
15197c478bd9Sstevel@tonic-gate * Host MAC Address Registers) are cleared on every reset and have to be
15207c478bd9Sstevel@tonic-gate * reinitialized.
15217c478bd9Sstevel@tonic-gate */
15227c478bd9Sstevel@tonic-gate static void
eri_init_macregs_generic(struct eri * erip)15237c478bd9Sstevel@tonic-gate eri_init_macregs_generic(struct eri *erip)
15247c478bd9Sstevel@tonic-gate {
15257c478bd9Sstevel@tonic-gate /*
15267c478bd9Sstevel@tonic-gate * set up the MAC parameter registers once
15277c478bd9Sstevel@tonic-gate * after power cycle. SUSPEND/RESUME also requires
15287c478bd9Sstevel@tonic-gate * setting these registers.
15297c478bd9Sstevel@tonic-gate */
15307c478bd9Sstevel@tonic-gate if ((erip->stats.inits == 1) || (erip->init_macregs)) {
15317c478bd9Sstevel@tonic-gate erip->init_macregs = 0;
15327c478bd9Sstevel@tonic-gate PUT_MACREG(ipg0, param_ipg0);
15337c478bd9Sstevel@tonic-gate PUT_MACREG(ipg1, param_ipg1);
15347c478bd9Sstevel@tonic-gate PUT_MACREG(ipg2, param_ipg2);
15357c478bd9Sstevel@tonic-gate PUT_MACREG(macmin, BMAC_MIN_FRAME_SIZE);
15367c478bd9Sstevel@tonic-gate #ifdef ERI_RX_TAG_ERROR_WORKAROUND
15377c478bd9Sstevel@tonic-gate PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE_TAG | BMAC_MAX_BURST);
15387c478bd9Sstevel@tonic-gate #else
15397c478bd9Sstevel@tonic-gate PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE | BMAC_MAX_BURST);
15407c478bd9Sstevel@tonic-gate #endif
15417c478bd9Sstevel@tonic-gate PUT_MACREG(palen, BMAC_PREAMBLE_SIZE);
15427c478bd9Sstevel@tonic-gate PUT_MACREG(jam, BMAC_JAM_SIZE);
15437c478bd9Sstevel@tonic-gate PUT_MACREG(alimit, BMAC_ATTEMPT_LIMIT);
15447c478bd9Sstevel@tonic-gate PUT_MACREG(macctl_type, BMAC_CONTROL_TYPE);
15457c478bd9Sstevel@tonic-gate PUT_MACREG(rseed,
1546d64540e3Sgd ((erip->ouraddr[0] & 0x3) << 8) | erip->ouraddr[1]);
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate PUT_MACREG(madd3, BMAC_ADDRESS_3);
15497c478bd9Sstevel@tonic-gate PUT_MACREG(madd4, BMAC_ADDRESS_4);
15507c478bd9Sstevel@tonic-gate PUT_MACREG(madd5, BMAC_ADDRESS_5);
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate /* Program MAC Control address */
15537c478bd9Sstevel@tonic-gate PUT_MACREG(madd6, BMAC_ADDRESS_6);
15547c478bd9Sstevel@tonic-gate PUT_MACREG(madd7, BMAC_ADDRESS_7);
15557c478bd9Sstevel@tonic-gate PUT_MACREG(madd8, BMAC_ADDRESS_8);
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate PUT_MACREG(afr0, BMAC_AF_0);
15587c478bd9Sstevel@tonic-gate PUT_MACREG(afr1, BMAC_AF_1);
15597c478bd9Sstevel@tonic-gate PUT_MACREG(afr2, BMAC_AF_2);
15607c478bd9Sstevel@tonic-gate PUT_MACREG(afmr1_2, BMAC_AF21_MASK);
15617c478bd9Sstevel@tonic-gate PUT_MACREG(afmr0, BMAC_AF0_MASK);
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate /* The counters need to be zeroed */
15657c478bd9Sstevel@tonic-gate PUT_MACREG(nccnt, 0);
15667c478bd9Sstevel@tonic-gate PUT_MACREG(fccnt, 0);
15677c478bd9Sstevel@tonic-gate PUT_MACREG(excnt, 0);
15687c478bd9Sstevel@tonic-gate PUT_MACREG(ltcnt, 0);
15697c478bd9Sstevel@tonic-gate PUT_MACREG(dcnt, 0);
15707c478bd9Sstevel@tonic-gate PUT_MACREG(frcnt, 0);
15717c478bd9Sstevel@tonic-gate PUT_MACREG(lecnt, 0);
15727c478bd9Sstevel@tonic-gate PUT_MACREG(aecnt, 0);
15737c478bd9Sstevel@tonic-gate PUT_MACREG(fecnt, 0);
15747c478bd9Sstevel@tonic-gate PUT_MACREG(rxcv, 0);
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate if (erip->pauseTX)
15777c478bd9Sstevel@tonic-gate PUT_MACREG(spcmd, BMAC_SEND_PAUSE_CMD);
15787c478bd9Sstevel@tonic-gate else
15797c478bd9Sstevel@tonic-gate PUT_MACREG(spcmd, 0);
1580fd8be74fSgd
1581fd8be74fSgd /*
1582fd8be74fSgd * Program BigMAC with local individual ethernet address.
1583fd8be74fSgd */
1584fd8be74fSgd
1585fd8be74fSgd PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]);
1586fd8be74fSgd PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]);
1587fd8be74fSgd PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]);
1588fd8be74fSgd
1589fd8be74fSgd /*
1590fd8be74fSgd * Install multicast address filter.
1591fd8be74fSgd */
1592fd8be74fSgd
1593fd8be74fSgd PUT_MACREG(hash0, erip->ladrf[0]);
1594fd8be74fSgd PUT_MACREG(hash1, erip->ladrf[1]);
1595fd8be74fSgd PUT_MACREG(hash2, erip->ladrf[2]);
1596fd8be74fSgd PUT_MACREG(hash3, erip->ladrf[3]);
1597fd8be74fSgd PUT_MACREG(hash4, erip->ladrf[4]);
1598fd8be74fSgd PUT_MACREG(hash5, erip->ladrf[5]);
1599fd8be74fSgd PUT_MACREG(hash6, erip->ladrf[6]);
1600fd8be74fSgd PUT_MACREG(hash7, erip->ladrf[7]);
1601fd8be74fSgd PUT_MACREG(hash8, erip->ladrf[8]);
1602fd8be74fSgd PUT_MACREG(hash9, erip->ladrf[9]);
1603fd8be74fSgd PUT_MACREG(hash10, erip->ladrf[10]);
1604fd8be74fSgd PUT_MACREG(hash11, erip->ladrf[11]);
1605fd8be74fSgd PUT_MACREG(hash12, erip->ladrf[12]);
1606fd8be74fSgd PUT_MACREG(hash13, erip->ladrf[13]);
1607fd8be74fSgd PUT_MACREG(hash14, erip->ladrf[14]);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate static int
eri_flush_rxbufs(struct eri * erip)16117c478bd9Sstevel@tonic-gate eri_flush_rxbufs(struct eri *erip)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate uint_t i;
16147c478bd9Sstevel@tonic-gate int status = 0;
16157c478bd9Sstevel@tonic-gate /*
16167c478bd9Sstevel@tonic-gate * Free and dvma_unload pending recv buffers.
16177c478bd9Sstevel@tonic-gate * Maintaining the 1-to-1 ordered sequence of
16187c478bd9Sstevel@tonic-gate * dvma_load() followed by dvma_unload() is critical.
16197c478bd9Sstevel@tonic-gate * Always unload anything before loading it again.
16207c478bd9Sstevel@tonic-gate * Never unload anything twice. Always unload
16217c478bd9Sstevel@tonic-gate * before freeing the buffer. We satisfy these
16227c478bd9Sstevel@tonic-gate * requirements by unloading only those descriptors
16237c478bd9Sstevel@tonic-gate * which currently have an mblk associated with them.
16247c478bd9Sstevel@tonic-gate */
16257c478bd9Sstevel@tonic-gate for (i = 0; i < ERI_RPENDING; i++) {
16267c478bd9Sstevel@tonic-gate if (erip->rmblkp[i]) {
16277c478bd9Sstevel@tonic-gate if (erip->eri_dvmarh)
16287c478bd9Sstevel@tonic-gate dvma_unload(erip->eri_dvmarh, 2 * i,
1629d64540e3Sgd DDI_DMA_SYNC_FORCPU);
16307c478bd9Sstevel@tonic-gate else if ((ddi_dma_unbind_handle(erip->ndmarh[i]) ==
16317c478bd9Sstevel@tonic-gate DDI_FAILURE))
16327c478bd9Sstevel@tonic-gate status = -1;
16337c478bd9Sstevel@tonic-gate freeb(erip->rmblkp[i]);
16347c478bd9Sstevel@tonic-gate erip->rmblkp[i] = NULL;
16357c478bd9Sstevel@tonic-gate }
16367c478bd9Sstevel@tonic-gate }
16377c478bd9Sstevel@tonic-gate return (status);
16387c478bd9Sstevel@tonic-gate }
16397c478bd9Sstevel@tonic-gate
16407c478bd9Sstevel@tonic-gate static void
eri_init_txbufs(struct eri * erip)16417c478bd9Sstevel@tonic-gate eri_init_txbufs(struct eri *erip)
16427c478bd9Sstevel@tonic-gate {
16437c478bd9Sstevel@tonic-gate /*
16447c478bd9Sstevel@tonic-gate * Clear TX descriptors.
16457c478bd9Sstevel@tonic-gate */
16467c478bd9Sstevel@tonic-gate bzero((caddr_t)erip->eri_tmdp, ERI_TPENDING * sizeof (struct eri_tmd));
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate /*
16497c478bd9Sstevel@tonic-gate * sync TXDMA descriptors.
16507c478bd9Sstevel@tonic-gate */
16517c478bd9Sstevel@tonic-gate ERI_SYNCIOPB(erip, erip->eri_tmdp,
16527c478bd9Sstevel@tonic-gate (ERI_TPENDING * sizeof (struct eri_tmd)), DDI_DMA_SYNC_FORDEV);
16537c478bd9Sstevel@tonic-gate /*
16547c478bd9Sstevel@tonic-gate * Reset TMD 'walking' pointers.
16557c478bd9Sstevel@tonic-gate */
16567c478bd9Sstevel@tonic-gate erip->tcurp = erip->eri_tmdp;
16577c478bd9Sstevel@tonic-gate erip->tnextp = erip->eri_tmdp;
16587c478bd9Sstevel@tonic-gate erip->tx_cur_cnt = 0;
16597c478bd9Sstevel@tonic-gate erip->tx_kick = 0;
16607c478bd9Sstevel@tonic-gate erip->tx_completion = 0;
16617c478bd9Sstevel@tonic-gate }
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate static int
eri_init_rxbufs(struct eri * erip)16647c478bd9Sstevel@tonic-gate eri_init_rxbufs(struct eri *erip)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate ddi_dma_cookie_t dma_cookie;
16687c478bd9Sstevel@tonic-gate mblk_t *bp;
16697c478bd9Sstevel@tonic-gate int i, status = 0;
16707c478bd9Sstevel@tonic-gate uint32_t ccnt;
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate /*
16737c478bd9Sstevel@tonic-gate * clear rcv descriptors
16747c478bd9Sstevel@tonic-gate */
16757c478bd9Sstevel@tonic-gate bzero((caddr_t)erip->rmdp, ERI_RPENDING * sizeof (struct rmd));
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate for (i = 0; i < ERI_RPENDING; i++) {
16787c478bd9Sstevel@tonic-gate if ((bp = eri_allocb(ERI_BUFSIZE)) == NULL) {
16797c478bd9Sstevel@tonic-gate status = -1;
16807c478bd9Sstevel@tonic-gate continue;
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate /* Load data buffer to DVMA space */
16837c478bd9Sstevel@tonic-gate if (erip->eri_dvmarh)
1684d64540e3Sgd dvma_kaddr_load(erip->eri_dvmarh,
1685d64540e3Sgd (caddr_t)bp->b_rptr, ERI_BUFSIZE,
1686d64540e3Sgd 2 * i, &dma_cookie);
16877c478bd9Sstevel@tonic-gate /*
16887c478bd9Sstevel@tonic-gate * Bind data buffer to DMA handle
16897c478bd9Sstevel@tonic-gate */
16907c478bd9Sstevel@tonic-gate else if (ddi_dma_addr_bind_handle(erip->ndmarh[i], NULL,
1691d64540e3Sgd (caddr_t)bp->b_rptr, ERI_BUFSIZE,
1692d64540e3Sgd DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
1693d64540e3Sgd &dma_cookie, &ccnt) != DDI_DMA_MAPPED)
1694d64540e3Sgd status = -1;
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate PUT_RMD((&erip->rmdp[i]), dma_cookie);
16977c478bd9Sstevel@tonic-gate erip->rmblkp[i] = bp; /* save for later use */
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate /*
17017c478bd9Sstevel@tonic-gate * sync RXDMA descriptors.
17027c478bd9Sstevel@tonic-gate */
1703d64540e3Sgd ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)),
1704d64540e3Sgd DDI_DMA_SYNC_FORDEV);
17057c478bd9Sstevel@tonic-gate /*
17067c478bd9Sstevel@tonic-gate * Reset RMD 'walking' pointers.
17077c478bd9Sstevel@tonic-gate */
17087c478bd9Sstevel@tonic-gate erip->rnextp = erip->rmdp;
17097c478bd9Sstevel@tonic-gate erip->rx_completion = 0;
17107c478bd9Sstevel@tonic-gate erip->rx_kick = ERI_RPENDING - 4;
17117c478bd9Sstevel@tonic-gate return (status);
17127c478bd9Sstevel@tonic-gate }
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate static uint32_t
eri_txmac_disable(struct eri * erip)17157c478bd9Sstevel@tonic-gate eri_txmac_disable(struct eri *erip)
17167c478bd9Sstevel@tonic-gate {
17177c478bd9Sstevel@tonic-gate int n;
17187c478bd9Sstevel@tonic-gate
17197c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, GET_MACREG(txcfg) & ~BMAC_TXCFG_ENAB);
17207c478bd9Sstevel@tonic-gate n = (BMACTXRSTDELAY * 10) / ERI_WAITPERIOD;
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate while (--n > 0) {
17237c478bd9Sstevel@tonic-gate drv_usecwait(ERI_WAITPERIOD);
17247c478bd9Sstevel@tonic-gate if ((GET_MACREG(txcfg) & 1) == 0)
17257c478bd9Sstevel@tonic-gate return (0);
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate return (1);
17287c478bd9Sstevel@tonic-gate }
17297c478bd9Sstevel@tonic-gate
17307c478bd9Sstevel@tonic-gate static uint32_t
eri_rxmac_disable(struct eri * erip)17317c478bd9Sstevel@tonic-gate eri_rxmac_disable(struct eri *erip)
17327c478bd9Sstevel@tonic-gate {
17337c478bd9Sstevel@tonic-gate int n;
17347c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, GET_MACREG(rxcfg) & ~BMAC_RXCFG_ENAB);
17357c478bd9Sstevel@tonic-gate n = BMACRXRSTDELAY / ERI_WAITPERIOD;
17367c478bd9Sstevel@tonic-gate
17377c478bd9Sstevel@tonic-gate while (--n > 0) {
17387c478bd9Sstevel@tonic-gate drv_usecwait(ERI_WAITPERIOD);
17397c478bd9Sstevel@tonic-gate if ((GET_MACREG(rxcfg) & 1) == 0)
17407c478bd9Sstevel@tonic-gate return (0);
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate return (1);
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate /*
17467c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure.
17477c478bd9Sstevel@tonic-gate */
17487c478bd9Sstevel@tonic-gate static int
eri_stop(struct eri * erip)17497c478bd9Sstevel@tonic-gate eri_stop(struct eri *erip)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate (void) eri_erx_reset(erip);
17527c478bd9Sstevel@tonic-gate (void) eri_etx_reset(erip);
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate /*
17557c478bd9Sstevel@tonic-gate * set up cache line to 16 for 64 bytes of pci burst size
17567c478bd9Sstevel@tonic-gate */
17577c478bd9Sstevel@tonic-gate PUT_SWRSTREG(reset, ERI_G_RESET_GLOBAL | ERI_CACHE_LINE_SIZE);
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate if (erip->linkcheck) {
17607c478bd9Sstevel@tonic-gate erip->linkcheck = 0;
17617c478bd9Sstevel@tonic-gate erip->global_reset_issued = 2;
17627c478bd9Sstevel@tonic-gate } else {
17637c478bd9Sstevel@tonic-gate param_linkup = 0;
1764d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
1765d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
17667c478bd9Sstevel@tonic-gate erip->global_reset_issued = -1;
17677c478bd9Sstevel@tonic-gate }
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate ERI_DELAY((GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE),
1770d64540e3Sgd ERI_MAX_RST_DELAY);
17717c478bd9Sstevel@tonic-gate erip->rx_reset_issued = -1;
17727c478bd9Sstevel@tonic-gate erip->tx_reset_issued = -1;
17737c478bd9Sstevel@tonic-gate
17747c478bd9Sstevel@tonic-gate /*
17757c478bd9Sstevel@tonic-gate * workaround for RIO not resetting the interrupt mask
17767c478bd9Sstevel@tonic-gate * register to default value 0xffffffff.
17777c478bd9Sstevel@tonic-gate */
17787c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, ERI_G_MASK_ALL);
17797c478bd9Sstevel@tonic-gate
17807c478bd9Sstevel@tonic-gate if (GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE) {
17817c478bd9Sstevel@tonic-gate return (0);
17827c478bd9Sstevel@tonic-gate } else {
17837c478bd9Sstevel@tonic-gate return (1);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate /*
17887c478bd9Sstevel@tonic-gate * Reset Just the RX Portion
17897c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure.
17907c478bd9Sstevel@tonic-gate *
17917c478bd9Sstevel@tonic-gate * Resetting the rxdma while there is a rx dma transaction going on the
17927c478bd9Sstevel@tonic-gate * bus, will cause bus hang or parity errors. To avoid this, we would first
17937c478bd9Sstevel@tonic-gate * disable the rxdma by clearing the ENABLE bit (bit 0). To make sure it is
17947c478bd9Sstevel@tonic-gate * disabled, we will poll it until it realy clears. Furthermore, to verify
17957c478bd9Sstevel@tonic-gate * any RX DMA activity is subsided, we delay for 5 msec.
17967c478bd9Sstevel@tonic-gate */
17977c478bd9Sstevel@tonic-gate static uint32_t
eri_erx_reset(struct eri * erip)17987c478bd9Sstevel@tonic-gate eri_erx_reset(struct eri *erip)
17997c478bd9Sstevel@tonic-gate {
18007c478bd9Sstevel@tonic-gate (void) eri_rxmac_disable(erip); /* Disable the RX MAC */
18017c478bd9Sstevel@tonic-gate
18021ac4c836Sjoycey /* Disable the RX DMA */
18031ac4c836Sjoycey PUT_ERXREG(config, GET_ERXREG(config) & ~GET_CONFIG_RXDMA_EN);
18047c478bd9Sstevel@tonic-gate ERI_DELAY(((GET_ERXREG(config) & 1) == 0), ERI_MAX_RST_DELAY);
18057c478bd9Sstevel@tonic-gate if ((GET_ERXREG(config) & 1) != 0)
18067c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1807d64540e3Sgd disable_erx_msg);
18087c478bd9Sstevel@tonic-gate
18097c478bd9Sstevel@tonic-gate drv_usecwait(5000); /* Delay to insure no RX DMA activity */
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate PUT_SWRSTREG(reset, ERI_G_RESET_ERX | ERI_CACHE_LINE_SIZE);
18127c478bd9Sstevel@tonic-gate /*
18137c478bd9Sstevel@tonic-gate * Wait until the reset is completed which is indicated by
18147c478bd9Sstevel@tonic-gate * the reset bit cleared or time out..
18157c478bd9Sstevel@tonic-gate */
1816d64540e3Sgd ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ==
1817d64540e3Sgd ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY);
18187c478bd9Sstevel@tonic-gate erip->rx_reset_issued = -1;
18197c478bd9Sstevel@tonic-gate
1820d64540e3Sgd return ((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ? 1 : 0);
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate /*
18247c478bd9Sstevel@tonic-gate * Reset Just the TX Portion
18257c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure.
18267c478bd9Sstevel@tonic-gate * Resetting the txdma while there is a tx dma transaction on the bus, may cause
18277c478bd9Sstevel@tonic-gate * bus hang or parity errors. To avoid this we would first disable the txdma by
18287c478bd9Sstevel@tonic-gate * clearing the ENABLE bit (bit 0). To make sure it is disabled, we will poll
18297c478bd9Sstevel@tonic-gate * it until it realy clears. Furthermore, to any TX DMA activity is subsided,
18307c478bd9Sstevel@tonic-gate * we delay for 1 msec.
18317c478bd9Sstevel@tonic-gate */
18327c478bd9Sstevel@tonic-gate static uint32_t
eri_etx_reset(struct eri * erip)18337c478bd9Sstevel@tonic-gate eri_etx_reset(struct eri *erip)
18347c478bd9Sstevel@tonic-gate {
18357c478bd9Sstevel@tonic-gate (void) eri_txmac_disable(erip);
18361ac4c836Sjoycey
18371ac4c836Sjoycey /* Disable the TX DMA */
18381ac4c836Sjoycey PUT_ETXREG(config, GET_ETXREG(config) & ~GET_CONFIG_TXDMA_EN);
18397c478bd9Sstevel@tonic-gate #ifdef ORIG
18407c478bd9Sstevel@tonic-gate ERI_DELAY(((GET_ETXREG(config) & 1) == 0), ERI_MAX_RST_DELAY);
18417c478bd9Sstevel@tonic-gate if ((GET_ETXREG(config) & 1) != 0)
18427c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1843d64540e3Sgd disable_etx_msg);
18447c478bd9Sstevel@tonic-gate drv_usecwait(5000); /* Delay to ensure DMA completed (if any). */
18457c478bd9Sstevel@tonic-gate #endif
18467c478bd9Sstevel@tonic-gate drv_usecwait(5000); /* Delay to ensure DMA completed (if any). */
18477c478bd9Sstevel@tonic-gate ERI_DELAY(((GET_ETXREG(config) & 1) == 0), ERI_MAX_RST_DELAY);
18487c478bd9Sstevel@tonic-gate if ((GET_ETXREG(config) & 1) != 0)
18497c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1850d64540e3Sgd disable_etx_msg);
18517c478bd9Sstevel@tonic-gate
18527c478bd9Sstevel@tonic-gate PUT_SWRSTREG(reset, ERI_G_RESET_ETX | ERI_CACHE_LINE_SIZE);
18537c478bd9Sstevel@tonic-gate
18547c478bd9Sstevel@tonic-gate /*
18557c478bd9Sstevel@tonic-gate * Wait until the reset is completed which is indicated by the reset bit
18567c478bd9Sstevel@tonic-gate * cleared or time out..
18577c478bd9Sstevel@tonic-gate */
18587c478bd9Sstevel@tonic-gate ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ETX)) ==
1859d64540e3Sgd ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY);
18607c478bd9Sstevel@tonic-gate erip->tx_reset_issued = -1;
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate if (GET_SWRSTREG(reset) & (ERI_G_RESET_ETX)) {
18637c478bd9Sstevel@tonic-gate return (1);
18647c478bd9Sstevel@tonic-gate } else
18657c478bd9Sstevel@tonic-gate return (0);
18667c478bd9Sstevel@tonic-gate }
18677c478bd9Sstevel@tonic-gate
18687c478bd9Sstevel@tonic-gate
18697c478bd9Sstevel@tonic-gate /*
18707c478bd9Sstevel@tonic-gate * Initialize the TX DMA registers and Enable the TX DMA.
18717c478bd9Sstevel@tonic-gate */
18727c478bd9Sstevel@tonic-gate static uint32_t
eri_init_txregs(struct eri * erip)18737c478bd9Sstevel@tonic-gate eri_init_txregs(struct eri *erip)
18747c478bd9Sstevel@tonic-gate {
18757c478bd9Sstevel@tonic-gate
18767c478bd9Sstevel@tonic-gate uint32_t i;
18777c478bd9Sstevel@tonic-gate uint64_t tx_ring;
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate /*
18807c478bd9Sstevel@tonic-gate * Initialize ETX Registers:
18817c478bd9Sstevel@tonic-gate * config, txring_lo, txring_hi
18827c478bd9Sstevel@tonic-gate */
18837c478bd9Sstevel@tonic-gate tx_ring = ERI_IOPBIOADDR(erip, erip->eri_tmdp);
18847c478bd9Sstevel@tonic-gate PUT_ETXREG(txring_lo, (uint32_t)(tx_ring));
18857c478bd9Sstevel@tonic-gate PUT_ETXREG(txring_hi, (uint32_t)(tx_ring >> 32));
18867c478bd9Sstevel@tonic-gate
18877c478bd9Sstevel@tonic-gate /*
18887c478bd9Sstevel@tonic-gate * Get TX Ring Size Masks.
18897c478bd9Sstevel@tonic-gate * The ring size ERI_TPENDING is defined in eri_mac.h.
18907c478bd9Sstevel@tonic-gate */
18917c478bd9Sstevel@tonic-gate switch (ERI_TPENDING) {
18927c478bd9Sstevel@tonic-gate case 32: i = ETX_RINGSZ_32;
18937c478bd9Sstevel@tonic-gate break;
18947c478bd9Sstevel@tonic-gate case 64: i = ETX_RINGSZ_64;
18957c478bd9Sstevel@tonic-gate break;
18967c478bd9Sstevel@tonic-gate case 128: i = ETX_RINGSZ_128;
18977c478bd9Sstevel@tonic-gate break;
18987c478bd9Sstevel@tonic-gate case 256: i = ETX_RINGSZ_256;
18997c478bd9Sstevel@tonic-gate break;
19007c478bd9Sstevel@tonic-gate case 512: i = ETX_RINGSZ_512;
19017c478bd9Sstevel@tonic-gate break;
19027c478bd9Sstevel@tonic-gate case 1024: i = ETX_RINGSZ_1024;
19037c478bd9Sstevel@tonic-gate break;
19047c478bd9Sstevel@tonic-gate case 2048: i = ETX_RINGSZ_2048;
19057c478bd9Sstevel@tonic-gate break;
19067c478bd9Sstevel@tonic-gate case 4096: i = ETX_RINGSZ_4096;
19077c478bd9Sstevel@tonic-gate break;
19087c478bd9Sstevel@tonic-gate default:
19097c478bd9Sstevel@tonic-gate ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
1910d64540e3Sgd unk_tx_descr_sze_msg, ERI_TPENDING);
19117c478bd9Sstevel@tonic-gate return (1);
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate
19147c478bd9Sstevel@tonic-gate i <<= ERI_TX_RINGSZ_SHIFT;
19157c478bd9Sstevel@tonic-gate PUT_ETXREG(config, ETX_CONFIG_THRESHOLD | i);
19167c478bd9Sstevel@tonic-gate ENABLE_TXDMA(erip);
19177c478bd9Sstevel@tonic-gate ENABLE_MAC(erip);
19187c478bd9Sstevel@tonic-gate return (0);
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate
19217c478bd9Sstevel@tonic-gate
19227c478bd9Sstevel@tonic-gate /*
19237c478bd9Sstevel@tonic-gate * Initialize the RX DMA registers and Enable the RX DMA.
19247c478bd9Sstevel@tonic-gate */
19257c478bd9Sstevel@tonic-gate static uint32_t
eri_init_rxregs(struct eri * erip)19267c478bd9Sstevel@tonic-gate eri_init_rxregs(struct eri *erip)
19277c478bd9Sstevel@tonic-gate {
19287c478bd9Sstevel@tonic-gate int i;
19297c478bd9Sstevel@tonic-gate uint64_t rx_ring;
19307c478bd9Sstevel@tonic-gate
19317c478bd9Sstevel@tonic-gate /*
19327c478bd9Sstevel@tonic-gate * Initialize ERX Registers:
19337c478bd9Sstevel@tonic-gate * rxring_lo, rxring_hi, config, rx_blanking, rx_pause_threshold.
19347c478bd9Sstevel@tonic-gate * Also, rx_kick
19357c478bd9Sstevel@tonic-gate * Read and save rxfifo_size.
19367c478bd9Sstevel@tonic-gate * XXX: Use this to properly configure PAUSE threshold values.
19377c478bd9Sstevel@tonic-gate */
19387c478bd9Sstevel@tonic-gate rx_ring = ERI_IOPBIOADDR(erip, erip->rmdp);
19397c478bd9Sstevel@tonic-gate PUT_ERXREG(rxring_lo, (uint32_t)(rx_ring));
19407c478bd9Sstevel@tonic-gate PUT_ERXREG(rxring_hi, (uint32_t)(rx_ring >> 32));
19417c478bd9Sstevel@tonic-gate PUT_ERXREG(rx_kick, erip->rx_kick);
19427c478bd9Sstevel@tonic-gate
19437c478bd9Sstevel@tonic-gate /*
19447c478bd9Sstevel@tonic-gate * The Max ring size, ERI_RMDMAX is defined in eri_mac.h.
19457c478bd9Sstevel@tonic-gate * More ERI_RPENDING will provide better performance but requires more
19467c478bd9Sstevel@tonic-gate * system DVMA memory.
19477c478bd9Sstevel@tonic-gate * eri_rx_ring_size can be used to tune this value from /etc/system
19487c478bd9Sstevel@tonic-gate * eri_rx_ring_size cannot be NDD'able due to non-recoverable errors
19497c478bd9Sstevel@tonic-gate * which cannot be detected from NDD operations
19507c478bd9Sstevel@tonic-gate */
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate /*
19537c478bd9Sstevel@tonic-gate * get the rxring size bits
19547c478bd9Sstevel@tonic-gate */
19557c478bd9Sstevel@tonic-gate switch (ERI_RPENDING) {
19567c478bd9Sstevel@tonic-gate case 32: i = ERX_RINGSZ_32;
19577c478bd9Sstevel@tonic-gate break;
19587c478bd9Sstevel@tonic-gate case 64: i = ERX_RINGSZ_64;
19597c478bd9Sstevel@tonic-gate break;
19607c478bd9Sstevel@tonic-gate case 128: i = ERX_RINGSZ_128;
19617c478bd9Sstevel@tonic-gate break;
19627c478bd9Sstevel@tonic-gate case 256: i = ERX_RINGSZ_256;
19637c478bd9Sstevel@tonic-gate break;
19647c478bd9Sstevel@tonic-gate case 512: i = ERX_RINGSZ_512;
19657c478bd9Sstevel@tonic-gate break;
19667c478bd9Sstevel@tonic-gate case 1024: i = ERX_RINGSZ_1024;
19677c478bd9Sstevel@tonic-gate break;
19687c478bd9Sstevel@tonic-gate case 2048: i = ERX_RINGSZ_2048;
19697c478bd9Sstevel@tonic-gate break;
19707c478bd9Sstevel@tonic-gate case 4096: i = ERX_RINGSZ_4096;
19717c478bd9Sstevel@tonic-gate break;
19727c478bd9Sstevel@tonic-gate default:
19737c478bd9Sstevel@tonic-gate ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
1974d64540e3Sgd unk_rx_descr_sze_msg, ERI_RPENDING);
19757c478bd9Sstevel@tonic-gate return (1);
19767c478bd9Sstevel@tonic-gate }
19777c478bd9Sstevel@tonic-gate
19787c478bd9Sstevel@tonic-gate i <<= ERI_RX_RINGSZ_SHIFT;
19797c478bd9Sstevel@tonic-gate i |= (ERI_FSTBYTE_OFFSET << ERI_RX_CONFIG_FBO_SHIFT) |
1980d64540e3Sgd (ETHERHEADER_SIZE << ERI_RX_CONFIG_RX_CSSTART_SHIFT) |
1981d64540e3Sgd (ERI_RX_FIFOTH_1024 << ERI_RX_CONFIG_RXFIFOTH_SHIFT);
19827c478bd9Sstevel@tonic-gate
19837c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i);
19847c478bd9Sstevel@tonic-gate PUT_ERXREG(rx_blanking,
1985d64540e3Sgd (param_intr_blank_time << ERI_RX_BLNK_INTR_TIME_SHIFT) |
1986d64540e3Sgd param_intr_blank_packets);
19877c478bd9Sstevel@tonic-gate
19887c478bd9Sstevel@tonic-gate PUT_ERXREG(rx_pause_threshold, rx_pause_threshold);
19897c478bd9Sstevel@tonic-gate erip->rxfifo_size = GET_ERXREG(rxfifo_size);
19907c478bd9Sstevel@tonic-gate ENABLE_RXDMA(erip);
19917c478bd9Sstevel@tonic-gate return (0);
19927c478bd9Sstevel@tonic-gate }
19937c478bd9Sstevel@tonic-gate
19947c478bd9Sstevel@tonic-gate static int
eri_freebufs(struct eri * erip)19957c478bd9Sstevel@tonic-gate eri_freebufs(struct eri *erip)
19967c478bd9Sstevel@tonic-gate {
19977c478bd9Sstevel@tonic-gate int status = 0;
19987c478bd9Sstevel@tonic-gate
1999bd78278bSGarrett D'Amore status = eri_flush_rxbufs(erip);
20007c478bd9Sstevel@tonic-gate return (status);
20017c478bd9Sstevel@tonic-gate }
20027c478bd9Sstevel@tonic-gate
20037c478bd9Sstevel@tonic-gate static void
eri_update_rxbufs(struct eri * erip)20047c478bd9Sstevel@tonic-gate eri_update_rxbufs(struct eri *erip)
20057c478bd9Sstevel@tonic-gate {
20067c478bd9Sstevel@tonic-gate int i;
20077c478bd9Sstevel@tonic-gate volatile struct rmd *rmdp, *rmdpbase;
20087c478bd9Sstevel@tonic-gate
20097c478bd9Sstevel@tonic-gate /*
20107c478bd9Sstevel@tonic-gate * Hang out receive buffers.
20117c478bd9Sstevel@tonic-gate */
20127c478bd9Sstevel@tonic-gate rmdpbase = erip->rmdp;
20137c478bd9Sstevel@tonic-gate for (i = 0; i < ERI_RPENDING; i++) {
20147c478bd9Sstevel@tonic-gate rmdp = rmdpbase + i;
20157c478bd9Sstevel@tonic-gate UPDATE_RMD(rmdp);
20167c478bd9Sstevel@tonic-gate }
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate /*
20197c478bd9Sstevel@tonic-gate * sync RXDMA descriptors.
20207c478bd9Sstevel@tonic-gate */
2021d64540e3Sgd ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)),
2022d64540e3Sgd DDI_DMA_SYNC_FORDEV);
20237c478bd9Sstevel@tonic-gate /*
20247c478bd9Sstevel@tonic-gate * Reset RMD 'walking' pointers.
20257c478bd9Sstevel@tonic-gate */
20267c478bd9Sstevel@tonic-gate erip->rnextp = erip->rmdp;
20277c478bd9Sstevel@tonic-gate erip->rx_completion = 0;
20287c478bd9Sstevel@tonic-gate erip->rx_kick = ERI_RPENDING - 4;
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate
20317c478bd9Sstevel@tonic-gate /*
20327c478bd9Sstevel@tonic-gate * This routine is used to reset the RX DMA only. In the case of RX
20337c478bd9Sstevel@tonic-gate * failures such as RX Tag Error, RX hang etc... we don't want to
20347c478bd9Sstevel@tonic-gate * do global reset which takes down the link and clears the FIFO's
20357c478bd9Sstevel@tonic-gate * By doing RX only reset, we leave the TX and the link intact.
20367c478bd9Sstevel@tonic-gate */
20377c478bd9Sstevel@tonic-gate static uint32_t
eri_init_rx_channel(struct eri * erip)20387c478bd9Sstevel@tonic-gate eri_init_rx_channel(struct eri *erip)
20397c478bd9Sstevel@tonic-gate {
20407c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_RXINIT;
20417c478bd9Sstevel@tonic-gate (void) eri_erx_reset(erip);
20427c478bd9Sstevel@tonic-gate eri_update_rxbufs(erip);
20437c478bd9Sstevel@tonic-gate if (eri_init_rxregs(erip))
20447c478bd9Sstevel@tonic-gate return (1);
20457c478bd9Sstevel@tonic-gate PUT_MACREG(rxmask, BMAC_RXINTR_MASK);
20467c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB);
20477c478bd9Sstevel@tonic-gate erip->rx_reset_issued = 0;
20487c478bd9Sstevel@tonic-gate HSTAT(erip, rx_inits);
20497c478bd9Sstevel@tonic-gate erip->flags |= ERI_RXINIT;
20507c478bd9Sstevel@tonic-gate return (0);
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate
20537c478bd9Sstevel@tonic-gate static void
eri_init_rx(struct eri * erip)20547c478bd9Sstevel@tonic-gate eri_init_rx(struct eri *erip)
20557c478bd9Sstevel@tonic-gate {
2056d64540e3Sgd uint16_t *ladrf;
20577c478bd9Sstevel@tonic-gate
20587c478bd9Sstevel@tonic-gate /*
20597c478bd9Sstevel@tonic-gate * First of all make sure the Receive MAC is stop.
20607c478bd9Sstevel@tonic-gate */
20617c478bd9Sstevel@tonic-gate (void) eri_rxmac_disable(erip); /* Disable the RX MAC */
20627c478bd9Sstevel@tonic-gate
20637c478bd9Sstevel@tonic-gate /*
20647c478bd9Sstevel@tonic-gate * Program BigMAC with local individual ethernet address.
20657c478bd9Sstevel@tonic-gate */
20667c478bd9Sstevel@tonic-gate
2067d64540e3Sgd PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]);
2068d64540e3Sgd PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]);
2069d64540e3Sgd PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]);
20707c478bd9Sstevel@tonic-gate
20717c478bd9Sstevel@tonic-gate /*
20727c478bd9Sstevel@tonic-gate * Set up multicast address filter by passing all multicast
20737c478bd9Sstevel@tonic-gate * addresses through a crc generator, and then using the
20747c478bd9Sstevel@tonic-gate * low order 8 bits as a index into the 256 bit logical
20757c478bd9Sstevel@tonic-gate * address filter. The high order four bits select the word,
20767c478bd9Sstevel@tonic-gate * while the rest of the bits select the bit within the word.
20777c478bd9Sstevel@tonic-gate */
20787c478bd9Sstevel@tonic-gate
2079d64540e3Sgd ladrf = erip->ladrf;
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate PUT_MACREG(hash0, ladrf[0]);
20827c478bd9Sstevel@tonic-gate PUT_MACREG(hash1, ladrf[1]);
20837c478bd9Sstevel@tonic-gate PUT_MACREG(hash2, ladrf[2]);
20847c478bd9Sstevel@tonic-gate PUT_MACREG(hash3, ladrf[3]);
20857c478bd9Sstevel@tonic-gate PUT_MACREG(hash4, ladrf[4]);
20867c478bd9Sstevel@tonic-gate PUT_MACREG(hash5, ladrf[5]);
20877c478bd9Sstevel@tonic-gate PUT_MACREG(hash6, ladrf[6]);
20887c478bd9Sstevel@tonic-gate PUT_MACREG(hash7, ladrf[7]);
20897c478bd9Sstevel@tonic-gate PUT_MACREG(hash8, ladrf[8]);
20907c478bd9Sstevel@tonic-gate PUT_MACREG(hash9, ladrf[9]);
20917c478bd9Sstevel@tonic-gate PUT_MACREG(hash10, ladrf[10]);
20927c478bd9Sstevel@tonic-gate PUT_MACREG(hash11, ladrf[11]);
20937c478bd9Sstevel@tonic-gate PUT_MACREG(hash12, ladrf[12]);
20947c478bd9Sstevel@tonic-gate PUT_MACREG(hash13, ladrf[13]);
20957c478bd9Sstevel@tonic-gate PUT_MACREG(hash14, ladrf[14]);
20967c478bd9Sstevel@tonic-gate PUT_MACREG(hash15, ladrf[15]);
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate #ifdef ERI_DONT_STRIP_CRC
20997c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg,
2100d64540e3Sgd ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2101d64540e3Sgd (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
21027c478bd9Sstevel@tonic-gate BMAC_RXCFG_ENAB));
21037c478bd9Sstevel@tonic-gate #else
21047c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg,
2105d64540e3Sgd ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2106d64540e3Sgd (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
21077c478bd9Sstevel@tonic-gate BMAC_RXCFG_ENAB | BMAC_RXCFG_STRIP_CRC));
21087c478bd9Sstevel@tonic-gate #endif
21097c478bd9Sstevel@tonic-gate /* wait after setting Hash Enable bit */
21107c478bd9Sstevel@tonic-gate /* drv_usecwait(10); */
21117c478bd9Sstevel@tonic-gate
21127c478bd9Sstevel@tonic-gate HSTAT(erip, rx_inits);
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate /*
21167c478bd9Sstevel@tonic-gate * This routine is used to init the TX MAC only.
21177c478bd9Sstevel@tonic-gate * &erip->xmitlock is held before calling this routine.
21187c478bd9Sstevel@tonic-gate */
21197c478bd9Sstevel@tonic-gate void
eri_init_txmac(struct eri * erip)21207c478bd9Sstevel@tonic-gate eri_init_txmac(struct eri *erip)
21217c478bd9Sstevel@tonic-gate {
21227c478bd9Sstevel@tonic-gate uint32_t carrier_ext = 0;
21237c478bd9Sstevel@tonic-gate
21247c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_TXINIT;
21257c478bd9Sstevel@tonic-gate /*
21267c478bd9Sstevel@tonic-gate * Stop the Transmit MAC.
21277c478bd9Sstevel@tonic-gate */
21287c478bd9Sstevel@tonic-gate (void) eri_txmac_disable(erip);
21297c478bd9Sstevel@tonic-gate
21307c478bd9Sstevel@tonic-gate /*
21317c478bd9Sstevel@tonic-gate * Must be Internal Transceiver
21327c478bd9Sstevel@tonic-gate */
21337c478bd9Sstevel@tonic-gate if (param_mode)
21347c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
21357c478bd9Sstevel@tonic-gate BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE));
21367c478bd9Sstevel@tonic-gate else
21377c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
21387c478bd9Sstevel@tonic-gate BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE |
21397c478bd9Sstevel@tonic-gate BMAC_XIFC_DIS_ECHO));
21407c478bd9Sstevel@tonic-gate
21417c478bd9Sstevel@tonic-gate /*
21427c478bd9Sstevel@tonic-gate * Initialize the interpacket gap registers
21437c478bd9Sstevel@tonic-gate */
21447c478bd9Sstevel@tonic-gate PUT_MACREG(ipg1, param_ipg1);
21457c478bd9Sstevel@tonic-gate PUT_MACREG(ipg2, param_ipg2);
21467c478bd9Sstevel@tonic-gate
21477c478bd9Sstevel@tonic-gate if (erip->ngu_enable)
2148d64540e3Sgd PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) |
2149d64540e3Sgd ((param_lance_mode && (erip->lance_mode_enable)) ?
2150d64540e3Sgd BMAC_TXCFG_ENIPG0 : 0) |
2151d64540e3Sgd (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) |
2152d64540e3Sgd BMAC_TXCFG_NGU));
21537c478bd9Sstevel@tonic-gate else
2154d64540e3Sgd PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) |
2155d64540e3Sgd ((param_lance_mode && (erip->lance_mode_enable)) ?
2156d64540e3Sgd BMAC_TXCFG_ENIPG0 : 0) |
2157d64540e3Sgd (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0)));
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate ENABLE_TXDMA(erip);
21607c478bd9Sstevel@tonic-gate ENABLE_TXMAC(erip);
21617c478bd9Sstevel@tonic-gate
21627c478bd9Sstevel@tonic-gate HSTAT(erip, tx_inits);
21637c478bd9Sstevel@tonic-gate erip->flags |= ERI_TXINIT;
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate
21667c478bd9Sstevel@tonic-gate static void
eri_unallocthings(struct eri * erip)21677c478bd9Sstevel@tonic-gate eri_unallocthings(struct eri *erip)
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate uint32_t flag;
21707c478bd9Sstevel@tonic-gate uint32_t i;
21717c478bd9Sstevel@tonic-gate
21727c478bd9Sstevel@tonic-gate flag = erip->alloc_flag;
21737c478bd9Sstevel@tonic-gate
21747c478bd9Sstevel@tonic-gate if (flag & ERI_DESC_MEM_MAP)
21757c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(erip->md_h);
21767c478bd9Sstevel@tonic-gate
21777c478bd9Sstevel@tonic-gate if (flag & ERI_DESC_MEM_ALLOC) {
21787c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&erip->mdm_h);
21797c478bd9Sstevel@tonic-gate erip->rmdp = NULL;
21807c478bd9Sstevel@tonic-gate erip->eri_tmdp = NULL;
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate
21837c478bd9Sstevel@tonic-gate if (flag & ERI_DESC_HANDLE_ALLOC)
21847c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&erip->md_h);
21857c478bd9Sstevel@tonic-gate
21867c478bd9Sstevel@tonic-gate (void) eri_freebufs(erip);
21877c478bd9Sstevel@tonic-gate
21887c478bd9Sstevel@tonic-gate if (flag & ERI_RCV_HANDLE_ALLOC)
21897c478bd9Sstevel@tonic-gate for (i = 0; i < erip->rcv_handle_cnt; i++)
21907c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&erip->ndmarh[i]);
21917c478bd9Sstevel@tonic-gate
21927c478bd9Sstevel@tonic-gate if (flag & ERI_RCV_DVMA_ALLOC) {
21937c478bd9Sstevel@tonic-gate (void) dvma_release(erip->eri_dvmarh);
21947c478bd9Sstevel@tonic-gate erip->eri_dvmarh = NULL;
21957c478bd9Sstevel@tonic-gate }
21967c478bd9Sstevel@tonic-gate
21977c478bd9Sstevel@tonic-gate if (flag & ERI_XBUFS_KMEM_DMABIND) {
21987c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(erip->tbuf_handle);
21997c478bd9Sstevel@tonic-gate erip->tbuf_ioaddr = 0;
22007c478bd9Sstevel@tonic-gate }
22017c478bd9Sstevel@tonic-gate
22027c478bd9Sstevel@tonic-gate if (flag & ERI_XBUFS_KMEM_ALLOC) {
2203bd78278bSGarrett D'Amore ddi_dma_mem_free(&erip->tbuf_acch);
22047c478bd9Sstevel@tonic-gate erip->tbuf_kaddr = NULL;
22057c478bd9Sstevel@tonic-gate }
22067c478bd9Sstevel@tonic-gate
22077c478bd9Sstevel@tonic-gate if (flag & ERI_XBUFS_HANDLE_ALLOC) {
22087c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&erip->tbuf_handle);
22097c478bd9Sstevel@tonic-gate erip->tbuf_handle = NULL;
22107c478bd9Sstevel@tonic-gate }
22117c478bd9Sstevel@tonic-gate
22127c478bd9Sstevel@tonic-gate }
22137c478bd9Sstevel@tonic-gate
22147c478bd9Sstevel@tonic-gate /*
22157c478bd9Sstevel@tonic-gate * Initialize channel.
2216d64540e3Sgd * Return true on success, false on error.
22177c478bd9Sstevel@tonic-gate *
22187c478bd9Sstevel@tonic-gate * The recommended sequence for initialization is:
22197c478bd9Sstevel@tonic-gate * 1. Issue a Global Reset command to the Ethernet Channel.
22207c478bd9Sstevel@tonic-gate * 2. Poll the Global_Reset bits until the execution of the reset has been
22217c478bd9Sstevel@tonic-gate * completed.
22227c478bd9Sstevel@tonic-gate * 2(a). Use the MIF Frame/Output register to reset the transceiver.
22237c478bd9Sstevel@tonic-gate * Poll Register 0 to till the Resetbit is 0.
22247c478bd9Sstevel@tonic-gate * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op,
22257c478bd9Sstevel@tonic-gate * 100Mbps and Non-Isolated mode. The main point here is to bring the
22267c478bd9Sstevel@tonic-gate * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk
22277c478bd9Sstevel@tonic-gate * to the MII interface so that the Bigmac core can correctly reset
22287c478bd9Sstevel@tonic-gate * upon a software reset.
22297c478bd9Sstevel@tonic-gate * 2(c). Issue another Global Reset command to the Ethernet Channel and poll
22307c478bd9Sstevel@tonic-gate * the Global_Reset bits till completion.
22317c478bd9Sstevel@tonic-gate * 3. Set up all the data structures in the host memory.
22327c478bd9Sstevel@tonic-gate * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration
22337c478bd9Sstevel@tonic-gate * Register).
22347c478bd9Sstevel@tonic-gate * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration
22357c478bd9Sstevel@tonic-gate * Register).
22367c478bd9Sstevel@tonic-gate * 6. Program the Transmit Descriptor Ring Base Address in the ETX.
22377c478bd9Sstevel@tonic-gate * 7. Program the Receive Descriptor Ring Base Address in the ERX.
22387c478bd9Sstevel@tonic-gate * 8. Program the Global Configuration and the Global Interrupt Mask Registers.
22397c478bd9Sstevel@tonic-gate * 9. Program the ETX Configuration register (enable the Transmit DMA channel).
22407c478bd9Sstevel@tonic-gate * 10. Program the ERX Configuration register (enable the Receive DMA channel).
22417c478bd9Sstevel@tonic-gate * 11. Program the XIF Configuration Register (enable the XIF).
22427c478bd9Sstevel@tonic-gate * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC).
22437c478bd9Sstevel@tonic-gate * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC).
22447c478bd9Sstevel@tonic-gate */
22457c478bd9Sstevel@tonic-gate /*
22467c478bd9Sstevel@tonic-gate * lock order:
2247d64540e3Sgd * intrlock->linklock->xmitlock->xcvrlock
22487c478bd9Sstevel@tonic-gate */
2249d64540e3Sgd static boolean_t
eri_init(struct eri * erip)22507c478bd9Sstevel@tonic-gate eri_init(struct eri *erip)
22517c478bd9Sstevel@tonic-gate {
22527c478bd9Sstevel@tonic-gate uint32_t init_stat = 0;
22537c478bd9Sstevel@tonic-gate uint32_t partial_init = 0;
22547c478bd9Sstevel@tonic-gate uint32_t carrier_ext = 0;
22557c478bd9Sstevel@tonic-gate uint32_t mac_ctl = 0;
2256d64540e3Sgd boolean_t ret;
2257*7e996435SToomas Soome uint32_t link_timeout = ERI_LINKCHECK_TIMER;
2258d64540e3Sgd link_state_t linkupdate = LINK_STATE_UNKNOWN;
22597c478bd9Sstevel@tonic-gate
22607c478bd9Sstevel@tonic-gate /*
2261d64540e3Sgd * Just return successfully if device is suspended.
22627c478bd9Sstevel@tonic-gate * eri_init() will be called again from resume.
22637c478bd9Sstevel@tonic-gate */
2264d64540e3Sgd ASSERT(erip != NULL);
2265d64540e3Sgd
2266d64540e3Sgd if (erip->flags & ERI_SUSPENDED) {
2267d64540e3Sgd ret = B_TRUE;
22687c478bd9Sstevel@tonic-gate goto init_exit;
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate
22717c478bd9Sstevel@tonic-gate mutex_enter(&erip->intrlock);
22727c478bd9Sstevel@tonic-gate eri_stop_timer(erip); /* acquire linklock */
22737c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
2274d64540e3Sgd erip->flags &= (ERI_DLPI_LINKUP | ERI_STARTED);
2275d64540e3Sgd erip->wantw = B_FALSE;
22767c478bd9Sstevel@tonic-gate HSTAT(erip, inits);
22777c478bd9Sstevel@tonic-gate erip->txhung = 0;
22787c478bd9Sstevel@tonic-gate
2279fd8be74fSgd if ((erip->stats.inits > 1) && (erip->init_macregs == 0))
22807c478bd9Sstevel@tonic-gate eri_savecntrs(erip);
22817c478bd9Sstevel@tonic-gate
22827c478bd9Sstevel@tonic-gate mutex_enter(&erip->xcvrlock);
22837c478bd9Sstevel@tonic-gate if (!param_linkup || erip->linkcheck) {
2284860c4cd4Scarlsonj if (!erip->linkcheck)
2285d64540e3Sgd linkupdate = LINK_STATE_DOWN;
22867c478bd9Sstevel@tonic-gate (void) eri_stop(erip);
22877c478bd9Sstevel@tonic-gate }
22887c478bd9Sstevel@tonic-gate if (!(erip->flags & ERI_DLPI_LINKUP) || !param_linkup) {
22897c478bd9Sstevel@tonic-gate erip->flags |= ERI_DLPI_LINKUP;
22907c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_STOP);
22917c478bd9Sstevel@tonic-gate (void) eri_new_xcvr(erip);
2292d64540e3Sgd ERI_DEBUG_MSG1(erip, XCVR_MSG, "New transceiver detected.");
22937c478bd9Sstevel@tonic-gate if (param_transceiver != NO_XCVR) {
22947c478bd9Sstevel@tonic-gate /*
22957c478bd9Sstevel@tonic-gate * Reset the new PHY and bring up the
22967c478bd9Sstevel@tonic-gate * link
22977c478bd9Sstevel@tonic-gate */
22987c478bd9Sstevel@tonic-gate if (eri_reset_xcvr(erip)) {
22997c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE,
23007c478bd9Sstevel@tonic-gate ERI_VERB_MSG, "In Init after reset");
23017c478bd9Sstevel@tonic-gate mutex_exit(&erip->xcvrlock);
23027c478bd9Sstevel@tonic-gate link_timeout = 0;
23037c478bd9Sstevel@tonic-gate goto done;
23047c478bd9Sstevel@tonic-gate }
2305d64540e3Sgd if (erip->stats.link_up == LINK_STATE_UP)
2306d64540e3Sgd linkupdate = LINK_STATE_UP;
23077c478bd9Sstevel@tonic-gate } else {
23087c478bd9Sstevel@tonic-gate erip->flags |= (ERI_RUNNING | ERI_INITIALIZED);
23097c478bd9Sstevel@tonic-gate param_linkup = 0;
2310d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
2311d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2312d64540e3Sgd linkupdate = LINK_STATE_DOWN;
23137c478bd9Sstevel@tonic-gate /*
23147c478bd9Sstevel@tonic-gate * Still go on and complete the MAC initialization as
23157c478bd9Sstevel@tonic-gate * xcvr might show up later.
23167c478bd9Sstevel@tonic-gate * you must return to their mutex ordering.
23177c478bd9Sstevel@tonic-gate */
23187c478bd9Sstevel@tonic-gate }
23197c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_START);
23207c478bd9Sstevel@tonic-gate }
23217c478bd9Sstevel@tonic-gate
23227c478bd9Sstevel@tonic-gate mutex_exit(&erip->xcvrlock);
23237c478bd9Sstevel@tonic-gate
23247c478bd9Sstevel@tonic-gate /*
23257c478bd9Sstevel@tonic-gate * Allocate data structures.
23267c478bd9Sstevel@tonic-gate */
23277c478bd9Sstevel@tonic-gate if (erip->global_reset_issued) {
23287c478bd9Sstevel@tonic-gate if (erip->global_reset_issued == 2) { /* fast path */
2329bd78278bSGarrett D'Amore
23307c478bd9Sstevel@tonic-gate /*
23317c478bd9Sstevel@tonic-gate * Hang out/Initialize descriptors and buffers.
23327c478bd9Sstevel@tonic-gate */
23337c478bd9Sstevel@tonic-gate eri_init_txbufs(erip);
23347c478bd9Sstevel@tonic-gate
23357c478bd9Sstevel@tonic-gate eri_update_rxbufs(erip);
23367c478bd9Sstevel@tonic-gate } else {
23377c478bd9Sstevel@tonic-gate init_stat = eri_allocthings(erip);
23387c478bd9Sstevel@tonic-gate if (init_stat)
23397c478bd9Sstevel@tonic-gate goto done;
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate if (eri_freebufs(erip))
23427c478bd9Sstevel@tonic-gate goto done;
23437c478bd9Sstevel@tonic-gate /*
23447c478bd9Sstevel@tonic-gate * Hang out/Initialize descriptors and buffers.
23457c478bd9Sstevel@tonic-gate */
23467c478bd9Sstevel@tonic-gate eri_init_txbufs(erip);
23477c478bd9Sstevel@tonic-gate if (eri_init_rxbufs(erip))
23487c478bd9Sstevel@tonic-gate goto done;
23497c478bd9Sstevel@tonic-gate }
23507c478bd9Sstevel@tonic-gate }
23517c478bd9Sstevel@tonic-gate
23527c478bd9Sstevel@tonic-gate /*
23537c478bd9Sstevel@tonic-gate * BigMAC requires that we confirm that tx, rx and hash are in
23547c478bd9Sstevel@tonic-gate * quiescent state.
23557c478bd9Sstevel@tonic-gate * MAC will not reset successfully if the transceiver is not reset and
23567c478bd9Sstevel@tonic-gate * brought out of Isolate mode correctly. TXMAC reset may fail if the
23577c478bd9Sstevel@tonic-gate * ext. transceiver is just disconnected. If it fails, try again by
23587c478bd9Sstevel@tonic-gate * checking the transceiver.
23597c478bd9Sstevel@tonic-gate */
23607c478bd9Sstevel@tonic-gate if (eri_txmac_disable(erip)) {
23617c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
2362d64540e3Sgd disable_txmac_msg);
23637c478bd9Sstevel@tonic-gate param_linkup = 0; /* force init again */
2364d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
2365d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2366d64540e3Sgd linkupdate = LINK_STATE_DOWN;
23677c478bd9Sstevel@tonic-gate goto done;
23687c478bd9Sstevel@tonic-gate }
23697c478bd9Sstevel@tonic-gate
23707c478bd9Sstevel@tonic-gate if (eri_rxmac_disable(erip)) {
23717c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
2372d64540e3Sgd disable_rxmac_msg);
23737c478bd9Sstevel@tonic-gate param_linkup = 0; /* force init again */
2374d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
2375d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2376d64540e3Sgd linkupdate = LINK_STATE_DOWN;
23777c478bd9Sstevel@tonic-gate goto done;
23787c478bd9Sstevel@tonic-gate }
23797c478bd9Sstevel@tonic-gate
23807c478bd9Sstevel@tonic-gate eri_init_macregs_generic(erip);
23817c478bd9Sstevel@tonic-gate
23827c478bd9Sstevel@tonic-gate /*
23837c478bd9Sstevel@tonic-gate * Initialize ERI Global registers :
23847c478bd9Sstevel@tonic-gate * config
23857c478bd9Sstevel@tonic-gate * For PCI : err_mask, bif_cfg
23867c478bd9Sstevel@tonic-gate *
23877c478bd9Sstevel@tonic-gate * Use user-configurable parameter for enabling 64-bit transfers.
23887c478bd9Sstevel@tonic-gate * Note:For PCI, burst sizes are in multiples of 64-bytes.
23897c478bd9Sstevel@tonic-gate */
23907c478bd9Sstevel@tonic-gate
23917c478bd9Sstevel@tonic-gate /*
23927c478bd9Sstevel@tonic-gate * Significant performance improvements can be achieved by
23937c478bd9Sstevel@tonic-gate * disabling transmit interrupt. Thus TMD's are reclaimed
23947c478bd9Sstevel@tonic-gate * only very infrequently.
23957c478bd9Sstevel@tonic-gate * The PCS Interrupt is masked here. It is enabled only when
23967c478bd9Sstevel@tonic-gate * a PCS link is brought up because there is no second level
23977c478bd9Sstevel@tonic-gate * mask for this interrupt..
23987c478bd9Sstevel@tonic-gate * Init GLOBAL, TXMAC, RXMAC and MACCTL interrupt masks here.
23997c478bd9Sstevel@tonic-gate */
24007c478bd9Sstevel@tonic-gate if (! partial_init) {
24017c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, ERI_G_MASK_INTR);
24027c478bd9Sstevel@tonic-gate erip->tx_int_me = 0;
24037c478bd9Sstevel@tonic-gate PUT_MACREG(txmask, BMAC_TXINTR_MASK);
24047c478bd9Sstevel@tonic-gate PUT_MACREG(rxmask, BMAC_RXINTR_MASK);
24057c478bd9Sstevel@tonic-gate PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK);
24067c478bd9Sstevel@tonic-gate }
24077c478bd9Sstevel@tonic-gate
24087c478bd9Sstevel@tonic-gate if (erip->global_reset_issued) {
24097c478bd9Sstevel@tonic-gate /*
24107c478bd9Sstevel@tonic-gate * Initialize ETX Registers:
24117c478bd9Sstevel@tonic-gate * config, txring_lo, txring_hi
24127c478bd9Sstevel@tonic-gate */
24137c478bd9Sstevel@tonic-gate if (eri_init_txregs(erip))
2414d64540e3Sgd goto done;
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate * Initialize ERX Registers:
24177c478bd9Sstevel@tonic-gate * rxring_lo, rxring_hi, config, rx_blanking,
24187c478bd9Sstevel@tonic-gate * rx_pause_threshold. Also, rx_kick
24197c478bd9Sstevel@tonic-gate * Read and save rxfifo_size.
24207c478bd9Sstevel@tonic-gate */
24217c478bd9Sstevel@tonic-gate if (eri_init_rxregs(erip))
24227c478bd9Sstevel@tonic-gate goto done;
24237c478bd9Sstevel@tonic-gate }
24247c478bd9Sstevel@tonic-gate
24257c478bd9Sstevel@tonic-gate PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK);
24267c478bd9Sstevel@tonic-gate
24277c478bd9Sstevel@tonic-gate /*
24287c478bd9Sstevel@tonic-gate * Set up the slottime,and rxconfig, txconfig without enabling
24297c478bd9Sstevel@tonic-gate * the latter two at this time
24307c478bd9Sstevel@tonic-gate */
24317c478bd9Sstevel@tonic-gate PUT_MACREG(slot, BMAC_SLOT_TIME);
24327c478bd9Sstevel@tonic-gate carrier_ext = 0;
24337c478bd9Sstevel@tonic-gate
24347c478bd9Sstevel@tonic-gate #ifdef ERI_DONT_STRIP_CRC
24357c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg,
2436d64540e3Sgd ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2437d64540e3Sgd (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
24387c478bd9Sstevel@tonic-gate (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0)));
24397c478bd9Sstevel@tonic-gate #else
24407c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg,
2441d64540e3Sgd ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2442d64540e3Sgd (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
24437c478bd9Sstevel@tonic-gate BMAC_RXCFG_STRIP_CRC |
24447c478bd9Sstevel@tonic-gate (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0)));
24457c478bd9Sstevel@tonic-gate #endif
24467c478bd9Sstevel@tonic-gate drv_usecwait(10); /* wait after setting Hash Enable bit */
24477c478bd9Sstevel@tonic-gate
24487c478bd9Sstevel@tonic-gate if (erip->ngu_enable)
24497c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg,
24507c478bd9Sstevel@tonic-gate ((param_mode ? BMAC_TXCFG_FDX: 0) |
24517c478bd9Sstevel@tonic-gate ((param_lance_mode && (erip->lance_mode_enable)) ?
24527c478bd9Sstevel@tonic-gate BMAC_TXCFG_ENIPG0 : 0) |
24537c478bd9Sstevel@tonic-gate (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) |
24547c478bd9Sstevel@tonic-gate BMAC_TXCFG_NGU));
24557c478bd9Sstevel@tonic-gate else
24567c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg,
24577c478bd9Sstevel@tonic-gate ((param_mode ? BMAC_TXCFG_FDX: 0) |
24587c478bd9Sstevel@tonic-gate ((param_lance_mode && (erip->lance_mode_enable)) ?
24597c478bd9Sstevel@tonic-gate BMAC_TXCFG_ENIPG0 : 0) |
24607c478bd9Sstevel@tonic-gate (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0)));
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate if (erip->pauseRX)
24637c478bd9Sstevel@tonic-gate mac_ctl = ERI_MCTLCFG_RXPAUSE;
24647c478bd9Sstevel@tonic-gate if (erip->pauseTX)
24657c478bd9Sstevel@tonic-gate mac_ctl |= ERI_MCTLCFG_TXPAUSE;
24667c478bd9Sstevel@tonic-gate
24677c478bd9Sstevel@tonic-gate PUT_MACREG(macctl_cfg, mac_ctl);
24687c478bd9Sstevel@tonic-gate
24697c478bd9Sstevel@tonic-gate /*
24707c478bd9Sstevel@tonic-gate * Must be Internal Transceiver
24717c478bd9Sstevel@tonic-gate */
24727c478bd9Sstevel@tonic-gate if (param_mode)
24737c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
24747c478bd9Sstevel@tonic-gate BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE));
24757c478bd9Sstevel@tonic-gate else {
24767c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
24777c478bd9Sstevel@tonic-gate BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE |
24787c478bd9Sstevel@tonic-gate BMAC_XIFC_DIS_ECHO));
24797c478bd9Sstevel@tonic-gate
24807c478bd9Sstevel@tonic-gate link_timeout = ERI_CHECK_HANG_TIMER;
24817c478bd9Sstevel@tonic-gate }
24827c478bd9Sstevel@tonic-gate
24837c478bd9Sstevel@tonic-gate /*
24847c478bd9Sstevel@tonic-gate * if MAC int loopback flag is set, put xifc reg in mii loopback
24857c478bd9Sstevel@tonic-gate * mode {DIAG}
24867c478bd9Sstevel@tonic-gate */
24877c478bd9Sstevel@tonic-gate if (erip->flags & ERI_MACLOOPBACK) {
24887c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIILPBK);
24897c478bd9Sstevel@tonic-gate }
24907c478bd9Sstevel@tonic-gate
24917c478bd9Sstevel@tonic-gate /*
24927c478bd9Sstevel@tonic-gate * Enable TX and RX MACs.
24937c478bd9Sstevel@tonic-gate */
24947c478bd9Sstevel@tonic-gate ENABLE_MAC(erip);
24957c478bd9Sstevel@tonic-gate erip->flags |= (ERI_RUNNING | ERI_INITIALIZED |
2496d64540e3Sgd ERI_TXINIT | ERI_RXINIT);
2497d64540e3Sgd mac_tx_update(erip->mh);
24987c478bd9Sstevel@tonic-gate erip->global_reset_issued = 0;
24997c478bd9Sstevel@tonic-gate
25007c478bd9Sstevel@tonic-gate #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND
25017c478bd9Sstevel@tonic-gate eri_xcvr_force_mode(erip, &link_timeout);
25027c478bd9Sstevel@tonic-gate #endif
25037c478bd9Sstevel@tonic-gate
25047c478bd9Sstevel@tonic-gate done:
25057c478bd9Sstevel@tonic-gate if (init_stat)
25067c478bd9Sstevel@tonic-gate eri_unallocthings(erip);
25077c478bd9Sstevel@tonic-gate
25087c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
25097c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, link_timeout);
25107c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
25117c478bd9Sstevel@tonic-gate
2512d64540e3Sgd if (linkupdate != LINK_STATE_UNKNOWN)
2513d64540e3Sgd mac_link_update(erip->mh, linkupdate);
2514860c4cd4Scarlsonj
2515d64540e3Sgd ret = (erip->flags & ERI_RUNNING) ? B_TRUE : B_FALSE;
2516d64540e3Sgd if (!ret) {
25177c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
2518d64540e3Sgd "eri_init failed");
25197c478bd9Sstevel@tonic-gate }
25207c478bd9Sstevel@tonic-gate
25217c478bd9Sstevel@tonic-gate init_exit:
25227c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&erip->linklock));
25237c478bd9Sstevel@tonic-gate return (ret);
25247c478bd9Sstevel@tonic-gate }
25257c478bd9Sstevel@tonic-gate
25267c478bd9Sstevel@tonic-gate /*
25277c478bd9Sstevel@tonic-gate * 0 as burstsize upon failure as it signifies no burst size.
25287c478bd9Sstevel@tonic-gate */
25297c478bd9Sstevel@tonic-gate static int
eri_burstsize(struct eri * erip)25307c478bd9Sstevel@tonic-gate eri_burstsize(struct eri *erip)
25317c478bd9Sstevel@tonic-gate {
25327c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle;
25337c478bd9Sstevel@tonic-gate
2534d64540e3Sgd if (ddi_dma_alloc_handle(erip->dip, &dma_attr, DDI_DMA_DONTWAIT,
2535d64540e3Sgd NULL, &handle))
25367c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
25377c478bd9Sstevel@tonic-gate
25387c478bd9Sstevel@tonic-gate erip->burstsizes = ddi_dma_burstsizes(handle);
25397c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&handle);
25407c478bd9Sstevel@tonic-gate
25417c478bd9Sstevel@tonic-gate if (erip->burstsizes)
25427c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
25437c478bd9Sstevel@tonic-gate
25447c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
25457c478bd9Sstevel@tonic-gate }
25467c478bd9Sstevel@tonic-gate
25477c478bd9Sstevel@tonic-gate /*
25487c478bd9Sstevel@tonic-gate * Un-initialize (STOP) ERI channel.
25497c478bd9Sstevel@tonic-gate */
25507c478bd9Sstevel@tonic-gate static void
eri_uninit(struct eri * erip)25517c478bd9Sstevel@tonic-gate eri_uninit(struct eri *erip)
25527c478bd9Sstevel@tonic-gate {
2553860c4cd4Scarlsonj boolean_t needind;
2554860c4cd4Scarlsonj
25557c478bd9Sstevel@tonic-gate /*
25567c478bd9Sstevel@tonic-gate * Allow up to 'ERI_DRAINTIME' for pending xmit's to complete.
25577c478bd9Sstevel@tonic-gate */
25587c478bd9Sstevel@tonic-gate ERI_DELAY((erip->tcurp == erip->tnextp), ERI_DRAINTIME);
25597c478bd9Sstevel@tonic-gate
25607c478bd9Sstevel@tonic-gate mutex_enter(&erip->intrlock);
25617c478bd9Sstevel@tonic-gate eri_stop_timer(erip); /* acquire linklock */
25627c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
25637c478bd9Sstevel@tonic-gate mutex_enter(&erip->xcvrlock);
25647c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_STOP);
25657c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_DLPI_LINKUP;
25667c478bd9Sstevel@tonic-gate mutex_exit(&erip->xcvrlock);
25677c478bd9Sstevel@tonic-gate
2568860c4cd4Scarlsonj needind = !erip->linkcheck;
25697c478bd9Sstevel@tonic-gate (void) eri_stop(erip);
25707c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_RUNNING;
25717c478bd9Sstevel@tonic-gate
25727c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
25737c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, 0);
25747c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
2575860c4cd4Scarlsonj
2576860c4cd4Scarlsonj if (needind)
2577d64540e3Sgd mac_link_update(erip->mh, LINK_STATE_DOWN);
25787c478bd9Sstevel@tonic-gate }
25797c478bd9Sstevel@tonic-gate
25807c478bd9Sstevel@tonic-gate /*
25817c478bd9Sstevel@tonic-gate * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and
25827c478bd9Sstevel@tonic-gate * map it in IO space.
25837c478bd9Sstevel@tonic-gate *
25847c478bd9Sstevel@tonic-gate * The driver allocates STREAMS buffers which will be mapped in DVMA
25857c478bd9Sstevel@tonic-gate * space using DDI DMA resources.
25867c478bd9Sstevel@tonic-gate *
25877c478bd9Sstevel@tonic-gate */
25887c478bd9Sstevel@tonic-gate static int
eri_allocthings(struct eri * erip)25897c478bd9Sstevel@tonic-gate eri_allocthings(struct eri *erip)
25907c478bd9Sstevel@tonic-gate {
25917c478bd9Sstevel@tonic-gate
25927c478bd9Sstevel@tonic-gate uintptr_t a;
25937c478bd9Sstevel@tonic-gate int size;
25947c478bd9Sstevel@tonic-gate uint32_t rval;
25957c478bd9Sstevel@tonic-gate int i;
25967c478bd9Sstevel@tonic-gate size_t real_len;
25977c478bd9Sstevel@tonic-gate uint32_t cookiec;
25987c478bd9Sstevel@tonic-gate int alloc_stat = 0;
25997c478bd9Sstevel@tonic-gate ddi_dma_cookie_t dma_cookie;
26007c478bd9Sstevel@tonic-gate
26017c478bd9Sstevel@tonic-gate /*
26027c478bd9Sstevel@tonic-gate * Return if resources are already allocated.
26037c478bd9Sstevel@tonic-gate */
26047c478bd9Sstevel@tonic-gate if (erip->rmdp)
26057c478bd9Sstevel@tonic-gate return (alloc_stat);
26067c478bd9Sstevel@tonic-gate
26077c478bd9Sstevel@tonic-gate erip->alloc_flag = 0;
26087c478bd9Sstevel@tonic-gate
26097c478bd9Sstevel@tonic-gate /*
26107c478bd9Sstevel@tonic-gate * Allocate the TMD and RMD descriptors and extra for alignments.
26117c478bd9Sstevel@tonic-gate */
2612d64540e3Sgd size = (ERI_RPENDING * sizeof (struct rmd) +
2613d64540e3Sgd ERI_TPENDING * sizeof (struct eri_tmd)) + ERI_GMDALIGN;
26147c478bd9Sstevel@tonic-gate
26157c478bd9Sstevel@tonic-gate rval = ddi_dma_alloc_handle(erip->dip, &desc_dma_attr,
2616d64540e3Sgd DDI_DMA_DONTWAIT, 0, &erip->md_h);
26177c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) {
26187c478bd9Sstevel@tonic-gate return (++alloc_stat);
26197c478bd9Sstevel@tonic-gate }
26207c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_DESC_HANDLE_ALLOC;
26217c478bd9Sstevel@tonic-gate
26227c478bd9Sstevel@tonic-gate rval = ddi_dma_mem_alloc(erip->md_h, size, &erip->dev_attr,
2623d64540e3Sgd DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
2624d64540e3Sgd (caddr_t *)&erip->iopbkbase, &real_len, &erip->mdm_h);
26257c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) {
26267c478bd9Sstevel@tonic-gate return (++alloc_stat);
26277c478bd9Sstevel@tonic-gate }
26287c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_DESC_MEM_ALLOC;
26297c478bd9Sstevel@tonic-gate
26307c478bd9Sstevel@tonic-gate rval = ddi_dma_addr_bind_handle(erip->md_h, NULL,
2631d64540e3Sgd (caddr_t)erip->iopbkbase, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2632d64540e3Sgd DDI_DMA_DONTWAIT, 0, &erip->md_c, &cookiec);
26337c478bd9Sstevel@tonic-gate
26347c478bd9Sstevel@tonic-gate if (rval != DDI_DMA_MAPPED)
26357c478bd9Sstevel@tonic-gate return (++alloc_stat);
26367c478bd9Sstevel@tonic-gate
26377c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_DESC_MEM_MAP;
26387c478bd9Sstevel@tonic-gate
26397c478bd9Sstevel@tonic-gate if (cookiec != 1)
26407c478bd9Sstevel@tonic-gate return (++alloc_stat);
26417c478bd9Sstevel@tonic-gate
26427c478bd9Sstevel@tonic-gate erip->iopbiobase = erip->md_c.dmac_address;
26437c478bd9Sstevel@tonic-gate
26447c478bd9Sstevel@tonic-gate a = erip->iopbkbase;
26457c478bd9Sstevel@tonic-gate a = ROUNDUP(a, ERI_GMDALIGN);
26467c478bd9Sstevel@tonic-gate erip->rmdp = (struct rmd *)a;
26477c478bd9Sstevel@tonic-gate a += ERI_RPENDING * sizeof (struct rmd);
26487c478bd9Sstevel@tonic-gate erip->eri_tmdp = (struct eri_tmd *)a;
2649*7e996435SToomas Soome /*
2650*7e996435SToomas Soome * Specifically we reserve n (ERI_TPENDING + ERI_RPENDING)
2651*7e996435SToomas Soome * pagetable entries. Therefore we have 2 ptes for each
2652*7e996435SToomas Soome * descriptor. Since the ethernet buffers are 1518 bytes
2653*7e996435SToomas Soome * so they can at most use 2 ptes.
2654*7e996435SToomas Soome * Will do a ddi_dma_addr_setup for each bufer
2655*7e996435SToomas Soome */
26567c478bd9Sstevel@tonic-gate /*
26577c478bd9Sstevel@tonic-gate * In the current implementation, we use the ddi compliant
2658bd78278bSGarrett D'Amore * dma interface. We allocate ERI_RPENDING dma handles for receive
2659bd78278bSGarrett D'Amore * activity. The actual dma mapping is done in the io function
2660bd78278bSGarrett D'Amore * eri_read_dma(), by calling the ddi_dma_addr_bind_handle.
26617c478bd9Sstevel@tonic-gate * Dma resources are deallocated by calling ddi_dma_unbind_handle
26627c478bd9Sstevel@tonic-gate * in eri_reclaim() for transmit and eri_read_dma(), for receive io.
26637c478bd9Sstevel@tonic-gate */
26647c478bd9Sstevel@tonic-gate
26657c478bd9Sstevel@tonic-gate if (eri_use_dvma_rx &&
26667c478bd9Sstevel@tonic-gate (dvma_reserve(erip->dip, &eri_dma_limits, (ERI_RPENDING * 2),
26677c478bd9Sstevel@tonic-gate &erip->eri_dvmarh)) == DDI_SUCCESS) {
26687c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_RCV_DVMA_ALLOC;
26697c478bd9Sstevel@tonic-gate } else {
26707c478bd9Sstevel@tonic-gate erip->eri_dvmarh = NULL;
26717c478bd9Sstevel@tonic-gate
26727c478bd9Sstevel@tonic-gate for (i = 0; i < ERI_RPENDING; i++) {
26737c478bd9Sstevel@tonic-gate rval = ddi_dma_alloc_handle(erip->dip,
26747c478bd9Sstevel@tonic-gate &dma_attr, DDI_DMA_DONTWAIT,
26757c478bd9Sstevel@tonic-gate 0, &erip->ndmarh[i]);
26767c478bd9Sstevel@tonic-gate
26777c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) {
26787c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_HIGH,
26797c478bd9Sstevel@tonic-gate ERI_VERB_MSG, alloc_rx_dmah_msg);
26807c478bd9Sstevel@tonic-gate alloc_stat++;
26817c478bd9Sstevel@tonic-gate break;
26827c478bd9Sstevel@tonic-gate }
26837c478bd9Sstevel@tonic-gate }
26847c478bd9Sstevel@tonic-gate
26857c478bd9Sstevel@tonic-gate erip->rcv_handle_cnt = i;
26867c478bd9Sstevel@tonic-gate
26877c478bd9Sstevel@tonic-gate if (i)
26887c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_RCV_HANDLE_ALLOC;
26897c478bd9Sstevel@tonic-gate
26907c478bd9Sstevel@tonic-gate if (alloc_stat)
26917c478bd9Sstevel@tonic-gate return (alloc_stat);
26927c478bd9Sstevel@tonic-gate
26937c478bd9Sstevel@tonic-gate }
26947c478bd9Sstevel@tonic-gate
26957c478bd9Sstevel@tonic-gate /*
2696bd78278bSGarrett D'Amore * Allocate TX buffer
2697bd78278bSGarrett D'Amore * Note: buffers must always be allocated in the native
26987c478bd9Sstevel@tonic-gate * ordering of the CPU (always big-endian for Sparc).
26997c478bd9Sstevel@tonic-gate * ddi_dma_mem_alloc returns memory in the native ordering
27007c478bd9Sstevel@tonic-gate * of the bus (big endian for SBus, little endian for PCI).
27017c478bd9Sstevel@tonic-gate * So we cannot use ddi_dma_mem_alloc(, &erip->ge_dev_attr)
27027c478bd9Sstevel@tonic-gate * because we'll get little endian memory on PCI.
27037c478bd9Sstevel@tonic-gate */
2704d64540e3Sgd if (ddi_dma_alloc_handle(erip->dip, &desc_dma_attr, DDI_DMA_DONTWAIT,
2705d64540e3Sgd 0, &erip->tbuf_handle) != DDI_SUCCESS) {
2706d64540e3Sgd ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
2707d64540e3Sgd alloc_tx_dmah_msg);
2708d64540e3Sgd return (++alloc_stat);
27097c478bd9Sstevel@tonic-gate }
27107c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_XBUFS_HANDLE_ALLOC;
2711bd78278bSGarrett D'Amore size = ERI_TPENDING * ERI_BUFSIZE;
2712bd78278bSGarrett D'Amore if (ddi_dma_mem_alloc(erip->tbuf_handle, size, &buf_attr,
2713bd78278bSGarrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, &erip->tbuf_kaddr,
2714bd78278bSGarrett D'Amore &real_len, &erip->tbuf_acch) != DDI_SUCCESS) {
27157c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
2716d64540e3Sgd alloc_tx_dmah_msg);
27177c478bd9Sstevel@tonic-gate return (++alloc_stat);
27187c478bd9Sstevel@tonic-gate }
27197c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_XBUFS_KMEM_ALLOC;
27207c478bd9Sstevel@tonic-gate if (ddi_dma_addr_bind_handle(erip->tbuf_handle, NULL,
2721d64540e3Sgd erip->tbuf_kaddr, size, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
2722d64540e3Sgd DDI_DMA_DONTWAIT, 0, &dma_cookie, &cookiec) != DDI_DMA_MAPPED) {
27237c478bd9Sstevel@tonic-gate return (++alloc_stat);
27247c478bd9Sstevel@tonic-gate }
27257c478bd9Sstevel@tonic-gate erip->tbuf_ioaddr = dma_cookie.dmac_address;
27267c478bd9Sstevel@tonic-gate erip->alloc_flag |= ERI_XBUFS_KMEM_DMABIND;
27277c478bd9Sstevel@tonic-gate if (cookiec != 1)
27287c478bd9Sstevel@tonic-gate return (++alloc_stat);
27297c478bd9Sstevel@tonic-gate
27307c478bd9Sstevel@tonic-gate /*
27317c478bd9Sstevel@tonic-gate * Keep handy limit values for RMD, TMD, and Buffers.
27327c478bd9Sstevel@tonic-gate */
27337c478bd9Sstevel@tonic-gate erip->rmdlimp = &((erip->rmdp)[ERI_RPENDING]);
27347c478bd9Sstevel@tonic-gate erip->eri_tmdlimp = &((erip->eri_tmdp)[ERI_TPENDING]);
27357c478bd9Sstevel@tonic-gate
27367c478bd9Sstevel@tonic-gate /*
2737bd78278bSGarrett D'Amore * Zero out RCV holders.
27387c478bd9Sstevel@tonic-gate */
27397c478bd9Sstevel@tonic-gate bzero((caddr_t)erip->rmblkp, sizeof (erip->rmblkp));
27407c478bd9Sstevel@tonic-gate return (alloc_stat);
27417c478bd9Sstevel@tonic-gate }
27427c478bd9Sstevel@tonic-gate
27437c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<< INTERRUPT HANDLING FUNCTION >>>>>>>>>>>>>>>>>>>> */
27447c478bd9Sstevel@tonic-gate /*
27457c478bd9Sstevel@tonic-gate * First check to see if it is our device interrupting.
27467c478bd9Sstevel@tonic-gate */
27477c478bd9Sstevel@tonic-gate static uint_t
eri_intr(caddr_t arg)2748d64540e3Sgd eri_intr(caddr_t arg)
27497c478bd9Sstevel@tonic-gate {
2750d64540e3Sgd struct eri *erip = (void *)arg;
27517c478bd9Sstevel@tonic-gate uint32_t erisbits;
27527c478bd9Sstevel@tonic-gate uint32_t mif_status;
27537c478bd9Sstevel@tonic-gate uint32_t serviced = DDI_INTR_UNCLAIMED;
2754d64540e3Sgd link_state_t linkupdate = LINK_STATE_UNKNOWN;
2755d64540e3Sgd boolean_t macupdate = B_FALSE;
2756d64540e3Sgd mblk_t *mp;
2757d64540e3Sgd mblk_t *head;
2758d64540e3Sgd mblk_t **tail;
2759d64540e3Sgd
2760d64540e3Sgd head = NULL;
2761d64540e3Sgd tail = &head;
2762860c4cd4Scarlsonj
27637c478bd9Sstevel@tonic-gate mutex_enter(&erip->intrlock);
27647c478bd9Sstevel@tonic-gate
27657c478bd9Sstevel@tonic-gate erisbits = GET_GLOBREG(status);
27667c478bd9Sstevel@tonic-gate
27677c478bd9Sstevel@tonic-gate /*
27687c478bd9Sstevel@tonic-gate * Check if it is only the RX_DONE interrupt, which is
27697c478bd9Sstevel@tonic-gate * the most frequent one.
27707c478bd9Sstevel@tonic-gate */
27717c478bd9Sstevel@tonic-gate if (((erisbits & ERI_G_STATUS_RX_INT) == ERI_G_STATUS_RX_DONE) &&
2772d64540e3Sgd (erip->flags & ERI_RUNNING)) {
27737c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED;
27747c478bd9Sstevel@tonic-gate goto rx_done_int;
27757c478bd9Sstevel@tonic-gate }
27767c478bd9Sstevel@tonic-gate
27777c478bd9Sstevel@tonic-gate /* Claim the first interrupt after initialization */
27787c478bd9Sstevel@tonic-gate if (erip->flags & ERI_INITIALIZED) {
27797c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_INITIALIZED;
27807c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED;
27817c478bd9Sstevel@tonic-gate }
27827c478bd9Sstevel@tonic-gate
27837c478bd9Sstevel@tonic-gate /* Check for interesting events */
27847c478bd9Sstevel@tonic-gate if ((erisbits & ERI_G_STATUS_INTR) == 0) {
2785860c4cd4Scarlsonj #ifdef ESTAR_WORKAROUND
2786d64540e3Sgd uint32_t linkupdate;
2787860c4cd4Scarlsonj #endif
2788860c4cd4Scarlsonj
27897c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, DIAG_MSG,
2790d64540e3Sgd "eri_intr: Interrupt Not Claimed gsbits %X", erisbits);
27917c478bd9Sstevel@tonic-gate #ifdef DEBUG
27927c478bd9Sstevel@tonic-gate noteri++;
27937c478bd9Sstevel@tonic-gate #endif
2794d64540e3Sgd ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF Config = 0x%X",
2795d64540e3Sgd GET_MIFREG(mif_cfg));
2796d64540e3Sgd ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF imask = 0x%X",
2797d64540e3Sgd GET_MIFREG(mif_imask));
2798d64540e3Sgd ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:INT imask = 0x%X",
2799d64540e3Sgd GET_GLOBREG(intmask));
2800d64540e3Sgd ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:alias %X",
2801d64540e3Sgd GET_GLOBREG(status_alias));
28027c478bd9Sstevel@tonic-gate #ifdef ESTAR_WORKAROUND
2803d64540e3Sgd linkupdate = eri_check_link_noind(erip);
28047c478bd9Sstevel@tonic-gate #endif
28057c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
2806860c4cd4Scarlsonj #ifdef ESTAR_WORKAROUND
2807d64540e3Sgd if (linkupdate != LINK_STATE_UNKNOWN)
2808d64540e3Sgd mac_link_update(erip->mh, linkupdate);
2809860c4cd4Scarlsonj #endif
28107c478bd9Sstevel@tonic-gate return (serviced);
28117c478bd9Sstevel@tonic-gate }
28127c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED;
28137c478bd9Sstevel@tonic-gate
28147c478bd9Sstevel@tonic-gate if (!(erip->flags & ERI_RUNNING)) {
28157c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
28167c478bd9Sstevel@tonic-gate eri_uninit(erip);
28177c478bd9Sstevel@tonic-gate return (serviced);
28187c478bd9Sstevel@tonic-gate }
28197c478bd9Sstevel@tonic-gate
28207c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_FATAL_ERR) {
28217c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, INTR_MSG,
2822d64540e3Sgd "eri_intr: fatal error: erisbits = %X", erisbits);
28237c478bd9Sstevel@tonic-gate (void) eri_fatal_err(erip, erisbits);
28247c478bd9Sstevel@tonic-gate eri_reinit_fatal++;
28257c478bd9Sstevel@tonic-gate
28267c478bd9Sstevel@tonic-gate if (erip->rx_reset_issued) {
28277c478bd9Sstevel@tonic-gate erip->rx_reset_issued = 0;
28287c478bd9Sstevel@tonic-gate (void) eri_init_rx_channel(erip);
28297c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
28307c478bd9Sstevel@tonic-gate } else {
28317c478bd9Sstevel@tonic-gate param_linkup = 0;
2832d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
2833d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
28347c478bd9Sstevel@tonic-gate DISABLE_MAC(erip);
28357c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
28367c478bd9Sstevel@tonic-gate (void) eri_init(erip);
28377c478bd9Sstevel@tonic-gate }
28387c478bd9Sstevel@tonic-gate return (serviced);
28397c478bd9Sstevel@tonic-gate }
28407c478bd9Sstevel@tonic-gate
28417c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_NONFATAL_ERR) {
28427c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, INTR_MSG,
2843d64540e3Sgd "eri_intr: non-fatal error: erisbits = %X", erisbits);
28447c478bd9Sstevel@tonic-gate (void) eri_nonfatal_err(erip, erisbits);
28457c478bd9Sstevel@tonic-gate if (erip->linkcheck) {
28467c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
28477c478bd9Sstevel@tonic-gate (void) eri_init(erip);
28487c478bd9Sstevel@tonic-gate return (serviced);
28497c478bd9Sstevel@tonic-gate }
28507c478bd9Sstevel@tonic-gate }
28517c478bd9Sstevel@tonic-gate
28527c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_MIF_INT) {
28537c478bd9Sstevel@tonic-gate uint16_t stat;
28547c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, XCVR_MSG,
2855d64540e3Sgd "eri_intr:MIF Interrupt:mii_status %X", erip->mii_status);
28567c478bd9Sstevel@tonic-gate eri_stop_timer(erip); /* acquire linklock */
28577c478bd9Sstevel@tonic-gate
28587c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
28597c478bd9Sstevel@tonic-gate mutex_enter(&erip->xcvrlock);
28607c478bd9Sstevel@tonic-gate #ifdef ERI_MIF_POLL_STATUS_WORKAROUND
28617c478bd9Sstevel@tonic-gate mif_status = GET_MIFREG(mif_bsts);
28627c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_STOP);
28637c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG3(erip, XCVR_MSG,
2864d64540e3Sgd "eri_intr: new MIF interrupt status %X XCVR status %X",
2865d64540e3Sgd mif_status, erip->mii_status);
28667c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
2867d64540e3Sgd linkupdate = eri_mif_check(erip, stat, stat);
28687c478bd9Sstevel@tonic-gate
28697c478bd9Sstevel@tonic-gate #else
28707c478bd9Sstevel@tonic-gate mif_status = GET_MIFREG(mif_bsts);
28717c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_STOP);
2872d64540e3Sgd linkupdate = eri_mif_check(erip, (uint16_t)mif_status,
2873d64540e3Sgd (uint16_t)(mif_status >> 16));
28747c478bd9Sstevel@tonic-gate #endif
28757c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_START);
28767c478bd9Sstevel@tonic-gate mutex_exit(&erip->xcvrlock);
28777c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
28787c478bd9Sstevel@tonic-gate
28797c478bd9Sstevel@tonic-gate if (!erip->openloop_autoneg)
28807c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link,
2881d64540e3Sgd ERI_LINKCHECK_TIMER);
28827c478bd9Sstevel@tonic-gate else
28837c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link,
2884d64540e3Sgd ERI_P_FAULT_TIMER);
28857c478bd9Sstevel@tonic-gate }
28867c478bd9Sstevel@tonic-gate
28877c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, INTR_MSG,
2888d64540e3Sgd "eri_intr:May have Read Interrupt status:status %X", erisbits);
28897c478bd9Sstevel@tonic-gate
28907c478bd9Sstevel@tonic-gate rx_done_int:
28917c478bd9Sstevel@tonic-gate if ((erisbits & (ERI_G_STATUS_TX_INT_ME)) ||
28927c478bd9Sstevel@tonic-gate (erip->tx_cur_cnt >= tx_interrupt_rate)) {
28937c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
28947c478bd9Sstevel@tonic-gate erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
28957c478bd9Sstevel@tonic-gate ETX_COMPLETION_MASK);
28967c478bd9Sstevel@tonic-gate
2897d64540e3Sgd macupdate |= eri_reclaim(erip, erip->tx_completion);
28986213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic if (macupdate)
28996213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic erip->wantw = B_FALSE;
29006213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic
29017c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
29027c478bd9Sstevel@tonic-gate }
29037c478bd9Sstevel@tonic-gate
29047c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_RX_DONE) {
29057c478bd9Sstevel@tonic-gate volatile struct rmd *rmdp, *rmdpbase;
29067c478bd9Sstevel@tonic-gate volatile uint32_t rmdi;
29077c478bd9Sstevel@tonic-gate uint8_t loop_limit = 0x20;
29087c478bd9Sstevel@tonic-gate uint64_t flags;
29097c478bd9Sstevel@tonic-gate uint32_t rmdmax_mask = erip->rmdmax_mask;
29107c478bd9Sstevel@tonic-gate
29117c478bd9Sstevel@tonic-gate rmdpbase = erip->rmdp;
29127c478bd9Sstevel@tonic-gate rmdi = erip->rx_completion;
29137c478bd9Sstevel@tonic-gate rmdp = rmdpbase + rmdi;
29147c478bd9Sstevel@tonic-gate
29157c478bd9Sstevel@tonic-gate /*
29167c478bd9Sstevel@tonic-gate * Sync RMD before looking at it.
29177c478bd9Sstevel@tonic-gate */
29187c478bd9Sstevel@tonic-gate ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
2919d64540e3Sgd DDI_DMA_SYNC_FORCPU);
29207c478bd9Sstevel@tonic-gate /*
29217c478bd9Sstevel@tonic-gate * Loop through each RMD.
29227c478bd9Sstevel@tonic-gate */
29237c478bd9Sstevel@tonic-gate
29247c478bd9Sstevel@tonic-gate flags = GET_RMD_FLAGS(rmdp);
29257c478bd9Sstevel@tonic-gate while (((flags & ERI_RMD_OWN) == 0) && (loop_limit)) {
29267c478bd9Sstevel@tonic-gate /* process one packet */
2927d64540e3Sgd mp = eri_read_dma(erip, rmdp, rmdi, flags);
29287c478bd9Sstevel@tonic-gate rmdi = (rmdi + 1) & rmdmax_mask;
29297c478bd9Sstevel@tonic-gate rmdp = rmdpbase + rmdi;
29307c478bd9Sstevel@tonic-gate
2931d64540e3Sgd if (mp != NULL) {
2932d64540e3Sgd *tail = mp;
2933d64540e3Sgd tail = &mp->b_next;
2934d64540e3Sgd }
2935d64540e3Sgd
29367c478bd9Sstevel@tonic-gate /*
29377c478bd9Sstevel@tonic-gate * ERI RCV DMA fetches or updates four descriptors
29387c478bd9Sstevel@tonic-gate * a time. Also we don't want to update the desc.
29397c478bd9Sstevel@tonic-gate * batch we just received packet on. So we update
29407c478bd9Sstevel@tonic-gate * descriptors for every 4 packets and we update
29417c478bd9Sstevel@tonic-gate * the group of 4 after the current batch.
29427c478bd9Sstevel@tonic-gate */
29437c478bd9Sstevel@tonic-gate
29447c478bd9Sstevel@tonic-gate if (!(rmdi % 4)) {
29457c478bd9Sstevel@tonic-gate if (eri_overflow_reset &&
29467c478bd9Sstevel@tonic-gate (GET_GLOBREG(status_alias) &
29477c478bd9Sstevel@tonic-gate ERI_G_STATUS_NONFATAL_ERR)) {
29487c478bd9Sstevel@tonic-gate loop_limit = 1;
29497c478bd9Sstevel@tonic-gate } else {
29507c478bd9Sstevel@tonic-gate erip->rx_kick =
2951d64540e3Sgd (rmdi + ERI_RPENDING - 4) &
2952d64540e3Sgd rmdmax_mask;
29537c478bd9Sstevel@tonic-gate PUT_ERXREG(rx_kick, erip->rx_kick);
29547c478bd9Sstevel@tonic-gate }
29557c478bd9Sstevel@tonic-gate }
29567c478bd9Sstevel@tonic-gate
29577c478bd9Sstevel@tonic-gate /*
29587c478bd9Sstevel@tonic-gate * Sync the next RMD before looking at it.
29597c478bd9Sstevel@tonic-gate */
29607c478bd9Sstevel@tonic-gate ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
2961d64540e3Sgd DDI_DMA_SYNC_FORCPU);
29627c478bd9Sstevel@tonic-gate flags = GET_RMD_FLAGS(rmdp);
29637c478bd9Sstevel@tonic-gate loop_limit--;
29647c478bd9Sstevel@tonic-gate }
29657c478bd9Sstevel@tonic-gate erip->rx_completion = rmdi;
29667c478bd9Sstevel@tonic-gate }
2967d64540e3Sgd
29687c478bd9Sstevel@tonic-gate mutex_exit(&erip->intrlock);
29697c478bd9Sstevel@tonic-gate
2970d64540e3Sgd if (head)
2971d64540e3Sgd mac_rx(erip->mh, NULL, head);
2972d64540e3Sgd
2973d64540e3Sgd if (macupdate)
2974d64540e3Sgd mac_tx_update(erip->mh);
2975d64540e3Sgd
2976d64540e3Sgd if (linkupdate != LINK_STATE_UNKNOWN)
2977d64540e3Sgd mac_link_update(erip->mh, linkupdate);
2978860c4cd4Scarlsonj
29797c478bd9Sstevel@tonic-gate return (serviced);
29807c478bd9Sstevel@tonic-gate }
29817c478bd9Sstevel@tonic-gate
29827c478bd9Sstevel@tonic-gate /*
29837c478bd9Sstevel@tonic-gate * Handle interrupts for fatal errors
29847c478bd9Sstevel@tonic-gate * Need reinitialization.
29857c478bd9Sstevel@tonic-gate */
29867c478bd9Sstevel@tonic-gate #define PCI_DATA_PARITY_REP (1 << 8)
29877c478bd9Sstevel@tonic-gate #define PCI_SING_TARGET_ABORT (1 << 11)
29887c478bd9Sstevel@tonic-gate #define PCI_RCV_TARGET_ABORT (1 << 12)
29897c478bd9Sstevel@tonic-gate #define PCI_RCV_MASTER_ABORT (1 << 13)
29907c478bd9Sstevel@tonic-gate #define PCI_SING_SYSTEM_ERR (1 << 14)
29917c478bd9Sstevel@tonic-gate #define PCI_DATA_PARITY_ERR (1 << 15)
29927c478bd9Sstevel@tonic-gate
29937c478bd9Sstevel@tonic-gate /* called with intrlock held */
29947c478bd9Sstevel@tonic-gate static void
eri_fatal_err(struct eri * erip,uint32_t erisbits)29957c478bd9Sstevel@tonic-gate eri_fatal_err(struct eri *erip, uint32_t erisbits)
29967c478bd9Sstevel@tonic-gate {
29977c478bd9Sstevel@tonic-gate uint16_t pci_status;
29987c478bd9Sstevel@tonic-gate uint32_t pci_error_int = 0;
29997c478bd9Sstevel@tonic-gate
30007c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_RX_TAG_ERR) {
30017c478bd9Sstevel@tonic-gate erip->rx_reset_issued = 1;
30027c478bd9Sstevel@tonic-gate HSTAT(erip, rxtag_err);
30037c478bd9Sstevel@tonic-gate } else {
30047c478bd9Sstevel@tonic-gate erip->global_reset_issued = 1;
30057c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_BUS_ERR_INT) {
30067c478bd9Sstevel@tonic-gate pci_error_int = 1;
30077c478bd9Sstevel@tonic-gate HSTAT(erip, pci_error_int);
30087c478bd9Sstevel@tonic-gate } else if (erisbits & ERI_G_STATUS_PERR_INT) {
30097c478bd9Sstevel@tonic-gate HSTAT(erip, parity_error);
30107c478bd9Sstevel@tonic-gate } else {
30117c478bd9Sstevel@tonic-gate HSTAT(erip, unknown_fatal);
30127c478bd9Sstevel@tonic-gate }
30137c478bd9Sstevel@tonic-gate }
30147c478bd9Sstevel@tonic-gate
30157c478bd9Sstevel@tonic-gate /*
30167c478bd9Sstevel@tonic-gate * PCI bus error
30177c478bd9Sstevel@tonic-gate */
30187c478bd9Sstevel@tonic-gate if (pci_error_int && erip->pci_config_handle) {
30197c478bd9Sstevel@tonic-gate pci_status = pci_config_get16(erip->pci_config_handle,
3020d64540e3Sgd PCI_CONF_STAT);
3021d64540e3Sgd ERI_DEBUG_MSG2(erip, FATAL_ERR_MSG, "Bus Error Status %x",
3022d64540e3Sgd pci_status);
30237c478bd9Sstevel@tonic-gate if (pci_status & PCI_DATA_PARITY_REP)
30247c478bd9Sstevel@tonic-gate HSTAT(erip, pci_data_parity_err);
30257c478bd9Sstevel@tonic-gate if (pci_status & PCI_SING_TARGET_ABORT)
30267c478bd9Sstevel@tonic-gate HSTAT(erip, pci_signal_target_abort);
30277c478bd9Sstevel@tonic-gate if (pci_status & PCI_RCV_TARGET_ABORT)
30287c478bd9Sstevel@tonic-gate HSTAT(erip, pci_rcvd_target_abort);
30297c478bd9Sstevel@tonic-gate if (pci_status & PCI_RCV_MASTER_ABORT)
30307c478bd9Sstevel@tonic-gate HSTAT(erip, pci_rcvd_master_abort);
30317c478bd9Sstevel@tonic-gate if (pci_status & PCI_SING_SYSTEM_ERR)
30327c478bd9Sstevel@tonic-gate HSTAT(erip, pci_signal_system_err);
30337c478bd9Sstevel@tonic-gate if (pci_status & PCI_DATA_PARITY_ERR)
30347c478bd9Sstevel@tonic-gate HSTAT(erip, pci_signal_system_err);
30357c478bd9Sstevel@tonic-gate /*
30367c478bd9Sstevel@tonic-gate * clear it by writing the value that was read back.
30377c478bd9Sstevel@tonic-gate */
3038d64540e3Sgd pci_config_put16(erip->pci_config_handle, PCI_CONF_STAT,
3039d64540e3Sgd pci_status);
30407c478bd9Sstevel@tonic-gate }
30417c478bd9Sstevel@tonic-gate }
30427c478bd9Sstevel@tonic-gate
30437c478bd9Sstevel@tonic-gate /*
30447c478bd9Sstevel@tonic-gate * Handle interrupts regarding non-fatal events.
30457c478bd9Sstevel@tonic-gate * TXMAC, RXMAC and MACCTL events
30467c478bd9Sstevel@tonic-gate */
30477c478bd9Sstevel@tonic-gate static void
eri_nonfatal_err(struct eri * erip,uint32_t erisbits)30487c478bd9Sstevel@tonic-gate eri_nonfatal_err(struct eri *erip, uint32_t erisbits)
30497c478bd9Sstevel@tonic-gate {
30507c478bd9Sstevel@tonic-gate
30517c478bd9Sstevel@tonic-gate uint32_t txmac_sts, rxmac_sts, macctl_sts, pause_time;
30527c478bd9Sstevel@tonic-gate
30537c478bd9Sstevel@tonic-gate #ifdef ERI_PM_WORKAROUND
30547c478bd9Sstevel@tonic-gate if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
30557c478bd9Sstevel@tonic-gate PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS)
30567c478bd9Sstevel@tonic-gate erip->stats.pmcap = ERI_PMCAP_NONE;
30577c478bd9Sstevel@tonic-gate #endif
30587c478bd9Sstevel@tonic-gate
30597c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_TX_MAC_INT) {
30607c478bd9Sstevel@tonic-gate txmac_sts = GET_MACREG(txsts);
30617c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_TX_URUN) {
30627c478bd9Sstevel@tonic-gate erip->linkcheck = 1;
30637c478bd9Sstevel@tonic-gate HSTAT(erip, txmac_urun);
30647c478bd9Sstevel@tonic-gate HSTAT(erip, oerrors);
30657c478bd9Sstevel@tonic-gate }
30667c478bd9Sstevel@tonic-gate
30677c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_MAXPKT_ERR) {
30687c478bd9Sstevel@tonic-gate erip->linkcheck = 1;
30697c478bd9Sstevel@tonic-gate HSTAT(erip, txmac_maxpkt_err);
30707c478bd9Sstevel@tonic-gate HSTAT(erip, oerrors);
30717c478bd9Sstevel@tonic-gate }
30727c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_NCC_EXP) {
30737c478bd9Sstevel@tonic-gate erip->stats.collisions += 0x10000;
30747c478bd9Sstevel@tonic-gate }
30757c478bd9Sstevel@tonic-gate
30767c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_ECC_EXP) {
30777c478bd9Sstevel@tonic-gate erip->stats.excessive_coll += 0x10000;
30787c478bd9Sstevel@tonic-gate }
30797c478bd9Sstevel@tonic-gate
30807c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_LCC_EXP) {
30817c478bd9Sstevel@tonic-gate erip->stats.late_coll += 0x10000;
30827c478bd9Sstevel@tonic-gate }
30837c478bd9Sstevel@tonic-gate
30847c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_FCC_EXP) {
30857c478bd9Sstevel@tonic-gate erip->stats.first_coll += 0x10000;
30867c478bd9Sstevel@tonic-gate }
30877c478bd9Sstevel@tonic-gate
30887c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_DEFER_EXP) {
30897c478bd9Sstevel@tonic-gate HSTAT(erip, defer_timer_exp);
30907c478bd9Sstevel@tonic-gate }
30917c478bd9Sstevel@tonic-gate
30927c478bd9Sstevel@tonic-gate if (txmac_sts & BMAC_TXSTS_PEAK_EXP) {
30937c478bd9Sstevel@tonic-gate erip->stats.peak_attempt_cnt += 0x100;
30947c478bd9Sstevel@tonic-gate }
30957c478bd9Sstevel@tonic-gate }
30967c478bd9Sstevel@tonic-gate
30977c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_RX_NO_BUF) {
3098d64540e3Sgd ERI_DEBUG_MSG1(erip, NONFATAL_MSG, "rx dropped/no free desc");
30997c478bd9Sstevel@tonic-gate
31007c478bd9Sstevel@tonic-gate if (eri_overflow_reset)
31017c478bd9Sstevel@tonic-gate erip->linkcheck = 1;
31027c478bd9Sstevel@tonic-gate
31037c478bd9Sstevel@tonic-gate HSTAT(erip, no_free_rx_desc);
31047c478bd9Sstevel@tonic-gate HSTAT(erip, ierrors);
31057c478bd9Sstevel@tonic-gate }
31067c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_RX_MAC_INT) {
31077c478bd9Sstevel@tonic-gate rxmac_sts = GET_MACREG(rxsts);
31087c478bd9Sstevel@tonic-gate if (rxmac_sts & BMAC_RXSTS_RX_OVF) {
31097c478bd9Sstevel@tonic-gate #ifndef ERI_RMAC_HANG_WORKAROUND
31107c478bd9Sstevel@tonic-gate eri_stop_timer(erip); /* acquire linklock */
31117c478bd9Sstevel@tonic-gate erip->check_rmac_hang ++;
31127c478bd9Sstevel@tonic-gate erip->check2_rmac_hang = 0;
31137c478bd9Sstevel@tonic-gate erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr);
31147c478bd9Sstevel@tonic-gate erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr);
31157c478bd9Sstevel@tonic-gate
3116d64540e3Sgd ERI_DEBUG_MSG5(erip, NONFATAL_MSG,
31177c478bd9Sstevel@tonic-gate "overflow intr %d: %8x wr:%2x rd:%2x",
31187c478bd9Sstevel@tonic-gate erip->check_rmac_hang,
31197c478bd9Sstevel@tonic-gate GET_MACREG(macsm),
31207c478bd9Sstevel@tonic-gate GET_ERXREG(rxfifo_wr_ptr),
31217c478bd9Sstevel@tonic-gate GET_ERXREG(rxfifo_rd_ptr));
31227c478bd9Sstevel@tonic-gate
31237c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link,
3124d64540e3Sgd ERI_CHECK_HANG_TIMER);
31257c478bd9Sstevel@tonic-gate #endif
31267c478bd9Sstevel@tonic-gate if (eri_overflow_reset)
31277c478bd9Sstevel@tonic-gate erip->linkcheck = 1;
31287c478bd9Sstevel@tonic-gate
31297c478bd9Sstevel@tonic-gate HSTAT(erip, rx_overflow);
31307c478bd9Sstevel@tonic-gate HSTAT(erip, ierrors);
31317c478bd9Sstevel@tonic-gate }
31327c478bd9Sstevel@tonic-gate
31337c478bd9Sstevel@tonic-gate if (rxmac_sts & BMAC_RXSTS_ALE_EXP) {
31347c478bd9Sstevel@tonic-gate erip->stats.rx_align_err += 0x10000;
31357c478bd9Sstevel@tonic-gate erip->stats.ierrors += 0x10000;
31367c478bd9Sstevel@tonic-gate }
31377c478bd9Sstevel@tonic-gate
31387c478bd9Sstevel@tonic-gate if (rxmac_sts & BMAC_RXSTS_CRC_EXP) {
31397c478bd9Sstevel@tonic-gate erip->stats.rx_crc_err += 0x10000;
31407c478bd9Sstevel@tonic-gate erip->stats.ierrors += 0x10000;
31417c478bd9Sstevel@tonic-gate }
31427c478bd9Sstevel@tonic-gate
31437c478bd9Sstevel@tonic-gate if (rxmac_sts & BMAC_RXSTS_LEN_EXP) {
31447c478bd9Sstevel@tonic-gate erip->stats.rx_length_err += 0x10000;
31457c478bd9Sstevel@tonic-gate erip->stats.ierrors += 0x10000;
31467c478bd9Sstevel@tonic-gate }
31477c478bd9Sstevel@tonic-gate
31487c478bd9Sstevel@tonic-gate if (rxmac_sts & BMAC_RXSTS_CVI_EXP) {
31497c478bd9Sstevel@tonic-gate erip->stats.rx_code_viol_err += 0x10000;
31507c478bd9Sstevel@tonic-gate erip->stats.ierrors += 0x10000;
31517c478bd9Sstevel@tonic-gate }
31527c478bd9Sstevel@tonic-gate }
31537c478bd9Sstevel@tonic-gate
31547c478bd9Sstevel@tonic-gate if (erisbits & ERI_G_STATUS_MAC_CTRL_INT) {
31557c478bd9Sstevel@tonic-gate
31567c478bd9Sstevel@tonic-gate macctl_sts = GET_MACREG(macctl_sts);
31577c478bd9Sstevel@tonic-gate if (macctl_sts & ERI_MCTLSTS_PAUSE_RCVD) {
31587c478bd9Sstevel@tonic-gate pause_time = ((macctl_sts &
3159d64540e3Sgd ERI_MCTLSTS_PAUSE_TIME) >> 16);
31607c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, NONFATAL_MSG,
3161d64540e3Sgd "PAUSE Received. pause time = %X slot_times",
3162d64540e3Sgd pause_time);
31637c478bd9Sstevel@tonic-gate HSTAT(erip, pause_rxcount);
31647c478bd9Sstevel@tonic-gate erip->stats.pause_time_count += pause_time;
31657c478bd9Sstevel@tonic-gate }
31667c478bd9Sstevel@tonic-gate
31677c478bd9Sstevel@tonic-gate if (macctl_sts & ERI_MCTLSTS_PAUSE_STATE) {
31687c478bd9Sstevel@tonic-gate HSTAT(erip, pause_oncount);
3169d64540e3Sgd erip->stats.pausing = 1;
31707c478bd9Sstevel@tonic-gate }
31717c478bd9Sstevel@tonic-gate
31727c478bd9Sstevel@tonic-gate if (macctl_sts & ERI_MCTLSTS_NONPAUSE) {
31737c478bd9Sstevel@tonic-gate HSTAT(erip, pause_offcount);
3174d64540e3Sgd erip->stats.pausing = 0;
31757c478bd9Sstevel@tonic-gate }
31767c478bd9Sstevel@tonic-gate }
31777c478bd9Sstevel@tonic-gate
31787c478bd9Sstevel@tonic-gate }
31797c478bd9Sstevel@tonic-gate
31807c478bd9Sstevel@tonic-gate /*
31817c478bd9Sstevel@tonic-gate * if this is the first init do not bother to save the
31827c478bd9Sstevel@tonic-gate * counters.
31837c478bd9Sstevel@tonic-gate */
31847c478bd9Sstevel@tonic-gate static void
eri_savecntrs(struct eri * erip)31857c478bd9Sstevel@tonic-gate eri_savecntrs(struct eri *erip)
31867c478bd9Sstevel@tonic-gate {
31877c478bd9Sstevel@tonic-gate uint32_t fecnt, aecnt, lecnt, rxcv;
31887c478bd9Sstevel@tonic-gate uint32_t ltcnt, excnt, fccnt;
31897c478bd9Sstevel@tonic-gate
31907c478bd9Sstevel@tonic-gate /* XXX What all gets added in ierrors and oerrors? */
31917c478bd9Sstevel@tonic-gate fecnt = GET_MACREG(fecnt);
31927c478bd9Sstevel@tonic-gate HSTATN(erip, rx_crc_err, fecnt);
31937c478bd9Sstevel@tonic-gate PUT_MACREG(fecnt, 0);
31947c478bd9Sstevel@tonic-gate
31957c478bd9Sstevel@tonic-gate aecnt = GET_MACREG(aecnt);
31967c478bd9Sstevel@tonic-gate HSTATN(erip, rx_align_err, aecnt);
31977c478bd9Sstevel@tonic-gate PUT_MACREG(aecnt, 0);
31987c478bd9Sstevel@tonic-gate
31997c478bd9Sstevel@tonic-gate lecnt = GET_MACREG(lecnt);
32007c478bd9Sstevel@tonic-gate HSTATN(erip, rx_length_err, lecnt);
32017c478bd9Sstevel@tonic-gate PUT_MACREG(lecnt, 0);
32027c478bd9Sstevel@tonic-gate
32037c478bd9Sstevel@tonic-gate rxcv = GET_MACREG(rxcv);
32047c478bd9Sstevel@tonic-gate HSTATN(erip, rx_code_viol_err, rxcv);
32057c478bd9Sstevel@tonic-gate PUT_MACREG(rxcv, 0);
32067c478bd9Sstevel@tonic-gate
32077c478bd9Sstevel@tonic-gate ltcnt = GET_MACREG(ltcnt);
32087c478bd9Sstevel@tonic-gate HSTATN(erip, late_coll, ltcnt);
32097c478bd9Sstevel@tonic-gate PUT_MACREG(ltcnt, 0);
32107c478bd9Sstevel@tonic-gate
32117c478bd9Sstevel@tonic-gate erip->stats.collisions += (GET_MACREG(nccnt) + ltcnt);
32127c478bd9Sstevel@tonic-gate PUT_MACREG(nccnt, 0);
32137c478bd9Sstevel@tonic-gate
32147c478bd9Sstevel@tonic-gate excnt = GET_MACREG(excnt);
32157c478bd9Sstevel@tonic-gate HSTATN(erip, excessive_coll, excnt);
32167c478bd9Sstevel@tonic-gate PUT_MACREG(excnt, 0);
32177c478bd9Sstevel@tonic-gate
32187c478bd9Sstevel@tonic-gate fccnt = GET_MACREG(fccnt);
32197c478bd9Sstevel@tonic-gate HSTATN(erip, first_coll, fccnt);
32207c478bd9Sstevel@tonic-gate PUT_MACREG(fccnt, 0);
32217c478bd9Sstevel@tonic-gate
32227c478bd9Sstevel@tonic-gate /*
32237c478bd9Sstevel@tonic-gate * Do not add code violations to input errors.
32247c478bd9Sstevel@tonic-gate * They are already counted in CRC errors
32257c478bd9Sstevel@tonic-gate */
32267c478bd9Sstevel@tonic-gate HSTATN(erip, ierrors, (fecnt + aecnt + lecnt));
32277c478bd9Sstevel@tonic-gate HSTATN(erip, oerrors, (ltcnt + excnt));
32287c478bd9Sstevel@tonic-gate }
32297c478bd9Sstevel@tonic-gate
32307c478bd9Sstevel@tonic-gate mblk_t *
eri_allocb_sp(size_t size)32317c478bd9Sstevel@tonic-gate eri_allocb_sp(size_t size)
32327c478bd9Sstevel@tonic-gate {
32337c478bd9Sstevel@tonic-gate mblk_t *mp;
32347c478bd9Sstevel@tonic-gate
32357c478bd9Sstevel@tonic-gate size += 128;
32367c478bd9Sstevel@tonic-gate if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) {
32377c478bd9Sstevel@tonic-gate return (NULL);
32387c478bd9Sstevel@tonic-gate }
32397c478bd9Sstevel@tonic-gate mp->b_wptr += 128;
32407c478bd9Sstevel@tonic-gate mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE);
32417c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_wptr;
32427c478bd9Sstevel@tonic-gate
32437c478bd9Sstevel@tonic-gate return (mp);
32447c478bd9Sstevel@tonic-gate }
32457c478bd9Sstevel@tonic-gate
32467c478bd9Sstevel@tonic-gate mblk_t *
eri_allocb(size_t size)32477c478bd9Sstevel@tonic-gate eri_allocb(size_t size)
32487c478bd9Sstevel@tonic-gate {
32497c478bd9Sstevel@tonic-gate mblk_t *mp;
32507c478bd9Sstevel@tonic-gate
32517c478bd9Sstevel@tonic-gate if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) {
32527c478bd9Sstevel@tonic-gate return (NULL);
32537c478bd9Sstevel@tonic-gate }
32547c478bd9Sstevel@tonic-gate mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE);
32557c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_wptr;
32567c478bd9Sstevel@tonic-gate
32577c478bd9Sstevel@tonic-gate return (mp);
32587c478bd9Sstevel@tonic-gate }
32597c478bd9Sstevel@tonic-gate
32607c478bd9Sstevel@tonic-gate /*
32617c478bd9Sstevel@tonic-gate * Hardware Dependent Functions
32627c478bd9Sstevel@tonic-gate * New Section.
32637c478bd9Sstevel@tonic-gate */
32647c478bd9Sstevel@tonic-gate
32657c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<< Fast Ethernet PHY Bit Bang Operations >>>>>>>>>>>>>>>>>> */
32667c478bd9Sstevel@tonic-gate
32677c478bd9Sstevel@tonic-gate static void
send_bit(struct eri * erip,uint32_t x)32687c478bd9Sstevel@tonic-gate send_bit(struct eri *erip, uint32_t x)
32697c478bd9Sstevel@tonic-gate {
32707c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbdata, x);
32717c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW);
32727c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH);
32737c478bd9Sstevel@tonic-gate }
32747c478bd9Sstevel@tonic-gate
32757c478bd9Sstevel@tonic-gate /*
32767c478bd9Sstevel@tonic-gate * To read the MII register bits according to the IEEE Standard
32777c478bd9Sstevel@tonic-gate */
32787c478bd9Sstevel@tonic-gate static uint32_t
get_bit_std(struct eri * erip)32797c478bd9Sstevel@tonic-gate get_bit_std(struct eri *erip)
32807c478bd9Sstevel@tonic-gate {
32817c478bd9Sstevel@tonic-gate uint32_t x;
32827c478bd9Sstevel@tonic-gate
32837c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW);
32847c478bd9Sstevel@tonic-gate drv_usecwait(1); /* wait for >330 ns for stable data */
32857c478bd9Sstevel@tonic-gate if (param_transceiver == INTERNAL_XCVR)
32867c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM0) ? 1 : 0;
32877c478bd9Sstevel@tonic-gate else
32887c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM1) ? 1 : 0;
32897c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH);
32907c478bd9Sstevel@tonic-gate return (x);
32917c478bd9Sstevel@tonic-gate }
32927c478bd9Sstevel@tonic-gate
32937c478bd9Sstevel@tonic-gate #define SEND_BIT(x) send_bit(erip, x)
32947c478bd9Sstevel@tonic-gate #define GET_BIT_STD(x) x = get_bit_std(erip)
32957c478bd9Sstevel@tonic-gate
32967c478bd9Sstevel@tonic-gate
32977c478bd9Sstevel@tonic-gate static void
eri_bb_mii_write(struct eri * erip,uint8_t regad,uint16_t data)32987c478bd9Sstevel@tonic-gate eri_bb_mii_write(struct eri *erip, uint8_t regad, uint16_t data)
32997c478bd9Sstevel@tonic-gate {
33007c478bd9Sstevel@tonic-gate uint8_t phyad;
33017c478bd9Sstevel@tonic-gate int i;
33027c478bd9Sstevel@tonic-gate
33037c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */
33047c478bd9Sstevel@tonic-gate phyad = erip->phyad;
33057c478bd9Sstevel@tonic-gate (void) eri_bb_force_idle(erip);
33067c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */
33077c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <OP> */
33087c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */
33097c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1);
33107c478bd9Sstevel@tonic-gate }
33117c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */
33127c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1);
33137c478bd9Sstevel@tonic-gate }
33147c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <TA> */
33157c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */
33167c478bd9Sstevel@tonic-gate SEND_BIT((data >> i) & 1);
33177c478bd9Sstevel@tonic-gate }
33187c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */
33197c478bd9Sstevel@tonic-gate }
33207c478bd9Sstevel@tonic-gate
33217c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
33227c478bd9Sstevel@tonic-gate static uint32_t
eri_bb_mii_read(struct eri * erip,uint8_t regad,uint16_t * datap)33237c478bd9Sstevel@tonic-gate eri_bb_mii_read(struct eri *erip, uint8_t regad, uint16_t *datap)
33247c478bd9Sstevel@tonic-gate {
33257c478bd9Sstevel@tonic-gate uint8_t phyad;
33267c478bd9Sstevel@tonic-gate int i;
33277c478bd9Sstevel@tonic-gate uint32_t x;
33287c478bd9Sstevel@tonic-gate uint32_t y;
33297c478bd9Sstevel@tonic-gate
33307c478bd9Sstevel@tonic-gate *datap = 0;
33317c478bd9Sstevel@tonic-gate
33327c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */
33337c478bd9Sstevel@tonic-gate phyad = erip->phyad;
33347c478bd9Sstevel@tonic-gate (void) eri_bb_force_idle(erip);
33357c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */
33367c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <OP> */
33377c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */
33387c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1);
33397c478bd9Sstevel@tonic-gate }
33407c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */
33417c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1);
33427c478bd9Sstevel@tonic-gate }
33437c478bd9Sstevel@tonic-gate
33447c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */
33457c478bd9Sstevel@tonic-gate
33467c478bd9Sstevel@tonic-gate GET_BIT_STD(x);
33477c478bd9Sstevel@tonic-gate GET_BIT_STD(y); /* <TA> */
33487c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */
33497c478bd9Sstevel@tonic-gate GET_BIT_STD(x);
33507c478bd9Sstevel@tonic-gate *datap += (x << i);
33517c478bd9Sstevel@tonic-gate }
33527c478bd9Sstevel@tonic-gate /* Kludge to get the Transceiver out of hung mode */
33537c478bd9Sstevel@tonic-gate /* XXX: Test if this is still needed */
33547c478bd9Sstevel@tonic-gate GET_BIT_STD(x);
33557c478bd9Sstevel@tonic-gate GET_BIT_STD(x);
33567c478bd9Sstevel@tonic-gate GET_BIT_STD(x);
33577c478bd9Sstevel@tonic-gate
33587c478bd9Sstevel@tonic-gate return (y);
33597c478bd9Sstevel@tonic-gate }
33607c478bd9Sstevel@tonic-gate
33617c478bd9Sstevel@tonic-gate static void
eri_bb_force_idle(struct eri * erip)33627c478bd9Sstevel@tonic-gate eri_bb_force_idle(struct eri *erip)
33637c478bd9Sstevel@tonic-gate {
33647c478bd9Sstevel@tonic-gate int i;
33657c478bd9Sstevel@tonic-gate
33667c478bd9Sstevel@tonic-gate for (i = 0; i < 33; i++) {
33677c478bd9Sstevel@tonic-gate SEND_BIT(1);
33687c478bd9Sstevel@tonic-gate }
33697c478bd9Sstevel@tonic-gate }
33707c478bd9Sstevel@tonic-gate
33717c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
33727c478bd9Sstevel@tonic-gate
33737c478bd9Sstevel@tonic-gate
33747c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
33757c478bd9Sstevel@tonic-gate
33767c478bd9Sstevel@tonic-gate #ifdef ERI_FRM_DEBUG
33777c478bd9Sstevel@tonic-gate int frame_flag = 0;
33787c478bd9Sstevel@tonic-gate #endif
33797c478bd9Sstevel@tonic-gate
33807c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
33817c478bd9Sstevel@tonic-gate static uint32_t
eri_mii_read(struct eri * erip,uint8_t regad,uint16_t * datap)33827c478bd9Sstevel@tonic-gate eri_mii_read(struct eri *erip, uint8_t regad, uint16_t *datap)
33837c478bd9Sstevel@tonic-gate {
33847c478bd9Sstevel@tonic-gate uint32_t frame;
33857c478bd9Sstevel@tonic-gate uint8_t phyad;
33867c478bd9Sstevel@tonic-gate
33877c478bd9Sstevel@tonic-gate if (param_transceiver == NO_XCVR)
33887c478bd9Sstevel@tonic-gate return (1); /* No xcvr present */
33897c478bd9Sstevel@tonic-gate
33907c478bd9Sstevel@tonic-gate if (!erip->frame_enable)
33917c478bd9Sstevel@tonic-gate return (eri_bb_mii_read(erip, regad, datap));
33927c478bd9Sstevel@tonic-gate
33937c478bd9Sstevel@tonic-gate phyad = erip->phyad;
33947c478bd9Sstevel@tonic-gate #ifdef ERI_FRM_DEBUG
33957c478bd9Sstevel@tonic-gate if (!frame_flag) {
33967c478bd9Sstevel@tonic-gate eri_errror(erip->dip, "Frame Register used for MII");
33977c478bd9Sstevel@tonic-gate frame_flag = 1;
33987c478bd9Sstevel@tonic-gate }
33997c478bd9Sstevel@tonic-gate #endif
34007c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG3(erip, FRM_MSG,
3401d64540e3Sgd "Frame Reg :mii_read: phyad = %X reg = %X ", phyad, regad);
34027c478bd9Sstevel@tonic-gate
34037c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_frame, ERI_MIF_FRREAD |
3404d64540e3Sgd (phyad << ERI_MIF_FRPHYAD_SHIFT) |
3405d64540e3Sgd (regad << ERI_MIF_FRREGAD_SHIFT));
34067c478bd9Sstevel@tonic-gate MIF_ERIDELAY(300, phyad, regad);
34077c478bd9Sstevel@tonic-gate frame = GET_MIFREG(mif_frame);
34087c478bd9Sstevel@tonic-gate if ((frame & ERI_MIF_FRTA0) == 0) {
34097c478bd9Sstevel@tonic-gate return (1);
34107c478bd9Sstevel@tonic-gate } else {
34117c478bd9Sstevel@tonic-gate *datap = (uint16_t)(frame & ERI_MIF_FRDATA);
34127c478bd9Sstevel@tonic-gate return (0);
34137c478bd9Sstevel@tonic-gate }
34147c478bd9Sstevel@tonic-gate
34157c478bd9Sstevel@tonic-gate }
34167c478bd9Sstevel@tonic-gate
34177c478bd9Sstevel@tonic-gate static void
eri_mii_write(struct eri * erip,uint8_t regad,uint16_t data)34187c478bd9Sstevel@tonic-gate eri_mii_write(struct eri *erip, uint8_t regad, uint16_t data)
34197c478bd9Sstevel@tonic-gate {
34207c478bd9Sstevel@tonic-gate uint8_t phyad;
34217c478bd9Sstevel@tonic-gate
34227c478bd9Sstevel@tonic-gate if (!erip->frame_enable) {
34237c478bd9Sstevel@tonic-gate eri_bb_mii_write(erip, regad, data);
34247c478bd9Sstevel@tonic-gate return;
34257c478bd9Sstevel@tonic-gate }
34267c478bd9Sstevel@tonic-gate
34277c478bd9Sstevel@tonic-gate phyad = erip->phyad;
34287c478bd9Sstevel@tonic-gate
34297c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_frame, (ERI_MIF_FRWRITE |
3430d64540e3Sgd (phyad << ERI_MIF_FRPHYAD_SHIFT) |
3431d64540e3Sgd (regad << ERI_MIF_FRREGAD_SHIFT) | data));
34327c478bd9Sstevel@tonic-gate MIF_ERIDELAY(300, phyad, regad);
3433d64540e3Sgd (void) GET_MIFREG(mif_frame);
34347c478bd9Sstevel@tonic-gate }
34357c478bd9Sstevel@tonic-gate
34367c478bd9Sstevel@tonic-gate
34377c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<< PACKET TRANSMIT FUNCTIONS >>>>>>>>>>>>>>>>>>>> */
34387c478bd9Sstevel@tonic-gate
34397c478bd9Sstevel@tonic-gate #define ERI_CROSS_PAGE_BOUNDRY(i, size, pagesize) \
34407c478bd9Sstevel@tonic-gate ((i & pagesize) != ((i + size) & pagesize))
34417c478bd9Sstevel@tonic-gate
3442d64540e3Sgd /*
3443d64540e3Sgd * Send a single mblk. Returns B_TRUE if the packet is sent, or disposed of
3444d64540e3Sgd * by freemsg. Returns B_FALSE if the packet was not sent or queued, and
3445d64540e3Sgd * should be retried later (due to tx resource exhaustion.)
3446d64540e3Sgd */
3447d64540e3Sgd static boolean_t
eri_send_msg(struct eri * erip,mblk_t * mp)3448d64540e3Sgd eri_send_msg(struct eri *erip, mblk_t *mp)
34497c478bd9Sstevel@tonic-gate {
34507c478bd9Sstevel@tonic-gate volatile struct eri_tmd *tmdp = NULL;
34517c478bd9Sstevel@tonic-gate volatile struct eri_tmd *tbasep = NULL;
3452bd78278bSGarrett D'Amore uint32_t len_msg = 0;
3453bd78278bSGarrett D'Amore uint32_t i;
34547c478bd9Sstevel@tonic-gate uint64_t int_me = 0;
34557c478bd9Sstevel@tonic-gate uint_t tmdcsum = 0;
34567c478bd9Sstevel@tonic-gate uint_t start_offset = 0;
34577c478bd9Sstevel@tonic-gate uint_t stuff_offset = 0;
34587c478bd9Sstevel@tonic-gate uint_t flags = 0;
34597c478bd9Sstevel@tonic-gate
34607c478bd9Sstevel@tonic-gate caddr_t ptr;
34617c478bd9Sstevel@tonic-gate uint32_t offset;
34627c478bd9Sstevel@tonic-gate uint64_t ctrl;
34637c478bd9Sstevel@tonic-gate ddi_dma_cookie_t c;
34647c478bd9Sstevel@tonic-gate
34657c478bd9Sstevel@tonic-gate if (!param_linkup) {
34667c478bd9Sstevel@tonic-gate freemsg(mp);
3467d64540e3Sgd HSTAT(erip, tnocar);
34687c478bd9Sstevel@tonic-gate HSTAT(erip, oerrors);
3469d64540e3Sgd return (B_TRUE);
34707c478bd9Sstevel@tonic-gate }
34717c478bd9Sstevel@tonic-gate
34727c478bd9Sstevel@tonic-gate #ifdef ERI_HWCSUM
34730dc2366fSVenugopal Iyer mac_hcksum_get(mp, &start_offset, &stuff_offset, NULL, NULL, &flags);
3474d64540e3Sgd
3475d64540e3Sgd if (flags & HCK_PARTIALCKSUM) {
3476fd8be74fSgd if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) {
3477fd8be74fSgd start_offset += ETHERHEADER_SIZE + 4;
3478fd8be74fSgd stuff_offset += ETHERHEADER_SIZE + 4;
3479fd8be74fSgd } else {
3480fd8be74fSgd start_offset += ETHERHEADER_SIZE;
3481fd8be74fSgd stuff_offset += ETHERHEADER_SIZE;
3482fd8be74fSgd }
3483d64540e3Sgd tmdcsum = ERI_TMD_CSENABL;
34847c478bd9Sstevel@tonic-gate }
34857c478bd9Sstevel@tonic-gate #endif /* ERI_HWCSUM */
3486bd78278bSGarrett D'Amore
3487bd78278bSGarrett D'Amore if ((len_msg = msgsize(mp)) > ERI_BUFSIZE) {
3488bd78278bSGarrett D'Amore /*
3489bd78278bSGarrett D'Amore * This sholdn't ever occur, as GLD should not send us
3490bd78278bSGarrett D'Amore * packets that are too big.
3491bd78278bSGarrett D'Amore */
3492bd78278bSGarrett D'Amore HSTAT(erip, oerrors);
3493bd78278bSGarrett D'Amore freemsg(mp);
3494bd78278bSGarrett D'Amore return (B_TRUE);
34957c478bd9Sstevel@tonic-gate }
34967c478bd9Sstevel@tonic-gate
34977c478bd9Sstevel@tonic-gate /*
34987c478bd9Sstevel@tonic-gate * update MIB II statistics
34997c478bd9Sstevel@tonic-gate */
3500d64540e3Sgd BUMP_OutNUcast(erip, mp->b_rptr);
35017c478bd9Sstevel@tonic-gate
35027c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
35037c478bd9Sstevel@tonic-gate
35047c478bd9Sstevel@tonic-gate tbasep = erip->eri_tmdp;
35057c478bd9Sstevel@tonic-gate
35067c478bd9Sstevel@tonic-gate /* Check if there are enough descriptors for this packet */
35077c478bd9Sstevel@tonic-gate tmdp = erip->tnextp;
35087c478bd9Sstevel@tonic-gate
35097c478bd9Sstevel@tonic-gate if (tmdp >= erip->tcurp) /* check notmds */
35107c478bd9Sstevel@tonic-gate i = tmdp - erip->tcurp;
35117c478bd9Sstevel@tonic-gate else
35127c478bd9Sstevel@tonic-gate i = tmdp + ERI_TPENDING - erip->tcurp;
35137c478bd9Sstevel@tonic-gate
35147c478bd9Sstevel@tonic-gate if (i > (ERI_TPENDING - 4))
35157c478bd9Sstevel@tonic-gate goto notmds;
35167c478bd9Sstevel@tonic-gate
35176213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic if (i >= (ERI_TPENDING >> 1) && !(erip->starts & 0x7)) {
35187c478bd9Sstevel@tonic-gate int_me = ERI_TMD_INTME;
35197c478bd9Sstevel@tonic-gate
35206213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic if (!erip->tx_int_me) {
35216213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic PUT_GLOBREG(intmask, GET_GLOBREG(intmask) &
35226213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic ~(ERI_G_MASK_TX_INT_ME));
35236213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic erip->tx_int_me = 1;
35246213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic }
35256213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic }
35266213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic
3527bd78278bSGarrett D'Amore i = tmdp - tbasep; /* index */
35287c478bd9Sstevel@tonic-gate
3529bd78278bSGarrett D'Amore offset = (i * ERI_BUFSIZE);
3530bd78278bSGarrett D'Amore ptr = erip->tbuf_kaddr + offset;
35317c478bd9Sstevel@tonic-gate
3532bd78278bSGarrett D'Amore mcopymsg(mp, ptr);
35337c478bd9Sstevel@tonic-gate
35347c478bd9Sstevel@tonic-gate #ifdef ERI_HDX_BUG_WORKAROUND
3535bd78278bSGarrett D'Amore if ((param_mode) || (eri_hdx_pad_enable == 0)) {
3536bd78278bSGarrett D'Amore if (len_msg < ETHERMIN) {
3537bd78278bSGarrett D'Amore bzero((ptr + len_msg), (ETHERMIN - len_msg));
3538bd78278bSGarrett D'Amore len_msg = ETHERMIN;
35397c478bd9Sstevel@tonic-gate }
3540bd78278bSGarrett D'Amore } else {
3541bd78278bSGarrett D'Amore if (len_msg < 97) {
3542bd78278bSGarrett D'Amore bzero((ptr + len_msg), (97 - len_msg));
3543bd78278bSGarrett D'Amore len_msg = 97;
35447c478bd9Sstevel@tonic-gate }
3545bd78278bSGarrett D'Amore }
3546bd78278bSGarrett D'Amore #endif
3547bd78278bSGarrett D'Amore c.dmac_address = erip->tbuf_ioaddr + offset;
3548bd78278bSGarrett D'Amore (void) ddi_dma_sync(erip->tbuf_handle,
3549bd78278bSGarrett D'Amore (off_t)offset, len_msg, DDI_DMA_SYNC_FORDEV);
35507c478bd9Sstevel@tonic-gate
3551bd78278bSGarrett D'Amore /* first and last (and only!) descr of packet */
3552bd78278bSGarrett D'Amore ctrl = ERI_TMD_SOP | ERI_TMD_EOP | int_me | tmdcsum |
3553bd78278bSGarrett D'Amore (start_offset << ERI_TMD_CSSTART_SHIFT) |
3554bd78278bSGarrett D'Amore (stuff_offset << ERI_TMD_CSSTUFF_SHIFT);
35557c478bd9Sstevel@tonic-gate
3556bd78278bSGarrett D'Amore PUT_TMD(tmdp, c, len_msg, ctrl);
3557bd78278bSGarrett D'Amore ERI_SYNCIOPB(erip, tmdp, sizeof (struct eri_tmd),
3558bd78278bSGarrett D'Amore DDI_DMA_SYNC_FORDEV);
35597c478bd9Sstevel@tonic-gate
3560bd78278bSGarrett D'Amore tmdp = NEXTTMD(erip, tmdp);
3561bd78278bSGarrett D'Amore erip->tx_cur_cnt++;
35627c478bd9Sstevel@tonic-gate
35637c478bd9Sstevel@tonic-gate erip->tx_kick = tmdp - tbasep;
35647c478bd9Sstevel@tonic-gate PUT_ETXREG(tx_kick, erip->tx_kick);
35657c478bd9Sstevel@tonic-gate erip->tnextp = tmdp;
35667c478bd9Sstevel@tonic-gate
35677c478bd9Sstevel@tonic-gate erip->starts++;
35687c478bd9Sstevel@tonic-gate
35697c478bd9Sstevel@tonic-gate if (erip->tx_cur_cnt >= tx_interrupt_rate) {
35707c478bd9Sstevel@tonic-gate erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
35717c478bd9Sstevel@tonic-gate ETX_COMPLETION_MASK);
35726213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic (void) eri_reclaim(erip, erip->tx_completion);
35737c478bd9Sstevel@tonic-gate }
35747c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
35757c478bd9Sstevel@tonic-gate
3576d64540e3Sgd return (B_TRUE);
35777c478bd9Sstevel@tonic-gate
35787c478bd9Sstevel@tonic-gate notmds:
35797c478bd9Sstevel@tonic-gate HSTAT(erip, notmds);
3580d64540e3Sgd erip->wantw = B_TRUE;
35817c478bd9Sstevel@tonic-gate
35827c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
35837c478bd9Sstevel@tonic-gate
3584d64540e3Sgd return (B_FALSE);
3585d64540e3Sgd }
3586d64540e3Sgd
3587d64540e3Sgd static mblk_t *
eri_m_tx(void * arg,mblk_t * mp)3588d64540e3Sgd eri_m_tx(void *arg, mblk_t *mp)
3589d64540e3Sgd {
3590d64540e3Sgd struct eri *erip = arg;
3591d64540e3Sgd mblk_t *next;
3592d64540e3Sgd
3593d64540e3Sgd while (mp != NULL) {
3594d64540e3Sgd next = mp->b_next;
3595d64540e3Sgd mp->b_next = NULL;
3596d64540e3Sgd if (!eri_send_msg(erip, mp)) {
3597d64540e3Sgd mp->b_next = next;
3598d64540e3Sgd break;
3599d64540e3Sgd }
3600d64540e3Sgd mp = next;
3601d64540e3Sgd }
3602d64540e3Sgd
3603d64540e3Sgd return (mp);
36047c478bd9Sstevel@tonic-gate }
36057c478bd9Sstevel@tonic-gate
36067c478bd9Sstevel@tonic-gate /*
36077c478bd9Sstevel@tonic-gate * Transmit completion reclaiming.
36087c478bd9Sstevel@tonic-gate */
3609d64540e3Sgd static boolean_t
eri_reclaim(struct eri * erip,uint32_t tx_completion)36107c478bd9Sstevel@tonic-gate eri_reclaim(struct eri *erip, uint32_t tx_completion)
36117c478bd9Sstevel@tonic-gate {
36127c478bd9Sstevel@tonic-gate volatile struct eri_tmd *tmdp;
36137c478bd9Sstevel@tonic-gate struct eri_tmd *tcomp;
36147c478bd9Sstevel@tonic-gate struct eri_tmd *tbasep;
36157c478bd9Sstevel@tonic-gate struct eri_tmd *tlimp;
36167c478bd9Sstevel@tonic-gate uint64_t flags;
36177c478bd9Sstevel@tonic-gate uint_t reclaimed = 0;
36187c478bd9Sstevel@tonic-gate
36197c478bd9Sstevel@tonic-gate tbasep = erip->eri_tmdp;
36207c478bd9Sstevel@tonic-gate tlimp = erip->eri_tmdlimp;
36217c478bd9Sstevel@tonic-gate
36227c478bd9Sstevel@tonic-gate tmdp = erip->tcurp;
36237c478bd9Sstevel@tonic-gate tcomp = tbasep + tx_completion; /* pointer to completion tmd */
36247c478bd9Sstevel@tonic-gate
36257c478bd9Sstevel@tonic-gate /*
36267c478bd9Sstevel@tonic-gate * Loop through each TMD starting from tcurp and upto tcomp.
36277c478bd9Sstevel@tonic-gate */
36287c478bd9Sstevel@tonic-gate while (tmdp != tcomp) {
36297c478bd9Sstevel@tonic-gate flags = GET_TMD_FLAGS(tmdp);
36307c478bd9Sstevel@tonic-gate if (flags & (ERI_TMD_SOP))
36317c478bd9Sstevel@tonic-gate HSTAT(erip, opackets64);
36327c478bd9Sstevel@tonic-gate
36337c478bd9Sstevel@tonic-gate HSTATN(erip, obytes64, (flags & ERI_TMD_BUFSIZE));
36347c478bd9Sstevel@tonic-gate
36357c478bd9Sstevel@tonic-gate tmdp = NEXTTMDP(tbasep, tlimp, tmdp);
36367c478bd9Sstevel@tonic-gate reclaimed++;
36377c478bd9Sstevel@tonic-gate }
36387c478bd9Sstevel@tonic-gate
36397c478bd9Sstevel@tonic-gate erip->tcurp = tmdp;
36407c478bd9Sstevel@tonic-gate erip->tx_cur_cnt -= reclaimed;
36417c478bd9Sstevel@tonic-gate
3642d64540e3Sgd return (erip->wantw && reclaimed ? B_TRUE : B_FALSE);
36437c478bd9Sstevel@tonic-gate }
36447c478bd9Sstevel@tonic-gate
36457c478bd9Sstevel@tonic-gate
36467c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<< PACKET RECEIVE FUNCTIONS >>>>>>>>>>>>>>>>>>> */
3647d64540e3Sgd static mblk_t *
eri_read_dma(struct eri * erip,volatile struct rmd * rmdp,int rmdi,uint64_t flags)36487c478bd9Sstevel@tonic-gate eri_read_dma(struct eri *erip, volatile struct rmd *rmdp,
3649*7e996435SToomas Soome int rmdi, uint64_t flags)
36507c478bd9Sstevel@tonic-gate {
36517c478bd9Sstevel@tonic-gate mblk_t *bp, *nbp;
36527c478bd9Sstevel@tonic-gate int len;
36537c478bd9Sstevel@tonic-gate uint_t ccnt;
36547c478bd9Sstevel@tonic-gate ddi_dma_cookie_t c;
36557c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
36567c478bd9Sstevel@tonic-gate ushort_t sum;
36577c478bd9Sstevel@tonic-gate #endif /* ERI_RCV_CKSUM */
3658d64540e3Sgd mblk_t *retmp = NULL;
36597c478bd9Sstevel@tonic-gate
36607c478bd9Sstevel@tonic-gate bp = erip->rmblkp[rmdi];
36617c478bd9Sstevel@tonic-gate len = (flags & ERI_RMD_BUFSIZE) >> ERI_RMD_BUFSIZE_SHIFT;
36627c478bd9Sstevel@tonic-gate #ifdef ERI_DONT_STRIP_CRC
36637c478bd9Sstevel@tonic-gate len -= 4;
36647c478bd9Sstevel@tonic-gate #endif
36657c478bd9Sstevel@tonic-gate /*
36667c478bd9Sstevel@tonic-gate * In the event of RX FIFO overflow error, ERI REV 1.0 ASIC can
36677c478bd9Sstevel@tonic-gate * corrupt packets following the descriptor corresponding the
36687c478bd9Sstevel@tonic-gate * overflow. To detect the corrupted packets, we disable the
36697c478bd9Sstevel@tonic-gate * dropping of the "bad" packets at the MAC. The descriptor
36707c478bd9Sstevel@tonic-gate * then would have the "BAD" bit set. We drop the overflowing
36717c478bd9Sstevel@tonic-gate * packet and the packet following it. We could have done some sort
36727c478bd9Sstevel@tonic-gate * of checking to determine if the second packet was indeed bad
36737c478bd9Sstevel@tonic-gate * (using CRC or checksum) but it would be expensive in this
36747c478bd9Sstevel@tonic-gate * routine, since it is run in interrupt context.
36757c478bd9Sstevel@tonic-gate */
3676d64540e3Sgd if ((flags & ERI_RMD_BAD) || (len < ETHERMIN) || (len > ETHERMAX+4)) {
36777c478bd9Sstevel@tonic-gate
36787c478bd9Sstevel@tonic-gate HSTAT(erip, rx_bad_pkts);
36797c478bd9Sstevel@tonic-gate if ((flags & ERI_RMD_BAD) == 0)
36807c478bd9Sstevel@tonic-gate HSTAT(erip, ierrors);
36817c478bd9Sstevel@tonic-gate if (len < ETHERMIN) {
36827c478bd9Sstevel@tonic-gate HSTAT(erip, rx_runt);
3683d64540e3Sgd } else if (len > ETHERMAX+4) {
36847c478bd9Sstevel@tonic-gate HSTAT(erip, rx_toolong_pkts);
36857c478bd9Sstevel@tonic-gate }
36867c478bd9Sstevel@tonic-gate HSTAT(erip, drop);
36877c478bd9Sstevel@tonic-gate UPDATE_RMD(rmdp);
36887c478bd9Sstevel@tonic-gate
36897c478bd9Sstevel@tonic-gate ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3690d64540e3Sgd DDI_DMA_SYNC_FORDEV);
3691d64540e3Sgd return (NULL);
36927c478bd9Sstevel@tonic-gate }
36937c478bd9Sstevel@tonic-gate #ifdef ERI_DONT_STRIP_CRC
36947c478bd9Sstevel@tonic-gate {
36957c478bd9Sstevel@tonic-gate uint32_t hw_fcs, tail_fcs;
36967c478bd9Sstevel@tonic-gate /*
369783fcdc8cSyc * since we don't let the hardware strip the CRC in hdx
36987c478bd9Sstevel@tonic-gate * then the driver needs to do it.
36997c478bd9Sstevel@tonic-gate * this is to workaround a hardware bug
37007c478bd9Sstevel@tonic-gate */
37017c478bd9Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + ERI_FSTBYTE_OFFSET + len;
37027c478bd9Sstevel@tonic-gate /*
37037c478bd9Sstevel@tonic-gate * Get the Checksum calculated by the hardware.
37047c478bd9Sstevel@tonic-gate */
37057c478bd9Sstevel@tonic-gate hw_fcs = flags & ERI_RMD_CKSUM;
37067c478bd9Sstevel@tonic-gate /*
37077c478bd9Sstevel@tonic-gate * Catch the case when the CRC starts on an odd
37087c478bd9Sstevel@tonic-gate * boundary.
37097c478bd9Sstevel@tonic-gate */
37107c478bd9Sstevel@tonic-gate tail_fcs = bp->b_wptr[0] << 8 | bp->b_wptr[1];
37117c478bd9Sstevel@tonic-gate tail_fcs += bp->b_wptr[2] << 8 | bp->b_wptr[3];
37127c478bd9Sstevel@tonic-gate tail_fcs = (tail_fcs & 0xffff) + (tail_fcs >> 16);
371383fcdc8cSyc if ((uintptr_t)(bp->b_wptr) & 1) {
37147c478bd9Sstevel@tonic-gate tail_fcs = (tail_fcs << 8) & 0xffff | (tail_fcs >> 8);
37157c478bd9Sstevel@tonic-gate }
37167c478bd9Sstevel@tonic-gate hw_fcs += tail_fcs;
37177c478bd9Sstevel@tonic-gate hw_fcs = (hw_fcs & 0xffff) + (hw_fcs >> 16);
37187c478bd9Sstevel@tonic-gate hw_fcs &= 0xffff;
37197c478bd9Sstevel@tonic-gate /*
37207c478bd9Sstevel@tonic-gate * Now we can replace what the hardware wrote, make believe
37217c478bd9Sstevel@tonic-gate * it got it right in the first place.
37227c478bd9Sstevel@tonic-gate */
37237c478bd9Sstevel@tonic-gate flags = (flags & ~(uint64_t)ERI_RMD_CKSUM) | hw_fcs;
37247c478bd9Sstevel@tonic-gate }
37257c478bd9Sstevel@tonic-gate #endif
37267c478bd9Sstevel@tonic-gate /*
37277c478bd9Sstevel@tonic-gate * Packet Processing
37287c478bd9Sstevel@tonic-gate * Once we get a packet bp, we try allocate a new mblk, nbp
37297c478bd9Sstevel@tonic-gate * to replace this one. If we succeed, we map it to the current
37307c478bd9Sstevel@tonic-gate * dma handle and update the descriptor with the new cookie. We
37317c478bd9Sstevel@tonic-gate * then put bp in our read service queue erip->ipq, if it exists
37327c478bd9Sstevel@tonic-gate * or we just bp to the streams expecting it.
37337c478bd9Sstevel@tonic-gate * If allocation of the new mblk fails, we implicitly drop the
37347c478bd9Sstevel@tonic-gate * current packet, i.e do not pass up the mblk and re-use it.
37357c478bd9Sstevel@tonic-gate * Re-mapping is not required.
37367c478bd9Sstevel@tonic-gate */
37377c478bd9Sstevel@tonic-gate
37387c478bd9Sstevel@tonic-gate if (len < eri_rx_bcopy_max) {
37397c478bd9Sstevel@tonic-gate if ((nbp = eri_allocb_sp(len + ERI_FSTBYTE_OFFSET))) {
37407c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(erip->ndmarh[rmdi], 0,
3741d64540e3Sgd len + ERI_FSTBYTE_OFFSET, DDI_DMA_SYNC_FORCPU);
37427c478bd9Sstevel@tonic-gate DB_TYPE(nbp) = M_DATA;
37437c478bd9Sstevel@tonic-gate bcopy(bp->b_rptr, nbp->b_rptr,
3744d64540e3Sgd len + ERI_FSTBYTE_OFFSET);
37457c478bd9Sstevel@tonic-gate UPDATE_RMD(rmdp);
37467c478bd9Sstevel@tonic-gate ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3747d64540e3Sgd DDI_DMA_SYNC_FORDEV);
37487c478bd9Sstevel@tonic-gate
37497c478bd9Sstevel@tonic-gate /* Add the First Byte offset to the b_rptr */
37507c478bd9Sstevel@tonic-gate nbp->b_rptr += ERI_FSTBYTE_OFFSET;
37517c478bd9Sstevel@tonic-gate nbp->b_wptr = nbp->b_rptr + len;
37527c478bd9Sstevel@tonic-gate
37537c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
37547c478bd9Sstevel@tonic-gate sum = ~(uint16_t)(flags & ERI_RMD_CKSUM);
37557c478bd9Sstevel@tonic-gate ERI_PROCESS_READ(erip, nbp, sum);
37567c478bd9Sstevel@tonic-gate #else
37577c478bd9Sstevel@tonic-gate ERI_PROCESS_READ(erip, nbp);
37587c478bd9Sstevel@tonic-gate #endif
3759d64540e3Sgd retmp = nbp;
37607c478bd9Sstevel@tonic-gate } else {
37617c478bd9Sstevel@tonic-gate
37627c478bd9Sstevel@tonic-gate /*
37637c478bd9Sstevel@tonic-gate * mblk allocation has failed. Re-use the old mblk for
37647c478bd9Sstevel@tonic-gate * the next packet. Re-mapping is not required since
37657c478bd9Sstevel@tonic-gate * the same mblk and dma cookie is to be used again.
37667c478bd9Sstevel@tonic-gate */
37677c478bd9Sstevel@tonic-gate HSTAT(erip, ierrors);
37687c478bd9Sstevel@tonic-gate HSTAT(erip, allocbfail);
37697c478bd9Sstevel@tonic-gate HSTAT(erip, norcvbuf);
37707c478bd9Sstevel@tonic-gate
37717c478bd9Sstevel@tonic-gate UPDATE_RMD(rmdp);
37727c478bd9Sstevel@tonic-gate ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3773d64540e3Sgd DDI_DMA_SYNC_FORDEV);
3774d64540e3Sgd ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail");
37757c478bd9Sstevel@tonic-gate }
37767c478bd9Sstevel@tonic-gate } else {
37777c478bd9Sstevel@tonic-gate /* Use dma unmap/map */
37787c478bd9Sstevel@tonic-gate if ((nbp = eri_allocb_sp(ERI_BUFSIZE))) {
37797c478bd9Sstevel@tonic-gate /*
37807c478bd9Sstevel@tonic-gate * How do we harden this, specially if unbind
37817c478bd9Sstevel@tonic-gate * succeeds and then bind fails?
37827c478bd9Sstevel@tonic-gate * If Unbind fails, we can leave without updating
37837c478bd9Sstevel@tonic-gate * the descriptor but would it continue to work on
37847c478bd9Sstevel@tonic-gate * next round?
37857c478bd9Sstevel@tonic-gate */
37867c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(erip->ndmarh[rmdi]);
37877c478bd9Sstevel@tonic-gate (void) ddi_dma_addr_bind_handle(erip->ndmarh[rmdi],
3788d64540e3Sgd NULL, (caddr_t)nbp->b_rptr, ERI_BUFSIZE,
3789d64540e3Sgd DDI_DMA_READ | DDI_DMA_CONSISTENT,
3790d64540e3Sgd DDI_DMA_DONTWAIT, 0, &c, &ccnt);
37917c478bd9Sstevel@tonic-gate
3792d64540e3Sgd erip->rmblkp[rmdi] = nbp;
3793d64540e3Sgd PUT_RMD(rmdp, c);
3794d64540e3Sgd ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3795d64540e3Sgd DDI_DMA_SYNC_FORDEV);
37967c478bd9Sstevel@tonic-gate
3797d64540e3Sgd /* Add the First Byte offset to the b_rptr */
37987c478bd9Sstevel@tonic-gate
3799d64540e3Sgd bp->b_rptr += ERI_FSTBYTE_OFFSET;
3800d64540e3Sgd bp->b_wptr = bp->b_rptr + len;
38017c478bd9Sstevel@tonic-gate
38027c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
3803d64540e3Sgd sum = ~(uint16_t)(flags & ERI_RMD_CKSUM);
3804d64540e3Sgd ERI_PROCESS_READ(erip, bp, sum);
38057c478bd9Sstevel@tonic-gate #else
3806d64540e3Sgd ERI_PROCESS_READ(erip, bp);
38077c478bd9Sstevel@tonic-gate #endif
3808d64540e3Sgd retmp = bp;
38097c478bd9Sstevel@tonic-gate } else {
38107c478bd9Sstevel@tonic-gate
38117c478bd9Sstevel@tonic-gate /*
38127c478bd9Sstevel@tonic-gate * mblk allocation has failed. Re-use the old mblk for
38137c478bd9Sstevel@tonic-gate * the next packet. Re-mapping is not required since
38147c478bd9Sstevel@tonic-gate * the same mblk and dma cookie is to be used again.
38157c478bd9Sstevel@tonic-gate */
38167c478bd9Sstevel@tonic-gate HSTAT(erip, ierrors);
3817d64540e3Sgd HSTAT(erip, allocbfail);
3818d64540e3Sgd HSTAT(erip, norcvbuf);
38197c478bd9Sstevel@tonic-gate
3820d64540e3Sgd UPDATE_RMD(rmdp);
3821d64540e3Sgd ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3822d64540e3Sgd DDI_DMA_SYNC_FORDEV);
3823d64540e3Sgd ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail");
38247c478bd9Sstevel@tonic-gate }
38257c478bd9Sstevel@tonic-gate }
38267c478bd9Sstevel@tonic-gate
3827d64540e3Sgd return (retmp);
3828d64540e3Sgd }
38297c478bd9Sstevel@tonic-gate
38307c478bd9Sstevel@tonic-gate #define LINK_STAT_DISPLAY_TIME 20
38317c478bd9Sstevel@tonic-gate
38327c478bd9Sstevel@tonic-gate static int
eri_init_xfer_params(struct eri * erip)38337c478bd9Sstevel@tonic-gate eri_init_xfer_params(struct eri *erip)
38347c478bd9Sstevel@tonic-gate {
38357c478bd9Sstevel@tonic-gate int i;
38367c478bd9Sstevel@tonic-gate dev_info_t *dip;
38377c478bd9Sstevel@tonic-gate
38387c478bd9Sstevel@tonic-gate dip = erip->dip;
38397c478bd9Sstevel@tonic-gate
38407c478bd9Sstevel@tonic-gate for (i = 0; i < A_CNT(param_arr); i++)
38417c478bd9Sstevel@tonic-gate erip->param_arr[i] = param_arr[i];
38427c478bd9Sstevel@tonic-gate
38437c478bd9Sstevel@tonic-gate erip->xmit_dma_mode = 0;
38447c478bd9Sstevel@tonic-gate erip->rcv_dma_mode = 0;
38457c478bd9Sstevel@tonic-gate erip->mifpoll_enable = mifpoll_enable;
38467c478bd9Sstevel@tonic-gate erip->lance_mode_enable = lance_mode;
38477c478bd9Sstevel@tonic-gate erip->frame_enable = 1;
38487c478bd9Sstevel@tonic-gate erip->ngu_enable = ngu_enable;
38497c478bd9Sstevel@tonic-gate
38507c478bd9Sstevel@tonic-gate if (!erip->g_nd && !eri_param_register(erip,
38517c478bd9Sstevel@tonic-gate erip->param_arr, A_CNT(param_arr))) {
38527c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
3853d64540e3Sgd param_reg_fail_msg);
38547c478bd9Sstevel@tonic-gate return (-1);
38557c478bd9Sstevel@tonic-gate }
38567c478bd9Sstevel@tonic-gate
38577c478bd9Sstevel@tonic-gate /*
38587c478bd9Sstevel@tonic-gate * Set up the start-up values for user-configurable parameters
38597c478bd9Sstevel@tonic-gate * Get the values from the global variables first.
38607c478bd9Sstevel@tonic-gate * Use the MASK to limit the value to allowed maximum.
38617c478bd9Sstevel@tonic-gate */
3862d64540e3Sgd
38637c478bd9Sstevel@tonic-gate param_transceiver = NO_XCVR;
38647c478bd9Sstevel@tonic-gate
38657c478bd9Sstevel@tonic-gate /*
38667c478bd9Sstevel@tonic-gate * The link speed may be forced to either 10 Mbps or 100 Mbps using the
38677c478bd9Sstevel@tonic-gate * property "transfer-speed". This may be done in OBP by using the command
38687c478bd9Sstevel@tonic-gate * "apply transfer-speed=<speed> <device>". The speed may be either 10 or 100.
38697c478bd9Sstevel@tonic-gate */
3870d64540e3Sgd i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "transfer-speed", 0);
3871d64540e3Sgd if (i != 0) {
38727c478bd9Sstevel@tonic-gate param_autoneg = 0; /* force speed */
38737c478bd9Sstevel@tonic-gate param_anar_100T4 = 0;
38747c478bd9Sstevel@tonic-gate param_anar_10fdx = 0;
38757c478bd9Sstevel@tonic-gate param_anar_10hdx = 0;
38767c478bd9Sstevel@tonic-gate param_anar_100fdx = 0;
38777c478bd9Sstevel@tonic-gate param_anar_100hdx = 0;
38787c478bd9Sstevel@tonic-gate param_anar_asm_dir = 0;
38797c478bd9Sstevel@tonic-gate param_anar_pause = 0;
38807c478bd9Sstevel@tonic-gate
38817c478bd9Sstevel@tonic-gate if (i == 10)
38827c478bd9Sstevel@tonic-gate param_anar_10hdx = 1;
38837c478bd9Sstevel@tonic-gate else if (i == 100)
38847c478bd9Sstevel@tonic-gate param_anar_100hdx = 1;
38857c478bd9Sstevel@tonic-gate }
38867c478bd9Sstevel@tonic-gate
38877c478bd9Sstevel@tonic-gate /*
38887c478bd9Sstevel@tonic-gate * Get the parameter values configured in .conf file.
38897c478bd9Sstevel@tonic-gate */
3890d64540e3Sgd param_ipg1 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg1", ipg1) &
3891d64540e3Sgd ERI_MASK_8BIT;
38927c478bd9Sstevel@tonic-gate
3893d64540e3Sgd param_ipg2 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg2", ipg2) &
3894d64540e3Sgd ERI_MASK_8BIT;
38957c478bd9Sstevel@tonic-gate
3896d64540e3Sgd param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3897d64540e3Sgd "use_int_xcvr", use_int_xcvr) & ERI_MASK_1BIT;
38987c478bd9Sstevel@tonic-gate
3899d64540e3Sgd param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3900d64540e3Sgd "pace_size", pace_size) & ERI_MASK_8BIT;
39017c478bd9Sstevel@tonic-gate
3902d64540e3Sgd param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3903d64540e3Sgd "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT;
39047c478bd9Sstevel@tonic-gate
3905d64540e3Sgd param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3906d64540e3Sgd "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT;
39077c478bd9Sstevel@tonic-gate
3908d64540e3Sgd param_anar_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3909d64540e3Sgd "adv_100T4_cap", adv_100T4_cap) & ERI_MASK_1BIT;
3910d64540e3Sgd
3911d64540e3Sgd param_anar_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3912d64540e3Sgd "adv_100fdx_cap", adv_100fdx_cap) & ERI_MASK_1BIT;
3913d64540e3Sgd
3914d64540e3Sgd param_anar_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3915d64540e3Sgd "adv_100hdx_cap", adv_100hdx_cap) & ERI_MASK_1BIT;
3916d64540e3Sgd
3917d64540e3Sgd param_anar_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3918d64540e3Sgd "adv_10fdx_cap", adv_10fdx_cap) & ERI_MASK_1BIT;
3919d64540e3Sgd
3920d64540e3Sgd param_anar_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3921d64540e3Sgd "adv_10hdx_cap", adv_10hdx_cap) & ERI_MASK_1BIT;
3922d64540e3Sgd
3923d64540e3Sgd param_ipg0 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg0", ipg0) &
3924d64540e3Sgd ERI_MASK_8BIT;
3925d64540e3Sgd
3926d64540e3Sgd param_intr_blank_time = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3927d64540e3Sgd "intr_blank_time", intr_blank_time) & ERI_MASK_8BIT;
3928d64540e3Sgd
3929d64540e3Sgd param_intr_blank_packets = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3930d64540e3Sgd "intr_blank_packets", intr_blank_packets) & ERI_MASK_8BIT;
3931d64540e3Sgd
3932d64540e3Sgd param_lance_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3933d64540e3Sgd "lance_mode", lance_mode) & ERI_MASK_1BIT;
3934d64540e3Sgd
3935d64540e3Sgd param_select_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3936d64540e3Sgd "select_link", select_link) & ERI_MASK_1BIT;
3937d64540e3Sgd
3938d64540e3Sgd param_default_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3939d64540e3Sgd "default_link", default_link) & ERI_MASK_1BIT;
3940d64540e3Sgd
3941d64540e3Sgd param_anar_asm_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3942d64540e3Sgd "adv_asm_dir_cap", adv_pauseTX_cap) & ERI_MASK_1BIT;
3943d64540e3Sgd
3944d64540e3Sgd param_anar_pause = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3945d64540e3Sgd "adv_pause_cap", adv_pauseRX_cap) & ERI_MASK_1BIT;
3946d64540e3Sgd
3947d64540e3Sgd if (link_pulse_disabled)
3948d64540e3Sgd erip->link_pulse_disabled = 1;
3949d64540e3Sgd if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0, "link-pulse-disabled"))
3950d64540e3Sgd erip->link_pulse_disabled = 1;
3951d64540e3Sgd
3952d64540e3Sgd eri_statinit(erip);
3953d64540e3Sgd return (0);
39547c478bd9Sstevel@tonic-gate
39557c478bd9Sstevel@tonic-gate }
39567c478bd9Sstevel@tonic-gate
39577c478bd9Sstevel@tonic-gate static void
eri_process_ndd_ioctl(struct eri * erip,queue_t * wq,mblk_t * mp,int cmd)3958d64540e3Sgd eri_process_ndd_ioctl(struct eri *erip, queue_t *wq, mblk_t *mp, int cmd)
39597c478bd9Sstevel@tonic-gate {
39607c478bd9Sstevel@tonic-gate
39617c478bd9Sstevel@tonic-gate uint32_t old_ipg1, old_ipg2, old_use_int_xcvr, old_autoneg;
39627c478bd9Sstevel@tonic-gate uint32_t old_100T4;
39637c478bd9Sstevel@tonic-gate uint32_t old_100fdx, old_100hdx, old_10fdx, old_10hdx;
39647c478bd9Sstevel@tonic-gate uint32_t old_ipg0, old_lance_mode;
39657c478bd9Sstevel@tonic-gate uint32_t old_intr_blank_time, old_intr_blank_packets;
39667c478bd9Sstevel@tonic-gate uint32_t old_asm_dir, old_pause;
39677c478bd9Sstevel@tonic-gate uint32_t old_select_link, old_default_link;
39687c478bd9Sstevel@tonic-gate
39697c478bd9Sstevel@tonic-gate switch (cmd) {
39707c478bd9Sstevel@tonic-gate case ERI_ND_GET:
39717c478bd9Sstevel@tonic-gate
39727c478bd9Sstevel@tonic-gate old_autoneg = param_autoneg;
39737c478bd9Sstevel@tonic-gate old_100T4 = param_anar_100T4;
39747c478bd9Sstevel@tonic-gate old_100fdx = param_anar_100fdx;
39757c478bd9Sstevel@tonic-gate old_100hdx = param_anar_100hdx;
39767c478bd9Sstevel@tonic-gate old_10fdx = param_anar_10fdx;
39777c478bd9Sstevel@tonic-gate old_10hdx = param_anar_10hdx;
39787c478bd9Sstevel@tonic-gate old_asm_dir = param_anar_asm_dir;
39797c478bd9Sstevel@tonic-gate old_pause = param_anar_pause;
39807c478bd9Sstevel@tonic-gate
39817c478bd9Sstevel@tonic-gate param_autoneg = old_autoneg & ~ERI_NOTUSR;
39827c478bd9Sstevel@tonic-gate param_anar_100T4 = old_100T4 & ~ERI_NOTUSR;
39837c478bd9Sstevel@tonic-gate param_anar_100fdx = old_100fdx & ~ERI_NOTUSR;
39847c478bd9Sstevel@tonic-gate param_anar_100hdx = old_100hdx & ~ERI_NOTUSR;
39857c478bd9Sstevel@tonic-gate param_anar_10fdx = old_10fdx & ~ERI_NOTUSR;
39867c478bd9Sstevel@tonic-gate param_anar_10hdx = old_10hdx & ~ERI_NOTUSR;
39877c478bd9Sstevel@tonic-gate param_anar_asm_dir = old_asm_dir & ~ERI_NOTUSR;
39887c478bd9Sstevel@tonic-gate param_anar_pause = old_pause & ~ERI_NOTUSR;
39897c478bd9Sstevel@tonic-gate
39907c478bd9Sstevel@tonic-gate if (!eri_nd_getset(wq, erip->g_nd, mp)) {
39917c478bd9Sstevel@tonic-gate param_autoneg = old_autoneg;
39927c478bd9Sstevel@tonic-gate param_anar_100T4 = old_100T4;
39937c478bd9Sstevel@tonic-gate param_anar_100fdx = old_100fdx;
39947c478bd9Sstevel@tonic-gate param_anar_100hdx = old_100hdx;
39957c478bd9Sstevel@tonic-gate param_anar_10fdx = old_10fdx;
39967c478bd9Sstevel@tonic-gate param_anar_10hdx = old_10hdx;
39977c478bd9Sstevel@tonic-gate param_anar_asm_dir = old_asm_dir;
39987c478bd9Sstevel@tonic-gate param_anar_pause = old_pause;
39997c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL);
40007c478bd9Sstevel@tonic-gate return;
40017c478bd9Sstevel@tonic-gate }
40027c478bd9Sstevel@tonic-gate param_autoneg = old_autoneg;
40037c478bd9Sstevel@tonic-gate param_anar_100T4 = old_100T4;
40047c478bd9Sstevel@tonic-gate param_anar_100fdx = old_100fdx;
40057c478bd9Sstevel@tonic-gate param_anar_100hdx = old_100hdx;
40067c478bd9Sstevel@tonic-gate param_anar_10fdx = old_10fdx;
40077c478bd9Sstevel@tonic-gate param_anar_10hdx = old_10hdx;
40087c478bd9Sstevel@tonic-gate param_anar_asm_dir = old_asm_dir;
40097c478bd9Sstevel@tonic-gate param_anar_pause = old_pause;
40107c478bd9Sstevel@tonic-gate
40117c478bd9Sstevel@tonic-gate qreply(wq, mp);
40127c478bd9Sstevel@tonic-gate break;
40137c478bd9Sstevel@tonic-gate
40147c478bd9Sstevel@tonic-gate case ERI_ND_SET:
40157c478bd9Sstevel@tonic-gate old_ipg0 = param_ipg0;
40167c478bd9Sstevel@tonic-gate old_intr_blank_time = param_intr_blank_time;
40177c478bd9Sstevel@tonic-gate old_intr_blank_packets = param_intr_blank_packets;
40187c478bd9Sstevel@tonic-gate old_lance_mode = param_lance_mode;
40197c478bd9Sstevel@tonic-gate old_ipg1 = param_ipg1;
40207c478bd9Sstevel@tonic-gate old_ipg2 = param_ipg2;
40217c478bd9Sstevel@tonic-gate old_use_int_xcvr = param_use_intphy;
40227c478bd9Sstevel@tonic-gate old_autoneg = param_autoneg;
40237c478bd9Sstevel@tonic-gate old_100T4 = param_anar_100T4;
40247c478bd9Sstevel@tonic-gate old_100fdx = param_anar_100fdx;
40257c478bd9Sstevel@tonic-gate old_100hdx = param_anar_100hdx;
40267c478bd9Sstevel@tonic-gate old_10fdx = param_anar_10fdx;
40277c478bd9Sstevel@tonic-gate old_10hdx = param_anar_10hdx;
40287c478bd9Sstevel@tonic-gate param_autoneg = 0xff;
40297c478bd9Sstevel@tonic-gate old_asm_dir = param_anar_asm_dir;
40307c478bd9Sstevel@tonic-gate param_anar_asm_dir = 0xff;
40317c478bd9Sstevel@tonic-gate old_pause = param_anar_pause;
40327c478bd9Sstevel@tonic-gate param_anar_pause = 0xff;
40337c478bd9Sstevel@tonic-gate old_select_link = param_select_link;
40347c478bd9Sstevel@tonic-gate old_default_link = param_default_link;
40357c478bd9Sstevel@tonic-gate
40367c478bd9Sstevel@tonic-gate if (!eri_nd_getset(wq, erip->g_nd, mp)) {
40377c478bd9Sstevel@tonic-gate param_autoneg = old_autoneg;
40387c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL);
40397c478bd9Sstevel@tonic-gate return;
40407c478bd9Sstevel@tonic-gate }
40417c478bd9Sstevel@tonic-gate
40427c478bd9Sstevel@tonic-gate qreply(wq, mp);
40437c478bd9Sstevel@tonic-gate
40447c478bd9Sstevel@tonic-gate if (param_autoneg != 0xff) {
40457c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, NDD_MSG,
4046d64540e3Sgd "ndd_ioctl: new param_autoneg %d", param_autoneg);
40477c478bd9Sstevel@tonic-gate param_linkup = 0;
4048d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
4049d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
40507c478bd9Sstevel@tonic-gate (void) eri_init(erip);
40517c478bd9Sstevel@tonic-gate } else {
40527c478bd9Sstevel@tonic-gate param_autoneg = old_autoneg;
40537c478bd9Sstevel@tonic-gate if ((old_use_int_xcvr != param_use_intphy) ||
4054d64540e3Sgd (old_default_link != param_default_link) ||
4055d64540e3Sgd (old_select_link != param_select_link)) {
40567c478bd9Sstevel@tonic-gate param_linkup = 0;
4057d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
4058d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
40597c478bd9Sstevel@tonic-gate (void) eri_init(erip);
40607c478bd9Sstevel@tonic-gate } else if ((old_ipg1 != param_ipg1) ||
40617c478bd9Sstevel@tonic-gate (old_ipg2 != param_ipg2) ||
40627c478bd9Sstevel@tonic-gate (old_ipg0 != param_ipg0) ||
40637c478bd9Sstevel@tonic-gate (old_intr_blank_time != param_intr_blank_time) ||
40647c478bd9Sstevel@tonic-gate (old_intr_blank_packets !=
40657c478bd9Sstevel@tonic-gate param_intr_blank_packets) ||
4066d64540e3Sgd (old_lance_mode != param_lance_mode)) {
40677c478bd9Sstevel@tonic-gate param_linkup = 0;
4068d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
4069d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
40707c478bd9Sstevel@tonic-gate (void) eri_init(erip);
40717c478bd9Sstevel@tonic-gate }
40727c478bd9Sstevel@tonic-gate }
40737c478bd9Sstevel@tonic-gate break;
40747c478bd9Sstevel@tonic-gate }
40757c478bd9Sstevel@tonic-gate }
40767c478bd9Sstevel@tonic-gate
40777c478bd9Sstevel@tonic-gate
40787c478bd9Sstevel@tonic-gate static int
eri_stat_kstat_update(kstat_t * ksp,int rw)40797c478bd9Sstevel@tonic-gate eri_stat_kstat_update(kstat_t *ksp, int rw)
40807c478bd9Sstevel@tonic-gate {
40817c478bd9Sstevel@tonic-gate struct eri *erip;
40827c478bd9Sstevel@tonic-gate struct erikstat *erikp;
40837c478bd9Sstevel@tonic-gate struct stats *esp;
4084d64540e3Sgd boolean_t macupdate = B_FALSE;
40857c478bd9Sstevel@tonic-gate
40867c478bd9Sstevel@tonic-gate erip = (struct eri *)ksp->ks_private;
40877c478bd9Sstevel@tonic-gate erikp = (struct erikstat *)ksp->ks_data;
40887c478bd9Sstevel@tonic-gate
4089d64540e3Sgd if (rw != KSTAT_READ)
4090d64540e3Sgd return (EACCES);
40917c478bd9Sstevel@tonic-gate /*
40927c478bd9Sstevel@tonic-gate * Update all the stats by reading all the counter registers.
40937c478bd9Sstevel@tonic-gate * Counter register stats are not updated till they overflow
40947c478bd9Sstevel@tonic-gate * and interrupt.
40957c478bd9Sstevel@tonic-gate */
40967c478bd9Sstevel@tonic-gate
40977c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
40987c478bd9Sstevel@tonic-gate if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) {
40997c478bd9Sstevel@tonic-gate erip->tx_completion =
4100d64540e3Sgd GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK;
4101d64540e3Sgd macupdate |= eri_reclaim(erip, erip->tx_completion);
41027c478bd9Sstevel@tonic-gate }
41037c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
4104d64540e3Sgd if (macupdate)
4105d64540e3Sgd mac_tx_update(erip->mh);
41067c478bd9Sstevel@tonic-gate
41077c478bd9Sstevel@tonic-gate eri_savecntrs(erip);
41087c478bd9Sstevel@tonic-gate
41097c478bd9Sstevel@tonic-gate esp = &erip->stats;
41107c478bd9Sstevel@tonic-gate
4111d64540e3Sgd erikp->erik_txmac_maxpkt_err.value.ul = esp->txmac_maxpkt_err;
4112d64540e3Sgd erikp->erik_defer_timer_exp.value.ul = esp->defer_timer_exp;
4113d64540e3Sgd erikp->erik_peak_attempt_cnt.value.ul = esp->peak_attempt_cnt;
4114d64540e3Sgd erikp->erik_tx_hang.value.ul = esp->tx_hang;
4115d64540e3Sgd
4116d64540e3Sgd erikp->erik_no_free_rx_desc.value.ul = esp->no_free_rx_desc;
4117d64540e3Sgd
4118d64540e3Sgd erikp->erik_rx_hang.value.ul = esp->rx_hang;
4119d64540e3Sgd erikp->erik_rx_length_err.value.ul = esp->rx_length_err;
4120d64540e3Sgd erikp->erik_rx_code_viol_err.value.ul = esp->rx_code_viol_err;
4121d64540e3Sgd erikp->erik_pause_rxcount.value.ul = esp->pause_rxcount;
4122d64540e3Sgd erikp->erik_pause_oncount.value.ul = esp->pause_oncount;
4123d64540e3Sgd erikp->erik_pause_offcount.value.ul = esp->pause_offcount;
4124d64540e3Sgd erikp->erik_pause_time_count.value.ul = esp->pause_time_count;
4125d64540e3Sgd
4126d64540e3Sgd erikp->erik_inits.value.ul = esp->inits;
4127d64540e3Sgd erikp->erik_jab.value.ul = esp->jab;
4128d64540e3Sgd erikp->erik_notmds.value.ul = esp->notmds;
4129d64540e3Sgd erikp->erik_allocbfail.value.ul = esp->allocbfail;
4130d64540e3Sgd erikp->erik_drop.value.ul = esp->drop;
4131d64540e3Sgd erikp->erik_rx_bad_pkts.value.ul = esp->rx_bad_pkts;
4132d64540e3Sgd erikp->erik_rx_inits.value.ul = esp->rx_inits;
4133d64540e3Sgd erikp->erik_tx_inits.value.ul = esp->tx_inits;
4134d64540e3Sgd erikp->erik_rxtag_err.value.ul = esp->rxtag_err;
4135d64540e3Sgd erikp->erik_parity_error.value.ul = esp->parity_error;
4136d64540e3Sgd erikp->erik_pci_error_int.value.ul = esp->pci_error_int;
4137d64540e3Sgd erikp->erik_unknown_fatal.value.ul = esp->unknown_fatal;
4138d64540e3Sgd erikp->erik_pci_data_parity_err.value.ul = esp->pci_data_parity_err;
4139d64540e3Sgd erikp->erik_pci_signal_target_abort.value.ul =
4140d64540e3Sgd esp->pci_signal_target_abort;
4141d64540e3Sgd erikp->erik_pci_rcvd_target_abort.value.ul =
4142d64540e3Sgd esp->pci_rcvd_target_abort;
4143d64540e3Sgd erikp->erik_pci_rcvd_master_abort.value.ul =
4144d64540e3Sgd esp->pci_rcvd_master_abort;
4145d64540e3Sgd erikp->erik_pci_signal_system_err.value.ul =
4146d64540e3Sgd esp->pci_signal_system_err;
4147d64540e3Sgd erikp->erik_pci_det_parity_err.value.ul = esp->pci_det_parity_err;
4148d64540e3Sgd
4149d64540e3Sgd erikp->erik_pmcap.value.ul = esp->pmcap;
41507c478bd9Sstevel@tonic-gate
41517c478bd9Sstevel@tonic-gate return (0);
41527c478bd9Sstevel@tonic-gate }
41537c478bd9Sstevel@tonic-gate
41547c478bd9Sstevel@tonic-gate static void
eri_statinit(struct eri * erip)41557c478bd9Sstevel@tonic-gate eri_statinit(struct eri *erip)
41567c478bd9Sstevel@tonic-gate {
41577c478bd9Sstevel@tonic-gate struct kstat *ksp;
41587c478bd9Sstevel@tonic-gate struct erikstat *erikp;
41597c478bd9Sstevel@tonic-gate
4160d64540e3Sgd if ((ksp = kstat_create("eri", erip->instance, "driver_info", "net",
4161d64540e3Sgd KSTAT_TYPE_NAMED,
41627c478bd9Sstevel@tonic-gate sizeof (struct erikstat) / sizeof (kstat_named_t), 0)) == NULL) {
41637c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
4164d64540e3Sgd kstat_create_fail_msg);
41657c478bd9Sstevel@tonic-gate return;
41667c478bd9Sstevel@tonic-gate }
41677c478bd9Sstevel@tonic-gate
41687c478bd9Sstevel@tonic-gate erip->ksp = ksp;
41697c478bd9Sstevel@tonic-gate erikp = (struct erikstat *)(ksp->ks_data);
41707c478bd9Sstevel@tonic-gate /*
41717c478bd9Sstevel@tonic-gate * MIB II kstat variables
41727c478bd9Sstevel@tonic-gate */
4173d64540e3Sgd
4174d64540e3Sgd kstat_named_init(&erikp->erik_inits, "inits", KSTAT_DATA_ULONG);
4175d64540e3Sgd
41767c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_txmac_maxpkt_err, "txmac_maxpkt_err",
4177d64540e3Sgd KSTAT_DATA_ULONG);
4178d64540e3Sgd kstat_named_init(&erikp->erik_defer_timer_exp, "defer_timer_exp",
4179d64540e3Sgd KSTAT_DATA_ULONG);
41807c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_peak_attempt_cnt, "peak_attempt_cnt",
4181d64540e3Sgd KSTAT_DATA_ULONG);
4182d64540e3Sgd kstat_named_init(&erikp->erik_tx_hang, "tx_hang", KSTAT_DATA_ULONG);
4183d64540e3Sgd
4184d64540e3Sgd kstat_named_init(&erikp->erik_no_free_rx_desc, "no_free_rx_desc",
4185d64540e3Sgd KSTAT_DATA_ULONG);
4186d64540e3Sgd kstat_named_init(&erikp->erik_rx_hang, "rx_hang", KSTAT_DATA_ULONG);
4187d64540e3Sgd kstat_named_init(&erikp->erik_rx_length_err, "rx_length_err",
4188d64540e3Sgd KSTAT_DATA_ULONG);
41897c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_rx_code_viol_err, "rx_code_viol_err",
4190d64540e3Sgd KSTAT_DATA_ULONG);
41917c478bd9Sstevel@tonic-gate
4192d64540e3Sgd kstat_named_init(&erikp->erik_pause_rxcount, "pause_rcv_cnt",
4193d64540e3Sgd KSTAT_DATA_ULONG);
41947c478bd9Sstevel@tonic-gate
4195d64540e3Sgd kstat_named_init(&erikp->erik_pause_oncount, "pause_on_cnt",
4196d64540e3Sgd KSTAT_DATA_ULONG);
41977c478bd9Sstevel@tonic-gate
4198d64540e3Sgd kstat_named_init(&erikp->erik_pause_offcount, "pause_off_cnt",
4199d64540e3Sgd KSTAT_DATA_ULONG);
42007c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pause_time_count, "pause_time_cnt",
4201d64540e3Sgd KSTAT_DATA_ULONG);
4202d64540e3Sgd
4203d64540e3Sgd kstat_named_init(&erikp->erik_jab, "jabber", KSTAT_DATA_ULONG);
4204d64540e3Sgd kstat_named_init(&erikp->erik_notmds, "no_tmds", KSTAT_DATA_ULONG);
42057c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_allocbfail, "allocbfail",
4206d64540e3Sgd KSTAT_DATA_ULONG);
42077c478bd9Sstevel@tonic-gate
4208d64540e3Sgd kstat_named_init(&erikp->erik_drop, "drop", KSTAT_DATA_ULONG);
42097c478bd9Sstevel@tonic-gate
42107c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_rx_bad_pkts, "bad_pkts",
4211d64540e3Sgd KSTAT_DATA_ULONG);
42127c478bd9Sstevel@tonic-gate
4213d64540e3Sgd kstat_named_init(&erikp->erik_rx_inits, "rx_inits", KSTAT_DATA_ULONG);
42147c478bd9Sstevel@tonic-gate
4215d64540e3Sgd kstat_named_init(&erikp->erik_tx_inits, "tx_inits", KSTAT_DATA_ULONG);
42167c478bd9Sstevel@tonic-gate
42177c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_rxtag_err, "rxtag_error",
4218d64540e3Sgd KSTAT_DATA_ULONG);
42197c478bd9Sstevel@tonic-gate
4220d64540e3Sgd kstat_named_init(&erikp->erik_parity_error, "parity_error",
4221d64540e3Sgd KSTAT_DATA_ULONG);
42227c478bd9Sstevel@tonic-gate
4223d64540e3Sgd kstat_named_init(&erikp->erik_pci_error_int, "pci_error_interrupt",
4224d64540e3Sgd KSTAT_DATA_ULONG);
42257c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_unknown_fatal, "unknown_fatal",
4226d64540e3Sgd KSTAT_DATA_ULONG);
42277c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pci_data_parity_err,
4228d64540e3Sgd "pci_data_parity_err", KSTAT_DATA_ULONG);
42297c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pci_signal_target_abort,
4230d64540e3Sgd "pci_signal_target_abort", KSTAT_DATA_ULONG);
42317c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pci_rcvd_target_abort,
4232d64540e3Sgd "pci_rcvd_target_abort", KSTAT_DATA_ULONG);
42337c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pci_rcvd_master_abort,
4234d64540e3Sgd "pci_rcvd_master_abort", KSTAT_DATA_ULONG);
42357c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pci_signal_system_err,
4236d64540e3Sgd "pci_signal_system_err", KSTAT_DATA_ULONG);
42377c478bd9Sstevel@tonic-gate kstat_named_init(&erikp->erik_pci_det_parity_err,
4238d64540e3Sgd "pci_det_parity_err", KSTAT_DATA_ULONG);
42397c478bd9Sstevel@tonic-gate
4240d64540e3Sgd kstat_named_init(&erikp->erik_pmcap, "pmcap", KSTAT_DATA_ULONG);
42417c478bd9Sstevel@tonic-gate
42427c478bd9Sstevel@tonic-gate
42437c478bd9Sstevel@tonic-gate ksp->ks_update = eri_stat_kstat_update;
42447c478bd9Sstevel@tonic-gate ksp->ks_private = (void *) erip;
42457c478bd9Sstevel@tonic-gate kstat_install(ksp);
42467c478bd9Sstevel@tonic-gate }
42477c478bd9Sstevel@tonic-gate
42487c478bd9Sstevel@tonic-gate
42497c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<< NDD SUPPORT FUNCTIONS >>>>>>>>>>>>>>>>>>> */
42507c478bd9Sstevel@tonic-gate /*
42517c478bd9Sstevel@tonic-gate * ndd support functions to get/set parameters
42527c478bd9Sstevel@tonic-gate */
42537c478bd9Sstevel@tonic-gate /* Free the Named Dispatch Table by calling eri_nd_free */
42547c478bd9Sstevel@tonic-gate static void
eri_param_cleanup(struct eri * erip)42557c478bd9Sstevel@tonic-gate eri_param_cleanup(struct eri *erip)
42567c478bd9Sstevel@tonic-gate {
42577c478bd9Sstevel@tonic-gate if (erip->g_nd)
42587c478bd9Sstevel@tonic-gate (void) eri_nd_free(&erip->g_nd);
42597c478bd9Sstevel@tonic-gate }
42607c478bd9Sstevel@tonic-gate
42617c478bd9Sstevel@tonic-gate /*
42627c478bd9Sstevel@tonic-gate * Extracts the value from the eri parameter array and prints the
42637c478bd9Sstevel@tonic-gate * parameter value. cp points to the required parameter.
42647c478bd9Sstevel@tonic-gate */
42657c478bd9Sstevel@tonic-gate /* ARGSUSED */
42667c478bd9Sstevel@tonic-gate static int
eri_param_get(queue_t * q,mblk_t * mp,caddr_t cp)42677c478bd9Sstevel@tonic-gate eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp)
42687c478bd9Sstevel@tonic-gate {
4269d64540e3Sgd param_t *eripa = (void *)cp;
42707c478bd9Sstevel@tonic-gate int param_len = 1;
42717c478bd9Sstevel@tonic-gate uint32_t param_val;
42727c478bd9Sstevel@tonic-gate mblk_t *nmp;
42737c478bd9Sstevel@tonic-gate int ok;
42747c478bd9Sstevel@tonic-gate
42757c478bd9Sstevel@tonic-gate param_val = eripa->param_val;
42767c478bd9Sstevel@tonic-gate /*
42777c478bd9Sstevel@tonic-gate * Calculate space required in mblk.
42787c478bd9Sstevel@tonic-gate * Remember to include NULL terminator.
42797c478bd9Sstevel@tonic-gate */
42807c478bd9Sstevel@tonic-gate do {
42817c478bd9Sstevel@tonic-gate param_len++;
42827c478bd9Sstevel@tonic-gate param_val /= 10;
42837c478bd9Sstevel@tonic-gate } while (param_val);
42847c478bd9Sstevel@tonic-gate
42857c478bd9Sstevel@tonic-gate ok = eri_mk_mblk_tail_space(mp, &nmp, param_len);
42867c478bd9Sstevel@tonic-gate if (ok == 0) {
42877c478bd9Sstevel@tonic-gate (void) sprintf((char *)nmp->b_wptr, "%d", eripa->param_val);
42887c478bd9Sstevel@tonic-gate nmp->b_wptr += param_len;
42897c478bd9Sstevel@tonic-gate }
42907c478bd9Sstevel@tonic-gate
42917c478bd9Sstevel@tonic-gate return (ok);
42927c478bd9Sstevel@tonic-gate }
42937c478bd9Sstevel@tonic-gate
42947c478bd9Sstevel@tonic-gate /*
42957c478bd9Sstevel@tonic-gate * Check if there is space for p_val at the end if mblk.
42967c478bd9Sstevel@tonic-gate * If not, allocate new 1k mblk.
42977c478bd9Sstevel@tonic-gate */
42987c478bd9Sstevel@tonic-gate static int
eri_mk_mblk_tail_space(mblk_t * mp,mblk_t ** nmp,size_t sz)42997c478bd9Sstevel@tonic-gate eri_mk_mblk_tail_space(mblk_t *mp, mblk_t **nmp, size_t sz)
43007c478bd9Sstevel@tonic-gate {
43017c478bd9Sstevel@tonic-gate mblk_t *tmp = mp;
43027c478bd9Sstevel@tonic-gate
43037c478bd9Sstevel@tonic-gate while (tmp->b_cont)
43047c478bd9Sstevel@tonic-gate tmp = tmp->b_cont;
43057c478bd9Sstevel@tonic-gate
43067c478bd9Sstevel@tonic-gate if (MBLKTAIL(tmp) < sz) {
43077c478bd9Sstevel@tonic-gate if ((tmp->b_cont = allocb(1024, BPRI_HI)) == NULL)
43087c478bd9Sstevel@tonic-gate return (ENOMEM);
43097c478bd9Sstevel@tonic-gate tmp = tmp->b_cont;
43107c478bd9Sstevel@tonic-gate }
43117c478bd9Sstevel@tonic-gate *nmp = tmp;
43127c478bd9Sstevel@tonic-gate return (0);
43137c478bd9Sstevel@tonic-gate }
43147c478bd9Sstevel@tonic-gate
43157c478bd9Sstevel@tonic-gate /*
43167c478bd9Sstevel@tonic-gate * Register each element of the parameter array with the
43177c478bd9Sstevel@tonic-gate * named dispatch handler. Each element is loaded using
43187c478bd9Sstevel@tonic-gate * eri_nd_load()
43197c478bd9Sstevel@tonic-gate */
43207c478bd9Sstevel@tonic-gate static int
eri_param_register(struct eri * erip,param_t * eripa,int cnt)43217c478bd9Sstevel@tonic-gate eri_param_register(struct eri *erip, param_t *eripa, int cnt)
4322d64540e3Sgd {
43237c478bd9Sstevel@tonic-gate /* cnt gives the count of the number of */
43247c478bd9Sstevel@tonic-gate /* elements present in the parameter array */
43257c478bd9Sstevel@tonic-gate
4326d64540e3Sgd int i;
43277c478bd9Sstevel@tonic-gate
4328fd8be74fSgd for (i = 0; i < cnt; i++, eripa++) {
4329d64540e3Sgd pfi_t setter = (pfi_t)eri_param_set;
43307c478bd9Sstevel@tonic-gate
4331d64540e3Sgd switch (eripa->param_name[0]) {
4332d64540e3Sgd case '+': /* read-write */
4333d64540e3Sgd setter = (pfi_t)eri_param_set;
4334d64540e3Sgd break;
4335d64540e3Sgd
4336d64540e3Sgd case '-': /* read-only */
4337d64540e3Sgd setter = NULL;
4338d64540e3Sgd break;
4339d64540e3Sgd
4340d64540e3Sgd case '!': /* read-only, not displayed */
4341d64540e3Sgd case '%': /* read-write, not displayed */
4342d64540e3Sgd continue;
43437c478bd9Sstevel@tonic-gate }
4344d64540e3Sgd
4345d64540e3Sgd if (!eri_nd_load(&erip->g_nd, eripa->param_name + 1,
4346fd8be74fSgd (pfi_t)eri_param_get, setter, (caddr_t)eripa)) {
4347d64540e3Sgd (void) eri_nd_free(&erip->g_nd);
4348d64540e3Sgd return (B_FALSE);
43497c478bd9Sstevel@tonic-gate }
4350d64540e3Sgd }
43517c478bd9Sstevel@tonic-gate
43527c478bd9Sstevel@tonic-gate return (B_TRUE);
43537c478bd9Sstevel@tonic-gate }
43547c478bd9Sstevel@tonic-gate
43557c478bd9Sstevel@tonic-gate /*
43567c478bd9Sstevel@tonic-gate * Sets the eri parameter to the value in the param_register using
43577c478bd9Sstevel@tonic-gate * eri_nd_load().
43587c478bd9Sstevel@tonic-gate */
43597c478bd9Sstevel@tonic-gate /* ARGSUSED */
43607c478bd9Sstevel@tonic-gate static int
eri_param_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp)43617c478bd9Sstevel@tonic-gate eri_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp)
43627c478bd9Sstevel@tonic-gate {
43637c478bd9Sstevel@tonic-gate char *end;
4364d64540e3Sgd long new_value;
4365d64540e3Sgd param_t *eripa = (void *)cp;
43667c478bd9Sstevel@tonic-gate
4367d64540e3Sgd if (ddi_strtol(value, &end, 10, &new_value) != 0)
4368d64540e3Sgd return (EINVAL);
43697c478bd9Sstevel@tonic-gate if (end == value || new_value < eripa->param_min ||
43707c478bd9Sstevel@tonic-gate new_value > eripa->param_max) {
43717c478bd9Sstevel@tonic-gate return (EINVAL);
43727c478bd9Sstevel@tonic-gate }
4373d64540e3Sgd eripa->param_val = (uint32_t)new_value;
43747c478bd9Sstevel@tonic-gate return (0);
43757c478bd9Sstevel@tonic-gate
43767c478bd9Sstevel@tonic-gate }
43777c478bd9Sstevel@tonic-gate
43787c478bd9Sstevel@tonic-gate /* Free the table pointed to by 'ndp' */
43797c478bd9Sstevel@tonic-gate static void
eri_nd_free(caddr_t * nd_pparam)43807c478bd9Sstevel@tonic-gate eri_nd_free(caddr_t *nd_pparam)
43817c478bd9Sstevel@tonic-gate {
43827c478bd9Sstevel@tonic-gate ND *nd;
43837c478bd9Sstevel@tonic-gate
4384d64540e3Sgd if ((nd = (void *)(*nd_pparam)) != NULL) {
43857c478bd9Sstevel@tonic-gate if (nd->nd_tbl)
4386d64540e3Sgd kmem_free(nd->nd_tbl, nd->nd_size);
4387d64540e3Sgd kmem_free(nd, sizeof (ND));
43887c478bd9Sstevel@tonic-gate *nd_pparam = NULL;
43897c478bd9Sstevel@tonic-gate }
43907c478bd9Sstevel@tonic-gate }
43917c478bd9Sstevel@tonic-gate
43927c478bd9Sstevel@tonic-gate static int
eri_nd_getset(queue_t * q,caddr_t nd_param,MBLKP mp)43937c478bd9Sstevel@tonic-gate eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp)
43947c478bd9Sstevel@tonic-gate {
43957c478bd9Sstevel@tonic-gate int err;
43967c478bd9Sstevel@tonic-gate IOCP iocp;
43977c478bd9Sstevel@tonic-gate MBLKP mp1;
43987c478bd9Sstevel@tonic-gate ND *nd;
43997c478bd9Sstevel@tonic-gate NDE *nde;
44007c478bd9Sstevel@tonic-gate char *valp;
44017c478bd9Sstevel@tonic-gate size_t avail;
44027c478bd9Sstevel@tonic-gate mblk_t *nmp;
44037c478bd9Sstevel@tonic-gate
44047c478bd9Sstevel@tonic-gate if (!nd_param)
44057c478bd9Sstevel@tonic-gate return (B_FALSE);
44067c478bd9Sstevel@tonic-gate
4407d64540e3Sgd nd = (void *)nd_param;
4408d64540e3Sgd iocp = (void *)mp->b_rptr;
44097c478bd9Sstevel@tonic-gate if ((iocp->ioc_count == 0) || !(mp1 = mp->b_cont)) {
44107c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
44117c478bd9Sstevel@tonic-gate iocp->ioc_count = 0;
44127c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL;
44137c478bd9Sstevel@tonic-gate return (B_TRUE);
44147c478bd9Sstevel@tonic-gate }
44157c478bd9Sstevel@tonic-gate /*
44167c478bd9Sstevel@tonic-gate * NOTE - logic throughout nd_xxx assumes single data block for ioctl.
44177c478bd9Sstevel@tonic-gate * However, existing code sends in some big buffers.
44187c478bd9Sstevel@tonic-gate */
44197c478bd9Sstevel@tonic-gate avail = iocp->ioc_count;
44207c478bd9Sstevel@tonic-gate if (mp1->b_cont) {
44217c478bd9Sstevel@tonic-gate freemsg(mp1->b_cont);
44227c478bd9Sstevel@tonic-gate mp1->b_cont = NULL;
44237c478bd9Sstevel@tonic-gate }
44247c478bd9Sstevel@tonic-gate
44257c478bd9Sstevel@tonic-gate mp1->b_datap->db_lim[-1] = '\0'; /* Force null termination */
44267c478bd9Sstevel@tonic-gate valp = (char *)mp1->b_rptr;
44277c478bd9Sstevel@tonic-gate
44287c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; /* */; nde++) {
44297c478bd9Sstevel@tonic-gate if (!nde->nde_name)
44307c478bd9Sstevel@tonic-gate return (B_FALSE);
44317c478bd9Sstevel@tonic-gate if (strcmp(nde->nde_name, valp) == 0)
44327c478bd9Sstevel@tonic-gate break;
44337c478bd9Sstevel@tonic-gate }
44347c478bd9Sstevel@tonic-gate err = EINVAL;
44357c478bd9Sstevel@tonic-gate
44367c478bd9Sstevel@tonic-gate while (*valp++)
44377c478bd9Sstevel@tonic-gate ;
44387c478bd9Sstevel@tonic-gate
44397c478bd9Sstevel@tonic-gate if (!*valp || valp >= (char *)mp1->b_wptr)
44407c478bd9Sstevel@tonic-gate valp = NULL;
44417c478bd9Sstevel@tonic-gate
44427c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
44437c478bd9Sstevel@tonic-gate case ND_GET:
44447c478bd9Sstevel@tonic-gate /*
44457c478bd9Sstevel@tonic-gate * (XXX) hack: "*valp" is size of user buffer for copyout. If result
44467c478bd9Sstevel@tonic-gate * of action routine is too big, free excess and return ioc_rval as buf
44477c478bd9Sstevel@tonic-gate * size needed. Return as many mblocks as will fit, free the rest. For
44487c478bd9Sstevel@tonic-gate * backward compatibility, assume size of orig ioctl buffer if "*valp"
44497c478bd9Sstevel@tonic-gate * bad or not given.
44507c478bd9Sstevel@tonic-gate */
44517c478bd9Sstevel@tonic-gate if (valp)
4452d64540e3Sgd (void) ddi_strtol(valp, NULL, 10, (long *)&avail);
44537c478bd9Sstevel@tonic-gate /* We overwrite the name/value with the reply data */
44547c478bd9Sstevel@tonic-gate {
44557c478bd9Sstevel@tonic-gate mblk_t *mp2 = mp1;
44567c478bd9Sstevel@tonic-gate
44577c478bd9Sstevel@tonic-gate while (mp2) {
44587c478bd9Sstevel@tonic-gate mp2->b_wptr = mp2->b_rptr;
44597c478bd9Sstevel@tonic-gate mp2 = mp2->b_cont;
44607c478bd9Sstevel@tonic-gate }
44617c478bd9Sstevel@tonic-gate }
44627c478bd9Sstevel@tonic-gate err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr);
44637c478bd9Sstevel@tonic-gate if (!err) {
44647c478bd9Sstevel@tonic-gate size_t size_out;
44657c478bd9Sstevel@tonic-gate ssize_t excess;
44667c478bd9Sstevel@tonic-gate
44677c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0;
44687c478bd9Sstevel@tonic-gate
44697c478bd9Sstevel@tonic-gate /* Tack on the null */
44707c478bd9Sstevel@tonic-gate err = eri_mk_mblk_tail_space(mp1, &nmp, 1);
44717c478bd9Sstevel@tonic-gate if (!err) {
44727c478bd9Sstevel@tonic-gate *nmp->b_wptr++ = '\0';
44737c478bd9Sstevel@tonic-gate size_out = msgdsize(mp1);
44747c478bd9Sstevel@tonic-gate excess = size_out - avail;
44757c478bd9Sstevel@tonic-gate if (excess > 0) {
4476d64540e3Sgd iocp->ioc_rval = (unsigned)size_out;
44777c478bd9Sstevel@tonic-gate size_out -= excess;
44787c478bd9Sstevel@tonic-gate (void) adjmsg(mp1, -(excess + 1));
44797c478bd9Sstevel@tonic-gate err = eri_mk_mblk_tail_space(mp1,
4480d64540e3Sgd &nmp, 1);
44817c478bd9Sstevel@tonic-gate if (!err)
44827c478bd9Sstevel@tonic-gate *nmp->b_wptr++ = '\0';
44837c478bd9Sstevel@tonic-gate else
44847c478bd9Sstevel@tonic-gate size_out = 0;
44857c478bd9Sstevel@tonic-gate }
44867c478bd9Sstevel@tonic-gate
44877c478bd9Sstevel@tonic-gate } else
44887c478bd9Sstevel@tonic-gate size_out = 0;
44897c478bd9Sstevel@tonic-gate
44907c478bd9Sstevel@tonic-gate iocp->ioc_count = size_out;
44917c478bd9Sstevel@tonic-gate }
44927c478bd9Sstevel@tonic-gate break;
44937c478bd9Sstevel@tonic-gate
44947c478bd9Sstevel@tonic-gate case ND_SET:
44957c478bd9Sstevel@tonic-gate if (valp) {
4496d64540e3Sgd err = (*nde->nde_set_pfi)(q, mp1, valp,
4497d64540e3Sgd nde->nde_data, iocp->ioc_cr);
44987c478bd9Sstevel@tonic-gate iocp->ioc_count = 0;
44997c478bd9Sstevel@tonic-gate freemsg(mp1);
45007c478bd9Sstevel@tonic-gate mp->b_cont = NULL;
45017c478bd9Sstevel@tonic-gate }
45027c478bd9Sstevel@tonic-gate break;
45037c478bd9Sstevel@tonic-gate }
4504d64540e3Sgd
45057c478bd9Sstevel@tonic-gate iocp->ioc_error = err;
45067c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
45077c478bd9Sstevel@tonic-gate return (B_TRUE);
45087c478bd9Sstevel@tonic-gate }
45097c478bd9Sstevel@tonic-gate
45107c478bd9Sstevel@tonic-gate /*
45117c478bd9Sstevel@tonic-gate * Load 'name' into the named dispatch table pointed to by 'ndp'.
45127c478bd9Sstevel@tonic-gate * 'ndp' should be the address of a char pointer cell. If the table
45137c478bd9Sstevel@tonic-gate * does not exist (*ndp == 0), a new table is allocated and 'ndp'
45147c478bd9Sstevel@tonic-gate * is stuffed. If there is not enough space in the table for a new
45157c478bd9Sstevel@tonic-gate * entry, more space is allocated.
45167c478bd9Sstevel@tonic-gate */
45177c478bd9Sstevel@tonic-gate static boolean_t
eri_nd_load(caddr_t * nd_pparam,char * name,pfi_t get_pfi,pfi_t set_pfi,caddr_t data)45187c478bd9Sstevel@tonic-gate eri_nd_load(caddr_t *nd_pparam, char *name, pfi_t get_pfi,
45197c478bd9Sstevel@tonic-gate pfi_t set_pfi, caddr_t data)
45207c478bd9Sstevel@tonic-gate {
45217c478bd9Sstevel@tonic-gate ND *nd;
45227c478bd9Sstevel@tonic-gate NDE *nde;
45237c478bd9Sstevel@tonic-gate
45247c478bd9Sstevel@tonic-gate if (!nd_pparam)
45257c478bd9Sstevel@tonic-gate return (B_FALSE);
45267c478bd9Sstevel@tonic-gate
4527d64540e3Sgd if ((nd = (void *)(*nd_pparam)) == NULL) {
45287c478bd9Sstevel@tonic-gate if ((nd = (ND *)kmem_zalloc(sizeof (ND), KM_NOSLEEP))
45297c478bd9Sstevel@tonic-gate == NULL)
45307c478bd9Sstevel@tonic-gate return (B_FALSE);
45317c478bd9Sstevel@tonic-gate *nd_pparam = (caddr_t)nd;
45327c478bd9Sstevel@tonic-gate }
45337c478bd9Sstevel@tonic-gate if (nd->nd_tbl) {
45347c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) {
45357c478bd9Sstevel@tonic-gate if (strcmp(name, nde->nde_name) == 0)
45367c478bd9Sstevel@tonic-gate goto fill_it;
45377c478bd9Sstevel@tonic-gate }
45387c478bd9Sstevel@tonic-gate }
45397c478bd9Sstevel@tonic-gate if (nd->nd_free_count <= 1) {
45407c478bd9Sstevel@tonic-gate if ((nde = (NDE *)kmem_zalloc(nd->nd_size +
45417c478bd9Sstevel@tonic-gate NDE_ALLOC_SIZE, KM_NOSLEEP)) == NULL)
45427c478bd9Sstevel@tonic-gate return (B_FALSE);
45437c478bd9Sstevel@tonic-gate
45447c478bd9Sstevel@tonic-gate nd->nd_free_count += NDE_ALLOC_COUNT;
45457c478bd9Sstevel@tonic-gate if (nd->nd_tbl) {
45467c478bd9Sstevel@tonic-gate bcopy((char *)nd->nd_tbl, (char *)nde, nd->nd_size);
45477c478bd9Sstevel@tonic-gate kmem_free((char *)nd->nd_tbl, nd->nd_size);
45487c478bd9Sstevel@tonic-gate } else {
45497c478bd9Sstevel@tonic-gate nd->nd_free_count--;
45507c478bd9Sstevel@tonic-gate nde->nde_name = "?";
45517c478bd9Sstevel@tonic-gate nde->nde_get_pfi = nd_get_names;
45527c478bd9Sstevel@tonic-gate nde->nde_set_pfi = nd_set_default;
45537c478bd9Sstevel@tonic-gate }
45547c478bd9Sstevel@tonic-gate nde->nde_data = (caddr_t)nd;
45557c478bd9Sstevel@tonic-gate nd->nd_tbl = nde;
45567c478bd9Sstevel@tonic-gate nd->nd_size += NDE_ALLOC_SIZE;
45577c478bd9Sstevel@tonic-gate }
45587c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++)
45597c478bd9Sstevel@tonic-gate ;
45607c478bd9Sstevel@tonic-gate nd->nd_free_count--;
45617c478bd9Sstevel@tonic-gate fill_it:
45627c478bd9Sstevel@tonic-gate nde->nde_name = name;
45637c478bd9Sstevel@tonic-gate nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default;
45647c478bd9Sstevel@tonic-gate nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default;
45657c478bd9Sstevel@tonic-gate nde->nde_data = data;
45667c478bd9Sstevel@tonic-gate return (B_TRUE);
45677c478bd9Sstevel@tonic-gate }
45687c478bd9Sstevel@tonic-gate
45697c478bd9Sstevel@tonic-gate /*
45707c478bd9Sstevel@tonic-gate * Hardening Functions
45717c478bd9Sstevel@tonic-gate * New Section
45727c478bd9Sstevel@tonic-gate */
45737c478bd9Sstevel@tonic-gate #ifdef DEBUG
4574d64540e3Sgd /*PRINTFLIKE5*/
45757c478bd9Sstevel@tonic-gate static void
eri_debug_msg(const char * file,int line,struct eri * erip,debug_msg_t type,const char * fmt,...)4576d64540e3Sgd eri_debug_msg(const char *file, int line, struct eri *erip,
4577297a64e7Sgd debug_msg_t type, const char *fmt, ...)
45787c478bd9Sstevel@tonic-gate {
45797c478bd9Sstevel@tonic-gate char msg_buffer[255];
45807c478bd9Sstevel@tonic-gate va_list ap;
45817c478bd9Sstevel@tonic-gate
45827c478bd9Sstevel@tonic-gate va_start(ap, fmt);
45837c478bd9Sstevel@tonic-gate (void) vsprintf(msg_buffer, fmt, ap);
45847c478bd9Sstevel@tonic-gate va_end(ap);
45857c478bd9Sstevel@tonic-gate
45867c478bd9Sstevel@tonic-gate if (eri_msg_out & ERI_CON_MSG) {
45877c478bd9Sstevel@tonic-gate if (((type <= eri_debug_level) && eri_debug_all) ||
4588d64540e3Sgd ((type == eri_debug_level) && !eri_debug_all)) {
45897c478bd9Sstevel@tonic-gate if (erip)
4590d64540e3Sgd cmn_err(CE_CONT, "D: %s %s%d:(%s%d) %s\n",
4591d64540e3Sgd debug_msg_string[type], file, line,
4592d64540e3Sgd ddi_driver_name(erip->dip), erip->instance,
4593d64540e3Sgd msg_buffer);
45947c478bd9Sstevel@tonic-gate else
45957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "D: %s %s(%d): %s\n",
4596d64540e3Sgd debug_msg_string[type], file,
4597d64540e3Sgd line, msg_buffer);
45987c478bd9Sstevel@tonic-gate }
45997c478bd9Sstevel@tonic-gate }
46007c478bd9Sstevel@tonic-gate }
46017c478bd9Sstevel@tonic-gate #endif
46027c478bd9Sstevel@tonic-gate
46037c478bd9Sstevel@tonic-gate
4604d64540e3Sgd /*PRINTFLIKE4*/
46057c478bd9Sstevel@tonic-gate static void
eri_fault_msg(struct eri * erip,uint_t severity,msg_t type,const char * fmt,...)4606d64540e3Sgd eri_fault_msg(struct eri *erip, uint_t severity, msg_t type,
4607*7e996435SToomas Soome const char *fmt, ...)
46087c478bd9Sstevel@tonic-gate {
46097c478bd9Sstevel@tonic-gate char msg_buffer[255];
46107c478bd9Sstevel@tonic-gate va_list ap;
46117c478bd9Sstevel@tonic-gate
46127c478bd9Sstevel@tonic-gate va_start(ap, fmt);
46137c478bd9Sstevel@tonic-gate (void) vsprintf(msg_buffer, fmt, ap);
46147c478bd9Sstevel@tonic-gate va_end(ap);
46157c478bd9Sstevel@tonic-gate
46167c478bd9Sstevel@tonic-gate if (erip == NULL) {
46177c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "eri : %s", msg_buffer);
46187c478bd9Sstevel@tonic-gate return;
46197c478bd9Sstevel@tonic-gate }
46207c478bd9Sstevel@tonic-gate
46217c478bd9Sstevel@tonic-gate if (severity == SEVERITY_HIGH) {
4622d64540e3Sgd cmn_err(CE_WARN, "%s%d : %s", ddi_driver_name(erip->dip),
46237c478bd9Sstevel@tonic-gate erip->instance, msg_buffer);
46247c478bd9Sstevel@tonic-gate } else switch (type) {
46257c478bd9Sstevel@tonic-gate case ERI_VERB_MSG:
4626d64540e3Sgd cmn_err(CE_CONT, "?%s%d : %s", ddi_driver_name(erip->dip),
46277c478bd9Sstevel@tonic-gate erip->instance, msg_buffer);
46287c478bd9Sstevel@tonic-gate break;
46297c478bd9Sstevel@tonic-gate case ERI_LOG_MSG:
4630d64540e3Sgd cmn_err(CE_NOTE, "^%s%d : %s", ddi_driver_name(erip->dip),
46317c478bd9Sstevel@tonic-gate erip->instance, msg_buffer);
46327c478bd9Sstevel@tonic-gate break;
46337c478bd9Sstevel@tonic-gate case ERI_BUF_MSG:
4634d64540e3Sgd cmn_err(CE_NOTE, "!%s%d : %s", ddi_driver_name(erip->dip),
46357c478bd9Sstevel@tonic-gate erip->instance, msg_buffer);
46367c478bd9Sstevel@tonic-gate break;
46377c478bd9Sstevel@tonic-gate case ERI_CON_MSG:
4638d64540e3Sgd cmn_err(CE_CONT, "%s%d : %s", ddi_driver_name(erip->dip),
46397c478bd9Sstevel@tonic-gate erip->instance, msg_buffer);
46407c478bd9Sstevel@tonic-gate default:
46417c478bd9Sstevel@tonic-gate break;
46427c478bd9Sstevel@tonic-gate }
46437c478bd9Sstevel@tonic-gate }
46447c478bd9Sstevel@tonic-gate
46457c478bd9Sstevel@tonic-gate /*
46467c478bd9Sstevel@tonic-gate * Transceiver (xcvr) Functions
46477c478bd9Sstevel@tonic-gate * New Section
46487c478bd9Sstevel@tonic-gate */
46497c478bd9Sstevel@tonic-gate /*
46507c478bd9Sstevel@tonic-gate * eri_stop_timer function is used by a function before doing link-related
46517c478bd9Sstevel@tonic-gate * processing. It locks the "linklock" to protect the link-related data
46527c478bd9Sstevel@tonic-gate * structures. This lock will be subsequently released in eri_start_timer().
46537c478bd9Sstevel@tonic-gate */
46547c478bd9Sstevel@tonic-gate static void
eri_stop_timer(struct eri * erip)46557c478bd9Sstevel@tonic-gate eri_stop_timer(struct eri *erip)
46567c478bd9Sstevel@tonic-gate {
46577c478bd9Sstevel@tonic-gate timeout_id_t id;
46587c478bd9Sstevel@tonic-gate mutex_enter(&erip->linklock);
46597c478bd9Sstevel@tonic-gate if (erip->timerid) {
46607c478bd9Sstevel@tonic-gate erip->flags |= ERI_NOTIMEOUTS; /* prevent multiple timeout */
46617c478bd9Sstevel@tonic-gate id = erip->timerid;
46627c478bd9Sstevel@tonic-gate erip->timerid = 0; /* prevent other thread do untimeout */
46637c478bd9Sstevel@tonic-gate mutex_exit(&erip->linklock); /* no mutex across untimeout() */
46647c478bd9Sstevel@tonic-gate
46657c478bd9Sstevel@tonic-gate (void) untimeout(id);
46667c478bd9Sstevel@tonic-gate mutex_enter(&erip->linklock); /* acquire mutex again */
46677c478bd9Sstevel@tonic-gate erip->flags &= ~ERI_NOTIMEOUTS;
46687c478bd9Sstevel@tonic-gate }
46697c478bd9Sstevel@tonic-gate }
46707c478bd9Sstevel@tonic-gate
46717c478bd9Sstevel@tonic-gate /*
46727c478bd9Sstevel@tonic-gate * If msec parameter is zero, just release "linklock".
46737c478bd9Sstevel@tonic-gate */
46747c478bd9Sstevel@tonic-gate static void
eri_start_timer(struct eri * erip,fptrv_t func,clock_t msec)46757c478bd9Sstevel@tonic-gate eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec)
46767c478bd9Sstevel@tonic-gate {
46777c478bd9Sstevel@tonic-gate if (msec) {
46787c478bd9Sstevel@tonic-gate if (!(erip->flags & ERI_NOTIMEOUTS) &&
4679d64540e3Sgd (erip->flags & ERI_RUNNING)) {
4680d64540e3Sgd erip->timerid = timeout(func, (caddr_t)erip,
4681d64540e3Sgd drv_usectohz(1000*msec));
46827c478bd9Sstevel@tonic-gate }
46837c478bd9Sstevel@tonic-gate }
46847c478bd9Sstevel@tonic-gate
46857c478bd9Sstevel@tonic-gate mutex_exit(&erip->linklock);
46867c478bd9Sstevel@tonic-gate }
46877c478bd9Sstevel@tonic-gate
46887c478bd9Sstevel@tonic-gate static int
eri_new_xcvr(struct eri * erip)46897c478bd9Sstevel@tonic-gate eri_new_xcvr(struct eri *erip)
46907c478bd9Sstevel@tonic-gate {
46917c478bd9Sstevel@tonic-gate int status;
4692*7e996435SToomas Soome uint32_t cfg;
46937c478bd9Sstevel@tonic-gate int old_transceiver;
46947c478bd9Sstevel@tonic-gate
46957c478bd9Sstevel@tonic-gate if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
46967c478bd9Sstevel@tonic-gate PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS)
46977c478bd9Sstevel@tonic-gate erip->stats.pmcap = ERI_PMCAP_NONE;
46987c478bd9Sstevel@tonic-gate
46997c478bd9Sstevel@tonic-gate status = B_FALSE; /* no change */
47007c478bd9Sstevel@tonic-gate cfg = GET_MIFREG(mif_cfg);
4701d64540e3Sgd ERI_DEBUG_MSG2(erip, MIF_MSG, "cfg value = %X", cfg);
47027c478bd9Sstevel@tonic-gate old_transceiver = param_transceiver;
47037c478bd9Sstevel@tonic-gate
47047c478bd9Sstevel@tonic-gate if ((cfg & ERI_MIF_CFGM1) && !use_int_xcvr) {
47057c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, PHY_MSG, "Found External XCVR");
47067c478bd9Sstevel@tonic-gate /*
47077c478bd9Sstevel@tonic-gate * An External Transceiver was found and it takes priority
47087c478bd9Sstevel@tonic-gate * over an internal, given the use_int_xcvr flag
47097c478bd9Sstevel@tonic-gate * is false.
47107c478bd9Sstevel@tonic-gate */
47117c478bd9Sstevel@tonic-gate if (old_transceiver != EXTERNAL_XCVR) {
47127c478bd9Sstevel@tonic-gate /*
47137c478bd9Sstevel@tonic-gate * External transceiver has just been plugged
47147c478bd9Sstevel@tonic-gate * in. Isolate the internal Transceiver.
47157c478bd9Sstevel@tonic-gate */
47167c478bd9Sstevel@tonic-gate if (old_transceiver == INTERNAL_XCVR) {
47177c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR,
4718d64540e3Sgd (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN |
4719d64540e3Sgd PHY_BMCR_LPBK));
47207c478bd9Sstevel@tonic-gate }
47217c478bd9Sstevel@tonic-gate status = B_TRUE;
47227c478bd9Sstevel@tonic-gate }
47237c478bd9Sstevel@tonic-gate /*
47247c478bd9Sstevel@tonic-gate * Select the external Transceiver.
47257c478bd9Sstevel@tonic-gate */
47267c478bd9Sstevel@tonic-gate erip->phyad = ERI_EXTERNAL_PHYAD;
47277c478bd9Sstevel@tonic-gate param_transceiver = EXTERNAL_XCVR;
47287c478bd9Sstevel@tonic-gate erip->mif_config &= ~ERI_MIF_CFGPD;
47297c478bd9Sstevel@tonic-gate erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT);
47307c478bd9Sstevel@tonic-gate erip->mif_config |= ERI_MIF_CFGPS;
47317c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, erip->mif_config);
47327c478bd9Sstevel@tonic-gate
47337c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIIBUF_OE);
47347c478bd9Sstevel@tonic-gate drv_usecwait(ERI_MIF_POLL_DELAY);
47357c478bd9Sstevel@tonic-gate } else if (cfg & ERI_MIF_CFGM0) {
47367c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, PHY_MSG, "Found Internal XCVR");
47377c478bd9Sstevel@tonic-gate /*
47387c478bd9Sstevel@tonic-gate * An Internal Transceiver was found or the
47397c478bd9Sstevel@tonic-gate * use_int_xcvr flag is true.
47407c478bd9Sstevel@tonic-gate */
47417c478bd9Sstevel@tonic-gate if (old_transceiver != INTERNAL_XCVR) {
47427c478bd9Sstevel@tonic-gate /*
47437c478bd9Sstevel@tonic-gate * The external transceiver has just been
47447c478bd9Sstevel@tonic-gate * disconnected or we're moving from a no
47457c478bd9Sstevel@tonic-gate * transceiver state.
47467c478bd9Sstevel@tonic-gate */
47477c478bd9Sstevel@tonic-gate if ((old_transceiver == EXTERNAL_XCVR) &&
4748d64540e3Sgd (cfg & ERI_MIF_CFGM0)) {
47497c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR,
4750d64540e3Sgd (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN |
4751d64540e3Sgd PHY_BMCR_LPBK));
47527c478bd9Sstevel@tonic-gate }
47537c478bd9Sstevel@tonic-gate status = B_TRUE;
47547c478bd9Sstevel@tonic-gate }
47557c478bd9Sstevel@tonic-gate /*
47567c478bd9Sstevel@tonic-gate * Select the internal transceiver.
47577c478bd9Sstevel@tonic-gate */
47587c478bd9Sstevel@tonic-gate erip->phyad = ERI_INTERNAL_PHYAD;
47597c478bd9Sstevel@tonic-gate param_transceiver = INTERNAL_XCVR;
47607c478bd9Sstevel@tonic-gate erip->mif_config &= ~ERI_MIF_CFGPD;
47617c478bd9Sstevel@tonic-gate erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT);
47627c478bd9Sstevel@tonic-gate erip->mif_config &= ~ERI_MIF_CFGPS;
47637c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, erip->mif_config);
47647c478bd9Sstevel@tonic-gate
47657c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, GET_MACREG(xifc) & ~ BMAC_XIFC_MIIBUF_OE);
47667c478bd9Sstevel@tonic-gate drv_usecwait(ERI_MIF_POLL_DELAY);
47677c478bd9Sstevel@tonic-gate } else {
47687c478bd9Sstevel@tonic-gate /*
47697c478bd9Sstevel@tonic-gate * Did not find a valid xcvr.
47707c478bd9Sstevel@tonic-gate */
4771d64540e3Sgd ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
4772d64540e3Sgd "Eri_new_xcvr : Select None");
4773d64540e3Sgd param_transceiver = NO_XCVR;
4774d64540e3Sgd erip->xcvr_status = PHY_LINK_DOWN;
47757c478bd9Sstevel@tonic-gate }
47767c478bd9Sstevel@tonic-gate
47777c478bd9Sstevel@tonic-gate if (erip->stats.pmcap == ERI_PMCAP_NONE) {
47787c478bd9Sstevel@tonic-gate if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
47797c478bd9Sstevel@tonic-gate (void *)4000) == DDI_SUCCESS)
47807c478bd9Sstevel@tonic-gate erip->stats.pmcap = ERI_PMCAP_4MHZ;
47817c478bd9Sstevel@tonic-gate }
47827c478bd9Sstevel@tonic-gate
47837c478bd9Sstevel@tonic-gate return (status);
47847c478bd9Sstevel@tonic-gate }
47857c478bd9Sstevel@tonic-gate
4786860c4cd4Scarlsonj /*
4787860c4cd4Scarlsonj * This function is used for timers. No locks are held on timer expiry.
4788860c4cd4Scarlsonj */
4789860c4cd4Scarlsonj static void
eri_check_link(struct eri * erip)4790860c4cd4Scarlsonj eri_check_link(struct eri *erip)
4791860c4cd4Scarlsonj {
4792d64540e3Sgd link_state_t linkupdate = eri_check_link_noind(erip);
4793d64540e3Sgd
4794d64540e3Sgd if (linkupdate != LINK_STATE_UNKNOWN)
4795d64540e3Sgd mac_link_update(erip->mh, linkupdate);
4796860c4cd4Scarlsonj }
4797860c4cd4Scarlsonj
47987c478bd9Sstevel@tonic-gate /*
47997c478bd9Sstevel@tonic-gate * Compare our xcvr in our structure to the xcvr that we get from
48007c478bd9Sstevel@tonic-gate * eri_check_mii_xcvr(). If they are different then mark the
48017c478bd9Sstevel@tonic-gate * link down, reset xcvr, and return.
48027c478bd9Sstevel@tonic-gate *
48037c478bd9Sstevel@tonic-gate * Note without the MII connector, conditions can not change that
48047c478bd9Sstevel@tonic-gate * will then use a external phy, thus this code has been cleaned
48057c478bd9Sstevel@tonic-gate * to not even call the function or to possibly change the xcvr.
48067c478bd9Sstevel@tonic-gate */
4807860c4cd4Scarlsonj static uint32_t
eri_check_link_noind(struct eri * erip)4808860c4cd4Scarlsonj eri_check_link_noind(struct eri *erip)
48097c478bd9Sstevel@tonic-gate {
48107c478bd9Sstevel@tonic-gate uint16_t stat, control, mif_ints;
48117c478bd9Sstevel@tonic-gate uint32_t link_timeout = ERI_LINKCHECK_TIMER;
4812d64540e3Sgd uint32_t linkupdate = 0;
48137c478bd9Sstevel@tonic-gate
48147c478bd9Sstevel@tonic-gate eri_stop_timer(erip); /* acquire linklock */
48157c478bd9Sstevel@tonic-gate
48167c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
48177c478bd9Sstevel@tonic-gate mutex_enter(&erip->xcvrlock);
48187c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_STOP);
48197c478bd9Sstevel@tonic-gate
48207c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
48217c478bd9Sstevel@tonic-gate mif_ints = erip->mii_status ^ stat;
48227c478bd9Sstevel@tonic-gate
48237c478bd9Sstevel@tonic-gate if (erip->openloop_autoneg) {
48247c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
48257c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG3(erip, XCVR_MSG,
4826d64540e3Sgd "eri_check_link:openloop stat %X mii_status %X",
4827d64540e3Sgd stat, erip->mii_status);
48287c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
48297c478bd9Sstevel@tonic-gate if (!(stat & PHY_BMSR_LNKSTS) &&
4830d64540e3Sgd (erip->openloop_autoneg < 2)) {
48317c478bd9Sstevel@tonic-gate if (param_speed) {
48327c478bd9Sstevel@tonic-gate control &= ~PHY_BMCR_100M;
48337c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 0;
48347c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 1;
48357c478bd9Sstevel@tonic-gate param_speed = 0;
4836d64540e3Sgd erip->stats.ifspeed = 10;
48377c478bd9Sstevel@tonic-gate
48387c478bd9Sstevel@tonic-gate } else {
48397c478bd9Sstevel@tonic-gate control |= PHY_BMCR_100M;
48407c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 1;
48417c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 0;
48427c478bd9Sstevel@tonic-gate param_speed = 1;
4843d64540e3Sgd erip->stats.ifspeed = 100;
48447c478bd9Sstevel@tonic-gate }
48457c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG3(erip, XCVR_MSG,
4846d64540e3Sgd "eri_check_link: trying speed %X stat %X",
4847d64540e3Sgd param_speed, stat);
48487c478bd9Sstevel@tonic-gate
48497c478bd9Sstevel@tonic-gate erip->openloop_autoneg ++;
48507c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR, control);
48517c478bd9Sstevel@tonic-gate link_timeout = ERI_P_FAULT_TIMER;
48527c478bd9Sstevel@tonic-gate } else {
48537c478bd9Sstevel@tonic-gate erip->openloop_autoneg = 0;
4854d64540e3Sgd linkupdate = eri_mif_check(erip, stat, stat);
48557c478bd9Sstevel@tonic-gate if (erip->openloop_autoneg)
48567c478bd9Sstevel@tonic-gate link_timeout = ERI_P_FAULT_TIMER;
48577c478bd9Sstevel@tonic-gate }
48587c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_START);
48597c478bd9Sstevel@tonic-gate mutex_exit(&erip->xcvrlock);
48607c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
48617c478bd9Sstevel@tonic-gate
48627c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, link_timeout);
4863d64540e3Sgd return (linkupdate);
48647c478bd9Sstevel@tonic-gate }
48657c478bd9Sstevel@tonic-gate
4866d64540e3Sgd linkupdate = eri_mif_check(erip, mif_ints, stat);
48677c478bd9Sstevel@tonic-gate eri_mif_poll(erip, MIF_POLL_START);
48687c478bd9Sstevel@tonic-gate mutex_exit(&erip->xcvrlock);
48697c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
48707c478bd9Sstevel@tonic-gate
48717c478bd9Sstevel@tonic-gate #ifdef ERI_RMAC_HANG_WORKAROUND
48727c478bd9Sstevel@tonic-gate /*
48737c478bd9Sstevel@tonic-gate * Check if rx hung.
48747c478bd9Sstevel@tonic-gate */
48757c478bd9Sstevel@tonic-gate if ((erip->flags & ERI_RUNNING) && param_linkup) {
48767c478bd9Sstevel@tonic-gate if (erip->check_rmac_hang) {
48777c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG5(erip,
48787c478bd9Sstevel@tonic-gate NONFATAL_MSG,
48797c478bd9Sstevel@tonic-gate "check1 %d: macsm:%8x wr:%2x rd:%2x",
48807c478bd9Sstevel@tonic-gate erip->check_rmac_hang,
48817c478bd9Sstevel@tonic-gate GET_MACREG(macsm),
48827c478bd9Sstevel@tonic-gate GET_ERXREG(rxfifo_wr_ptr),
48837c478bd9Sstevel@tonic-gate GET_ERXREG(rxfifo_rd_ptr));
48847c478bd9Sstevel@tonic-gate
48857c478bd9Sstevel@tonic-gate erip->check_rmac_hang = 0;
48867c478bd9Sstevel@tonic-gate erip->check2_rmac_hang ++;
48877c478bd9Sstevel@tonic-gate
48887c478bd9Sstevel@tonic-gate erip->rxfifo_wr_ptr_c = GET_ERXREG(rxfifo_wr_ptr);
48897c478bd9Sstevel@tonic-gate erip->rxfifo_rd_ptr_c = GET_ERXREG(rxfifo_rd_ptr);
48907c478bd9Sstevel@tonic-gate
48917c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link,
48927c478bd9Sstevel@tonic-gate ERI_CHECK_HANG_TIMER);
4893d64540e3Sgd return (linkupdate);
48947c478bd9Sstevel@tonic-gate }
48957c478bd9Sstevel@tonic-gate
48967c478bd9Sstevel@tonic-gate if (erip->check2_rmac_hang) {
48977c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG5(erip,
48987c478bd9Sstevel@tonic-gate NONFATAL_MSG,
48997c478bd9Sstevel@tonic-gate "check2 %d: macsm:%8x wr:%2x rd:%2x",
49007c478bd9Sstevel@tonic-gate erip->check2_rmac_hang,
49017c478bd9Sstevel@tonic-gate GET_MACREG(macsm),
49027c478bd9Sstevel@tonic-gate GET_ERXREG(rxfifo_wr_ptr),
49037c478bd9Sstevel@tonic-gate GET_ERXREG(rxfifo_rd_ptr));
49047c478bd9Sstevel@tonic-gate
49057c478bd9Sstevel@tonic-gate erip->check2_rmac_hang = 0;
49067c478bd9Sstevel@tonic-gate
49077c478bd9Sstevel@tonic-gate erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr);
49087c478bd9Sstevel@tonic-gate erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr);
49097c478bd9Sstevel@tonic-gate
49107c478bd9Sstevel@tonic-gate if (((GET_MACREG(macsm) & BMAC_OVERFLOW_STATE) ==
49117c478bd9Sstevel@tonic-gate BMAC_OVERFLOW_STATE) &&
49127c478bd9Sstevel@tonic-gate ((erip->rxfifo_wr_ptr_c == erip->rxfifo_rd_ptr_c) ||
49137c478bd9Sstevel@tonic-gate ((erip->rxfifo_rd_ptr == erip->rxfifo_rd_ptr_c) &&
49147c478bd9Sstevel@tonic-gate (erip->rxfifo_wr_ptr == erip->rxfifo_wr_ptr_c)))) {
49157c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip,
49167c478bd9Sstevel@tonic-gate NONFATAL_MSG,
49177c478bd9Sstevel@tonic-gate "RX hang: Reset mac");
49187c478bd9Sstevel@tonic-gate
49197c478bd9Sstevel@tonic-gate HSTAT(erip, rx_hang);
49207c478bd9Sstevel@tonic-gate erip->linkcheck = 1;
49217c478bd9Sstevel@tonic-gate
49227c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link,
49237c478bd9Sstevel@tonic-gate ERI_LINKCHECK_TIMER);
49247c478bd9Sstevel@tonic-gate (void) eri_init(erip);
4925d64540e3Sgd return (linkupdate);
49267c478bd9Sstevel@tonic-gate }
49277c478bd9Sstevel@tonic-gate }
49287c478bd9Sstevel@tonic-gate }
49297c478bd9Sstevel@tonic-gate #endif
49307c478bd9Sstevel@tonic-gate
49317c478bd9Sstevel@tonic-gate /*
49327c478bd9Sstevel@tonic-gate * Check if tx hung.
49337c478bd9Sstevel@tonic-gate */
49347c478bd9Sstevel@tonic-gate #ifdef ERI_TX_HUNG
4935d64540e3Sgd if ((erip->flags & ERI_RUNNING) && param_linkup &&
4936d64540e3Sgd (eri_check_txhung(erip))) {
49377c478bd9Sstevel@tonic-gate HSTAT(erip, tx_hang);
49387c478bd9Sstevel@tonic-gate eri_reinit_txhung++;
49397c478bd9Sstevel@tonic-gate erip->linkcheck = 1;
49407c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER);
49417c478bd9Sstevel@tonic-gate (void) eri_init(erip);
4942d64540e3Sgd return (linkupdate);
49437c478bd9Sstevel@tonic-gate }
49447c478bd9Sstevel@tonic-gate #endif
49457c478bd9Sstevel@tonic-gate
49467c478bd9Sstevel@tonic-gate #ifdef ERI_PM_WORKAROUND
49477c478bd9Sstevel@tonic-gate if (erip->stats.pmcap == ERI_PMCAP_NONE) {
49487c478bd9Sstevel@tonic-gate if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
49497c478bd9Sstevel@tonic-gate (void *)4000) == DDI_SUCCESS)
49507c478bd9Sstevel@tonic-gate erip->stats.pmcap = ERI_PMCAP_4MHZ;
49517c478bd9Sstevel@tonic-gate
49527c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, NONFATAL_MSG,
49537c478bd9Sstevel@tonic-gate "eri_check_link: PMCAP %d", erip->stats.pmcap);
49547c478bd9Sstevel@tonic-gate }
49557c478bd9Sstevel@tonic-gate #endif
49567c478bd9Sstevel@tonic-gate if ((!param_mode) && (param_transceiver != NO_XCVR))
49577c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER);
49587c478bd9Sstevel@tonic-gate else
49597c478bd9Sstevel@tonic-gate eri_start_timer(erip, eri_check_link, ERI_LINKCHECK_TIMER);
4960d64540e3Sgd return (linkupdate);
49617c478bd9Sstevel@tonic-gate }
49627c478bd9Sstevel@tonic-gate
4963d64540e3Sgd static link_state_t
eri_mif_check(struct eri * erip,uint16_t mif_ints,uint16_t mif_data)49647c478bd9Sstevel@tonic-gate eri_mif_check(struct eri *erip, uint16_t mif_ints, uint16_t mif_data)
49657c478bd9Sstevel@tonic-gate {
49667c478bd9Sstevel@tonic-gate uint16_t control, aner, anlpar, anar, an_common;
49677c478bd9Sstevel@tonic-gate uint16_t old_mintrans;
49687c478bd9Sstevel@tonic-gate int restart_autoneg = 0;
4969d64540e3Sgd link_state_t retv;
49707c478bd9Sstevel@tonic-gate
4971d64540e3Sgd ERI_DEBUG_MSG4(erip, XCVR_MSG, "eri_mif_check: mif_mask: %X, %X, %X",
4972d64540e3Sgd erip->mif_mask, mif_ints, mif_data);
49737c478bd9Sstevel@tonic-gate
49747c478bd9Sstevel@tonic-gate mif_ints &= ~erip->mif_mask;
49757c478bd9Sstevel@tonic-gate erip->mii_status = mif_data;
49767c478bd9Sstevel@tonic-gate /*
49777c478bd9Sstevel@tonic-gate * Now check if someone has pulled the xcvr or
49787c478bd9Sstevel@tonic-gate * a new xcvr has shown up
49797c478bd9Sstevel@tonic-gate * If so try to find out what the new xcvr setup is.
49807c478bd9Sstevel@tonic-gate */
49817c478bd9Sstevel@tonic-gate if (((mif_ints & PHY_BMSR_RES1) && (mif_data == 0xFFFF)) ||
4982d64540e3Sgd (param_transceiver == NO_XCVR)) {
49837c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
4984d64540e3Sgd "No status transceiver gone");
49857c478bd9Sstevel@tonic-gate if (eri_new_xcvr(erip)) {
49867c478bd9Sstevel@tonic-gate if (param_transceiver != NO_XCVR) {
49877c478bd9Sstevel@tonic-gate /*
49887c478bd9Sstevel@tonic-gate * Reset the new PHY and bring up the link
49897c478bd9Sstevel@tonic-gate */
49907c478bd9Sstevel@tonic-gate (void) eri_reset_xcvr(erip);
49917c478bd9Sstevel@tonic-gate }
49927c478bd9Sstevel@tonic-gate }
4993d64540e3Sgd return (LINK_STATE_UNKNOWN);
49947c478bd9Sstevel@tonic-gate }
49957c478bd9Sstevel@tonic-gate
49967c478bd9Sstevel@tonic-gate if (param_autoneg && (mif_ints & PHY_BMSR_LNKSTS) &&
4997d64540e3Sgd (mif_data & PHY_BMSR_LNKSTS) && (mif_data & PHY_BMSR_ANC)) {
49987c478bd9Sstevel@tonic-gate mif_ints |= PHY_BMSR_ANC;
49997c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG3(erip, PHY_MSG,
5000d64540e3Sgd "eri_mif_check: Set ANC bit mif_data %X mig_ints %X",
5001d64540e3Sgd mif_data, mif_ints);
50027c478bd9Sstevel@tonic-gate }
50037c478bd9Sstevel@tonic-gate
50047c478bd9Sstevel@tonic-gate if ((mif_ints & PHY_BMSR_ANC) && (mif_data & PHY_BMSR_ANC)) {
5005d64540e3Sgd ERI_DEBUG_MSG1(erip, PHY_MSG, "Auto-negotiation interrupt.");
50067c478bd9Sstevel@tonic-gate
50077c478bd9Sstevel@tonic-gate /*
50087c478bd9Sstevel@tonic-gate * Switch off Auto-negotiation interrupts and switch on
50097c478bd9Sstevel@tonic-gate * Link ststus interrupts.
50107c478bd9Sstevel@tonic-gate */
50117c478bd9Sstevel@tonic-gate erip->mif_mask |= PHY_BMSR_ANC;
50127c478bd9Sstevel@tonic-gate erip->mif_mask &= ~PHY_BMSR_LNKSTS;
50137c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_ANER, &aner);
50147c478bd9Sstevel@tonic-gate param_aner_lpancap = 1 && (aner & PHY_ANER_LPNW);
50157c478bd9Sstevel@tonic-gate if ((aner & PHY_ANER_MLF) || (eri_force_mlf)) {
50167c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, XCVR_MSG,
5017d64540e3Sgd "parallel detection fault");
50187c478bd9Sstevel@tonic-gate /*
50197c478bd9Sstevel@tonic-gate * Consider doing open loop auto-negotiation.
50207c478bd9Sstevel@tonic-gate */
50217c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, XCVR_MSG,
5022d64540e3Sgd "Going into Open loop Auto-neg");
50237c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
50247c478bd9Sstevel@tonic-gate
50257c478bd9Sstevel@tonic-gate control &= ~(PHY_BMCR_ANE | PHY_BMCR_RAN |
5026d64540e3Sgd PHY_BMCR_FDX);
50277c478bd9Sstevel@tonic-gate if (param_anar_100fdx || param_anar_100hdx) {
50287c478bd9Sstevel@tonic-gate control |= PHY_BMCR_100M;
50297c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 1;
50307c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 0;
50317c478bd9Sstevel@tonic-gate param_speed = 1;
5032d64540e3Sgd erip->stats.ifspeed = 100;
5033d64540e3Sgd
5034d64540e3Sgd } else if (param_anar_10fdx || param_anar_10hdx) {
5035d64540e3Sgd control &= ~PHY_BMCR_100M;
5036d64540e3Sgd param_anlpar_100hdx = 0;
5037d64540e3Sgd param_anlpar_10hdx = 1;
5038d64540e3Sgd param_speed = 0;
5039d64540e3Sgd erip->stats.ifspeed = 10;
50407c478bd9Sstevel@tonic-gate } else {
50417c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE,
5042d64540e3Sgd ERI_VERB_MSG,
5043d64540e3Sgd "Transceiver speed set incorrectly.");
5044860c4cd4Scarlsonj return (0);
50457c478bd9Sstevel@tonic-gate }
50467c478bd9Sstevel@tonic-gate
50477c478bd9Sstevel@tonic-gate (void) eri_mii_write(erip, ERI_PHY_BMCR, control);
50487c478bd9Sstevel@tonic-gate param_anlpar_100fdx = 0;
50497c478bd9Sstevel@tonic-gate param_anlpar_10fdx = 0;
50507c478bd9Sstevel@tonic-gate param_mode = 0;
50517c478bd9Sstevel@tonic-gate erip->openloop_autoneg = 1;
5052860c4cd4Scarlsonj return (0);
50537c478bd9Sstevel@tonic-gate }
50547c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_ANLPAR, &anlpar);
50557c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
50567c478bd9Sstevel@tonic-gate an_common = anar & anlpar;
50577c478bd9Sstevel@tonic-gate
5058d64540e3Sgd ERI_DEBUG_MSG2(erip, XCVR_MSG, "an_common = 0x%X", an_common);
50597c478bd9Sstevel@tonic-gate
50607c478bd9Sstevel@tonic-gate if (an_common & (PHY_ANLPAR_TXFDX | PHY_ANLPAR_TX)) {
50617c478bd9Sstevel@tonic-gate param_speed = 1;
5062d64540e3Sgd erip->stats.ifspeed = 100;
50637c478bd9Sstevel@tonic-gate param_mode = 1 && (an_common & PHY_ANLPAR_TXFDX);
50647c478bd9Sstevel@tonic-gate
50657c478bd9Sstevel@tonic-gate } else if (an_common & (PHY_ANLPAR_10FDX | PHY_ANLPAR_10)) {
50667c478bd9Sstevel@tonic-gate param_speed = 0;
5067d64540e3Sgd erip->stats.ifspeed = 10;
50687c478bd9Sstevel@tonic-gate param_mode = 1 && (an_common & PHY_ANLPAR_10FDX);
50697c478bd9Sstevel@tonic-gate
50707c478bd9Sstevel@tonic-gate } else an_common = 0x0;
50717c478bd9Sstevel@tonic-gate
50727c478bd9Sstevel@tonic-gate if (!an_common) {
50737c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG,
5074d64540e3Sgd "Transceiver: anar not set with speed selection");
50757c478bd9Sstevel@tonic-gate }
50767c478bd9Sstevel@tonic-gate param_anlpar_100T4 = 1 && (anlpar & PHY_ANLPAR_T4);
50777c478bd9Sstevel@tonic-gate param_anlpar_100fdx = 1 && (anlpar & PHY_ANLPAR_TXFDX);
50787c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 1 && (anlpar & PHY_ANLPAR_TX);
50797c478bd9Sstevel@tonic-gate param_anlpar_10fdx = 1 && (anlpar & PHY_ANLPAR_10FDX);
50807c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 1 && (anlpar & PHY_ANLPAR_10);
50817c478bd9Sstevel@tonic-gate
50827c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, PHY_MSG,
5083d64540e3Sgd "Link duplex = 0x%X", param_mode);
50847c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, PHY_MSG,
5085d64540e3Sgd "Link speed = 0x%X", param_speed);
50867c478bd9Sstevel@tonic-gate /* mif_ints |= PHY_BMSR_LNKSTS; prevent double msg */
50877c478bd9Sstevel@tonic-gate /* mif_data |= PHY_BMSR_LNKSTS; prevent double msg */
50887c478bd9Sstevel@tonic-gate }
5089d64540e3Sgd retv = LINK_STATE_UNKNOWN;
50907c478bd9Sstevel@tonic-gate if (mif_ints & PHY_BMSR_LNKSTS) {
50917c478bd9Sstevel@tonic-gate if (mif_data & PHY_BMSR_LNKSTS) {
50927c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, PHY_MSG, "Link Up");
50937c478bd9Sstevel@tonic-gate /*
50947c478bd9Sstevel@tonic-gate * Program Lu3X31T for mininum transition
50957c478bd9Sstevel@tonic-gate */
50967c478bd9Sstevel@tonic-gate if (eri_phy_mintrans) {
50977c478bd9Sstevel@tonic-gate eri_mii_write(erip, 31, 0x8000);
50987c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, 0, &old_mintrans);
50997c478bd9Sstevel@tonic-gate eri_mii_write(erip, 0, 0x00F1);
51007c478bd9Sstevel@tonic-gate eri_mii_write(erip, 31, 0x0000);
51017c478bd9Sstevel@tonic-gate }
51027c478bd9Sstevel@tonic-gate /*
51037c478bd9Sstevel@tonic-gate * The link is up.
51047c478bd9Sstevel@tonic-gate */
51057c478bd9Sstevel@tonic-gate eri_init_txmac(erip);
51067c478bd9Sstevel@tonic-gate param_linkup = 1;
5107d64540e3Sgd erip->stats.link_up = LINK_STATE_UP;
51087c478bd9Sstevel@tonic-gate if (param_mode)
5109d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_FULL;
51107c478bd9Sstevel@tonic-gate else
5111d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_HALF;
51127c478bd9Sstevel@tonic-gate
5113d64540e3Sgd retv = LINK_STATE_UP;
51147c478bd9Sstevel@tonic-gate } else {
5115d64540e3Sgd ERI_DEBUG_MSG1(erip, PHY_MSG, "Link down.");
51167c478bd9Sstevel@tonic-gate param_linkup = 0;
5117d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
5118d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
5119d64540e3Sgd retv = LINK_STATE_DOWN;
51207c478bd9Sstevel@tonic-gate if (param_autoneg) {
51217c478bd9Sstevel@tonic-gate restart_autoneg = 1;
51227c478bd9Sstevel@tonic-gate }
51237c478bd9Sstevel@tonic-gate }
51247c478bd9Sstevel@tonic-gate } else {
51257c478bd9Sstevel@tonic-gate if (mif_data & PHY_BMSR_LNKSTS) {
51267c478bd9Sstevel@tonic-gate if (!param_linkup) {
51277c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, PHY_MSG,
5128d64540e3Sgd "eri_mif_check: MIF data link up");
51297c478bd9Sstevel@tonic-gate /*
51307c478bd9Sstevel@tonic-gate * Program Lu3X31T for minimum transition
51317c478bd9Sstevel@tonic-gate */
51327c478bd9Sstevel@tonic-gate if (eri_phy_mintrans) {
51337c478bd9Sstevel@tonic-gate eri_mii_write(erip, 31, 0x8000);
51347c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, 0,
5135d64540e3Sgd &old_mintrans);
51367c478bd9Sstevel@tonic-gate eri_mii_write(erip, 0, 0x00F1);
51377c478bd9Sstevel@tonic-gate eri_mii_write(erip, 31, 0x0000);
51387c478bd9Sstevel@tonic-gate }
51397c478bd9Sstevel@tonic-gate /*
51407c478bd9Sstevel@tonic-gate * The link is up.
51417c478bd9Sstevel@tonic-gate */
51427c478bd9Sstevel@tonic-gate eri_init_txmac(erip);
51437c478bd9Sstevel@tonic-gate
51447c478bd9Sstevel@tonic-gate param_linkup = 1;
5145d64540e3Sgd erip->stats.link_up = LINK_STATE_UP;
51467c478bd9Sstevel@tonic-gate if (param_mode)
51477c478bd9Sstevel@tonic-gate erip->stats.link_duplex =
5148d64540e3Sgd LINK_DUPLEX_FULL;
51497c478bd9Sstevel@tonic-gate else
51507c478bd9Sstevel@tonic-gate erip->stats.link_duplex =
5151d64540e3Sgd LINK_DUPLEX_HALF;
51527c478bd9Sstevel@tonic-gate
5153d64540e3Sgd retv = LINK_STATE_UP;
51547c478bd9Sstevel@tonic-gate }
51557c478bd9Sstevel@tonic-gate } else if (param_linkup) {
51567c478bd9Sstevel@tonic-gate /*
51577c478bd9Sstevel@tonic-gate * The link is down now.
51587c478bd9Sstevel@tonic-gate */
51597c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, PHY_MSG,
5160d64540e3Sgd "eri_mif_check:Link was up and went down");
51617c478bd9Sstevel@tonic-gate param_linkup = 0;
5162d64540e3Sgd erip->stats.link_up = LINK_STATE_DOWN;
5163d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
5164d64540e3Sgd retv = LINK_STATE_DOWN;
51657c478bd9Sstevel@tonic-gate if (param_autoneg)
51667c478bd9Sstevel@tonic-gate restart_autoneg = 1;
51677c478bd9Sstevel@tonic-gate }
51687c478bd9Sstevel@tonic-gate }
51697c478bd9Sstevel@tonic-gate if (restart_autoneg) {
51707c478bd9Sstevel@tonic-gate /*
51717c478bd9Sstevel@tonic-gate * Restart normal auto-negotiation.
51727c478bd9Sstevel@tonic-gate */
51737c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, PHY_MSG,
5174d64540e3Sgd "eri_mif_check:Restart AUto Negotiation");
51757c478bd9Sstevel@tonic-gate erip->openloop_autoneg = 0;
51767c478bd9Sstevel@tonic-gate param_mode = 0;
51777c478bd9Sstevel@tonic-gate param_speed = 0;
51787c478bd9Sstevel@tonic-gate param_anlpar_100T4 = 0;
51797c478bd9Sstevel@tonic-gate param_anlpar_100fdx = 0;
51807c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 0;
51817c478bd9Sstevel@tonic-gate param_anlpar_10fdx = 0;
51827c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 0;
51837c478bd9Sstevel@tonic-gate param_aner_lpancap = 0;
5184d64540e3Sgd (void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
51857c478bd9Sstevel@tonic-gate control |= (PHY_BMCR_ANE | PHY_BMCR_RAN);
51867c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR, control);
51877c478bd9Sstevel@tonic-gate }
51887c478bd9Sstevel@tonic-gate if (mif_ints & PHY_BMSR_JABDET) {
51897c478bd9Sstevel@tonic-gate if (mif_data & PHY_BMSR_JABDET) {
5190d64540e3Sgd ERI_DEBUG_MSG1(erip, PHY_MSG, "Jabber detected.");
51917c478bd9Sstevel@tonic-gate HSTAT(erip, jab);
51927c478bd9Sstevel@tonic-gate /*
51937c478bd9Sstevel@tonic-gate * Reset the new PHY and bring up the link
5194d64540e3Sgd * (Check for failure?)
51957c478bd9Sstevel@tonic-gate */
51967c478bd9Sstevel@tonic-gate (void) eri_reset_xcvr(erip);
51977c478bd9Sstevel@tonic-gate }
51987c478bd9Sstevel@tonic-gate }
5199860c4cd4Scarlsonj return (retv);
52007c478bd9Sstevel@tonic-gate }
52017c478bd9Sstevel@tonic-gate
52027c478bd9Sstevel@tonic-gate #define PHYRST_PERIOD 500
52037c478bd9Sstevel@tonic-gate static int
eri_reset_xcvr(struct eri * erip)52047c478bd9Sstevel@tonic-gate eri_reset_xcvr(struct eri *erip)
52057c478bd9Sstevel@tonic-gate {
52067c478bd9Sstevel@tonic-gate uint16_t stat;
52077c478bd9Sstevel@tonic-gate uint16_t anar;
52087c478bd9Sstevel@tonic-gate uint16_t control;
52097c478bd9Sstevel@tonic-gate uint16_t idr1;
52107c478bd9Sstevel@tonic-gate uint16_t idr2;
52117c478bd9Sstevel@tonic-gate uint16_t nicr;
52127c478bd9Sstevel@tonic-gate uint32_t speed_100;
52137c478bd9Sstevel@tonic-gate uint32_t speed_10;
52147c478bd9Sstevel@tonic-gate int n;
52157c478bd9Sstevel@tonic-gate
52167c478bd9Sstevel@tonic-gate #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND
52177c478bd9Sstevel@tonic-gate erip->ifspeed_old = erip->stats.ifspeed;
52187c478bd9Sstevel@tonic-gate #endif
52197c478bd9Sstevel@tonic-gate /*
52207c478bd9Sstevel@tonic-gate * Reset Open loop auto-negotiation this means you can try
52217c478bd9Sstevel@tonic-gate * Normal auto-negotiation, until you get a Multiple Link fault
52227c478bd9Sstevel@tonic-gate * at which point you try 100M half duplex then 10M half duplex
52237c478bd9Sstevel@tonic-gate * until you get a Link up.
52247c478bd9Sstevel@tonic-gate */
52257c478bd9Sstevel@tonic-gate erip->openloop_autoneg = 0;
52267c478bd9Sstevel@tonic-gate
52277c478bd9Sstevel@tonic-gate /*
52287c478bd9Sstevel@tonic-gate * Reset the xcvr.
52297c478bd9Sstevel@tonic-gate */
52307c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR, PHY_BMCR_RESET);
52317c478bd9Sstevel@tonic-gate
52327c478bd9Sstevel@tonic-gate /* Check for transceiver reset completion */
52337c478bd9Sstevel@tonic-gate
52347c478bd9Sstevel@tonic-gate n = 1000;
52357c478bd9Sstevel@tonic-gate while (--n > 0) {
52367c478bd9Sstevel@tonic-gate drv_usecwait((clock_t)PHYRST_PERIOD);
52377c478bd9Sstevel@tonic-gate if (eri_mii_read(erip, ERI_PHY_BMCR, &control) == 1) {
52387c478bd9Sstevel@tonic-gate /* Transceiver does not talk MII */
52397c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
5240d64540e3Sgd "eri_reset_xcvr: no mii");
52417c478bd9Sstevel@tonic-gate }
52427c478bd9Sstevel@tonic-gate if ((control & PHY_BMCR_RESET) == 0)
52437c478bd9Sstevel@tonic-gate goto reset_done;
52447c478bd9Sstevel@tonic-gate }
52457c478bd9Sstevel@tonic-gate ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG,
5246d64540e3Sgd "eri_reset_xcvr:reset_failed n == 0, control %x", control);
52477c478bd9Sstevel@tonic-gate goto eri_reset_xcvr_failed;
52487c478bd9Sstevel@tonic-gate
52497c478bd9Sstevel@tonic-gate reset_done:
52507c478bd9Sstevel@tonic-gate
52517c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, AUTOCONFIG_MSG,
5252d64540e3Sgd "eri_reset_xcvr: reset complete in %d us",
5253d64540e3Sgd (1000 - n) * PHYRST_PERIOD);
52547c478bd9Sstevel@tonic-gate
52557c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
52567c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
52577c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_IDR1, &idr1);
52587c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_IDR2, &idr2);
52597c478bd9Sstevel@tonic-gate
52607c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG4(erip, XCVR_MSG,
5261d64540e3Sgd "eri_reset_xcvr: control %x stat %x anar %x", control, stat, anar);
52627c478bd9Sstevel@tonic-gate
52637c478bd9Sstevel@tonic-gate /*
52647c478bd9Sstevel@tonic-gate * Initialize the read only transceiver ndd information
52657c478bd9Sstevel@tonic-gate * the values are either 0 or 1.
52667c478bd9Sstevel@tonic-gate */
52677c478bd9Sstevel@tonic-gate param_bmsr_ancap = 1 && (stat & PHY_BMSR_ACFG);
52687c478bd9Sstevel@tonic-gate param_bmsr_100T4 = 1 && (stat & PHY_BMSR_100T4);
52697c478bd9Sstevel@tonic-gate param_bmsr_100fdx = 1 && (stat & PHY_BMSR_100FDX);
52707c478bd9Sstevel@tonic-gate param_bmsr_100hdx = 1 && (stat & PHY_BMSR_100HDX);
52717c478bd9Sstevel@tonic-gate param_bmsr_10fdx = 1 && (stat & PHY_BMSR_10FDX);
52727c478bd9Sstevel@tonic-gate param_bmsr_10hdx = 1 && (stat & PHY_BMSR_10HDX);
52737c478bd9Sstevel@tonic-gate
52747c478bd9Sstevel@tonic-gate /*
52757c478bd9Sstevel@tonic-gate * Match up the ndd capabilities with the transceiver.
52767c478bd9Sstevel@tonic-gate */
52777c478bd9Sstevel@tonic-gate param_autoneg &= param_bmsr_ancap;
52787c478bd9Sstevel@tonic-gate param_anar_100fdx &= param_bmsr_100fdx;
52797c478bd9Sstevel@tonic-gate param_anar_100hdx &= param_bmsr_100hdx;
52807c478bd9Sstevel@tonic-gate param_anar_10fdx &= param_bmsr_10fdx;
52817c478bd9Sstevel@tonic-gate param_anar_10hdx &= param_bmsr_10hdx;
52827c478bd9Sstevel@tonic-gate
52837c478bd9Sstevel@tonic-gate /*
52847c478bd9Sstevel@tonic-gate * Select the operation mode of the transceiver.
52857c478bd9Sstevel@tonic-gate */
52867c478bd9Sstevel@tonic-gate if (param_autoneg) {
52877c478bd9Sstevel@tonic-gate /*
52887c478bd9Sstevel@tonic-gate * Initialize our auto-negotiation capabilities.
52897c478bd9Sstevel@tonic-gate */
52907c478bd9Sstevel@tonic-gate anar = PHY_SELECTOR;
52917c478bd9Sstevel@tonic-gate if (param_anar_100T4)
52927c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_T4;
52937c478bd9Sstevel@tonic-gate if (param_anar_100fdx)
52947c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_TXFDX;
52957c478bd9Sstevel@tonic-gate if (param_anar_100hdx)
52967c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_TX;
52977c478bd9Sstevel@tonic-gate if (param_anar_10fdx)
52987c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_10FDX;
52997c478bd9Sstevel@tonic-gate if (param_anar_10hdx)
53007c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_10;
5301d64540e3Sgd ERI_DEBUG_MSG2(erip, XCVR_MSG, "anar = %x", anar);
53027c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_ANAR, anar);
53037c478bd9Sstevel@tonic-gate }
53047c478bd9Sstevel@tonic-gate
53057c478bd9Sstevel@tonic-gate /* Place the Transceiver in normal operation mode */
53067c478bd9Sstevel@tonic-gate if ((control & PHY_BMCR_ISOLATE) || (control & PHY_BMCR_LPBK)) {
53077c478bd9Sstevel@tonic-gate control &= ~(PHY_BMCR_ISOLATE | PHY_BMCR_LPBK);
53087c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR,
5309d64540e3Sgd (control & ~PHY_BMCR_ISOLATE));
53107c478bd9Sstevel@tonic-gate }
53117c478bd9Sstevel@tonic-gate
53127c478bd9Sstevel@tonic-gate /*
53137c478bd9Sstevel@tonic-gate * If Lu3X31T then allow nonzero eri_phy_mintrans
53147c478bd9Sstevel@tonic-gate */
53157c478bd9Sstevel@tonic-gate if (eri_phy_mintrans &&
53167c478bd9Sstevel@tonic-gate (idr1 != 0x43 || (idr2 & 0xFFF0) != 0x7420)) {
53177c478bd9Sstevel@tonic-gate eri_phy_mintrans = 0;
53187c478bd9Sstevel@tonic-gate }
53197c478bd9Sstevel@tonic-gate /*
53207c478bd9Sstevel@tonic-gate * Initialize the mif interrupt mask.
53217c478bd9Sstevel@tonic-gate */
53227c478bd9Sstevel@tonic-gate erip->mif_mask = (uint16_t)(~PHY_BMSR_RES1);
53237c478bd9Sstevel@tonic-gate
53247c478bd9Sstevel@tonic-gate /*
53257c478bd9Sstevel@tonic-gate * Establish link speeds and do necessary special stuff based
53267c478bd9Sstevel@tonic-gate * in the speed.
53277c478bd9Sstevel@tonic-gate */
53287c478bd9Sstevel@tonic-gate speed_100 = param_anar_100fdx | param_anar_100hdx;
53297c478bd9Sstevel@tonic-gate speed_10 = param_anar_10fdx | param_anar_10hdx;
53307c478bd9Sstevel@tonic-gate
53317c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG5(erip, XCVR_MSG, "eri_reset_xcvr: %d %d %d %d",
5332d64540e3Sgd param_anar_100fdx, param_anar_100hdx, param_anar_10fdx,
5333d64540e3Sgd param_anar_10hdx);
53347c478bd9Sstevel@tonic-gate
53357c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG3(erip, XCVR_MSG,
5336d64540e3Sgd "eri_reset_xcvr: speed_100 %d speed_10 %d", speed_100, speed_10);
53377c478bd9Sstevel@tonic-gate
53387c478bd9Sstevel@tonic-gate if ((!speed_100) && (speed_10)) {
53397c478bd9Sstevel@tonic-gate erip->mif_mask &= ~PHY_BMSR_JABDET;
53407c478bd9Sstevel@tonic-gate if (!(param_anar_10fdx) &&
53417c478bd9Sstevel@tonic-gate (param_anar_10hdx) &&
53427c478bd9Sstevel@tonic-gate (erip->link_pulse_disabled)) {
53437c478bd9Sstevel@tonic-gate param_speed = 0;
53447c478bd9Sstevel@tonic-gate param_mode = 0;
53457c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_NICR, &nicr);
53467c478bd9Sstevel@tonic-gate nicr &= ~PHY_NICR_LD;
53477c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_NICR, nicr);
53487c478bd9Sstevel@tonic-gate param_linkup = 1;
5349d64540e3Sgd erip->stats.link_up = LINK_STATE_UP;
53507c478bd9Sstevel@tonic-gate if (param_mode)
5351d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_FULL;
53527c478bd9Sstevel@tonic-gate else
5353d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_HALF;
53547c478bd9Sstevel@tonic-gate }
53557c478bd9Sstevel@tonic-gate }
53567c478bd9Sstevel@tonic-gate
53577c478bd9Sstevel@tonic-gate /*
53587c478bd9Sstevel@tonic-gate * Clear the autonegotitation before re-starting
53597c478bd9Sstevel@tonic-gate */
53607c478bd9Sstevel@tonic-gate control = PHY_BMCR_100M | PHY_BMCR_FDX;
53617c478bd9Sstevel@tonic-gate /* eri_mii_write(erip, ERI_PHY_BMCR, control); */
53627c478bd9Sstevel@tonic-gate if (param_autoneg) {
53637c478bd9Sstevel@tonic-gate /*
53647c478bd9Sstevel@tonic-gate * Setup the transceiver for autonegotiation.
53657c478bd9Sstevel@tonic-gate */
53667c478bd9Sstevel@tonic-gate erip->mif_mask &= ~PHY_BMSR_ANC;
53677c478bd9Sstevel@tonic-gate
53687c478bd9Sstevel@tonic-gate /*
53697c478bd9Sstevel@tonic-gate * Clear the Auto-negotiation before re-starting
53707c478bd9Sstevel@tonic-gate */
53717c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR, control & ~PHY_BMCR_ANE);
53727c478bd9Sstevel@tonic-gate
53737c478bd9Sstevel@tonic-gate /*
53747c478bd9Sstevel@tonic-gate * Switch on auto-negotiation.
53757c478bd9Sstevel@tonic-gate */
53767c478bd9Sstevel@tonic-gate control |= (PHY_BMCR_ANE | PHY_BMCR_RAN);
53777c478bd9Sstevel@tonic-gate
53787c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR, control);
53797c478bd9Sstevel@tonic-gate } else {
53807c478bd9Sstevel@tonic-gate /*
53817c478bd9Sstevel@tonic-gate * Force the transceiver.
53827c478bd9Sstevel@tonic-gate */
53837c478bd9Sstevel@tonic-gate erip->mif_mask &= ~PHY_BMSR_LNKSTS;
53847c478bd9Sstevel@tonic-gate
53857c478bd9Sstevel@tonic-gate /*
53867c478bd9Sstevel@tonic-gate * Switch off auto-negotiation.
53877c478bd9Sstevel@tonic-gate */
53887c478bd9Sstevel@tonic-gate control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN);
53897c478bd9Sstevel@tonic-gate
53907c478bd9Sstevel@tonic-gate if (speed_100) {
53917c478bd9Sstevel@tonic-gate control |= PHY_BMCR_100M;
53927c478bd9Sstevel@tonic-gate param_aner_lpancap = 0; /* Clear LP nway */
53937c478bd9Sstevel@tonic-gate param_anlpar_10fdx = 0;
53947c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 0;
53957c478bd9Sstevel@tonic-gate param_anlpar_100T4 = param_anar_100T4;
53967c478bd9Sstevel@tonic-gate param_anlpar_100fdx = param_anar_100fdx;
53977c478bd9Sstevel@tonic-gate param_anlpar_100hdx = param_anar_100hdx;
53987c478bd9Sstevel@tonic-gate param_speed = 1;
5399d64540e3Sgd erip->stats.ifspeed = 100;
54007c478bd9Sstevel@tonic-gate param_mode = param_anar_100fdx;
54017c478bd9Sstevel@tonic-gate if (param_mode) {
54027c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 0;
5403d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_FULL;
54047c478bd9Sstevel@tonic-gate } else {
5405d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_HALF;
54067c478bd9Sstevel@tonic-gate }
54077c478bd9Sstevel@tonic-gate } else if (speed_10) {
54087c478bd9Sstevel@tonic-gate control &= ~PHY_BMCR_100M;
54097c478bd9Sstevel@tonic-gate param_aner_lpancap = 0; /* Clear LP nway */
54107c478bd9Sstevel@tonic-gate param_anlpar_100fdx = 0;
54117c478bd9Sstevel@tonic-gate param_anlpar_100hdx = 0;
54127c478bd9Sstevel@tonic-gate param_anlpar_100T4 = 0;
54137c478bd9Sstevel@tonic-gate param_anlpar_10fdx = param_anar_10fdx;
54147c478bd9Sstevel@tonic-gate param_anlpar_10hdx = param_anar_10hdx;
54157c478bd9Sstevel@tonic-gate param_speed = 0;
5416d64540e3Sgd erip->stats.ifspeed = 10;
54177c478bd9Sstevel@tonic-gate param_mode = param_anar_10fdx;
54187c478bd9Sstevel@tonic-gate if (param_mode) {
54197c478bd9Sstevel@tonic-gate param_anlpar_10hdx = 0;
5420d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_FULL;
54217c478bd9Sstevel@tonic-gate } else {
5422d64540e3Sgd erip->stats.link_duplex = LINK_DUPLEX_HALF;
54237c478bd9Sstevel@tonic-gate }
54247c478bd9Sstevel@tonic-gate } else {
54257c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
5426d64540e3Sgd "Transceiver speed set incorrectly.");
54277c478bd9Sstevel@tonic-gate }
54287c478bd9Sstevel@tonic-gate
54297c478bd9Sstevel@tonic-gate if (param_mode) {
54307c478bd9Sstevel@tonic-gate control |= PHY_BMCR_FDX;
54317c478bd9Sstevel@tonic-gate }
54327c478bd9Sstevel@tonic-gate
54337c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG4(erip, PHY_MSG,
5434d64540e3Sgd "control = %x status = %x param_mode %d",
5435d64540e3Sgd control, stat, param_mode);
54367c478bd9Sstevel@tonic-gate
54377c478bd9Sstevel@tonic-gate eri_mii_write(erip, ERI_PHY_BMCR, control);
54387c478bd9Sstevel@tonic-gate /*
54397c478bd9Sstevel@tonic-gate * if (param_mode) {
54407c478bd9Sstevel@tonic-gate * control |= PHY_BMCR_FDX;
54417c478bd9Sstevel@tonic-gate * }
54427c478bd9Sstevel@tonic-gate * control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN);
54437c478bd9Sstevel@tonic-gate * eri_mii_write(erip, ERI_PHY_BMCR, control);
54447c478bd9Sstevel@tonic-gate */
54457c478bd9Sstevel@tonic-gate }
54467c478bd9Sstevel@tonic-gate
54477c478bd9Sstevel@tonic-gate #ifdef DEBUG
54487c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
54497c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
54507c478bd9Sstevel@tonic-gate (void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
54517c478bd9Sstevel@tonic-gate #endif
54527c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG4(erip, PHY_MSG,
5453d64540e3Sgd "control %X status %X anar %X", control, stat, anar);
54547c478bd9Sstevel@tonic-gate
54557c478bd9Sstevel@tonic-gate eri_reset_xcvr_exit:
54567c478bd9Sstevel@tonic-gate return (0);
54577c478bd9Sstevel@tonic-gate
54587c478bd9Sstevel@tonic-gate eri_reset_xcvr_failed:
54597c478bd9Sstevel@tonic-gate return (1);
54607c478bd9Sstevel@tonic-gate }
54617c478bd9Sstevel@tonic-gate
54627c478bd9Sstevel@tonic-gate #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND
54637c478bd9Sstevel@tonic-gate
54647c478bd9Sstevel@tonic-gate static void
eri_xcvr_force_mode(struct eri * erip,uint32_t * link_timeout)54657c478bd9Sstevel@tonic-gate eri_xcvr_force_mode(struct eri *erip, uint32_t *link_timeout)
54667c478bd9Sstevel@tonic-gate {
54677c478bd9Sstevel@tonic-gate
5468d64540e3Sgd if (!param_autoneg && !param_linkup && (erip->stats.ifspeed == 10) &&
5469d64540e3Sgd (param_anar_10fdx | param_anar_10hdx)) {
54707c478bd9Sstevel@tonic-gate *link_timeout = SECOND(1);
54717c478bd9Sstevel@tonic-gate return;
54727c478bd9Sstevel@tonic-gate }
54737c478bd9Sstevel@tonic-gate
5474d64540e3Sgd if (!param_autoneg && !param_linkup && (erip->ifspeed_old == 10) &&
5475d64540e3Sgd (param_anar_100fdx | param_anar_100hdx)) {
54767c478bd9Sstevel@tonic-gate /*
54777c478bd9Sstevel@tonic-gate * May have to set link partner's speed and mode.
54787c478bd9Sstevel@tonic-gate */
54797c478bd9Sstevel@tonic-gate ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_LOG_MSG,
54807c478bd9Sstevel@tonic-gate "May have to set link partner's speed and duplex mode.");
54817c478bd9Sstevel@tonic-gate }
54827c478bd9Sstevel@tonic-gate }
54837c478bd9Sstevel@tonic-gate #endif
54847c478bd9Sstevel@tonic-gate
54857c478bd9Sstevel@tonic-gate static void
eri_mif_poll(struct eri * erip,soft_mif_enable_t enable)54867c478bd9Sstevel@tonic-gate eri_mif_poll(struct eri *erip, soft_mif_enable_t enable)
54877c478bd9Sstevel@tonic-gate {
54887c478bd9Sstevel@tonic-gate if (enable == MIF_POLL_START) {
5489d64540e3Sgd if (erip->mifpoll_enable && !erip->openloop_autoneg) {
54907c478bd9Sstevel@tonic-gate erip->mif_config |= ERI_MIF_CFGPE;
54917c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, erip->mif_config);
54927c478bd9Sstevel@tonic-gate drv_usecwait(ERI_MIF_POLL_DELAY);
54937c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, GET_GLOBREG(intmask) &
5494d64540e3Sgd ~ERI_G_MASK_MIF_INT);
54957c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, erip->mif_mask);
54967c478bd9Sstevel@tonic-gate }
54977c478bd9Sstevel@tonic-gate } else if (enable == MIF_POLL_STOP) {
54987c478bd9Sstevel@tonic-gate erip->mif_config &= ~ERI_MIF_CFGPE;
54997c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, erip->mif_config);
55007c478bd9Sstevel@tonic-gate drv_usecwait(ERI_MIF_POLL_DELAY);
55017c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, GET_GLOBREG(intmask) |
5502d64540e3Sgd ERI_G_MASK_MIF_INT);
55037c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, ERI_MIF_INTMASK);
55047c478bd9Sstevel@tonic-gate }
55057c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF Config = 0x%X",
5506d64540e3Sgd GET_MIFREG(mif_cfg));
55077c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF imask = 0x%X",
5508d64540e3Sgd GET_MIFREG(mif_imask));
55097c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG2(erip, XCVR_MSG, "INT imask = 0x%X",
5510d64540e3Sgd GET_GLOBREG(intmask));
55117c478bd9Sstevel@tonic-gate ERI_DEBUG_MSG1(erip, XCVR_MSG, "<== mif_poll");
55127c478bd9Sstevel@tonic-gate }
55137c478bd9Sstevel@tonic-gate
55147c478bd9Sstevel@tonic-gate /* Decide if transmitter went dead and reinitialize everything */
55157c478bd9Sstevel@tonic-gate #ifdef ERI_TX_HUNG
55167c478bd9Sstevel@tonic-gate static int eri_txhung_limit = 2;
55177c478bd9Sstevel@tonic-gate static int
eri_check_txhung(struct eri * erip)55187c478bd9Sstevel@tonic-gate eri_check_txhung(struct eri *erip)
55197c478bd9Sstevel@tonic-gate {
5520d64540e3Sgd boolean_t macupdate = B_FALSE;
5521d64540e3Sgd
55227c478bd9Sstevel@tonic-gate mutex_enter(&erip->xmitlock);
5523*7e996435SToomas Soome if (erip->flags & ERI_RUNNING) {
5524d64540e3Sgd erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
5525d64540e3Sgd ETX_COMPLETION_MASK);
5526d64540e3Sgd macupdate |= eri_reclaim(erip, erip->tx_completion);
5527*7e996435SToomas Soome }
55287c478bd9Sstevel@tonic-gate
55297c478bd9Sstevel@tonic-gate /* Something needs to be sent out but it is not going out */
55307c478bd9Sstevel@tonic-gate if ((erip->tcurp != erip->tnextp) &&
55317c478bd9Sstevel@tonic-gate (erip->stats.opackets64 == erip->erisave.reclaim_opackets) &&
55327c478bd9Sstevel@tonic-gate (erip->stats.collisions == erip->erisave.starts))
55337c478bd9Sstevel@tonic-gate erip->txhung++;
55347c478bd9Sstevel@tonic-gate else
55357c478bd9Sstevel@tonic-gate erip->txhung = 0;
55367c478bd9Sstevel@tonic-gate
55377c478bd9Sstevel@tonic-gate erip->erisave.reclaim_opackets = erip->stats.opackets64;
55387c478bd9Sstevel@tonic-gate erip->erisave.starts = erip->stats.collisions;
55397c478bd9Sstevel@tonic-gate mutex_exit(&erip->xmitlock);
55407c478bd9Sstevel@tonic-gate
5541d64540e3Sgd if (macupdate)
5542d64540e3Sgd mac_tx_update(erip->mh);
5543d64540e3Sgd
55447c478bd9Sstevel@tonic-gate return (erip->txhung >= eri_txhung_limit);
55457c478bd9Sstevel@tonic-gate }
55467c478bd9Sstevel@tonic-gate #endif
5547