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