xref: /illumos-gate/usr/src/uts/common/io/rtls/rtls.c (revision 2c6a6ad1)
1cde2885fSGarrett D'Amore /*
2cde2885fSGarrett D'Amore  * CDDL HEADER START
3cde2885fSGarrett D'Amore  *
4cde2885fSGarrett D'Amore  * The contents of this file are subject to the terms of the
5cde2885fSGarrett D'Amore  * Common Development and Distribution License (the "License").
6cde2885fSGarrett D'Amore  * You may not use this file except in compliance with the License.
7cde2885fSGarrett D'Amore  *
8cde2885fSGarrett D'Amore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9cde2885fSGarrett D'Amore  * or http://www.opensolaris.org/os/licensing.
10cde2885fSGarrett D'Amore  * See the License for the specific language governing permissions
11cde2885fSGarrett D'Amore  * and limitations under the License.
12cde2885fSGarrett D'Amore  *
13cde2885fSGarrett D'Amore  * When distributing Covered Code, include this CDDL HEADER in each
14cde2885fSGarrett D'Amore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15cde2885fSGarrett D'Amore  * If applicable, add the following below this CDDL HEADER, with the
16cde2885fSGarrett D'Amore  * fields enclosed by brackets "[]" replaced with your own identifying
17cde2885fSGarrett D'Amore  * information: Portions Copyright [yyyy] [name of copyright owner]
18cde2885fSGarrett D'Amore  *
19cde2885fSGarrett D'Amore  * CDDL HEADER END
20cde2885fSGarrett D'Amore  */
21cde2885fSGarrett D'Amore 
22cde2885fSGarrett D'Amore /*
23ace3c3ffSVenugopal Iyer  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24*2c6a6ad1SIlya Yanok  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
25cde2885fSGarrett D'Amore  */
26cde2885fSGarrett D'Amore 
27cde2885fSGarrett D'Amore /*
28cde2885fSGarrett D'Amore  * rtls -- REALTEK 8139-serials PCI Fast Ethernet Driver, Depends on the
29cde2885fSGarrett D'Amore  * Generic LAN Driver utility functions in /kernel/misc/mac
30cde2885fSGarrett D'Amore  *
31cde2885fSGarrett D'Amore  * This product is covered by one or more of the following patents:
32cde2885fSGarrett D'Amore  * US5,307,459, US5,434,872, US5,732,094, US6,570,884, US6,115,776, and
33cde2885fSGarrett D'Amore  * US6,327,625.
34cde2885fSGarrett D'Amore  *
35cde2885fSGarrett D'Amore  * Currently supports:
36cde2885fSGarrett D'Amore  *	RTL8139
37cde2885fSGarrett D'Amore  */
38cde2885fSGarrett D'Amore 
39cde2885fSGarrett D'Amore #include <sys/types.h>
40cde2885fSGarrett D'Amore #include <sys/debug.h>
41cde2885fSGarrett D'Amore #include <sys/errno.h>
42cde2885fSGarrett D'Amore 
43cde2885fSGarrett D'Amore #include <sys/stropts.h>
44cde2885fSGarrett D'Amore #include <sys/stream.h>
45cde2885fSGarrett D'Amore #include <sys/kmem.h>
46cde2885fSGarrett D'Amore #include <sys/conf.h>
47cde2885fSGarrett D'Amore #include <sys/ddi.h>
48cde2885fSGarrett D'Amore #include <sys/devops.h>
49cde2885fSGarrett D'Amore #include <sys/ksynch.h>
50cde2885fSGarrett D'Amore #include <sys/stat.h>
51cde2885fSGarrett D'Amore #include <sys/conf.h>
52cde2885fSGarrett D'Amore #include <sys/modctl.h>
53cde2885fSGarrett D'Amore #include <sys/dlpi.h>
54cde2885fSGarrett D'Amore #include <sys/ethernet.h>
55cde2885fSGarrett D'Amore #include <sys/vlan.h>
56cde2885fSGarrett D'Amore #include <sys/strsun.h>
57cde2885fSGarrett D'Amore #include <sys/pci.h>
58cde2885fSGarrett D'Amore #include <sys/sunddi.h>
59bbb1277bSGarrett D'Amore #include <sys/mii.h>
60bbb1277bSGarrett D'Amore #include <sys/miiregs.h>
61cde2885fSGarrett D'Amore #include <sys/mac_provider.h>
62cde2885fSGarrett D'Amore #include <sys/mac_ether.h>
63cde2885fSGarrett D'Amore 
64cde2885fSGarrett D'Amore #include "rtls.h"
65cde2885fSGarrett D'Amore 
66cde2885fSGarrett D'Amore /*
67cde2885fSGarrett D'Amore  * Declarations and Module Linkage
68cde2885fSGarrett D'Amore  */
69cde2885fSGarrett D'Amore 
70cde2885fSGarrett D'Amore /*
71cde2885fSGarrett D'Amore  * This is the string displayed by modinfo, etc.
72cde2885fSGarrett D'Amore  */
73cde2885fSGarrett D'Amore static char rtls_ident[] = "RealTek 8139 Ethernet driver";
74cde2885fSGarrett D'Amore 
75cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
76cde2885fSGarrett D'Amore int rtls_debug = 0;
77cde2885fSGarrett D'Amore #endif
78cde2885fSGarrett D'Amore 
79cde2885fSGarrett D'Amore /*
80cde2885fSGarrett D'Amore  * Required system entry points
81cde2885fSGarrett D'Amore  */
82cde2885fSGarrett D'Amore static int rtls_attach(dev_info_t *, ddi_attach_cmd_t);
83cde2885fSGarrett D'Amore static int rtls_detach(dev_info_t *, ddi_detach_cmd_t);
84cde2885fSGarrett D'Amore static int rtls_quiesce(dev_info_t *);
85cde2885fSGarrett D'Amore 
86cde2885fSGarrett D'Amore /*
87cde2885fSGarrett D'Amore  * Required driver entry points for MAC
88cde2885fSGarrett D'Amore  */
89cde2885fSGarrett D'Amore static int rtls_m_start(void *);
90cde2885fSGarrett D'Amore static void rtls_m_stop(void *);
91cde2885fSGarrett D'Amore static int rtls_m_unicst(void *, const uint8_t *);
92cde2885fSGarrett D'Amore static int rtls_m_multicst(void *, boolean_t, const uint8_t *);
93cde2885fSGarrett D'Amore static int rtls_m_promisc(void *, boolean_t);
94cde2885fSGarrett D'Amore static mblk_t *rtls_m_tx(void *, mblk_t *);
95ace3c3ffSVenugopal Iyer static int rtls_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
96ace3c3ffSVenugopal Iyer     void *);
97ace3c3ffSVenugopal Iyer static int rtls_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
98ace3c3ffSVenugopal Iyer     const void *);
99ace3c3ffSVenugopal Iyer static void rtls_m_propinfo(void *, const char *, mac_prop_id_t,
100ace3c3ffSVenugopal Iyer     mac_prop_info_handle_t);
101cde2885fSGarrett D'Amore static int rtls_m_stat(void *, uint_t, uint64_t *);
102cde2885fSGarrett D'Amore 
103cde2885fSGarrett D'Amore static uint_t rtls_intr(caddr_t);
104cde2885fSGarrett D'Amore 
105bbb1277bSGarrett D'Amore /*
106bbb1277bSGarrett D'Amore  * MII entry points
107bbb1277bSGarrett D'Amore  */
108bbb1277bSGarrett D'Amore static uint16_t rtls_mii_read(void *, uint8_t, uint8_t);
109bbb1277bSGarrett D'Amore static void rtls_mii_write(void *, uint8_t, uint8_t, uint16_t);
110bbb1277bSGarrett D'Amore static void rtls_mii_notify(void *, link_state_t);
111bbb1277bSGarrett D'Amore 
112cde2885fSGarrett D'Amore /*
113cde2885fSGarrett D'Amore  * Internal functions used by the above entry points
114cde2885fSGarrett D'Amore  */
115cde2885fSGarrett D'Amore static int rtls_chip_reset(rtls_t *, boolean_t);
116cde2885fSGarrett D'Amore static void rtls_chip_init(rtls_t *);
117cde2885fSGarrett D'Amore static void rtls_chip_stop(rtls_t *rtlsp);
118cde2885fSGarrett D'Amore static void rtls_chip_start(rtls_t *rtlsp);
119cde2885fSGarrett D'Amore static void rtls_chip_restart(rtls_t *rtlsp);
120cde2885fSGarrett D'Amore static void rtls_get_mac_addr(rtls_t *, uint8_t *);
121cde2885fSGarrett D'Amore static void rtls_set_mac_addr(rtls_t *, const uint8_t *);
122cde2885fSGarrett D'Amore static uint_t rtls_hash_index(const uint8_t *);
123cde2885fSGarrett D'Amore static boolean_t rtls_send(rtls_t *, mblk_t *);
124cde2885fSGarrett D'Amore static void rtls_receive(rtls_t *);
125cde2885fSGarrett D'Amore 
126cde2885fSGarrett D'Amore /*
127cde2885fSGarrett D'Amore  * Buffer Management Routines
128cde2885fSGarrett D'Amore  */
129cde2885fSGarrett D'Amore static int rtls_alloc_bufs(rtls_t *);
130cde2885fSGarrett D'Amore static void rtls_free_bufs(rtls_t *);
131cde2885fSGarrett D'Amore static int rtls_alloc_dma_mem(rtls_t *, size_t,	ddi_device_acc_attr_t *,
132cde2885fSGarrett D'Amore 	uint_t, dma_area_t *);
133cde2885fSGarrett D'Amore static void rtls_free_dma_mem(dma_area_t *);
134cde2885fSGarrett D'Amore 
135cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
136cde2885fSGarrett D'Amore static void rtls_reg_print(rtls_t *);	/* debug routine */
137cde2885fSGarrett D'Amore #endif
138cde2885fSGarrett D'Amore 
139cde2885fSGarrett D'Amore #define	RTLS_DRIVER_NAME	"rtls"
140cde2885fSGarrett D'Amore 
141cde2885fSGarrett D'Amore /*
142cde2885fSGarrett D'Amore  * Used for buffers allocated by ddi_dma_mem_alloc()
143cde2885fSGarrett D'Amore  */
144cde2885fSGarrett D'Amore static ddi_dma_attr_t dma_attr = {
145cde2885fSGarrett D'Amore 	DMA_ATTR_V0,		/* dma_attr version */
146cde2885fSGarrett D'Amore 	0,			/* dma_attr_addr_lo */
147cde2885fSGarrett D'Amore 	(uint_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
148cde2885fSGarrett D'Amore 	0x7FFFFFFF,		/* dma_attr_count_max */
149cde2885fSGarrett D'Amore 	4,			/* dma_attr_align */
150cde2885fSGarrett D'Amore 	0x3F,			/* dma_attr_burstsizes */
151cde2885fSGarrett D'Amore 	1,			/* dma_attr_minxfer */
152cde2885fSGarrett D'Amore 	(uint_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
153cde2885fSGarrett D'Amore 	(uint_t)0xFFFFFFFF,	/* dma_attr_seg */
154cde2885fSGarrett D'Amore 	1,			/* dma_attr_sgllen */
155cde2885fSGarrett D'Amore 	1,			/* dma_attr_granular */
156cde2885fSGarrett D'Amore 	0,			/* dma_attr_flags */
157cde2885fSGarrett D'Amore };
158cde2885fSGarrett D'Amore 
159cde2885fSGarrett D'Amore /*
160cde2885fSGarrett D'Amore  * PIO access attributes for registers
161cde2885fSGarrett D'Amore  */
162cde2885fSGarrett D'Amore static ddi_device_acc_attr_t rtls_reg_accattr = {
163cde2885fSGarrett D'Amore 	DDI_DEVICE_ATTR_V0,
164cde2885fSGarrett D'Amore 	DDI_STRUCTURE_LE_ACC,
165cde2885fSGarrett D'Amore 	DDI_STRICTORDER_ACC
166cde2885fSGarrett D'Amore };
167cde2885fSGarrett D'Amore 
168cde2885fSGarrett D'Amore /*
169cde2885fSGarrett D'Amore  * DMA access attributes for data
170cde2885fSGarrett D'Amore  */
171cde2885fSGarrett D'Amore static ddi_device_acc_attr_t rtls_buf_accattr = {
172cde2885fSGarrett D'Amore 	DDI_DEVICE_ATTR_V0,
173cde2885fSGarrett D'Amore 	DDI_NEVERSWAP_ACC,
174cde2885fSGarrett D'Amore 	DDI_STRICTORDER_ACC
175cde2885fSGarrett D'Amore };
176cde2885fSGarrett D'Amore 
177cde2885fSGarrett D'Amore uchar_t rtls_broadcastaddr[] = {
178cde2885fSGarrett D'Amore 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
179cde2885fSGarrett D'Amore };
180cde2885fSGarrett D'Amore 
181cde2885fSGarrett D'Amore static mac_callbacks_t rtls_m_callbacks = {
182ace3c3ffSVenugopal Iyer 	MC_PROPERTIES,
183cde2885fSGarrett D'Amore 	rtls_m_stat,
184cde2885fSGarrett D'Amore 	rtls_m_start,
185cde2885fSGarrett D'Amore 	rtls_m_stop,
186cde2885fSGarrett D'Amore 	rtls_m_promisc,
187cde2885fSGarrett D'Amore 	rtls_m_multicst,
188cde2885fSGarrett D'Amore 	rtls_m_unicst,
189ace3c3ffSVenugopal Iyer 	rtls_m_tx,
190ace3c3ffSVenugopal Iyer 	NULL,
191ace3c3ffSVenugopal Iyer 	NULL,  /* mc_ioctl */
192ace3c3ffSVenugopal Iyer 	NULL,  /* mc_getcapab */
193ace3c3ffSVenugopal Iyer 	NULL,  /* mc_open */
194ace3c3ffSVenugopal Iyer 	NULL,  /* mc_close */
195ace3c3ffSVenugopal Iyer 	rtls_m_setprop,
196ace3c3ffSVenugopal Iyer 	rtls_m_getprop,
197ace3c3ffSVenugopal Iyer 	rtls_m_propinfo
198bbb1277bSGarrett D'Amore };
199bbb1277bSGarrett D'Amore 
200bbb1277bSGarrett D'Amore static mii_ops_t rtls_mii_ops = {
201bbb1277bSGarrett D'Amore 	MII_OPS_VERSION,
202bbb1277bSGarrett D'Amore 	rtls_mii_read,
203bbb1277bSGarrett D'Amore 	rtls_mii_write,
204bbb1277bSGarrett D'Amore 	rtls_mii_notify,	/* notify */
205bbb1277bSGarrett D'Amore 	NULL,			/* reset */
206cde2885fSGarrett D'Amore };
207cde2885fSGarrett D'Amore 
208cde2885fSGarrett D'Amore DDI_DEFINE_STREAM_OPS(rtls_dev_ops, nulldev, nulldev, rtls_attach, rtls_detach,
209cde2885fSGarrett D'Amore     nodev, NULL, D_MP, NULL, rtls_quiesce);
210cde2885fSGarrett D'Amore 
211cde2885fSGarrett D'Amore /*
212cde2885fSGarrett D'Amore  * Standard module linkage initialization for a MAC driver
213cde2885fSGarrett D'Amore  */
214cde2885fSGarrett D'Amore static struct modldrv rtls_modldrv = {
215cde2885fSGarrett D'Amore 	&mod_driverops,	/* type of module. This one is a driver */
216cde2885fSGarrett D'Amore 	rtls_ident,	/* short description */
217cde2885fSGarrett D'Amore 	&rtls_dev_ops	/* driver specific ops */
218cde2885fSGarrett D'Amore };
219cde2885fSGarrett D'Amore 
220cde2885fSGarrett D'Amore static struct modlinkage modlinkage = {
221cde2885fSGarrett D'Amore 	MODREV_1, { (void *)&rtls_modldrv, NULL }
222cde2885fSGarrett D'Amore };
223cde2885fSGarrett D'Amore 
224cde2885fSGarrett D'Amore /*
225cde2885fSGarrett D'Amore  *    ========== RealTek chip register access Routines ==========
226cde2885fSGarrett D'Amore  */
227cde2885fSGarrett D'Amore static uint8_t rtls_reg_get8(rtls_t *rtlsp, uint32_t reg);
228cde2885fSGarrett D'Amore #pragma	inline(rtls_reg_get8)
229cde2885fSGarrett D'Amore static uint8_t
rtls_reg_get8(rtls_t * rtlsp,uint32_t reg)230cde2885fSGarrett D'Amore rtls_reg_get8(rtls_t *rtlsp, uint32_t reg)
231cde2885fSGarrett D'Amore {
232cde2885fSGarrett D'Amore 	uint8_t *addr;
233cde2885fSGarrett D'Amore 
234cde2885fSGarrett D'Amore 	addr = REG8(rtlsp->io_reg, reg);
235cde2885fSGarrett D'Amore 	return (ddi_get8(rtlsp->io_handle, addr));
236cde2885fSGarrett D'Amore }
237cde2885fSGarrett D'Amore 
238cde2885fSGarrett D'Amore static uint16_t rtls_reg_get16(rtls_t *rtlsp, uint32_t reg);
239cde2885fSGarrett D'Amore #pragma	inline(rtls_reg_get16)
240cde2885fSGarrett D'Amore static uint16_t
rtls_reg_get16(rtls_t * rtlsp,uint32_t reg)241cde2885fSGarrett D'Amore rtls_reg_get16(rtls_t *rtlsp, uint32_t reg)
242cde2885fSGarrett D'Amore {
243cde2885fSGarrett D'Amore 	uint16_t *addr;
244cde2885fSGarrett D'Amore 
245cde2885fSGarrett D'Amore 	addr = REG16(rtlsp->io_reg, reg);
246cde2885fSGarrett D'Amore 	return (ddi_get16(rtlsp->io_handle, addr));
247cde2885fSGarrett D'Amore }
248cde2885fSGarrett D'Amore 
249cde2885fSGarrett D'Amore static uint32_t rtls_reg_get32(rtls_t *rtlsp, uint32_t reg);
250cde2885fSGarrett D'Amore #pragma	inline(rtls_reg_get32)
251cde2885fSGarrett D'Amore static uint32_t
rtls_reg_get32(rtls_t * rtlsp,uint32_t reg)252cde2885fSGarrett D'Amore rtls_reg_get32(rtls_t *rtlsp, uint32_t reg)
253cde2885fSGarrett D'Amore {
254cde2885fSGarrett D'Amore 	uint32_t *addr;
255cde2885fSGarrett D'Amore 
256cde2885fSGarrett D'Amore 	addr = REG32(rtlsp->io_reg, reg);
257cde2885fSGarrett D'Amore 	return (ddi_get32(rtlsp->io_handle, addr));
258cde2885fSGarrett D'Amore }
259cde2885fSGarrett D'Amore 
260cde2885fSGarrett D'Amore static void rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value);
261cde2885fSGarrett D'Amore #pragma	inline(rtls_reg_set8)
262cde2885fSGarrett D'Amore static void
rtls_reg_set8(rtls_t * rtlsp,uint32_t reg,uint8_t value)263cde2885fSGarrett D'Amore rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value)
264cde2885fSGarrett D'Amore {
265cde2885fSGarrett D'Amore 	uint8_t *addr;
266cde2885fSGarrett D'Amore 
267cde2885fSGarrett D'Amore 	addr = REG8(rtlsp->io_reg, reg);
268cde2885fSGarrett D'Amore 	ddi_put8(rtlsp->io_handle, addr, value);
269cde2885fSGarrett D'Amore }
270cde2885fSGarrett D'Amore 
271cde2885fSGarrett D'Amore static void rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value);
272cde2885fSGarrett D'Amore #pragma	inline(rtls_reg_set16)
273cde2885fSGarrett D'Amore static void
rtls_reg_set16(rtls_t * rtlsp,uint32_t reg,uint16_t value)274cde2885fSGarrett D'Amore rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value)
275cde2885fSGarrett D'Amore {
276cde2885fSGarrett D'Amore 	uint16_t *addr;
277cde2885fSGarrett D'Amore 
278cde2885fSGarrett D'Amore 	addr = REG16(rtlsp->io_reg, reg);
279cde2885fSGarrett D'Amore 	ddi_put16(rtlsp->io_handle, addr, value);
280cde2885fSGarrett D'Amore }
281cde2885fSGarrett D'Amore 
282cde2885fSGarrett D'Amore static void rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value);
283cde2885fSGarrett D'Amore #pragma	inline(rtls_reg_set32)
284cde2885fSGarrett D'Amore static void
rtls_reg_set32(rtls_t * rtlsp,uint32_t reg,uint32_t value)285cde2885fSGarrett D'Amore rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value)
286cde2885fSGarrett D'Amore {
287cde2885fSGarrett D'Amore 	uint32_t *addr;
288cde2885fSGarrett D'Amore 
289cde2885fSGarrett D'Amore 	addr = REG32(rtlsp->io_reg, reg);
290cde2885fSGarrett D'Amore 	ddi_put32(rtlsp->io_handle, addr, value);
291cde2885fSGarrett D'Amore }
292cde2885fSGarrett D'Amore 
293cde2885fSGarrett D'Amore /*
294cde2885fSGarrett D'Amore  *    ========== Module Loading Entry Points ==========
295cde2885fSGarrett D'Amore  */
296cde2885fSGarrett D'Amore int
_init(void)297cde2885fSGarrett D'Amore _init(void)
298cde2885fSGarrett D'Amore {
299cde2885fSGarrett D'Amore 	int	rv;
300cde2885fSGarrett D'Amore 
301cde2885fSGarrett D'Amore 	mac_init_ops(&rtls_dev_ops, RTLS_DRIVER_NAME);
302cde2885fSGarrett D'Amore 	if ((rv = mod_install(&modlinkage)) != DDI_SUCCESS) {
303cde2885fSGarrett D'Amore 		mac_fini_ops(&rtls_dev_ops);
304cde2885fSGarrett D'Amore 	}
305cde2885fSGarrett D'Amore 	return (rv);
306cde2885fSGarrett D'Amore }
307cde2885fSGarrett D'Amore 
308cde2885fSGarrett D'Amore int
_fini(void)309cde2885fSGarrett D'Amore _fini(void)
310cde2885fSGarrett D'Amore {
311cde2885fSGarrett D'Amore 	int	rv;
312cde2885fSGarrett D'Amore 
313cde2885fSGarrett D'Amore 	if ((rv = mod_remove(&modlinkage)) == DDI_SUCCESS) {
314cde2885fSGarrett D'Amore 		mac_fini_ops(&rtls_dev_ops);
315cde2885fSGarrett D'Amore 	}
316cde2885fSGarrett D'Amore 	return (rv);
317cde2885fSGarrett D'Amore }
318cde2885fSGarrett D'Amore 
319cde2885fSGarrett D'Amore int
_info(struct modinfo * modinfop)320cde2885fSGarrett D'Amore _info(struct modinfo *modinfop)
321cde2885fSGarrett D'Amore {
322cde2885fSGarrett D'Amore 	return (mod_info(&modlinkage, modinfop));
323cde2885fSGarrett D'Amore }
324cde2885fSGarrett D'Amore 
325cde2885fSGarrett D'Amore 
326cde2885fSGarrett D'Amore /*
327cde2885fSGarrett D'Amore  *    ========== DDI Entry Points ==========
328cde2885fSGarrett D'Amore  */
329cde2885fSGarrett D'Amore 
330cde2885fSGarrett D'Amore /*
331cde2885fSGarrett D'Amore  * attach(9E) -- Attach a device to the system
332cde2885fSGarrett D'Amore  *
333cde2885fSGarrett D'Amore  * Called once for each board successfully probed.
334cde2885fSGarrett D'Amore  */
335cde2885fSGarrett D'Amore static int
rtls_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)336cde2885fSGarrett D'Amore rtls_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
337cde2885fSGarrett D'Amore {
338cde2885fSGarrett D'Amore 	rtls_t *rtlsp;			/* Our private device info */
339cde2885fSGarrett D'Amore 	ddi_acc_handle_t pci_handle;
340cde2885fSGarrett D'Amore 	uint16_t pci_commond;
341cde2885fSGarrett D'Amore 	uint16_t vendorid;
342cde2885fSGarrett D'Amore 	uint16_t deviceid;
343cde2885fSGarrett D'Amore 	uint32_t device;
344cde2885fSGarrett D'Amore 	mac_register_t *macp;
345cde2885fSGarrett D'Amore 	int err;
346cde2885fSGarrett D'Amore 
347cde2885fSGarrett D'Amore 	switch (cmd) {
348cde2885fSGarrett D'Amore 	case DDI_ATTACH:
349cde2885fSGarrett D'Amore 		break;
350cde2885fSGarrett D'Amore 	case DDI_RESUME:
351cde2885fSGarrett D'Amore 		if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) {
352cde2885fSGarrett D'Amore 			return (DDI_FAILURE);
353cde2885fSGarrett D'Amore 		}
354cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_io_lock);
355cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_rx_lock);
356cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_tx_lock);
357cde2885fSGarrett D'Amore 		/*
358cde2885fSGarrett D'Amore 		 * Turn on Master Enable (DMA) and IO Enable bits.
359cde2885fSGarrett D'Amore 		 * Enable PCI Memory Space accesses
360cde2885fSGarrett D'Amore 		 * Disable Memory Write/Invalidate
361cde2885fSGarrett D'Amore 		 */
362cde2885fSGarrett D'Amore 		if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) {
363cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_tx_lock);
364cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_rx_lock);
365cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_io_lock);
366cde2885fSGarrett D'Amore 			return (DDI_FAILURE);
367cde2885fSGarrett D'Amore 		}
368cde2885fSGarrett D'Amore 		pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM);
369cde2885fSGarrett D'Amore 		pci_commond &= ~PCI_COMM_MEMWR_INVAL;
370cde2885fSGarrett D'Amore 		pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
371cde2885fSGarrett D'Amore 		pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond);
372cde2885fSGarrett D'Amore 		pci_config_teardown(&pci_handle);
373cde2885fSGarrett D'Amore 
374cde2885fSGarrett D'Amore 		rtls_chip_restart(rtlsp);
375cde2885fSGarrett D'Amore 		rtlsp->chip_error = B_FALSE;
376cde2885fSGarrett D'Amore 		rtlsp->tx_retry = 0;
377cde2885fSGarrett D'Amore 		rtlsp->rtls_suspended = B_FALSE;
378cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
379cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_rx_lock);
380cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_io_lock);
381cde2885fSGarrett D'Amore 
382bbb1277bSGarrett D'Amore 		mii_resume(rtlsp->mii);
383bbb1277bSGarrett D'Amore 
384cde2885fSGarrett D'Amore 		mac_tx_update(rtlsp->mh);
385cde2885fSGarrett D'Amore 		return (DDI_SUCCESS);
386cde2885fSGarrett D'Amore 	default:
387cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
388cde2885fSGarrett D'Amore 	}
389cde2885fSGarrett D'Amore 
390cde2885fSGarrett D'Amore 	/*
391cde2885fSGarrett D'Amore 	 * we don't support high level interrupts in the driver
392cde2885fSGarrett D'Amore 	 */
393cde2885fSGarrett D'Amore 	if (ddi_intr_hilevel(devinfo, 0) != 0) {
394bbb1277bSGarrett D'Amore 		cmn_err(CE_WARN, "unsupported high level interrupt");
395cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
396cde2885fSGarrett D'Amore 	}
397cde2885fSGarrett D'Amore 
398cde2885fSGarrett D'Amore 	/*
399cde2885fSGarrett D'Amore 	 * Get handle to access pci configuration space
400cde2885fSGarrett D'Amore 	 */
401cde2885fSGarrett D'Amore 	if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) {
402bbb1277bSGarrett D'Amore 		cmn_err(CE_WARN, "pci_config_setup fail.");
403cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
404cde2885fSGarrett D'Amore 	}
405cde2885fSGarrett D'Amore 
406cde2885fSGarrett D'Amore 	/*
407cde2885fSGarrett D'Amore 	 * Make sure we support this particular vendor/device
408cde2885fSGarrett D'Amore 	 */
409cde2885fSGarrett D'Amore 	vendorid = pci_config_get16(pci_handle, PCI_CONF_VENID);
410cde2885fSGarrett D'Amore 	deviceid = pci_config_get16(pci_handle, PCI_CONF_DEVID);
411cde2885fSGarrett D'Amore 	device = vendorid;
412cde2885fSGarrett D'Amore 	device = (device << 16) | deviceid;	/* combine two id together */
413cde2885fSGarrett D'Amore 
414cde2885fSGarrett D'Amore 	/*
415cde2885fSGarrett D'Amore 	 * See if we support this device
416cde2885fSGarrett D'Amore 	 * We do not return for wrong device id. It's user risk.
417cde2885fSGarrett D'Amore 	 */
418cde2885fSGarrett D'Amore 	switch (device) {
419cde2885fSGarrett D'Amore 	default:
420cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
421bbb1277bSGarrett D'Amore 		    "RTLS doesn't support this device: "
422cde2885fSGarrett D'Amore 		    "vendorID = 0x%x, deviceID = 0x%x",
423cde2885fSGarrett D'Amore 		    vendorid, deviceid);
424cde2885fSGarrett D'Amore 		break;
425cde2885fSGarrett D'Amore 	case RTLS_SUPPORT_DEVICE_1:
426cde2885fSGarrett D'Amore 	case RTLS_SUPPORT_DEVICE_2:
427cde2885fSGarrett D'Amore 	case RTLS_SUPPORT_DEVICE_3:
428bbb1277bSGarrett D'Amore 	case RTLS_SUPPORT_DEVICE_4:
429cde2885fSGarrett D'Amore 		break;
430cde2885fSGarrett D'Amore 	}
431cde2885fSGarrett D'Amore 
432cde2885fSGarrett D'Amore 	/*
433cde2885fSGarrett D'Amore 	 * Turn on Master Enable (DMA) and IO Enable bits.
434cde2885fSGarrett D'Amore 	 * Enable PCI Memory Space accesses
435cde2885fSGarrett D'Amore 	 * Disable Memory Write/Invalidate
436cde2885fSGarrett D'Amore 	 */
437cde2885fSGarrett D'Amore 	pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM);
438cde2885fSGarrett D'Amore 	pci_commond &= ~PCI_COMM_MEMWR_INVAL;
439cde2885fSGarrett D'Amore 	pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
440cde2885fSGarrett D'Amore 	pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond);
441cde2885fSGarrett D'Amore 
442cde2885fSGarrett D'Amore 	/*
443cde2885fSGarrett D'Amore 	 * Free handle to access pci configuration space
444cde2885fSGarrett D'Amore 	 */
445cde2885fSGarrett D'Amore 	pci_config_teardown(&pci_handle);
446cde2885fSGarrett D'Amore 
447cde2885fSGarrett D'Amore 	rtlsp = kmem_zalloc(sizeof (rtls_t), KM_SLEEP);
448cde2885fSGarrett D'Amore 
449cde2885fSGarrett D'Amore 	ddi_set_driver_private(devinfo, rtlsp);
450cde2885fSGarrett D'Amore 	rtlsp->devinfo			= devinfo;
451cde2885fSGarrett D'Amore 	rtlsp->instance			= ddi_get_instance(devinfo);
452cde2885fSGarrett D'Amore 
453cde2885fSGarrett D'Amore 	/*
454cde2885fSGarrett D'Amore 	 * Map operating register
455cde2885fSGarrett D'Amore 	 */
456cde2885fSGarrett D'Amore 	err = ddi_regs_map_setup(devinfo, 1, &rtlsp->io_reg,
457cde2885fSGarrett D'Amore 	    (offset_t)0, 0, &rtls_reg_accattr, &rtlsp->io_handle);
458cde2885fSGarrett D'Amore 	if (err != DDI_SUCCESS) {
459cde2885fSGarrett D'Amore 		kmem_free((caddr_t)rtlsp, sizeof (rtls_t));
460bbb1277bSGarrett D'Amore 		cmn_err(CE_WARN, "ddi_regs_map_setup fail.");
461cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
462cde2885fSGarrett D'Amore 	}
463cde2885fSGarrett D'Amore 
464cde2885fSGarrett D'Amore 	/*
465cde2885fSGarrett D'Amore 	 * Allocate the TX and RX descriptors/buffers
466cde2885fSGarrett D'Amore 	 */
467cde2885fSGarrett D'Amore 	if (rtls_alloc_bufs(rtlsp) == DDI_FAILURE) {
468bbb1277bSGarrett D'Amore 		cmn_err(CE_WARN, "DMA buffer allocation fail.");
469cde2885fSGarrett D'Amore 		goto fail;
470cde2885fSGarrett D'Amore 	}
471cde2885fSGarrett D'Amore 
472cde2885fSGarrett D'Amore 	/*
473cde2885fSGarrett D'Amore 	 * Reset the chip
474cde2885fSGarrett D'Amore 	 */
475cde2885fSGarrett D'Amore 	err = rtls_chip_reset(rtlsp, B_FALSE);
476cde2885fSGarrett D'Amore 	if (err != DDI_SUCCESS)
477cde2885fSGarrett D'Amore 		goto fail;
478cde2885fSGarrett D'Amore 
479cde2885fSGarrett D'Amore 	/*
480cde2885fSGarrett D'Amore 	 * Init rtls_t structure
481cde2885fSGarrett D'Amore 	 */
482cde2885fSGarrett D'Amore 	rtls_get_mac_addr(rtlsp, rtlsp->netaddr);
483cde2885fSGarrett D'Amore 
484cde2885fSGarrett D'Amore 	/*
485cde2885fSGarrett D'Amore 	 * Add the interrupt handler
486cde2885fSGarrett D'Amore 	 *
487cde2885fSGarrett D'Amore 	 * This will prevent receiving interrupts before device is ready, as
488cde2885fSGarrett D'Amore 	 * we are initializing device after setting the interrupts. So we
489cde2885fSGarrett D'Amore 	 * will not get our interrupt handler invoked by OS while our device
490cde2885fSGarrett D'Amore 	 * is still coming up or timer routines will not start till we are
491cde2885fSGarrett D'Amore 	 * all set to process...
492cde2885fSGarrett D'Amore 	 */
493cde2885fSGarrett D'Amore 
494cde2885fSGarrett D'Amore 	if (ddi_add_intr(devinfo, 0, &rtlsp->iblk, NULL, rtls_intr,
495cde2885fSGarrett D'Amore 	    (caddr_t)rtlsp) != DDI_SUCCESS) {
496bbb1277bSGarrett D'Amore 		cmn_err(CE_WARN, "ddi_add_intr fail.");
497bbb1277bSGarrett D'Amore 		goto late_fail;
498bbb1277bSGarrett D'Amore 	}
499bbb1277bSGarrett D'Amore 
500bbb1277bSGarrett D'Amore 	if ((rtlsp->mii = mii_alloc(rtlsp, devinfo, &rtls_mii_ops)) == NULL) {
501bbb1277bSGarrett D'Amore 		ddi_remove_intr(devinfo, 0, rtlsp->iblk);
502cde2885fSGarrett D'Amore 		goto late_fail;
503cde2885fSGarrett D'Amore 	}
504bbb1277bSGarrett D'Amore 	/*
505bbb1277bSGarrett D'Amore 	 * Note: Some models of 8139 can support pause, but we have
506bbb1277bSGarrett D'Amore 	 * not implemented support for it at this time.  This might be
507bbb1277bSGarrett D'Amore 	 * an interesting feature to add later.
508bbb1277bSGarrett D'Amore 	 */
509bbb1277bSGarrett D'Amore 	mii_set_pauseable(rtlsp->mii, B_FALSE, B_FALSE);
510cde2885fSGarrett D'Amore 
511cde2885fSGarrett D'Amore 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
512bbb1277bSGarrett D'Amore 		cmn_err(CE_WARN, "mac_alloc fail.");
513cde2885fSGarrett D'Amore 		ddi_remove_intr(devinfo, 0, rtlsp->iblk);
514cde2885fSGarrett D'Amore 		goto late_fail;
515cde2885fSGarrett D'Amore 	}
516cde2885fSGarrett D'Amore 
517cde2885fSGarrett D'Amore 	/*
518cde2885fSGarrett D'Amore 	 * Init mutex
519cde2885fSGarrett D'Amore 	 */
520cde2885fSGarrett D'Amore 	mutex_init(&rtlsp->rtls_io_lock, NULL, MUTEX_DRIVER, rtlsp->iblk);
521cde2885fSGarrett D'Amore 	mutex_init(&rtlsp->rtls_tx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk);
522cde2885fSGarrett D'Amore 	mutex_init(&rtlsp->rtls_rx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk);
523cde2885fSGarrett D'Amore 
524cde2885fSGarrett D'Amore 	/*
525cde2885fSGarrett D'Amore 	 * Initialize pointers to device specific functions which will be
526cde2885fSGarrett D'Amore 	 * used by the generic layer.
527cde2885fSGarrett D'Amore 	 */
528cde2885fSGarrett D'Amore 	macp->m_type_ident		= MAC_PLUGIN_IDENT_ETHER;
529cde2885fSGarrett D'Amore 	macp->m_driver			= rtlsp;
530cde2885fSGarrett D'Amore 	macp->m_dip			= devinfo;
531cde2885fSGarrett D'Amore 	macp->m_src_addr		= rtlsp->netaddr;
532cde2885fSGarrett D'Amore 	macp->m_callbacks		= &rtls_m_callbacks;
533cde2885fSGarrett D'Amore 	macp->m_min_sdu			= 0;
534cde2885fSGarrett D'Amore 	macp->m_max_sdu			= ETHERMTU;
535cde2885fSGarrett D'Amore 	macp->m_margin			= VLAN_TAGSZ;
536cde2885fSGarrett D'Amore 
537cde2885fSGarrett D'Amore 	if (mac_register(macp, &rtlsp->mh) != 0) {
538cde2885fSGarrett D'Amore 		ddi_remove_intr(devinfo, 0, rtlsp->iblk);
539cde2885fSGarrett D'Amore 		mutex_destroy(&rtlsp->rtls_io_lock);
540cde2885fSGarrett D'Amore 		mutex_destroy(&rtlsp->rtls_tx_lock);
541cde2885fSGarrett D'Amore 		mutex_destroy(&rtlsp->rtls_rx_lock);
542cde2885fSGarrett D'Amore 		goto late_fail;
543cde2885fSGarrett D'Amore 	}
544cde2885fSGarrett D'Amore 
545cde2885fSGarrett D'Amore 	mac_free(macp);
546cde2885fSGarrett D'Amore 
547cde2885fSGarrett D'Amore 	return (DDI_SUCCESS);
548cde2885fSGarrett D'Amore 
549cde2885fSGarrett D'Amore late_fail:
550cde2885fSGarrett D'Amore 	if (macp)
551cde2885fSGarrett D'Amore 		mac_free(macp);
552bbb1277bSGarrett D'Amore 	if (rtlsp->mii)
553bbb1277bSGarrett D'Amore 		mii_free(rtlsp->mii);
554cde2885fSGarrett D'Amore 
555cde2885fSGarrett D'Amore fail:
556cde2885fSGarrett D'Amore 	ddi_regs_map_free(&rtlsp->io_handle);
557cde2885fSGarrett D'Amore 	rtls_free_bufs(rtlsp);
558cde2885fSGarrett D'Amore 	kmem_free(rtlsp, sizeof (rtls_t));
559cde2885fSGarrett D'Amore 
560cde2885fSGarrett D'Amore 	return (DDI_FAILURE);
561cde2885fSGarrett D'Amore }
562cde2885fSGarrett D'Amore 
563cde2885fSGarrett D'Amore /*
564cde2885fSGarrett D'Amore  * detach(9E) -- Detach a device from the system
565cde2885fSGarrett D'Amore  */
566cde2885fSGarrett D'Amore static int
rtls_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)567cde2885fSGarrett D'Amore rtls_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
568cde2885fSGarrett D'Amore {
569cde2885fSGarrett D'Amore 	rtls_t *rtlsp;			/* our private device info */
570cde2885fSGarrett D'Amore 
571cde2885fSGarrett D'Amore 	/*
572cde2885fSGarrett D'Amore 	 * Get the driver private structure
573cde2885fSGarrett D'Amore 	 */
574cde2885fSGarrett D'Amore 	if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) {
575cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
576cde2885fSGarrett D'Amore 	}
577cde2885fSGarrett D'Amore 
578cde2885fSGarrett D'Amore 	switch (cmd) {
579cde2885fSGarrett D'Amore 	case DDI_DETACH:
580cde2885fSGarrett D'Amore 		break;
581cde2885fSGarrett D'Amore 
582cde2885fSGarrett D'Amore 	case DDI_SUSPEND:
583bbb1277bSGarrett D'Amore 		mii_suspend(rtlsp->mii);
584bbb1277bSGarrett D'Amore 
585cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_io_lock);
586cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_rx_lock);
587cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_tx_lock);
588cde2885fSGarrett D'Amore 
589cde2885fSGarrett D'Amore 		rtlsp->rtls_suspended = B_TRUE;
590cde2885fSGarrett D'Amore 		rtls_chip_stop(rtlsp);
591cde2885fSGarrett D'Amore 
592cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
593cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_rx_lock);
594cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_io_lock);
595cde2885fSGarrett D'Amore 		return (DDI_SUCCESS);
596cde2885fSGarrett D'Amore 
597cde2885fSGarrett D'Amore 	default:
598cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
599cde2885fSGarrett D'Amore 	}
600cde2885fSGarrett D'Amore 
601cde2885fSGarrett D'Amore 	if (mac_unregister(rtlsp->mh) != 0) {
602cde2885fSGarrett D'Amore 		/* device busy */
603cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
604cde2885fSGarrett D'Amore 	}
605cde2885fSGarrett D'Amore 
606cde2885fSGarrett D'Amore 	ddi_remove_intr(devinfo, 0, rtlsp->iblk);
607cde2885fSGarrett D'Amore 
608bbb1277bSGarrett D'Amore 	mii_free(rtlsp->mii);
609cde2885fSGarrett D'Amore 
610cde2885fSGarrett D'Amore 	mutex_destroy(&rtlsp->rtls_io_lock);
611cde2885fSGarrett D'Amore 	mutex_destroy(&rtlsp->rtls_tx_lock);
612cde2885fSGarrett D'Amore 	mutex_destroy(&rtlsp->rtls_rx_lock);
613cde2885fSGarrett D'Amore 
614cde2885fSGarrett D'Amore 	ddi_regs_map_free(&rtlsp->io_handle);
615cde2885fSGarrett D'Amore 	rtls_free_bufs(rtlsp);
616cde2885fSGarrett D'Amore 	kmem_free(rtlsp, sizeof (rtls_t));
617cde2885fSGarrett D'Amore 
618cde2885fSGarrett D'Amore 	return (DDI_SUCCESS);
619cde2885fSGarrett D'Amore }
620cde2885fSGarrett D'Amore 
621cde2885fSGarrett D'Amore /*
622cde2885fSGarrett D'Amore  * quiesce(9E) entry point.
623cde2885fSGarrett D'Amore  *
624cde2885fSGarrett D'Amore  * This function is called when the system is single-threaded at high
625cde2885fSGarrett D'Amore  * PIL with preemption disabled. Therefore, this function must not be
626cde2885fSGarrett D'Amore  * blocked.
627cde2885fSGarrett D'Amore  *
628cde2885fSGarrett D'Amore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
629cde2885fSGarrett D'Amore  * DDI_FAILURE indicates an error condition and should almost never happen.
630cde2885fSGarrett D'Amore  */
631cde2885fSGarrett D'Amore static int
rtls_quiesce(dev_info_t * devinfo)632cde2885fSGarrett D'Amore rtls_quiesce(dev_info_t *devinfo)
633cde2885fSGarrett D'Amore {
634cde2885fSGarrett D'Amore 	rtls_t *rtlsp;			/* our private device info */
635cde2885fSGarrett D'Amore 
636cde2885fSGarrett D'Amore 	/*
637cde2885fSGarrett D'Amore 	 * Get the driver private structure
638cde2885fSGarrett D'Amore 	 */
639cde2885fSGarrett D'Amore 	if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) {
640cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
641cde2885fSGarrett D'Amore 	}
642cde2885fSGarrett D'Amore 	return (rtls_chip_reset(rtlsp, B_TRUE));
643cde2885fSGarrett D'Amore }
644cde2885fSGarrett D'Amore 
645cde2885fSGarrett D'Amore /*
646cde2885fSGarrett D'Amore  *    ========== MAC Entry Points ==========
647cde2885fSGarrett D'Amore  */
648cde2885fSGarrett D'Amore 
649cde2885fSGarrett D'Amore /*
650cde2885fSGarrett D'Amore  * rtls_m_start() -- start the board receiving and allow transmits
651cde2885fSGarrett D'Amore  */
652cde2885fSGarrett D'Amore static int
rtls_m_start(void * arg)653cde2885fSGarrett D'Amore rtls_m_start(void *arg)
654cde2885fSGarrett D'Amore {
655cde2885fSGarrett D'Amore 	rtls_t *rtlsp = (rtls_t *)arg;
656cde2885fSGarrett D'Amore 
657cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_io_lock);
658cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_rx_lock);
659cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_tx_lock);
660cde2885fSGarrett D'Amore 
661cde2885fSGarrett D'Amore 	if (!rtlsp->rtls_suspended)
662cde2885fSGarrett D'Amore 		rtls_chip_restart(rtlsp);
663cde2885fSGarrett D'Amore 
664cde2885fSGarrett D'Amore 	rtlsp->rtls_running = B_TRUE;
665cde2885fSGarrett D'Amore 
666cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_tx_lock);
667cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_rx_lock);
668cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_io_lock);
669cde2885fSGarrett D'Amore 
670bbb1277bSGarrett D'Amore 	drv_usecwait(100);
671bbb1277bSGarrett D'Amore 
672bbb1277bSGarrett D'Amore 	mii_start(rtlsp->mii);
673bbb1277bSGarrett D'Amore 
674cde2885fSGarrett D'Amore 	return (0);
675cde2885fSGarrett D'Amore }
676cde2885fSGarrett D'Amore 
677cde2885fSGarrett D'Amore /*
678cde2885fSGarrett D'Amore  * rtls_m_stop() -- stop board receiving and transmits
679cde2885fSGarrett D'Amore  */
680cde2885fSGarrett D'Amore static void
rtls_m_stop(void * arg)681cde2885fSGarrett D'Amore rtls_m_stop(void *arg)
682cde2885fSGarrett D'Amore {
683cde2885fSGarrett D'Amore 	rtls_t *rtlsp = (rtls_t *)arg;
684cde2885fSGarrett D'Amore 
685bbb1277bSGarrett D'Amore 	mii_stop(rtlsp->mii);
686bbb1277bSGarrett D'Amore 
687cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_io_lock);
688cde2885fSGarrett D'Amore 
689cde2885fSGarrett D'Amore 	if (!rtlsp->rtls_suspended)
690cde2885fSGarrett D'Amore 		rtls_chip_stop(rtlsp);
691cde2885fSGarrett D'Amore 	rtlsp->rtls_running = B_FALSE;
692cde2885fSGarrett D'Amore 
693cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_io_lock);
694cde2885fSGarrett D'Amore }
695cde2885fSGarrett D'Amore 
696cde2885fSGarrett D'Amore /*
697cde2885fSGarrett D'Amore  * rtls_m_unicst() -- set the physical network address
698cde2885fSGarrett D'Amore  * on the board
699cde2885fSGarrett D'Amore  */
700cde2885fSGarrett D'Amore static int
rtls_m_unicst(void * arg,const uint8_t * macaddr)701cde2885fSGarrett D'Amore rtls_m_unicst(void *arg, const uint8_t *macaddr)
702cde2885fSGarrett D'Amore {
703cde2885fSGarrett D'Amore 	rtls_t *rtlsp = arg;
704cde2885fSGarrett D'Amore 
705cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_io_lock);
706cde2885fSGarrett D'Amore 	bcopy(macaddr, rtlsp->netaddr, ETHERADDRL);
707cde2885fSGarrett D'Amore 	if (!rtlsp->rtls_suspended)
708cde2885fSGarrett D'Amore 		rtls_set_mac_addr(rtlsp, rtlsp->netaddr);
709cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_io_lock);
710cde2885fSGarrett D'Amore 	return (0);
711cde2885fSGarrett D'Amore }
712cde2885fSGarrett D'Amore 
713cde2885fSGarrett D'Amore /*
714cde2885fSGarrett D'Amore  * rtls_m_multicst() -- set(enable) or disable a multicast address
715cde2885fSGarrett D'Amore  *
716cde2885fSGarrett D'Amore  * Program the hardware to enable/disable the multicast address in "mcast".
717cde2885fSGarrett D'Amore  */
718cde2885fSGarrett D'Amore static int
rtls_m_multicst(void * arg,boolean_t enable,const uint8_t * mcast)719cde2885fSGarrett D'Amore rtls_m_multicst(void *arg, boolean_t enable, const uint8_t *mcast)
720cde2885fSGarrett D'Amore {
721cde2885fSGarrett D'Amore 	rtls_t *rtlsp = (rtls_t *)arg;
722cde2885fSGarrett D'Amore 	uint_t index;
723cde2885fSGarrett D'Amore 	uint32_t *hashp;
724cde2885fSGarrett D'Amore 
725cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_io_lock);
726cde2885fSGarrett D'Amore 	hashp = rtlsp->multi_hash;
727cde2885fSGarrett D'Amore 	index = rtls_hash_index(mcast);
728cde2885fSGarrett D'Amore 			/* index value is between 0 and 63 */
729cde2885fSGarrett D'Amore 
730cde2885fSGarrett D'Amore 	if (enable) {
731cde2885fSGarrett D'Amore 		if (rtlsp->multicast_cnt[index]++) {
732cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_io_lock);
733cde2885fSGarrett D'Amore 			return (0);
734cde2885fSGarrett D'Amore 		}
735cde2885fSGarrett D'Amore 		hashp[index/32] |= 1<< (index % 32);
736cde2885fSGarrett D'Amore 	} else {
737cde2885fSGarrett D'Amore 		if (--rtlsp->multicast_cnt[index]) {
738cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_io_lock);
739cde2885fSGarrett D'Amore 			return (0);
740cde2885fSGarrett D'Amore 		}
741cde2885fSGarrett D'Amore 		hashp[index/32] &= ~(1<< (index % 32));
742cde2885fSGarrett D'Amore 	}
743cde2885fSGarrett D'Amore 
744cde2885fSGarrett D'Amore 	/*
745cde2885fSGarrett D'Amore 	 * Set multicast register
746cde2885fSGarrett D'Amore 	 */
747cde2885fSGarrett D'Amore 	if (!rtlsp->rtls_suspended) {
748cde2885fSGarrett D'Amore 		rtls_reg_set32(rtlsp, MULTICAST_0_REG, hashp[0]);
749cde2885fSGarrett D'Amore 		rtls_reg_set32(rtlsp, MULTICAST_4_REG, hashp[1]);
750cde2885fSGarrett D'Amore 	}
751cde2885fSGarrett D'Amore 
752cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_io_lock);
753cde2885fSGarrett D'Amore 
754cde2885fSGarrett D'Amore 	return (0);
755cde2885fSGarrett D'Amore }
756cde2885fSGarrett D'Amore 
757cde2885fSGarrett D'Amore /*
758cde2885fSGarrett D'Amore  * rtls_hash_index() -- a hashing function used for setting the
759cde2885fSGarrett D'Amore  * node address or a multicast address
760cde2885fSGarrett D'Amore  */
761cde2885fSGarrett D'Amore static uint_t
rtls_hash_index(const uint8_t * address)762cde2885fSGarrett D'Amore rtls_hash_index(const uint8_t *address)
763cde2885fSGarrett D'Amore {
764cde2885fSGarrett D'Amore 	uint32_t crc = (ulong_t)RTLS_HASH_CRC;
765cde2885fSGarrett D'Amore 	uint32_t const POLY = RTLS_HASH_POLY;
766cde2885fSGarrett D'Amore 	uint32_t msb;
767cde2885fSGarrett D'Amore 	int bytes;
768cde2885fSGarrett D'Amore 	uchar_t currentbyte;
769cde2885fSGarrett D'Amore 	uint_t index;
770cde2885fSGarrett D'Amore 	int bit;
771cde2885fSGarrett D'Amore 
772cde2885fSGarrett D'Amore 	for (bytes = 0; bytes < ETHERADDRL; bytes++) {
773cde2885fSGarrett D'Amore 		currentbyte = address[bytes];
774cde2885fSGarrett D'Amore 		for (bit = 0; bit < 8; bit++) {
775cde2885fSGarrett D'Amore 			msb = crc >> 31;
776cde2885fSGarrett D'Amore 			crc <<= 1;
777cde2885fSGarrett D'Amore 			if (msb ^ (currentbyte & 1)) {
778cde2885fSGarrett D'Amore 				crc ^= POLY;
779cde2885fSGarrett D'Amore 				crc |= 0x00000001;
780cde2885fSGarrett D'Amore 			}
781cde2885fSGarrett D'Amore 			currentbyte >>= 1;
782cde2885fSGarrett D'Amore 		}
783cde2885fSGarrett D'Amore 	}
784cde2885fSGarrett D'Amore 
785cde2885fSGarrett D'Amore 	index = crc >> 26;
786cde2885fSGarrett D'Amore 
787cde2885fSGarrett D'Amore 	return (index);
788cde2885fSGarrett D'Amore }
789cde2885fSGarrett D'Amore 
790cde2885fSGarrett D'Amore /*
791cde2885fSGarrett D'Amore  * rtls_m_promisc() -- set or reset promiscuous mode on the board
792cde2885fSGarrett D'Amore  */
793cde2885fSGarrett D'Amore static int
rtls_m_promisc(void * arg,boolean_t on)794cde2885fSGarrett D'Amore rtls_m_promisc(void *arg, boolean_t on)
795cde2885fSGarrett D'Amore {
796cde2885fSGarrett D'Amore 	rtls_t *rtlsp = arg;
797cde2885fSGarrett D'Amore 
798cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_io_lock);
799cde2885fSGarrett D'Amore 
800cde2885fSGarrett D'Amore 	rtlsp->promisc = on;
801cde2885fSGarrett D'Amore 	if (!rtlsp->rtls_suspended) {
802cde2885fSGarrett D'Amore 		uint32_t val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG);
803cde2885fSGarrett D'Amore 		if (on) {
804cde2885fSGarrett D'Amore 			val32 |= RX_ACCEPT_ALL_PACKET;
805cde2885fSGarrett D'Amore 		} else {
806cde2885fSGarrett D'Amore 			val32 &= ~RX_ACCEPT_ALL_PACKET;
807cde2885fSGarrett D'Amore 		}
808cde2885fSGarrett D'Amore 		rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32);
809cde2885fSGarrett D'Amore 	}
810cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_io_lock);
811cde2885fSGarrett D'Amore 
812cde2885fSGarrett D'Amore 	return (0);
813cde2885fSGarrett D'Amore }
814cde2885fSGarrett D'Amore 
815cde2885fSGarrett D'Amore /*
816cde2885fSGarrett D'Amore  * rtls_m_stat() -- retrieve statistic
817cde2885fSGarrett D'Amore  *
818cde2885fSGarrett D'Amore  * MAC calls this routine just before it reads the driver's statistics
819cde2885fSGarrett D'Amore  * structure.  If your board maintains statistics, this is the time to
820cde2885fSGarrett D'Amore  * read them in and update the values in the structure. If the driver
821cde2885fSGarrett D'Amore  * maintains statistics continuously, this routine need do nothing.
822cde2885fSGarrett D'Amore  */
823cde2885fSGarrett D'Amore static int
rtls_m_stat(void * arg,uint_t stat,uint64_t * val)824cde2885fSGarrett D'Amore rtls_m_stat(void *arg, uint_t stat, uint64_t *val)
825cde2885fSGarrett D'Amore {
826cde2885fSGarrett D'Amore 	rtls_t *rtlsp = arg;
827cde2885fSGarrett D'Amore 
828bbb1277bSGarrett D'Amore 	if (mii_m_getstat(rtlsp->mii, stat, val) == 0) {
829bbb1277bSGarrett D'Amore 		return (0);
830cde2885fSGarrett D'Amore 	}
831cde2885fSGarrett D'Amore 
832cde2885fSGarrett D'Amore 	switch (stat) {
833cde2885fSGarrett D'Amore 	case MAC_STAT_IPACKETS:
834cde2885fSGarrett D'Amore 		*val = rtlsp->stats.ipackets;
835cde2885fSGarrett D'Amore 		break;
836cde2885fSGarrett D'Amore 	case MAC_STAT_RBYTES:
837cde2885fSGarrett D'Amore 		*val = rtlsp->stats.rbytes;
838cde2885fSGarrett D'Amore 		break;
839cde2885fSGarrett D'Amore 	case MAC_STAT_OPACKETS:
840cde2885fSGarrett D'Amore 		*val = rtlsp->stats.opackets;
841cde2885fSGarrett D'Amore 		break;
842cde2885fSGarrett D'Amore 	case MAC_STAT_OBYTES:
843cde2885fSGarrett D'Amore 		*val = rtlsp->stats.obytes;
844cde2885fSGarrett D'Amore 		break;
845cde2885fSGarrett D'Amore 	case MAC_STAT_IERRORS:
846cde2885fSGarrett D'Amore 		*val = rtlsp->stats.rcv_err;
847cde2885fSGarrett D'Amore 		break;
848cde2885fSGarrett D'Amore 	case MAC_STAT_OERRORS:
849cde2885fSGarrett D'Amore 		*val = rtlsp->stats.xmt_err;
850cde2885fSGarrett D'Amore 		break;
851cde2885fSGarrett D'Amore 	case MAC_STAT_MULTIRCV:
852cde2885fSGarrett D'Amore 		*val = rtlsp->stats.multi_rcv;
853cde2885fSGarrett D'Amore 		break;
854cde2885fSGarrett D'Amore 	case MAC_STAT_BRDCSTRCV:
855cde2885fSGarrett D'Amore 		*val = rtlsp->stats.brdcst_rcv;
856cde2885fSGarrett D'Amore 		break;
857cde2885fSGarrett D'Amore 	case MAC_STAT_MULTIXMT:
858cde2885fSGarrett D'Amore 		*val = rtlsp->stats.multi_xmt;
859cde2885fSGarrett D'Amore 		break;
860cde2885fSGarrett D'Amore 	case MAC_STAT_BRDCSTXMT:
861cde2885fSGarrett D'Amore 		*val = rtlsp->stats.brdcst_xmt;
862cde2885fSGarrett D'Amore 		break;
863cde2885fSGarrett D'Amore 	case MAC_STAT_UNDERFLOWS:
864cde2885fSGarrett D'Amore 		*val = rtlsp->stats.underflow;
865cde2885fSGarrett D'Amore 		break;
866cde2885fSGarrett D'Amore 	case MAC_STAT_OVERFLOWS:
867cde2885fSGarrett D'Amore 		*val = rtlsp->stats.overflow;
868cde2885fSGarrett D'Amore 		break;
869cde2885fSGarrett D'Amore 	case MAC_STAT_NORCVBUF:
870cde2885fSGarrett D'Amore 		*val = rtlsp->stats.no_rcvbuf;
871cde2885fSGarrett D'Amore 		break;
872cde2885fSGarrett D'Amore 	case MAC_STAT_COLLISIONS:
873cde2885fSGarrett D'Amore 		*val = rtlsp->stats.collisions;
874cde2885fSGarrett D'Amore 		break;
875cde2885fSGarrett D'Amore 	case ETHER_STAT_FCS_ERRORS:
876cde2885fSGarrett D'Amore 		*val = rtlsp->stats.crc_err;
877cde2885fSGarrett D'Amore 		break;
878cde2885fSGarrett D'Amore 	case ETHER_STAT_ALIGN_ERRORS:
879cde2885fSGarrett D'Amore 		*val = rtlsp->stats.frame_err;
880cde2885fSGarrett D'Amore 		break;
881cde2885fSGarrett D'Amore 	case ETHER_STAT_DEFER_XMTS:
882cde2885fSGarrett D'Amore 		*val = rtlsp->stats.defer;
883cde2885fSGarrett D'Amore 		break;
884cde2885fSGarrett D'Amore 	case ETHER_STAT_TX_LATE_COLLISIONS:
885cde2885fSGarrett D'Amore 		*val = rtlsp->stats.xmt_latecoll;
886cde2885fSGarrett D'Amore 		break;
887cde2885fSGarrett D'Amore 	case ETHER_STAT_TOOLONG_ERRORS:
888cde2885fSGarrett D'Amore 		*val = rtlsp->stats.too_long;
889cde2885fSGarrett D'Amore 		break;
890cde2885fSGarrett D'Amore 	case ETHER_STAT_TOOSHORT_ERRORS:
891cde2885fSGarrett D'Amore 		*val = rtlsp->stats.in_short;
892cde2885fSGarrett D'Amore 		break;
893cde2885fSGarrett D'Amore 	case ETHER_STAT_CARRIER_ERRORS:
894cde2885fSGarrett D'Amore 		*val = rtlsp->stats.no_carrier;
895cde2885fSGarrett D'Amore 		break;
896cde2885fSGarrett D'Amore 	case ETHER_STAT_FIRST_COLLISIONS:
897cde2885fSGarrett D'Amore 		*val = rtlsp->stats.firstcol;
898cde2885fSGarrett D'Amore 		break;
899cde2885fSGarrett D'Amore 	case ETHER_STAT_MULTI_COLLISIONS:
900cde2885fSGarrett D'Amore 		*val = rtlsp->stats.multicol;
901cde2885fSGarrett D'Amore 		break;
902cde2885fSGarrett D'Amore 	default:
903cde2885fSGarrett D'Amore 		return (ENOTSUP);
904cde2885fSGarrett D'Amore 	}
905cde2885fSGarrett D'Amore 
906cde2885fSGarrett D'Amore 	/*
907cde2885fSGarrett D'Amore 	 * RTL8139 don't support MII statistics,
908cde2885fSGarrett D'Amore 	 * these values are maintained by the driver software.
909cde2885fSGarrett D'Amore 	 */
910cde2885fSGarrett D'Amore 
911cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
912cde2885fSGarrett D'Amore 	if (rtls_debug & RTLS_TRACE)
913cde2885fSGarrett D'Amore 		rtls_reg_print(rtlsp);
914cde2885fSGarrett D'Amore #endif
915cde2885fSGarrett D'Amore 
916cde2885fSGarrett D'Amore 	return (0);
917cde2885fSGarrett D'Amore }
918cde2885fSGarrett D'Amore 
919ace3c3ffSVenugopal Iyer int
rtls_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)920ace3c3ffSVenugopal Iyer rtls_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
921ace3c3ffSVenugopal Iyer     void *val)
922ace3c3ffSVenugopal Iyer {
923ace3c3ffSVenugopal Iyer 	rtls_t *rtlsp = arg;
924ace3c3ffSVenugopal Iyer 
925ace3c3ffSVenugopal Iyer 	return (mii_m_getprop(rtlsp->mii, name, num, sz, val));
926ace3c3ffSVenugopal Iyer }
927ace3c3ffSVenugopal Iyer 
928ace3c3ffSVenugopal Iyer int
rtls_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)929ace3c3ffSVenugopal Iyer rtls_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
930ace3c3ffSVenugopal Iyer     const void *val)
931ace3c3ffSVenugopal Iyer {
932ace3c3ffSVenugopal Iyer 	rtls_t *rtlsp = arg;
933ace3c3ffSVenugopal Iyer 
934ace3c3ffSVenugopal Iyer 	return (mii_m_setprop(rtlsp->mii, name, num, sz, val));
935ace3c3ffSVenugopal Iyer }
936ace3c3ffSVenugopal Iyer 
937ace3c3ffSVenugopal Iyer static void
rtls_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t prh)938ace3c3ffSVenugopal Iyer rtls_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
939ace3c3ffSVenugopal Iyer     mac_prop_info_handle_t prh)
940ace3c3ffSVenugopal Iyer {
941ace3c3ffSVenugopal Iyer 	rtls_t *rtlsp = arg;
942ace3c3ffSVenugopal Iyer 
943ace3c3ffSVenugopal Iyer 	mii_m_propinfo(rtlsp->mii, name, num, prh);
944ace3c3ffSVenugopal Iyer }
945ace3c3ffSVenugopal Iyer 
946cde2885fSGarrett D'Amore /*
947cde2885fSGarrett D'Amore  * rtls_send() -- send a packet
948cde2885fSGarrett D'Amore  *
949cde2885fSGarrett D'Amore  * Called when a packet is ready to be transmitted. A pointer to an
950cde2885fSGarrett D'Amore  * M_DATA message that contains the packet is passed to this routine.
951cde2885fSGarrett D'Amore  * The complete LLC header is contained in the message's first message
952cde2885fSGarrett D'Amore  * block, and the remainder of the packet is contained within
953cde2885fSGarrett D'Amore  * additional M_DATA message blocks linked to the first message block.
954cde2885fSGarrett D'Amore  *
955cde2885fSGarrett D'Amore  * Returns B_TRUE if the packet was properly disposed of, or B_FALSE if
956cde2885fSGarrett D'Amore  * if the packet is being deferred and should be tried again later.
957cde2885fSGarrett D'Amore  */
958cde2885fSGarrett D'Amore 
959cde2885fSGarrett D'Amore static boolean_t
rtls_send(rtls_t * rtlsp,mblk_t * mp)960cde2885fSGarrett D'Amore rtls_send(rtls_t *rtlsp, mblk_t *mp)
961cde2885fSGarrett D'Amore {
962cde2885fSGarrett D'Amore 	int totlen;
963cde2885fSGarrett D'Amore 	int ncc;
964cde2885fSGarrett D'Amore 	uint16_t cur_desc;
965cde2885fSGarrett D'Amore 	uint32_t tx_status;
966cde2885fSGarrett D'Amore 
967cde2885fSGarrett D'Amore 	ASSERT(mp != NULL);
968cde2885fSGarrett D'Amore 	ASSERT(rtlsp->rtls_running);
969cde2885fSGarrett D'Amore 
970cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_tx_lock);
971cde2885fSGarrett D'Amore 
972cde2885fSGarrett D'Amore 	if (rtlsp->rtls_suspended) {
973cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
974cde2885fSGarrett D'Amore 		return (B_FALSE);
975cde2885fSGarrett D'Amore 	}
976cde2885fSGarrett D'Amore 
977cde2885fSGarrett D'Amore 	/*
978cde2885fSGarrett D'Amore 	 * If chip error ...
979cde2885fSGarrett D'Amore 	 */
980cde2885fSGarrett D'Amore 	if (rtlsp->chip_error) {
981cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
982cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
983cde2885fSGarrett D'Amore 		    "%s: send fail--CHIP ERROR!",
984*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh));
985cde2885fSGarrett D'Amore #endif
986cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
987cde2885fSGarrett D'Amore 		freemsg(mp);
988cde2885fSGarrett D'Amore 		return (B_TRUE);
989cde2885fSGarrett D'Amore 	}
990cde2885fSGarrett D'Amore 
991cde2885fSGarrett D'Amore 	/*
992bbb1277bSGarrett D'Amore 	 * If chip link down ...  Note that experimentation shows that
993bbb1277bSGarrett D'Amore 	 * the device seems not to care about whether or not we have
994bbb1277bSGarrett D'Amore 	 * this check, but if we don't add the check here, it might
995bbb1277bSGarrett D'Amore 	 * not be properly reported as a carrier error.
996cde2885fSGarrett D'Amore 	 */
997bbb1277bSGarrett D'Amore 	if (rtls_reg_get8(rtlsp, MEDIA_STATUS_REG) & MEDIA_STATUS_LINK) {
998cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
999cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
1000cde2885fSGarrett D'Amore 		    "%s: send fail--LINK DOWN!",
1001*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh));
1002cde2885fSGarrett D'Amore #endif
1003cde2885fSGarrett D'Amore 		rtlsp->stats.no_carrier++;
1004cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
1005cde2885fSGarrett D'Amore 		freemsg(mp);
1006cde2885fSGarrett D'Amore 		return (B_TRUE);
1007cde2885fSGarrett D'Amore 	}
1008cde2885fSGarrett D'Amore 
1009cde2885fSGarrett D'Amore 	/*
1010cde2885fSGarrett D'Amore 	 * Current transmit descriptor
1011cde2885fSGarrett D'Amore 	 */
1012cde2885fSGarrett D'Amore 	cur_desc = rtlsp->tx_current_desc;
1013cde2885fSGarrett D'Amore 	ASSERT(cur_desc < RTLS_MAX_TX_DESC);
1014cde2885fSGarrett D'Amore 
1015cde2885fSGarrett D'Amore 	/*
1016cde2885fSGarrett D'Amore 	 * RealTek 8139 has 4 tx descriptor for transmit. In the first tx loop
1017cde2885fSGarrett D'Amore 	 * of transmit,we needn't judge transmit status.
1018cde2885fSGarrett D'Amore 	 */
1019cde2885fSGarrett D'Amore 	if (rtlsp->tx_first_loop < RTLS_MAX_TX_DESC) {
1020cde2885fSGarrett D'Amore 		rtlsp->tx_first_loop++;
1021cde2885fSGarrett D'Amore 		goto tx_ready;
1022cde2885fSGarrett D'Amore 	}
1023cde2885fSGarrett D'Amore 
1024cde2885fSGarrett D'Amore 	/*
1025cde2885fSGarrett D'Amore 	 * If it's not the first tx loop, we need judge whether the chip is
1026cde2885fSGarrett D'Amore 	 * busy or not. Otherwise, we have to reschedule send and wait...
1027cde2885fSGarrett D'Amore 	 */
1028cde2885fSGarrett D'Amore 	tx_status = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc);
1029cde2885fSGarrett D'Amore 
1030cde2885fSGarrett D'Amore 	/*
1031cde2885fSGarrett D'Amore 	 * H/W doesn't complete packet transmit
1032cde2885fSGarrett D'Amore 	 */
1033cde2885fSGarrett D'Amore 	if (!(tx_status & TX_COMPLETE_FLAG)) {
1034cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
1035cde2885fSGarrett D'Amore 		if (rtls_debug & RTLS_SEND) {
1036cde2885fSGarrett D'Amore 			cmn_err(CE_NOTE,
1037*2c6a6ad1SIlya Yanok 			    "%s: rtls_send: need_sched", mac_name(rtlsp->mh));
1038cde2885fSGarrett D'Amore 		}
1039cde2885fSGarrett D'Amore #endif
1040cde2885fSGarrett D'Amore 		/*
1041cde2885fSGarrett D'Amore 		 * Through test, we find RTL8139 tx status might be
1042cde2885fSGarrett D'Amore 		 * not-completing all along. We have to reset chip
1043cde2885fSGarrett D'Amore 		 * to make RTL8139 tansmit re-work.
1044cde2885fSGarrett D'Amore 		 */
1045cde2885fSGarrett D'Amore 		if (rtlsp->tx_retry++ > RTLS_TX_RETRY_NUM) {
1046cde2885fSGarrett D'Amore 
1047cde2885fSGarrett D'Amore 			/*
1048cde2885fSGarrett D'Amore 			 * Wait transmit h/w more time...
1049cde2885fSGarrett D'Amore 			 */
1050cde2885fSGarrett D'Amore 			RTLS_TX_WAIT_TIMEOUT;	/* 100 ms */
1051cde2885fSGarrett D'Amore 
1052cde2885fSGarrett D'Amore 			/*
1053cde2885fSGarrett D'Amore 			 * Judge tx status again, if it remains not-completing,
1054cde2885fSGarrett D'Amore 			 * we can confirm RTL8139 is in chip error state
1055cde2885fSGarrett D'Amore 			 * and must reset it.
1056cde2885fSGarrett D'Amore 			 */
1057cde2885fSGarrett D'Amore 			tx_status = rtls_reg_get32(rtlsp,
1058cde2885fSGarrett D'Amore 			    TX_STATUS_DESC0_REG + 4 * cur_desc);
1059cde2885fSGarrett D'Amore 			if (!(tx_status & TX_COMPLETE_FLAG)) {
1060cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
1061cde2885fSGarrett D'Amore 				cmn_err(CE_NOTE, "%s: tx chip_error = 0x%x",
1062*2c6a6ad1SIlya Yanok 				    mac_name(rtlsp->mh), tx_status);
1063cde2885fSGarrett D'Amore #endif
1064cde2885fSGarrett D'Amore 				rtlsp->tx_retry = 0;
1065cde2885fSGarrett D'Amore 				rtlsp->chip_error = B_TRUE;
1066cde2885fSGarrett D'Amore 				rtlsp->stats.xmt_err++;
1067cde2885fSGarrett D'Amore 				rtlsp->stats.mac_xmt_err++;
1068cde2885fSGarrett D'Amore 				mutex_exit(&rtlsp->rtls_tx_lock);
1069cde2885fSGarrett D'Amore 				freemsg(mp);
1070cde2885fSGarrett D'Amore 				return (B_TRUE);
1071cde2885fSGarrett D'Amore 			}
1072cde2885fSGarrett D'Amore 		} else {
1073cde2885fSGarrett D'Amore 			rtlsp->stats.defer++;
1074cde2885fSGarrett D'Amore 			rtlsp->need_sched = B_TRUE;
1075cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_tx_lock);
1076cde2885fSGarrett D'Amore 			return (B_FALSE);
1077cde2885fSGarrett D'Amore 		}
1078cde2885fSGarrett D'Amore 	}
1079cde2885fSGarrett D'Amore 
1080cde2885fSGarrett D'Amore 	/*
1081cde2885fSGarrett D'Amore 	 * Transmit error?
1082cde2885fSGarrett D'Amore 	 */
1083cde2885fSGarrett D'Amore 	if (tx_status & TX_ERR_FLAG) {
1084cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
1085cde2885fSGarrett D'Amore 		if (rtls_debug & RTLS_SEND) {
1086cde2885fSGarrett D'Amore 			cmn_err(CE_NOTE, "%s: transmit error, status = 0x%x",
1087*2c6a6ad1SIlya Yanok 			    mac_name(rtlsp->mh), tx_status);
1088cde2885fSGarrett D'Amore 		}
1089cde2885fSGarrett D'Amore #endif
1090cde2885fSGarrett D'Amore 		rtlsp->stats.xmt_err++;
1091cde2885fSGarrett D'Amore 		if (tx_status & TX_STATUS_TX_UNDERRUN)
1092cde2885fSGarrett D'Amore 			rtlsp->stats.underflow++;
1093cde2885fSGarrett D'Amore 		if (tx_status & TX_STATUS_CS_LOST)
1094cde2885fSGarrett D'Amore 			rtlsp->stats.no_carrier++;
1095cde2885fSGarrett D'Amore 		if (tx_status & TX_STATUS_OWC)
1096cde2885fSGarrett D'Amore 			rtlsp->stats.xmt_latecoll++;
1097cde2885fSGarrett D'Amore 	}
1098cde2885fSGarrett D'Amore 	ncc = ((tx_status & TX_STATUS_NCC) >> TX_STATUS_NCC_SHIFT);
1099cde2885fSGarrett D'Amore 	if (ncc != 0) {
1100cde2885fSGarrett D'Amore 		rtlsp->stats.collisions += ncc;
1101cde2885fSGarrett D'Amore 		rtlsp->stats.firstcol++;
1102cde2885fSGarrett D'Amore 		rtlsp->stats.multicol += ncc - 1;
1103cde2885fSGarrett D'Amore 	}
1104cde2885fSGarrett D'Amore 
1105cde2885fSGarrett D'Amore tx_ready:
1106cde2885fSGarrett D'Amore 	/*
1107cde2885fSGarrett D'Amore 	 * Initialize variable
1108cde2885fSGarrett D'Amore 	 */
1109cde2885fSGarrett D'Amore 	rtlsp->tx_retry = 0;
1110cde2885fSGarrett D'Amore 	totlen = 0;
1111cde2885fSGarrett D'Amore 
1112cde2885fSGarrett D'Amore 	/*
1113cde2885fSGarrett D'Amore 	 * Copy packet to tx descriptor buffer
1114cde2885fSGarrett D'Amore 	 */
1115cde2885fSGarrett D'Amore 	totlen = msgsize(mp);
1116cde2885fSGarrett D'Amore 	if (totlen > (ETHERMAX + 4)) {	/* 4 bytes for VLAN header */
1117cde2885fSGarrett D'Amore 		cmn_err(CE_NOTE,
1118cde2885fSGarrett D'Amore 		    "%s: rtls_send: try to send large %d packet",
1119*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh), totlen);
1120cde2885fSGarrett D'Amore 		rtlsp->stats.mac_xmt_err++;
1121cde2885fSGarrett D'Amore 		rtlsp->stats.xmt_err++;
1122cde2885fSGarrett D'Amore 		freemsg(mp);
1123cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
1124cde2885fSGarrett D'Amore 		return (B_TRUE);
1125cde2885fSGarrett D'Amore 	}
1126cde2885fSGarrett D'Amore 
1127cde2885fSGarrett D'Amore 	/* this will free the mblk */
1128cde2885fSGarrett D'Amore 	mcopymsg(mp, rtlsp->tx_buf[cur_desc]);
1129cde2885fSGarrett D'Amore 
1130cde2885fSGarrett D'Amore 	/* update stats */
1131cde2885fSGarrett D'Amore 	if (*rtlsp->tx_buf[cur_desc] & 0x1)  {
1132cde2885fSGarrett D'Amore 		uint16_t	*ptr = (void *)rtlsp->tx_buf[cur_desc];
1133cde2885fSGarrett D'Amore 		if ((ptr[0] == 0xffff) &&
1134cde2885fSGarrett D'Amore 		    (ptr[1] == 0xffff) &&
1135cde2885fSGarrett D'Amore 		    (ptr[2] == 0xffff)) {
1136cde2885fSGarrett D'Amore 			rtlsp->stats.brdcst_xmt++;
1137cde2885fSGarrett D'Amore 		} else {
1138cde2885fSGarrett D'Amore 			rtlsp->stats.multi_xmt++;
1139cde2885fSGarrett D'Amore 		}
1140cde2885fSGarrett D'Amore 	}
1141cde2885fSGarrett D'Amore 	rtlsp->stats.opackets++;
1142cde2885fSGarrett D'Amore 	rtlsp->stats.obytes += totlen;
1143cde2885fSGarrett D'Amore 
1144cde2885fSGarrett D'Amore 	if (totlen < ETHERMIN) {
1145cde2885fSGarrett D'Amore 		bzero(rtlsp->tx_buf[cur_desc] + totlen, ETHERMIN - totlen);
1146cde2885fSGarrett D'Amore 		totlen = ETHERMIN;
1147cde2885fSGarrett D'Amore 	}
1148cde2885fSGarrett D'Amore 
1149cde2885fSGarrett D'Amore 	/* make sure caches are flushed */
1150cde2885fSGarrett D'Amore 	(void) ddi_dma_sync(rtlsp->dma_area_tx[cur_desc].dma_hdl, 0, totlen,
1151cde2885fSGarrett D'Amore 	    DDI_DMA_SYNC_FORDEV);
1152cde2885fSGarrett D'Amore 
1153cde2885fSGarrett D'Amore 	/*
1154cde2885fSGarrett D'Amore 	 * Start transmit
1155cde2885fSGarrett D'Amore 	 * set transmit FIFO threshhold to 0x30*32 = 1536 bytes
1156cde2885fSGarrett D'Amore 	 * to avoid tx underrun.
1157cde2885fSGarrett D'Amore 	 */
1158cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc,
1159cde2885fSGarrett D'Amore 	    totlen | (0x30 << TX_STATUS_TX_THRESHOLD_SHIFT));
1160cde2885fSGarrett D'Amore 
1161cde2885fSGarrett D'Amore 	/*
1162cde2885fSGarrett D'Amore 	 * Update the value of current tx descriptor
1163cde2885fSGarrett D'Amore 	 */
1164cde2885fSGarrett D'Amore 	cur_desc++;
1165cde2885fSGarrett D'Amore 	cur_desc %= RTLS_MAX_TX_DESC;
1166cde2885fSGarrett D'Amore 	rtlsp->tx_current_desc = cur_desc;
1167cde2885fSGarrett D'Amore 
1168cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_tx_lock);
1169cde2885fSGarrett D'Amore 
1170cde2885fSGarrett D'Amore 	return (B_TRUE);
1171cde2885fSGarrett D'Amore }
1172cde2885fSGarrett D'Amore 
1173cde2885fSGarrett D'Amore /*
1174cde2885fSGarrett D'Amore  * rtls_m_tx() -- send a chain of packets, linked by mp->b_next.
1175cde2885fSGarrett D'Amore  */
1176cde2885fSGarrett D'Amore static mblk_t *
rtls_m_tx(void * arg,mblk_t * mp)1177cde2885fSGarrett D'Amore rtls_m_tx(void *arg, mblk_t *mp)
1178cde2885fSGarrett D'Amore {
1179cde2885fSGarrett D'Amore 	rtls_t *rtlsp = arg;
1180cde2885fSGarrett D'Amore 	mblk_t *next;
1181cde2885fSGarrett D'Amore 
1182cde2885fSGarrett D'Amore 	while (mp != NULL) {
1183cde2885fSGarrett D'Amore 		next = mp->b_next;
1184cde2885fSGarrett D'Amore 		mp->b_next = NULL;
1185cde2885fSGarrett D'Amore 		if (!rtls_send(rtlsp, mp)) {
1186cde2885fSGarrett D'Amore 			mp->b_next = next;
1187cde2885fSGarrett D'Amore 			break;
1188cde2885fSGarrett D'Amore 		}
1189cde2885fSGarrett D'Amore 		mp = next;
1190cde2885fSGarrett D'Amore 	}
1191cde2885fSGarrett D'Amore 	return (mp);
1192cde2885fSGarrett D'Amore }
1193cde2885fSGarrett D'Amore 
1194cde2885fSGarrett D'Amore /*
1195cde2885fSGarrett D'Amore  * rtls_receive() -- receive packets
1196cde2885fSGarrett D'Amore  *
1197cde2885fSGarrett D'Amore  * Called when receive interrupts detected
1198cde2885fSGarrett D'Amore  */
1199cde2885fSGarrett D'Amore static void
rtls_receive(rtls_t * rtlsp)1200cde2885fSGarrett D'Amore rtls_receive(rtls_t *rtlsp)
1201cde2885fSGarrett D'Amore {
1202cde2885fSGarrett D'Amore 	mblk_t *head = NULL;
1203cde2885fSGarrett D'Amore 	mblk_t **mpp;
1204cde2885fSGarrett D'Amore 	mblk_t *mp;
1205cde2885fSGarrett D'Amore 	uint16_t rx_status;
1206cde2885fSGarrett D'Amore 	uint16_t packet_len;
1207cde2885fSGarrett D'Amore 	int wrap_size;
1208cde2885fSGarrett D'Amore 	uint32_t cur_rx;
1209cde2885fSGarrett D'Amore 	uint8_t *rx_ptr;
1210cde2885fSGarrett D'Amore 
1211cde2885fSGarrett D'Amore 	mpp = &head;
1212cde2885fSGarrett D'Amore 
1213cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_rx_lock);
1214cde2885fSGarrett D'Amore 
1215cde2885fSGarrett D'Amore 	if (rtlsp->rtls_suspended) {
1216cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_rx_lock);
1217cde2885fSGarrett D'Amore 		return;
1218cde2885fSGarrett D'Amore 	}
1219cde2885fSGarrett D'Amore 
1220cde2885fSGarrett D'Amore 	while ((rtls_reg_get8(rtlsp, RT_COMMAND_REG)
1221cde2885fSGarrett D'Amore 	    & RT_COMMAND_BUFF_EMPTY) == 0) {
1222cde2885fSGarrett D'Amore 
1223cde2885fSGarrett D'Amore 		/*
1224cde2885fSGarrett D'Amore 		 * Chip error state
1225cde2885fSGarrett D'Amore 		 */
1226cde2885fSGarrett D'Amore 		if (rtlsp->chip_error) {
1227cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
1228cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
1229cde2885fSGarrett D'Amore 		    "%s: receive fail--CHIP ERROR!",
1230*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh));
1231cde2885fSGarrett D'Amore #endif
1232cde2885fSGarrett D'Amore 			break;
1233cde2885fSGarrett D'Amore 		}
1234cde2885fSGarrett D'Amore 
1235cde2885fSGarrett D'Amore 		cur_rx = rtlsp->cur_rx;
1236cde2885fSGarrett D'Amore 		rx_ptr = rtlsp->rx_ring + cur_rx;
1237cde2885fSGarrett D'Amore 		packet_len = (rx_ptr[3] << 8) | (rx_ptr[2]);
1238cde2885fSGarrett D'Amore 		rx_status = rx_ptr[0];
1239cde2885fSGarrett D'Amore 
1240cde2885fSGarrett D'Amore 		/*
1241cde2885fSGarrett D'Amore 		 * DMA still in progress
1242cde2885fSGarrett D'Amore 		 */
1243cde2885fSGarrett D'Amore 		if (packet_len == RX_STATUS_DMA_BUSY) {
1244cde2885fSGarrett D'Amore 			cmn_err(CE_NOTE, "%s: Rx DMA still in progress",
1245*2c6a6ad1SIlya Yanok 			    mac_name(rtlsp->mh));
1246cde2885fSGarrett D'Amore 			break;
1247cde2885fSGarrett D'Amore 		}
1248cde2885fSGarrett D'Amore 
1249cde2885fSGarrett D'Amore 		/*
1250cde2885fSGarrett D'Amore 		 * Check receive status
1251cde2885fSGarrett D'Amore 		 */
1252cde2885fSGarrett D'Amore 		if ((rx_status & RX_ERR_FLAGS) ||
1253cde2885fSGarrett D'Amore 		    (!(rx_status & RX_HEADER_STATUS_ROK)) ||
1254cde2885fSGarrett D'Amore 		    (packet_len < (ETHERMIN + ETHERFCSL)) ||
1255cde2885fSGarrett D'Amore 		    (packet_len > (ETHERMAX + ETHERFCSL + 4))) {
1256cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
1257cde2885fSGarrett D'Amore 			cmn_err(CE_NOTE,
1258cde2885fSGarrett D'Amore 			    "%s: receive error, status = 0x%x, length = %d",
1259*2c6a6ad1SIlya Yanok 			    mac_name(rtlsp->mh), rx_status, packet_len);
1260cde2885fSGarrett D'Amore #endif
1261cde2885fSGarrett D'Amore 			/*
1262cde2885fSGarrett D'Amore 			 * Rx error statistics
1263cde2885fSGarrett D'Amore 			 */
1264cde2885fSGarrett D'Amore 			if ((rx_status & RX_HEADER_STATUS_RUNT) ||
1265cde2885fSGarrett D'Amore 			    (packet_len < (ETHERMIN + ETHERFCSL)))
1266cde2885fSGarrett D'Amore 				rtlsp->stats.in_short++;
1267cde2885fSGarrett D'Amore 			else if (packet_len > (ETHERMAX + ETHERFCSL + 4))
1268cde2885fSGarrett D'Amore 				rtlsp->stats.too_long++;
1269cde2885fSGarrett D'Amore 			else if (rx_status & RX_HEADER_STATUS_CRC)
1270cde2885fSGarrett D'Amore 				rtlsp->stats.crc_err++;
1271cde2885fSGarrett D'Amore 			else if (rx_status & RX_HEADER_STATUS_FAE)
1272cde2885fSGarrett D'Amore 				rtlsp->stats.frame_err++;
1273cde2885fSGarrett D'Amore 
1274cde2885fSGarrett D'Amore 			/*
1275cde2885fSGarrett D'Amore 			 * Set chip_error flag to reset chip:
1276cde2885fSGarrett D'Amore 			 * (suggested in RealTek programming guide.)
1277cde2885fSGarrett D'Amore 			 */
1278cde2885fSGarrett D'Amore 			rtlsp->chip_error = B_TRUE;
1279cde2885fSGarrett D'Amore 			mutex_exit(&rtlsp->rtls_rx_lock);
1280cde2885fSGarrett D'Amore 			return;
1281cde2885fSGarrett D'Amore 		}
1282cde2885fSGarrett D'Amore 
1283cde2885fSGarrett D'Amore 		/*
1284cde2885fSGarrett D'Amore 		 * We need not up-send ETHERFCSL bytes of receive packet
1285cde2885fSGarrett D'Amore 		 */
1286cde2885fSGarrett D'Amore 		packet_len -= ETHERFCSL;
1287cde2885fSGarrett D'Amore 
1288cde2885fSGarrett D'Amore 		/*
1289cde2885fSGarrett D'Amore 		 * Allocate buffer to receive this good packet
1290cde2885fSGarrett D'Amore 		 */
1291cde2885fSGarrett D'Amore 		mp = allocb(packet_len, 0);
1292cde2885fSGarrett D'Amore 
1293cde2885fSGarrett D'Amore 		/*
1294cde2885fSGarrett D'Amore 		 * Copy the data found into the new cluster, we have (+4)
1295cde2885fSGarrett D'Amore 		 * to get us past the packet head data that the rtl chip
1296cde2885fSGarrett D'Amore 		 * places at the start of the message
1297cde2885fSGarrett D'Amore 		 */
1298cde2885fSGarrett D'Amore 		if ((cur_rx + packet_len + RX_HEADER_SIZE)
1299cde2885fSGarrett D'Amore 		    > RTLS_RX_BUF_RING) {
1300cde2885fSGarrett D'Amore 			wrap_size = cur_rx + packet_len + RX_HEADER_SIZE
1301cde2885fSGarrett D'Amore 			    - RTLS_RX_BUF_RING;
1302cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
1303cde2885fSGarrett D'Amore 			if (rtls_debug & RTLS_RECV) {
1304cde2885fSGarrett D'Amore 				cmn_err(CE_NOTE,
1305cde2885fSGarrett D'Amore 				    "%s: Rx: packet_len = %d, wrap_size = %d",
1306*2c6a6ad1SIlya Yanok 				    mac_name(rtlsp->mh), packet_len, wrap_size);
1307cde2885fSGarrett D'Amore 			}
1308cde2885fSGarrett D'Amore #endif
1309cde2885fSGarrett D'Amore 
1310cde2885fSGarrett D'Amore 			if (mp != NULL) {
1311cde2885fSGarrett D'Amore 				/* Flush caches */
1312cde2885fSGarrett D'Amore 				(void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl,
1313cde2885fSGarrett D'Amore 				    cur_rx + RX_HEADER_SIZE,
1314cde2885fSGarrett D'Amore 				    packet_len - wrap_size,
1315cde2885fSGarrett D'Amore 				    DDI_DMA_SYNC_FORKERNEL);
1316cde2885fSGarrett D'Amore 				(void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl,
1317cde2885fSGarrett D'Amore 				    0, wrap_size,
1318cde2885fSGarrett D'Amore 				    DDI_DMA_SYNC_FORKERNEL);
1319cde2885fSGarrett D'Amore 
1320cde2885fSGarrett D'Amore 				/*
1321cde2885fSGarrett D'Amore 				 * Copy in first section of message as stored
1322cde2885fSGarrett D'Amore 				 * at the end of the ring buffer
1323cde2885fSGarrett D'Amore 				 */
1324cde2885fSGarrett D'Amore 				bcopy(rx_ptr + RX_HEADER_SIZE,
1325cde2885fSGarrett D'Amore 				    mp->b_wptr, packet_len - wrap_size);
1326cde2885fSGarrett D'Amore 				mp->b_wptr += packet_len - wrap_size;
1327cde2885fSGarrett D'Amore 				bcopy(rtlsp->rx_ring, mp->b_wptr, wrap_size);
1328cde2885fSGarrett D'Amore 				mp->b_wptr += wrap_size;
1329cde2885fSGarrett D'Amore 				*mpp = mp;
1330cde2885fSGarrett D'Amore 				mpp = &mp->b_next;
1331cde2885fSGarrett D'Amore 
1332cde2885fSGarrett D'Amore 				rtlsp->stats.ipackets++;
1333cde2885fSGarrett D'Amore 				if (rx_status & RX_HEADER_STATUS_BCAST)
1334cde2885fSGarrett D'Amore 					rtlsp->stats.brdcst_rcv++;
1335cde2885fSGarrett D'Amore 				if (rx_status & RX_HEADER_STATUS_MULTI)
1336cde2885fSGarrett D'Amore 					rtlsp->stats.multi_rcv++;
1337cde2885fSGarrett D'Amore 				rtlsp->stats.rbytes += packet_len;
1338cde2885fSGarrett D'Amore 			} else  {
1339cde2885fSGarrett D'Amore 				rtlsp->stats.no_rcvbuf++;
1340cde2885fSGarrett D'Amore 			}
1341cde2885fSGarrett D'Amore 
1342cde2885fSGarrett D'Amore 			cur_rx = RTLS_RX_ADDR_ALIGNED(wrap_size + ETHERFCSL);
1343cde2885fSGarrett D'Amore 							/* 4-byte aligned */
1344cde2885fSGarrett D'Amore 		} else {
1345cde2885fSGarrett D'Amore 
1346cde2885fSGarrett D'Amore 			if (mp != NULL) {
1347cde2885fSGarrett D'Amore 				/* Flush caches */
1348cde2885fSGarrett D'Amore 				(void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl,
1349cde2885fSGarrett D'Amore 				    cur_rx + RX_HEADER_SIZE, packet_len,
1350cde2885fSGarrett D'Amore 				    DDI_DMA_SYNC_FORKERNEL);
1351cde2885fSGarrett D'Amore 				bcopy(rx_ptr + RX_HEADER_SIZE, mp->b_wptr,
1352cde2885fSGarrett D'Amore 				    packet_len);
1353cde2885fSGarrett D'Amore 				mp->b_wptr += packet_len;
1354cde2885fSGarrett D'Amore 				*mpp = mp;
1355cde2885fSGarrett D'Amore 				mpp = &mp->b_next;
1356cde2885fSGarrett D'Amore 
1357cde2885fSGarrett D'Amore 				rtlsp->stats.ipackets++;
1358cde2885fSGarrett D'Amore 				if (rx_status & RX_HEADER_STATUS_BCAST)
1359cde2885fSGarrett D'Amore 					rtlsp->stats.brdcst_rcv++;
1360cde2885fSGarrett D'Amore 				if (rx_status & RX_HEADER_STATUS_MULTI)
1361cde2885fSGarrett D'Amore 					rtlsp->stats.multi_rcv++;
1362cde2885fSGarrett D'Amore 				rtlsp->stats.rbytes += packet_len;
1363cde2885fSGarrett D'Amore 			} else {
1364cde2885fSGarrett D'Amore 				rtlsp->stats.no_rcvbuf++;
1365cde2885fSGarrett D'Amore 			}
1366cde2885fSGarrett D'Amore 			cur_rx += packet_len + RX_HEADER_SIZE + ETHERFCSL;
1367cde2885fSGarrett D'Amore 
1368cde2885fSGarrett D'Amore 			cur_rx = RTLS_RX_ADDR_ALIGNED(cur_rx);
1369cde2885fSGarrett D'Amore 							/* 4-byte aligned */
1370cde2885fSGarrett D'Amore 		}
1371cde2885fSGarrett D'Amore 
1372cde2885fSGarrett D'Amore 		/*
1373cde2885fSGarrett D'Amore 		 * Update rx buffer ring read pointer:
1374cde2885fSGarrett D'Amore 		 * give us a little leeway to ensure no overflow
1375cde2885fSGarrett D'Amore 		 */
1376cde2885fSGarrett D'Amore 		rtlsp->cur_rx = cur_rx;
1377cde2885fSGarrett D'Amore 		rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG,
1378cde2885fSGarrett D'Amore 		    cur_rx - READ_ADDR_GAP);
1379cde2885fSGarrett D'Amore 	}
1380cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_rx_lock);
1381cde2885fSGarrett D'Amore 
1382cde2885fSGarrett D'Amore 	/*
1383cde2885fSGarrett D'Amore 	 * Upsend packet
1384cde2885fSGarrett D'Amore 	 */
1385cde2885fSGarrett D'Amore 	if (head) {
1386cde2885fSGarrett D'Amore 		mac_rx(rtlsp->mh, NULL, head);
1387cde2885fSGarrett D'Amore 	}
1388cde2885fSGarrett D'Amore }
1389cde2885fSGarrett D'Amore 
1390cde2885fSGarrett D'Amore /*
1391cde2885fSGarrett D'Amore  * rtls_intr() -- interrupt from board to inform us that a receive or
1392cde2885fSGarrett D'Amore  * link change.
1393cde2885fSGarrett D'Amore  */
1394cde2885fSGarrett D'Amore static uint_t
rtls_intr(caddr_t arg)1395cde2885fSGarrett D'Amore rtls_intr(caddr_t arg)
1396cde2885fSGarrett D'Amore {
1397cde2885fSGarrett D'Amore 	rtls_t *rtlsp = (void *)arg;
1398cde2885fSGarrett D'Amore 	uint32_t int_status;
1399cde2885fSGarrett D'Amore 	uint32_t val32;
1400bbb1277bSGarrett D'Amore 	boolean_t	resched = B_FALSE;
1401cde2885fSGarrett D'Amore 
1402cde2885fSGarrett D'Amore 	mutex_enter(&rtlsp->rtls_io_lock);
1403bbb1277bSGarrett D'Amore 	if (rtlsp->rtls_suspended) {
1404bbb1277bSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_io_lock);
1405bbb1277bSGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
1406bbb1277bSGarrett D'Amore 	}
1407cde2885fSGarrett D'Amore 
1408cde2885fSGarrett D'Amore 	/*
1409cde2885fSGarrett D'Amore 	 * Was this interrupt caused by our device...
1410cde2885fSGarrett D'Amore 	 */
1411cde2885fSGarrett D'Amore 	int_status = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
1412cde2885fSGarrett D'Amore 	if (!(int_status & rtlsp->int_mask)) {
1413cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_io_lock);
1414cde2885fSGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
1415cde2885fSGarrett D'Amore 				/* indicate it wasn't our interrupt */
1416cde2885fSGarrett D'Amore 	}
1417cde2885fSGarrett D'Amore 
1418cde2885fSGarrett D'Amore 	/*
1419cde2885fSGarrett D'Amore 	 * Clear interrupt
1420cde2885fSGarrett D'Amore 	 */
1421cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, int_status);
1422cde2885fSGarrett D'Amore 
1423cde2885fSGarrett D'Amore 	/*
1424cde2885fSGarrett D'Amore 	 * If chip error, restart chip...
1425cde2885fSGarrett D'Amore 	 */
1426cde2885fSGarrett D'Amore 	if (rtlsp->chip_error) {
1427cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_rx_lock);
1428cde2885fSGarrett D'Amore 		mutex_enter(&rtlsp->rtls_tx_lock);
1429cde2885fSGarrett D'Amore 		rtls_chip_restart(rtlsp);
1430cde2885fSGarrett D'Amore 		rtlsp->chip_error = B_FALSE;
1431cde2885fSGarrett D'Amore 		rtlsp->tx_retry = 0;
1432cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_tx_lock);
1433cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_rx_lock);
1434cde2885fSGarrett D'Amore 		mutex_exit(&rtlsp->rtls_io_lock);
1435cde2885fSGarrett D'Amore 		return (DDI_INTR_CLAIMED);
1436cde2885fSGarrett D'Amore 			/* no need to hand other interrupts */
1437cde2885fSGarrett D'Amore 	}
1438cde2885fSGarrett D'Amore 
1439cde2885fSGarrett D'Amore 	/*
1440cde2885fSGarrett D'Amore 	 * Transmit error interrupt
1441cde2885fSGarrett D'Amore 	 */
1442cde2885fSGarrett D'Amore 	if (int_status & TX_ERR_INT) {
1443cde2885fSGarrett D'Amore 		val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG);
1444cde2885fSGarrett D'Amore 		val32 |= TX_CLEAR_ABORT;
1445cde2885fSGarrett D'Amore 		rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32);
1446*2c6a6ad1SIlya Yanok 		cmn_err(CE_WARN, "%s: transmit abort!!!", mac_name(rtlsp->mh));
1447cde2885fSGarrett D'Amore 	}
1448cde2885fSGarrett D'Amore 
1449cde2885fSGarrett D'Amore 	/*
1450cde2885fSGarrett D'Amore 	 * Trigger mac_tx_update
1451cde2885fSGarrett D'Amore 	 */
1452bbb1277bSGarrett D'Amore 	if (rtlsp->need_sched) {
1453bbb1277bSGarrett D'Amore 		rtlsp->need_sched = B_FALSE;
1454bbb1277bSGarrett D'Amore 		resched = B_TRUE;
1455cde2885fSGarrett D'Amore 	}
1456cde2885fSGarrett D'Amore 
1457cde2885fSGarrett D'Amore 	mutex_exit(&rtlsp->rtls_io_lock);
1458cde2885fSGarrett D'Amore 
1459cde2885fSGarrett D'Amore 	/*
1460cde2885fSGarrett D'Amore 	 * Receive interrupt
1461cde2885fSGarrett D'Amore 	 */
1462cde2885fSGarrett D'Amore 	if (int_status & RTLS_RX_INT) {
1463cde2885fSGarrett D'Amore 		if (int_status & RX_OVERFLOW_INT) {
1464cde2885fSGarrett D'Amore 			rtlsp->stats.overflow++;
1465cde2885fSGarrett D'Amore 			rtlsp->stats.rcv_err++;
1466cde2885fSGarrett D'Amore 		}
1467cde2885fSGarrett D'Amore 		rtls_receive(rtlsp);
1468cde2885fSGarrett D'Amore 	}
1469cde2885fSGarrett D'Amore 
1470bbb1277bSGarrett D'Amore 	/*
1471bbb1277bSGarrett D'Amore 	 * Link change interrupt.
1472bbb1277bSGarrett D'Amore 	 */
1473bbb1277bSGarrett D'Amore 	if (int_status & LINK_CHANGE_INT) {
1474bbb1277bSGarrett D'Amore 		mii_check(rtlsp->mii);
1475cde2885fSGarrett D'Amore 	}
1476cde2885fSGarrett D'Amore 
1477bbb1277bSGarrett D'Amore 	if (resched) {
1478cde2885fSGarrett D'Amore 		mac_tx_update(rtlsp->mh);
1479cde2885fSGarrett D'Amore 	}
1480cde2885fSGarrett D'Amore 
1481bbb1277bSGarrett D'Amore 	return (DDI_INTR_CLAIMED);	/* indicate it was our interrupt */
1482cde2885fSGarrett D'Amore }
1483cde2885fSGarrett D'Amore 
1484cde2885fSGarrett D'Amore /*
1485cde2885fSGarrett D'Amore  *    ========== Buffer Management Routines ==========
1486cde2885fSGarrett D'Amore  */
1487cde2885fSGarrett D'Amore 
1488cde2885fSGarrett D'Amore /*
1489cde2885fSGarrett D'Amore  * rtls_alloc_dma_mem() -- allocate an area of memory and a DMA handle
1490cde2885fSGarrett D'Amore  * for accessing it
1491cde2885fSGarrett D'Amore  */
1492cde2885fSGarrett D'Amore static int
rtls_alloc_dma_mem(rtls_t * rtlsp,size_t memsize,ddi_device_acc_attr_t * attr_p,uint_t dma_flags,dma_area_t * dma_p)1493cde2885fSGarrett D'Amore rtls_alloc_dma_mem(rtls_t *rtlsp, size_t memsize,
1494cde2885fSGarrett D'Amore 	ddi_device_acc_attr_t *attr_p, uint_t dma_flags, dma_area_t *dma_p)
1495cde2885fSGarrett D'Amore {
1496cde2885fSGarrett D'Amore 	caddr_t vaddr;
1497cde2885fSGarrett D'Amore 	int err;
1498cde2885fSGarrett D'Amore 
1499cde2885fSGarrett D'Amore 	/*
1500cde2885fSGarrett D'Amore 	 * Allocate handle
1501cde2885fSGarrett D'Amore 	 */
1502cde2885fSGarrett D'Amore 	err = ddi_dma_alloc_handle(rtlsp->devinfo, &dma_attr,
1503cde2885fSGarrett D'Amore 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
1504cde2885fSGarrett D'Amore 	if (err != DDI_SUCCESS) {
1505cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
1506cde2885fSGarrett D'Amore 		    "%s: rtls_alloc_dma_mem: ddi_dma_alloc_handle failed: %d",
1507*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh), err);
1508cde2885fSGarrett D'Amore 		dma_p->dma_hdl = NULL;
1509cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
1510cde2885fSGarrett D'Amore 	}
1511cde2885fSGarrett D'Amore 
1512cde2885fSGarrett D'Amore 	/*
1513cde2885fSGarrett D'Amore 	 * Allocate memory
1514cde2885fSGarrett D'Amore 	 */
1515cde2885fSGarrett D'Amore 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
1516cde2885fSGarrett D'Amore 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
1517cde2885fSGarrett D'Amore 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
1518cde2885fSGarrett D'Amore 	if (err != DDI_SUCCESS) {
1519cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
1520cde2885fSGarrett D'Amore 		    "%s: rtls_alloc_dma_mem: ddi_dma_mem_alloc failed: %d",
1521*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh), err);
1522cde2885fSGarrett D'Amore 		ddi_dma_free_handle(&dma_p->dma_hdl);
1523cde2885fSGarrett D'Amore 		dma_p->dma_hdl = NULL;
1524cde2885fSGarrett D'Amore 		dma_p->acc_hdl = NULL;
1525cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
1526cde2885fSGarrett D'Amore 	}
1527cde2885fSGarrett D'Amore 
1528cde2885fSGarrett D'Amore 	/*
1529cde2885fSGarrett D'Amore 	 * Bind the two together
1530cde2885fSGarrett D'Amore 	 */
1531cde2885fSGarrett D'Amore 	dma_p->mem_va = vaddr;
1532cde2885fSGarrett D'Amore 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1533cde2885fSGarrett D'Amore 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
1534cde2885fSGarrett D'Amore 	    &dma_p->cookie, &dma_p->ncookies);
1535cde2885fSGarrett D'Amore 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) {
1536cde2885fSGarrett D'Amore 		cmn_err(CE_WARN,
1537cde2885fSGarrett D'Amore 		    "%s: rtls_alloc_dma_mem: "
1538cde2885fSGarrett D'Amore 		    "ddi_dma_addr_bind_handle failed: %d",
1539*2c6a6ad1SIlya Yanok 		    mac_name(rtlsp->mh), err);
1540cde2885fSGarrett D'Amore 		ddi_dma_mem_free(&dma_p->acc_hdl);
1541cde2885fSGarrett D'Amore 		ddi_dma_free_handle(&dma_p->dma_hdl);
1542cde2885fSGarrett D'Amore 		dma_p->acc_hdl = NULL;
1543cde2885fSGarrett D'Amore 		dma_p->dma_hdl = NULL;
1544cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
1545cde2885fSGarrett D'Amore 	}
1546cde2885fSGarrett D'Amore 
1547cde2885fSGarrett D'Amore 	return (DDI_SUCCESS);
1548cde2885fSGarrett D'Amore }
1549cde2885fSGarrett D'Amore 
1550cde2885fSGarrett D'Amore /*
1551cde2885fSGarrett D'Amore  * rtls_free_dma_mem() -- free one allocated area of DMAable memory
1552cde2885fSGarrett D'Amore  */
1553cde2885fSGarrett D'Amore static void
rtls_free_dma_mem(dma_area_t * dma_p)1554cde2885fSGarrett D'Amore rtls_free_dma_mem(dma_area_t *dma_p)
1555cde2885fSGarrett D'Amore {
1556cde2885fSGarrett D'Amore 	if (dma_p->dma_hdl != NULL) {
1557cde2885fSGarrett D'Amore 		if (dma_p->ncookies) {
1558cde2885fSGarrett D'Amore 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1559cde2885fSGarrett D'Amore 			dma_p->ncookies = 0;
1560cde2885fSGarrett D'Amore 		}
1561cde2885fSGarrett D'Amore 		ddi_dma_free_handle(&dma_p->dma_hdl);
1562cde2885fSGarrett D'Amore 		dma_p->dma_hdl = NULL;
1563cde2885fSGarrett D'Amore 	}
1564cde2885fSGarrett D'Amore 
1565cde2885fSGarrett D'Amore 	if (dma_p->acc_hdl != NULL) {
1566cde2885fSGarrett D'Amore 		ddi_dma_mem_free(&dma_p->acc_hdl);
1567cde2885fSGarrett D'Amore 		dma_p->acc_hdl = NULL;
1568cde2885fSGarrett D'Amore 	}
1569cde2885fSGarrett D'Amore }
1570cde2885fSGarrett D'Amore 
1571cde2885fSGarrett D'Amore /*
1572cde2885fSGarrett D'Amore  * rtls_alloc_bufs() -- allocate descriptors/buffers for this device instance
1573cde2885fSGarrett D'Amore  */
1574cde2885fSGarrett D'Amore static int
rtls_alloc_bufs(rtls_t * rtlsp)1575cde2885fSGarrett D'Amore rtls_alloc_bufs(rtls_t *rtlsp)
1576cde2885fSGarrett D'Amore {
1577cde2885fSGarrett D'Amore 	int i;
1578cde2885fSGarrett D'Amore 	int err;
1579cde2885fSGarrett D'Amore 
1580cde2885fSGarrett D'Amore 	/*
1581cde2885fSGarrett D'Amore 	 * Allocate memory & handle for Tx buffers
1582cde2885fSGarrett D'Amore 	 */
1583cde2885fSGarrett D'Amore 	for (i = 0; i < RTLS_MAX_TX_DESC; i++) {
1584cde2885fSGarrett D'Amore 		err = rtls_alloc_dma_mem(rtlsp,
1585cde2885fSGarrett D'Amore 		    RTLS_TX_BUF_SIZE,
1586cde2885fSGarrett D'Amore 		    &rtls_buf_accattr,
1587cde2885fSGarrett D'Amore 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
1588cde2885fSGarrett D'Amore 		    &rtlsp->dma_area_tx[i]);
1589cde2885fSGarrett D'Amore 
1590cde2885fSGarrett D'Amore 		if (err != DDI_SUCCESS)
1591cde2885fSGarrett D'Amore 			return (DDI_FAILURE);
1592cde2885fSGarrett D'Amore 
1593cde2885fSGarrett D'Amore 		rtlsp->tx_buf[i] = (uint8_t *)rtlsp->dma_area_tx[i].mem_va;
1594cde2885fSGarrett D'Amore 	}
1595cde2885fSGarrett D'Amore 
1596cde2885fSGarrett D'Amore 	/*
1597cde2885fSGarrett D'Amore 	 * Allocate memory & handle for Rx buffers
1598cde2885fSGarrett D'Amore 	 */
1599cde2885fSGarrett D'Amore 	err = rtls_alloc_dma_mem(rtlsp,
1600cde2885fSGarrett D'Amore 	    RTLS_RX_BUF_SIZE,
1601cde2885fSGarrett D'Amore 	    &rtls_buf_accattr,
1602cde2885fSGarrett D'Amore 	    DDI_DMA_READ | DDI_DMA_STREAMING,
1603cde2885fSGarrett D'Amore 	    &rtlsp->dma_area_rx);
1604cde2885fSGarrett D'Amore 
1605cde2885fSGarrett D'Amore 	if (err != DDI_SUCCESS)
1606cde2885fSGarrett D'Amore 		return (DDI_FAILURE);
1607cde2885fSGarrett D'Amore 
1608cde2885fSGarrett D'Amore 	rtlsp->rx_ring = (uint8_t *)rtlsp->dma_area_rx.mem_va;
1609cde2885fSGarrett D'Amore 
1610cde2885fSGarrett D'Amore 	return (DDI_SUCCESS);
1611cde2885fSGarrett D'Amore }
1612cde2885fSGarrett D'Amore 
1613cde2885fSGarrett D'Amore /*
1614cde2885fSGarrett D'Amore  * rtls_free_bufs() -- free descriptors/buffers allocated for this
1615cde2885fSGarrett D'Amore  * device instance.
1616cde2885fSGarrett D'Amore  */
1617cde2885fSGarrett D'Amore static void
rtls_free_bufs(rtls_t * rtlsp)1618cde2885fSGarrett D'Amore rtls_free_bufs(rtls_t *rtlsp)
1619cde2885fSGarrett D'Amore {
1620cde2885fSGarrett D'Amore 	int i;
1621cde2885fSGarrett D'Amore 
1622cde2885fSGarrett D'Amore 	for (i = 0; i < RTLS_MAX_TX_DESC; i++) {
1623cde2885fSGarrett D'Amore 		rtls_free_dma_mem(&rtlsp->dma_area_tx[i]);
1624cde2885fSGarrett D'Amore 		rtlsp->tx_buf[i] = NULL;
1625cde2885fSGarrett D'Amore 	}
1626cde2885fSGarrett D'Amore 
1627cde2885fSGarrett D'Amore 	rtls_free_dma_mem(&rtlsp->dma_area_rx);
1628cde2885fSGarrett D'Amore 	rtlsp->rx_ring = NULL;
1629cde2885fSGarrett D'Amore }
1630cde2885fSGarrett D'Amore 
1631cde2885fSGarrett D'Amore /*
1632cde2885fSGarrett D'Amore  *    ========== Chip H/W Operation Routines ==========
1633cde2885fSGarrett D'Amore  */
1634cde2885fSGarrett D'Amore 
1635cde2885fSGarrett D'Amore /*
1636cde2885fSGarrett D'Amore  * rtls_chip_reset() -- reset chip
1637cde2885fSGarrett D'Amore  */
1638cde2885fSGarrett D'Amore static int
rtls_chip_reset(rtls_t * rtlsp,boolean_t quiesce)1639cde2885fSGarrett D'Amore rtls_chip_reset(rtls_t *rtlsp, boolean_t quiesce)
1640cde2885fSGarrett D'Amore {
1641cde2885fSGarrett D'Amore 	int i;
1642cde2885fSGarrett D'Amore 	uint16_t val16;
1643cde2885fSGarrett D'Amore 	uint8_t val8;
1644cde2885fSGarrett D'Amore 
1645cde2885fSGarrett D'Amore 	/*
1646cde2885fSGarrett D'Amore 	 * Chip should be in STOP state
1647cde2885fSGarrett D'Amore 	 */
1648cde2885fSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
1649cde2885fSGarrett D'Amore 	val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1650cde2885fSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8);
1651cde2885fSGarrett D'Amore 
1652cde2885fSGarrett D'Amore 	/*
1653cde2885fSGarrett D'Amore 	 * Disable interrupt
1654cde2885fSGarrett D'Amore 	 */
1655cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
1656cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL));
1657cde2885fSGarrett D'Amore 	rtlsp->int_mask = RTLS_INT_MASK_NONE;
1658cde2885fSGarrett D'Amore 
1659cde2885fSGarrett D'Amore 	/*
1660cde2885fSGarrett D'Amore 	 * Clear pended interrupt
1661cde2885fSGarrett D'Amore 	 */
1662cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
1663cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16);
1664cde2885fSGarrett D'Amore 
1665cde2885fSGarrett D'Amore 	/*
1666cde2885fSGarrett D'Amore 	 * Reset chip
1667cde2885fSGarrett D'Amore 	 */
1668cde2885fSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
1669cde2885fSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8 | RT_COMMAND_RESET);
1670cde2885fSGarrett D'Amore 
1671cde2885fSGarrett D'Amore 	/*
1672cde2885fSGarrett D'Amore 	 * Wait for reset success
1673cde2885fSGarrett D'Amore 	 */
1674cde2885fSGarrett D'Amore 	i = 0;
1675cde2885fSGarrett D'Amore 	while (rtls_reg_get8(rtlsp, RT_COMMAND_REG) & RT_COMMAND_RESET) {
1676cde2885fSGarrett D'Amore 		if (++i > RTLS_RESET_WAIT_NUM) {
1677cde2885fSGarrett D'Amore 			/*
1678cde2885fSGarrett D'Amore 			 * At quiesce path we can't call cmn_err(), as
1679cde2885fSGarrett D'Amore 			 * it might block
1680cde2885fSGarrett D'Amore 			 */
1681cde2885fSGarrett D'Amore 			if (!quiesce)
1682cde2885fSGarrett D'Amore 				cmn_err(CE_WARN,
1683*2c6a6ad1SIlya Yanok 				    "%s: chip reset fail.",
1684*2c6a6ad1SIlya Yanok 				    mac_name(rtlsp->mh));
1685cde2885fSGarrett D'Amore 			return (DDI_FAILURE);
1686cde2885fSGarrett D'Amore 		}
1687cde2885fSGarrett D'Amore 		RTLS_RESET_WAIT_INTERVAL;
1688cde2885fSGarrett D'Amore 	}
1689cde2885fSGarrett D'Amore 
1690cde2885fSGarrett D'Amore 	return (DDI_SUCCESS);
1691cde2885fSGarrett D'Amore }
1692cde2885fSGarrett D'Amore 
1693cde2885fSGarrett D'Amore /*
1694cde2885fSGarrett D'Amore  * rtls_chip_init() -- initialize the specified network board short of
1695cde2885fSGarrett D'Amore  * actually starting the board.  Call after rtls_chip_reset().
1696cde2885fSGarrett D'Amore  */
1697cde2885fSGarrett D'Amore static void
rtls_chip_init(rtls_t * rtlsp)1698cde2885fSGarrett D'Amore rtls_chip_init(rtls_t *rtlsp)
1699cde2885fSGarrett D'Amore {
1700cde2885fSGarrett D'Amore 	uint32_t val32;
1701cde2885fSGarrett D'Amore 	uint16_t val16;
1702cde2885fSGarrett D'Amore 	uint8_t val8;
1703cde2885fSGarrett D'Amore 
1704cde2885fSGarrett D'Amore 	/*
1705cde2885fSGarrett D'Amore 	 * Initialize internal data structures
1706cde2885fSGarrett D'Amore 	 */
1707cde2885fSGarrett D'Amore 	rtlsp->cur_rx = 0;
1708cde2885fSGarrett D'Amore 	rtlsp->tx_current_desc = 0;
1709cde2885fSGarrett D'Amore 	rtlsp->tx_first_loop = 0;
1710cde2885fSGarrett D'Amore 
1711cde2885fSGarrett D'Amore 	/*
1712cde2885fSGarrett D'Amore 	 * Set DMA physical rx/tx buffer address to register
1713cde2885fSGarrett D'Amore 	 */
1714cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, RX_BUFF_ADDR_REG,
1715cde2885fSGarrett D'Amore 	    (ulong_t)rtlsp->dma_area_rx.cookie.dmac_address);
1716cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, TX_ADDR_DESC0_REG,
1717cde2885fSGarrett D'Amore 	    (ulong_t)rtlsp->dma_area_tx[0].cookie.dmac_address);
1718cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, TX_ADDR_DESC1_REG,
1719cde2885fSGarrett D'Amore 	    (ulong_t)rtlsp->dma_area_tx[1].cookie.dmac_address);
1720cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, TX_ADDR_DESC2_REG,
1721cde2885fSGarrett D'Amore 	    (ulong_t)rtlsp->dma_area_tx[2].cookie.dmac_address);
1722cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, TX_ADDR_DESC3_REG,
1723cde2885fSGarrett D'Amore 	    (ulong_t)rtlsp->dma_area_tx[3].cookie.dmac_address);
1724cde2885fSGarrett D'Amore 
1725cde2885fSGarrett D'Amore 	/*
1726cde2885fSGarrett D'Amore 	 * Start transmit/receive before set tx/rx configuration register
1727cde2885fSGarrett D'Amore 	 */
1728cde2885fSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
1729cde2885fSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_COMMAND_REG,
1730cde2885fSGarrett D'Amore 	    val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1731cde2885fSGarrett D'Amore 
1732cde2885fSGarrett D'Amore 	/*
1733cde2885fSGarrett D'Amore 	 * Set transmit configuration register
1734cde2885fSGarrett D'Amore 	 */
1735cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG);
1736cde2885fSGarrett D'Amore 	val32 &= TX_CONSIG_REG_RESERVE;
1737cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32 | TX_CONFIG_DEFAULT);
1738cde2885fSGarrett D'Amore 
1739cde2885fSGarrett D'Amore 	/*
1740cde2885fSGarrett D'Amore 	 * Set receive configuration register
1741cde2885fSGarrett D'Amore 	 */
1742cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG);
1743cde2885fSGarrett D'Amore 	val32 &= RX_CONSIG_REG_RESERVE;
1744cde2885fSGarrett D'Amore 	if (rtlsp->promisc)
1745cde2885fSGarrett D'Amore 		val32 |= RX_ACCEPT_ALL_PACKET;
1746cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32 | RX_CONFIG_DEFAULT);
1747cde2885fSGarrett D'Amore 
1748cde2885fSGarrett D'Amore 	/*
1749cde2885fSGarrett D'Amore 	 * Set multicast register
1750cde2885fSGarrett D'Amore 	 */
1751cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, MULTICAST_0_REG, rtlsp->multi_hash[0]);
1752cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, MULTICAST_4_REG, rtlsp->multi_hash[1]);
1753cde2885fSGarrett D'Amore 
1754cde2885fSGarrett D'Amore 	/*
1755cde2885fSGarrett D'Amore 	 * Set unicast address
1756cde2885fSGarrett D'Amore 	 */
1757cde2885fSGarrett D'Amore 	rtls_set_mac_addr(rtlsp, rtlsp->netaddr);
1758cde2885fSGarrett D'Amore 
1759cde2885fSGarrett D'Amore 	/*
1760cde2885fSGarrett D'Amore 	 * Set current address of packet read
1761cde2885fSGarrett D'Amore 	 */
1762cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG, RX_READ_RESET_VAL);
1763cde2885fSGarrett D'Amore 
1764cde2885fSGarrett D'Amore 	/*
1765cde2885fSGarrett D'Amore 	 * No early-rx interrupts
1766cde2885fSGarrett D'Amore 	 */
1767cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_MUL_INTSEL_REG);
1768cde2885fSGarrett D'Amore 	val16 &= ~RT_MUL_INTSEL_BITS;
1769cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_MUL_INTSEL_REG, val16);
1770cde2885fSGarrett D'Amore }
1771cde2885fSGarrett D'Amore 
1772cde2885fSGarrett D'Amore /*
1773cde2885fSGarrett D'Amore  * rtls_chip_start() -- start chip
1774cde2885fSGarrett D'Amore  */
1775cde2885fSGarrett D'Amore static void
rtls_chip_start(rtls_t * rtlsp)1776cde2885fSGarrett D'Amore rtls_chip_start(rtls_t *rtlsp)
1777cde2885fSGarrett D'Amore {
1778cde2885fSGarrett D'Amore 	uint16_t val16;
1779cde2885fSGarrett D'Amore 	uint8_t val8;
1780cde2885fSGarrett D'Amore 
1781cde2885fSGarrett D'Amore 	/*
1782cde2885fSGarrett D'Amore 	 * Start transmit/receive
1783cde2885fSGarrett D'Amore 	 */
1784cde2885fSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
1785cde2885fSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_COMMAND_REG,
1786cde2885fSGarrett D'Amore 	    val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1787cde2885fSGarrett D'Amore 
1788cde2885fSGarrett D'Amore 	/*
1789cde2885fSGarrett D'Amore 	 * Enable interrupt
1790cde2885fSGarrett D'Amore 	 */
1791cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
1792cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 | RTLS_INT_MASK);
1793cde2885fSGarrett D'Amore 	rtlsp->int_mask = RTLS_INT_MASK;
1794cde2885fSGarrett D'Amore }
1795cde2885fSGarrett D'Amore 
1796cde2885fSGarrett D'Amore /*
1797cde2885fSGarrett D'Amore  * rtls_chip_restart() -- restart chip
1798cde2885fSGarrett D'Amore  */
1799cde2885fSGarrett D'Amore static void
rtls_chip_restart(rtls_t * rtlsp)1800cde2885fSGarrett D'Amore rtls_chip_restart(rtls_t *rtlsp)
1801cde2885fSGarrett D'Amore {
1802cde2885fSGarrett D'Amore 	(void) rtls_chip_reset(rtlsp, B_FALSE);
1803cde2885fSGarrett D'Amore 	rtls_chip_init(rtlsp);
1804cde2885fSGarrett D'Amore 	rtls_chip_start(rtlsp);
1805cde2885fSGarrett D'Amore }
1806cde2885fSGarrett D'Amore 
1807cde2885fSGarrett D'Amore /*
1808cde2885fSGarrett D'Amore  * rtls_chip_stop() -- stop board receiving
1809cde2885fSGarrett D'Amore  */
1810cde2885fSGarrett D'Amore static void
rtls_chip_stop(rtls_t * rtlsp)1811cde2885fSGarrett D'Amore rtls_chip_stop(rtls_t *rtlsp)
1812cde2885fSGarrett D'Amore {
1813cde2885fSGarrett D'Amore 	uint16_t val16;
1814cde2885fSGarrett D'Amore 	uint8_t val8;
1815cde2885fSGarrett D'Amore 
1816cde2885fSGarrett D'Amore 	/*
1817cde2885fSGarrett D'Amore 	 * Disable interrupt
1818cde2885fSGarrett D'Amore 	 */
1819cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
1820cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL));
1821cde2885fSGarrett D'Amore 	rtlsp->int_mask = RTLS_INT_MASK_NONE;
1822cde2885fSGarrett D'Amore 
1823cde2885fSGarrett D'Amore 	/*
1824cde2885fSGarrett D'Amore 	 * Clear pended interrupt
1825cde2885fSGarrett D'Amore 	 */
1826cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
1827cde2885fSGarrett D'Amore 	rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16);
1828cde2885fSGarrett D'Amore 
1829cde2885fSGarrett D'Amore 	/*
1830cde2885fSGarrett D'Amore 	 * Stop the board and disable transmit/receive
1831cde2885fSGarrett D'Amore 	 */
1832cde2885fSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
1833cde2885fSGarrett D'Amore 	val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1834cde2885fSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8);
1835cde2885fSGarrett D'Amore }
1836cde2885fSGarrett D'Amore 
1837cde2885fSGarrett D'Amore /*
1838cde2885fSGarrett D'Amore  * rtls_get_mac_addr() -- get the physical network address on the board
1839cde2885fSGarrett D'Amore  */
1840cde2885fSGarrett D'Amore static void
rtls_get_mac_addr(rtls_t * rtlsp,uint8_t * macaddr)1841cde2885fSGarrett D'Amore rtls_get_mac_addr(rtls_t *rtlsp, uint8_t *macaddr)
1842cde2885fSGarrett D'Amore {
1843cde2885fSGarrett D'Amore 	uint32_t val32;
1844cde2885fSGarrett D'Amore 
1845cde2885fSGarrett D'Amore 	/*
1846cde2885fSGarrett D'Amore 	 * Read first 4-byte of mac address
1847cde2885fSGarrett D'Amore 	 */
1848cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, ID_0_REG);
1849cde2885fSGarrett D'Amore 	macaddr[0] = val32 & 0xff;
1850cde2885fSGarrett D'Amore 	val32 = val32 >> 8;
1851cde2885fSGarrett D'Amore 	macaddr[1] = val32 & 0xff;
1852cde2885fSGarrett D'Amore 	val32 = val32 >> 8;
1853cde2885fSGarrett D'Amore 	macaddr[2] = val32 & 0xff;
1854cde2885fSGarrett D'Amore 	val32 = val32 >> 8;
1855cde2885fSGarrett D'Amore 	macaddr[3] = val32 & 0xff;
1856cde2885fSGarrett D'Amore 
1857cde2885fSGarrett D'Amore 	/*
1858cde2885fSGarrett D'Amore 	 * Read last 2-byte of mac address
1859cde2885fSGarrett D'Amore 	 */
1860cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, ID_4_REG);
1861cde2885fSGarrett D'Amore 	macaddr[4] = val32 & 0xff;
1862cde2885fSGarrett D'Amore 	val32 = val32 >> 8;
1863cde2885fSGarrett D'Amore 	macaddr[5] = val32 & 0xff;
1864cde2885fSGarrett D'Amore }
1865cde2885fSGarrett D'Amore 
1866cde2885fSGarrett D'Amore static void
rtls_set_mac_addr(rtls_t * rtlsp,const uint8_t * macaddr)1867cde2885fSGarrett D'Amore rtls_set_mac_addr(rtls_t *rtlsp, const uint8_t *macaddr)
1868cde2885fSGarrett D'Amore {
1869cde2885fSGarrett D'Amore 	uint32_t val32;
1870cde2885fSGarrett D'Amore 	uint8_t val8;
1871cde2885fSGarrett D'Amore 
1872cde2885fSGarrett D'Amore 	/*
1873cde2885fSGarrett D'Amore 	 * Change to config register write enable mode
1874cde2885fSGarrett D'Amore 	 */
1875bbb1277bSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG);
1876cde2885fSGarrett D'Amore 	val8 |= RT_93c46_MODE_CONFIG;
1877bbb1277bSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1878cde2885fSGarrett D'Amore 
1879cde2885fSGarrett D'Amore 	/*
1880cde2885fSGarrett D'Amore 	 * Get first 4 bytes of mac address
1881cde2885fSGarrett D'Amore 	 */
1882cde2885fSGarrett D'Amore 	val32 = macaddr[3];
1883cde2885fSGarrett D'Amore 	val32 = val32 << 8;
1884cde2885fSGarrett D'Amore 	val32 |= macaddr[2];
1885cde2885fSGarrett D'Amore 	val32 = val32 << 8;
1886cde2885fSGarrett D'Amore 	val32 |= macaddr[1];
1887cde2885fSGarrett D'Amore 	val32 = val32 << 8;
1888cde2885fSGarrett D'Amore 	val32 |= macaddr[0];
1889cde2885fSGarrett D'Amore 
1890cde2885fSGarrett D'Amore 	/*
1891cde2885fSGarrett D'Amore 	 * Set first 4 bytes of mac address
1892cde2885fSGarrett D'Amore 	 */
1893cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, ID_0_REG, val32);
1894cde2885fSGarrett D'Amore 
1895cde2885fSGarrett D'Amore 	/*
1896cde2885fSGarrett D'Amore 	 * Get last 2 bytes of mac address
1897cde2885fSGarrett D'Amore 	 */
1898cde2885fSGarrett D'Amore 	val32 = macaddr[5];
1899cde2885fSGarrett D'Amore 	val32 = val32 << 8;
1900cde2885fSGarrett D'Amore 	val32 |= macaddr[4];
1901cde2885fSGarrett D'Amore 
1902cde2885fSGarrett D'Amore 	/*
1903cde2885fSGarrett D'Amore 	 * Set last 2 bytes of mac address
1904cde2885fSGarrett D'Amore 	 */
1905cde2885fSGarrett D'Amore 	val32 |= rtls_reg_get32(rtlsp, ID_4_REG) & ~0xffff;
1906cde2885fSGarrett D'Amore 	rtls_reg_set32(rtlsp, ID_4_REG, val32);
1907cde2885fSGarrett D'Amore 
1908cde2885fSGarrett D'Amore 	/*
1909cde2885fSGarrett D'Amore 	 * Return to normal network/host communication mode
1910cde2885fSGarrett D'Amore 	 */
1911cde2885fSGarrett D'Amore 	val8 &= ~RT_93c46_MODE_CONFIG;
1912bbb1277bSGarrett D'Amore 	rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1913cde2885fSGarrett D'Amore }
1914cde2885fSGarrett D'Amore 
1915bbb1277bSGarrett D'Amore static uint16_t
rtls_mii_read(void * arg,uint8_t phy,uint8_t reg)1916bbb1277bSGarrett D'Amore rtls_mii_read(void *arg, uint8_t phy, uint8_t reg)
1917cde2885fSGarrett D'Amore {
1918bbb1277bSGarrett D'Amore 	rtls_t		*rtlsp = arg;
1919bbb1277bSGarrett D'Amore 	uint16_t	val;
1920cde2885fSGarrett D'Amore 
1921bbb1277bSGarrett D'Amore 	if (phy != 1) {
1922bbb1277bSGarrett D'Amore 		return (0xffff);
1923cde2885fSGarrett D'Amore 	}
1924bbb1277bSGarrett D'Amore 	switch (reg) {
1925bbb1277bSGarrett D'Amore 	case MII_CONTROL:
1926bbb1277bSGarrett D'Amore 		val = rtls_reg_get16(rtlsp, BASIC_MODE_CONTROL_REG);
1927cde2885fSGarrett D'Amore 		break;
1928bbb1277bSGarrett D'Amore 	case MII_STATUS:
1929bbb1277bSGarrett D'Amore 		val = rtls_reg_get16(rtlsp, BASIC_MODE_STATUS_REG);
1930cde2885fSGarrett D'Amore 		break;
1931bbb1277bSGarrett D'Amore 	case MII_AN_ADVERT:
1932bbb1277bSGarrett D'Amore 		val = rtls_reg_get16(rtlsp, AUTO_NEGO_AD_REG);
1933bbb1277bSGarrett D'Amore 		break;
1934bbb1277bSGarrett D'Amore 	case MII_AN_LPABLE:
1935bbb1277bSGarrett D'Amore 		val = rtls_reg_get16(rtlsp, AUTO_NEGO_LP_REG);
1936cde2885fSGarrett D'Amore 		break;
1937bbb1277bSGarrett D'Amore 	case MII_AN_EXPANSION:
1938bbb1277bSGarrett D'Amore 		val = rtls_reg_get16(rtlsp, AUTO_NEGO_EXP_REG);
1939cde2885fSGarrett D'Amore 		break;
1940bbb1277bSGarrett D'Amore 	case MII_VENDOR(0):
1941cde2885fSGarrett D'Amore 		/*
1942bbb1277bSGarrett D'Amore 		 * We "simulate" a vendor private register so that the
1943bbb1277bSGarrett D'Amore 		 * PHY layer can access it to determine detected link
1944bbb1277bSGarrett D'Amore 		 * speed/duplex.
1945cde2885fSGarrett D'Amore 		 */
1946bbb1277bSGarrett D'Amore 		val = rtls_reg_get8(rtlsp, MEDIA_STATUS_REG);
1947cde2885fSGarrett D'Amore 		break;
1948bbb1277bSGarrett D'Amore 	case MII_PHYIDH:
1949bbb1277bSGarrett D'Amore 	case MII_PHYIDL:
1950bbb1277bSGarrett D'Amore 	default:
1951bbb1277bSGarrett D'Amore 		val = 0;
1952cde2885fSGarrett D'Amore 		break;
1953cde2885fSGarrett D'Amore 	}
1954bbb1277bSGarrett D'Amore 	return (val);
1955bbb1277bSGarrett D'Amore }
1956cde2885fSGarrett D'Amore 
1957bbb1277bSGarrett D'Amore void
rtls_mii_write(void * arg,uint8_t phy,uint8_t reg,uint16_t val)1958bbb1277bSGarrett D'Amore rtls_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
1959bbb1277bSGarrett D'Amore {
1960bbb1277bSGarrett D'Amore 	rtls_t		*rtlsp = arg;
1961bbb1277bSGarrett D'Amore 	uint8_t		val8;
1962cde2885fSGarrett D'Amore 
1963bbb1277bSGarrett D'Amore 	if (phy != 1) {
1964bbb1277bSGarrett D'Amore 		return;
1965bbb1277bSGarrett D'Amore 	}
1966bbb1277bSGarrett D'Amore 	switch (reg) {
1967bbb1277bSGarrett D'Amore 	case MII_CONTROL:
1968bbb1277bSGarrett D'Amore 		/* Enable writes to all bits of BMCR */
1969bbb1277bSGarrett D'Amore 		val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG);
1970bbb1277bSGarrett D'Amore 		val8 |= RT_93c46_MODE_CONFIG;
1971bbb1277bSGarrett D'Amore 		rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1972bbb1277bSGarrett D'Amore 		/* write out the value */
1973bbb1277bSGarrett D'Amore 		rtls_reg_set16(rtlsp, BASIC_MODE_CONTROL_REG, val);
1974bbb1277bSGarrett D'Amore 
1975bbb1277bSGarrett D'Amore 		/* Return to normal network/host communication mode */
1976bbb1277bSGarrett D'Amore 		val8 &= ~RT_93c46_MODE_CONFIG;
1977bbb1277bSGarrett D'Amore 		rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1978bbb1277bSGarrett D'Amore 		return;
1979cde2885fSGarrett D'Amore 
1980bbb1277bSGarrett D'Amore 	case MII_STATUS:
1981bbb1277bSGarrett D'Amore 		rtls_reg_set16(rtlsp, BASIC_MODE_STATUS_REG, val);
1982bbb1277bSGarrett D'Amore 		break;
1983bbb1277bSGarrett D'Amore 	case MII_AN_ADVERT:
1984bbb1277bSGarrett D'Amore 		rtls_reg_set16(rtlsp, AUTO_NEGO_AD_REG, val);
1985bbb1277bSGarrett D'Amore 		break;
1986bbb1277bSGarrett D'Amore 	case MII_AN_LPABLE:
1987bbb1277bSGarrett D'Amore 		rtls_reg_set16(rtlsp, AUTO_NEGO_LP_REG, val);
1988bbb1277bSGarrett D'Amore 		break;
1989bbb1277bSGarrett D'Amore 	case MII_AN_EXPANSION:
1990bbb1277bSGarrett D'Amore 		rtls_reg_set16(rtlsp, AUTO_NEGO_EXP_REG, val);
1991bbb1277bSGarrett D'Amore 		break;
1992bbb1277bSGarrett D'Amore 	case MII_PHYIDH:
1993bbb1277bSGarrett D'Amore 	case MII_PHYIDL:
1994bbb1277bSGarrett D'Amore 	default:
1995bbb1277bSGarrett D'Amore 		/* these are not writable */
1996bbb1277bSGarrett D'Amore 		break;
1997bbb1277bSGarrett D'Amore 	}
1998bbb1277bSGarrett D'Amore }
1999cde2885fSGarrett D'Amore 
2000bbb1277bSGarrett D'Amore void
rtls_mii_notify(void * arg,link_state_t link)2001bbb1277bSGarrett D'Amore rtls_mii_notify(void *arg, link_state_t link)
2002bbb1277bSGarrett D'Amore {
2003bbb1277bSGarrett D'Amore 	rtls_t	*rtlsp = arg;
2004bbb1277bSGarrett D'Amore 
2005bbb1277bSGarrett D'Amore 	mac_link_update(rtlsp->mh, link);
2006cde2885fSGarrett D'Amore }
2007cde2885fSGarrett D'Amore 
2008cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG
2009cde2885fSGarrett D'Amore /*
2010cde2885fSGarrett D'Amore  * rtls_reg_print() -- print out reg value(for debug use only)
2011cde2885fSGarrett D'Amore  */
2012cde2885fSGarrett D'Amore static void
rtls_reg_print(rtls_t * rtlsp)2013cde2885fSGarrett D'Amore rtls_reg_print(rtls_t *rtlsp)
2014cde2885fSGarrett D'Amore {
2015cde2885fSGarrett D'Amore 	uint8_t val8;
2016cde2885fSGarrett D'Amore 	uint16_t val16;
2017cde2885fSGarrett D'Amore 	uint32_t val32;
2018cde2885fSGarrett D'Amore 
2019cde2885fSGarrett D'Amore 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
2020cde2885fSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: RT_COMMAND_REG = 0x%x",
2021*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val8);
2022cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2023cde2885fSGarrett D'Amore 
2024cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
2025cde2885fSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: RT_INT_STATUS_REG = 0x%x",
2026*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val16);
2027cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2028cde2885fSGarrett D'Amore 
2029cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
2030cde2885fSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: RT_INT_MASK_REG = 0x%x",
2031*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val16);
2032cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2033cde2885fSGarrett D'Amore 
2034cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG);
2035cde2885fSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: RX_CONFIG_REG = 0x%x",
2036*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val32);
2037cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2038cde2885fSGarrett D'Amore 
2039cde2885fSGarrett D'Amore 	val16 = rtls_reg_get16(rtlsp, TX_DESC_STAUS_REG);
2040bbb1277bSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: TX_DESC_STAUS_REG = 0x%x, cur_desc = %d",
2041*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val16, rtlsp->tx_current_desc);
2042cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2043cde2885fSGarrett D'Amore 
2044cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG);
2045bbb1277bSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC0_REG = 0x%x",
2046*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val32);
2047cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2048cde2885fSGarrett D'Amore 
2049cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC1_REG);
2050bbb1277bSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC1_REG = 0x%x",
2051*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val32);
2052cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2053cde2885fSGarrett D'Amore 
2054cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC2_REG);
2055bbb1277bSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC2_REG = 0x%x",
2056*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val32);
2057cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2058cde2885fSGarrett D'Amore 
2059cde2885fSGarrett D'Amore 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC3_REG);
2060bbb1277bSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC3_REG = 0x%x",
2061*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh), val32);
2062cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2063cde2885fSGarrett D'Amore 
2064bbb1277bSGarrett D'Amore 	cmn_err(CE_NOTE, "%s: in  = %llu, multicast = %llu, broadcast = %llu",
2065*2c6a6ad1SIlya Yanok 	    mac_name(rtlsp->mh),
2066cde2885fSGarrett D'Amore 	    (unsigned long long)rtlsp->stats.ipackets,
2067cde2885fSGarrett D'Amore 	    (unsigned long long)rtlsp->stats.multi_rcv,
2068cde2885fSGarrett D'Amore 	    (unsigned long long)rtlsp->stats.brdcst_rcv);
2069cde2885fSGarrett D'Amore 	delay(drv_usectohz(1000));
2070cde2885fSGarrett D'Amore }
2071cde2885fSGarrett D'Amore #endif
2072