xref: /illumos-gate/usr/src/uts/common/io/rge/rge_main.c (revision dfc2d53e)
1c7fd2ed0Sgs150176 /*
2c7fd2ed0Sgs150176  * CDDL HEADER START
3c7fd2ed0Sgs150176  *
4c7fd2ed0Sgs150176  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
7c7fd2ed0Sgs150176  *
8c7fd2ed0Sgs150176  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c7fd2ed0Sgs150176  * or http://www.opensolaris.org/os/licensing.
10c7fd2ed0Sgs150176  * See the License for the specific language governing permissions
11c7fd2ed0Sgs150176  * and limitations under the License.
12c7fd2ed0Sgs150176  *
13c7fd2ed0Sgs150176  * When distributing Covered Code, include this CDDL HEADER in each
14c7fd2ed0Sgs150176  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c7fd2ed0Sgs150176  * If applicable, add the following below this CDDL HEADER, with the
16c7fd2ed0Sgs150176  * fields enclosed by brackets "[]" replaced with your own identifying
17c7fd2ed0Sgs150176  * information: Portions Copyright [yyyy] [name of copyright owner]
18c7fd2ed0Sgs150176  *
19c7fd2ed0Sgs150176  * CDDL HEADER END
20c7fd2ed0Sgs150176  */
21c7fd2ed0Sgs150176 /*
220d2a8e5eSgd78059  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23c7fd2ed0Sgs150176  * Use is subject to license terms.
24c7fd2ed0Sgs150176  */
25c7fd2ed0Sgs150176 
26c7fd2ed0Sgs150176 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27c7fd2ed0Sgs150176 
28c7fd2ed0Sgs150176 #include "rge.h"
29c7fd2ed0Sgs150176 
30c7fd2ed0Sgs150176 /*
31c7fd2ed0Sgs150176  * This is the string displayed by modinfo, etc.
32c7fd2ed0Sgs150176  * Make sure you keep the version ID up to date!
33c7fd2ed0Sgs150176  */
34aa817493Sgs150176 static char rge_ident[] = "Realtek 1Gb Ethernet v%I%";
35c7fd2ed0Sgs150176 
36c7fd2ed0Sgs150176 /*
37c7fd2ed0Sgs150176  * Used for buffers allocated by ddi_dma_mem_alloc()
38c7fd2ed0Sgs150176  */
39c7fd2ed0Sgs150176 static ddi_dma_attr_t dma_attr_buf = {
40c7fd2ed0Sgs150176 	DMA_ATTR_V0,		/* dma_attr version */
41c7fd2ed0Sgs150176 	(uint32_t)0,		/* dma_attr_addr_lo */
42c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
43c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_count_max */
44c7fd2ed0Sgs150176 	(uint32_t)16,		/* dma_attr_align */
45c7fd2ed0Sgs150176 	0xFFFFFFFF,		/* dma_attr_burstsizes */
46c7fd2ed0Sgs150176 	1,			/* dma_attr_minxfer */
47c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
48c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_seg */
49c7fd2ed0Sgs150176 	1,			/* dma_attr_sgllen */
50c7fd2ed0Sgs150176 	1,			/* dma_attr_granular */
51c7fd2ed0Sgs150176 	0,			/* dma_attr_flags */
52c7fd2ed0Sgs150176 };
53c7fd2ed0Sgs150176 
54c7fd2ed0Sgs150176 /*
55c7fd2ed0Sgs150176  * Used for BDs allocated by ddi_dma_mem_alloc()
56c7fd2ed0Sgs150176  */
57c7fd2ed0Sgs150176 static ddi_dma_attr_t dma_attr_desc = {
58c7fd2ed0Sgs150176 	DMA_ATTR_V0,		/* dma_attr version */
59c7fd2ed0Sgs150176 	(uint32_t)0,		/* dma_attr_addr_lo */
60c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
61c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_count_max */
62c7fd2ed0Sgs150176 	(uint32_t)256,		/* dma_attr_align */
63c7fd2ed0Sgs150176 	0xFFFFFFFF,		/* dma_attr_burstsizes */
64c7fd2ed0Sgs150176 	1,			/* dma_attr_minxfer */
65c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
66c7fd2ed0Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_seg */
67c7fd2ed0Sgs150176 	1,			/* dma_attr_sgllen */
68c7fd2ed0Sgs150176 	1,			/* dma_attr_granular */
69c7fd2ed0Sgs150176 	0,			/* dma_attr_flags */
70c7fd2ed0Sgs150176 };
71c7fd2ed0Sgs150176 
72c7fd2ed0Sgs150176 /*
73c7fd2ed0Sgs150176  * PIO access attributes for registers
74c7fd2ed0Sgs150176  */
75c7fd2ed0Sgs150176 static ddi_device_acc_attr_t rge_reg_accattr = {
76c7fd2ed0Sgs150176 	DDI_DEVICE_ATTR_V0,
77c7fd2ed0Sgs150176 	DDI_STRUCTURE_LE_ACC,
78c7fd2ed0Sgs150176 	DDI_STRICTORDER_ACC,
79c7fd2ed0Sgs150176 	DDI_DEFAULT_ACC
80c7fd2ed0Sgs150176 };
81c7fd2ed0Sgs150176 
82c7fd2ed0Sgs150176 /*
83c7fd2ed0Sgs150176  * DMA access attributes for descriptors
84c7fd2ed0Sgs150176  */
85c7fd2ed0Sgs150176 static ddi_device_acc_attr_t rge_desc_accattr = {
86c7fd2ed0Sgs150176 	DDI_DEVICE_ATTR_V0,
87c7fd2ed0Sgs150176 	DDI_NEVERSWAP_ACC,
88c7fd2ed0Sgs150176 	DDI_STRICTORDER_ACC,
89c7fd2ed0Sgs150176 	DDI_DEFAULT_ACC
90c7fd2ed0Sgs150176 };
91c7fd2ed0Sgs150176 
92c7fd2ed0Sgs150176 /*
93c7fd2ed0Sgs150176  * DMA access attributes for data
94c7fd2ed0Sgs150176  */
95c7fd2ed0Sgs150176 static ddi_device_acc_attr_t rge_buf_accattr = {
96c7fd2ed0Sgs150176 	DDI_DEVICE_ATTR_V0,
97c7fd2ed0Sgs150176 	DDI_NEVERSWAP_ACC,
98c7fd2ed0Sgs150176 	DDI_STRICTORDER_ACC,
99c7fd2ed0Sgs150176 	DDI_DEFAULT_ACC
100c7fd2ed0Sgs150176 };
101c7fd2ed0Sgs150176 
102c7fd2ed0Sgs150176 /*
103c7fd2ed0Sgs150176  * Property names
104c7fd2ed0Sgs150176  */
105aa817493Sgs150176 static char debug_propname[] = "rge_debug_flags";
106aa817493Sgs150176 static char mtu_propname[] = "default_mtu";
107aa817493Sgs150176 static char msi_propname[] = "msi_enable";
108c7fd2ed0Sgs150176 
109ba2e4443Sseb static int		rge_m_start(void *);
110ba2e4443Sseb static void		rge_m_stop(void *);
111ba2e4443Sseb static int		rge_m_promisc(void *, boolean_t);
112ba2e4443Sseb static int		rge_m_multicst(void *, boolean_t, const uint8_t *);
113ba2e4443Sseb static int		rge_m_unicst(void *, const uint8_t *);
114ba2e4443Sseb static void		rge_m_resources(void *);
115ba2e4443Sseb static void		rge_m_ioctl(void *, queue_t *, mblk_t *);
116ba2e4443Sseb static boolean_t	rge_m_getcapab(void *, mac_capab_t, void *);
117ba2e4443Sseb 
118ba2e4443Sseb #define	RGE_M_CALLBACK_FLAGS	(MC_RESOURCES | MC_IOCTL | MC_GETCAPAB)
119ba2e4443Sseb 
120ba2e4443Sseb static mac_callbacks_t rge_m_callbacks = {
121ba2e4443Sseb 	RGE_M_CALLBACK_FLAGS,
122ba2e4443Sseb 	rge_m_stat,
123ba2e4443Sseb 	rge_m_start,
124ba2e4443Sseb 	rge_m_stop,
125ba2e4443Sseb 	rge_m_promisc,
126ba2e4443Sseb 	rge_m_multicst,
127ba2e4443Sseb 	rge_m_unicst,
128ba2e4443Sseb 	rge_m_tx,
129ba2e4443Sseb 	rge_m_resources,
130ba2e4443Sseb 	rge_m_ioctl,
131ba2e4443Sseb 	rge_m_getcapab
132ba2e4443Sseb };
133c7fd2ed0Sgs150176 
134c7fd2ed0Sgs150176 /*
135c7fd2ed0Sgs150176  * Allocate an area of memory and a DMA handle for accessing it
136c7fd2ed0Sgs150176  */
137c7fd2ed0Sgs150176 static int
138c7fd2ed0Sgs150176 rge_alloc_dma_mem(rge_t *rgep, size_t memsize, ddi_dma_attr_t *dma_attr_p,
139c7fd2ed0Sgs150176 	ddi_device_acc_attr_t *acc_attr_p, uint_t dma_flags, dma_area_t *dma_p)
140c7fd2ed0Sgs150176 {
141c7fd2ed0Sgs150176 	caddr_t vaddr;
142c7fd2ed0Sgs150176 	int err;
143c7fd2ed0Sgs150176 
144c7fd2ed0Sgs150176 	/*
145c7fd2ed0Sgs150176 	 * Allocate handle
146c7fd2ed0Sgs150176 	 */
147c7fd2ed0Sgs150176 	err = ddi_dma_alloc_handle(rgep->devinfo, dma_attr_p,
148c7fd2ed0Sgs150176 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
149c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
150c7fd2ed0Sgs150176 		dma_p->dma_hdl = NULL;
151c7fd2ed0Sgs150176 		return (DDI_FAILURE);
152c7fd2ed0Sgs150176 	}
153c7fd2ed0Sgs150176 
154c7fd2ed0Sgs150176 	/*
155c7fd2ed0Sgs150176 	 * Allocate memory
156c7fd2ed0Sgs150176 	 */
157c7fd2ed0Sgs150176 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
158c7fd2ed0Sgs150176 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
159c7fd2ed0Sgs150176 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
160c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
161c7fd2ed0Sgs150176 		ddi_dma_free_handle(&dma_p->dma_hdl);
162c7fd2ed0Sgs150176 		dma_p->dma_hdl = NULL;
163c7fd2ed0Sgs150176 		dma_p->acc_hdl = NULL;
164c7fd2ed0Sgs150176 		return (DDI_FAILURE);
165c7fd2ed0Sgs150176 	}
166c7fd2ed0Sgs150176 
167c7fd2ed0Sgs150176 	/*
168c7fd2ed0Sgs150176 	 * Bind the two together
169c7fd2ed0Sgs150176 	 */
170c7fd2ed0Sgs150176 	dma_p->mem_va = vaddr;
171c7fd2ed0Sgs150176 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
172c7fd2ed0Sgs150176 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
173c7fd2ed0Sgs150176 	    &dma_p->cookie, &dma_p->ncookies);
174c7fd2ed0Sgs150176 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) {
175c7fd2ed0Sgs150176 		ddi_dma_mem_free(&dma_p->acc_hdl);
176c7fd2ed0Sgs150176 		ddi_dma_free_handle(&dma_p->dma_hdl);
177c7fd2ed0Sgs150176 		dma_p->acc_hdl = NULL;
178c7fd2ed0Sgs150176 		dma_p->dma_hdl = NULL;
179c7fd2ed0Sgs150176 		return (DDI_FAILURE);
180c7fd2ed0Sgs150176 	}
181c7fd2ed0Sgs150176 
182c7fd2ed0Sgs150176 	dma_p->nslots = ~0U;
183c7fd2ed0Sgs150176 	dma_p->size = ~0U;
184c7fd2ed0Sgs150176 	dma_p->token = ~0U;
185c7fd2ed0Sgs150176 	dma_p->offset = 0;
186c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
187c7fd2ed0Sgs150176 }
188c7fd2ed0Sgs150176 
189c7fd2ed0Sgs150176 /*
190c7fd2ed0Sgs150176  * Free one allocated area of DMAable memory
191c7fd2ed0Sgs150176  */
192c7fd2ed0Sgs150176 static void
193c7fd2ed0Sgs150176 rge_free_dma_mem(dma_area_t *dma_p)
194c7fd2ed0Sgs150176 {
195c7fd2ed0Sgs150176 	if (dma_p->dma_hdl != NULL) {
196c7fd2ed0Sgs150176 		if (dma_p->ncookies) {
197c7fd2ed0Sgs150176 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
198c7fd2ed0Sgs150176 			dma_p->ncookies = 0;
199c7fd2ed0Sgs150176 		}
200c7fd2ed0Sgs150176 		ddi_dma_free_handle(&dma_p->dma_hdl);
201c7fd2ed0Sgs150176 		dma_p->dma_hdl = NULL;
202c7fd2ed0Sgs150176 	}
203c7fd2ed0Sgs150176 
204c7fd2ed0Sgs150176 	if (dma_p->acc_hdl != NULL) {
205c7fd2ed0Sgs150176 		ddi_dma_mem_free(&dma_p->acc_hdl);
206c7fd2ed0Sgs150176 		dma_p->acc_hdl = NULL;
207c7fd2ed0Sgs150176 	}
208c7fd2ed0Sgs150176 }
209c7fd2ed0Sgs150176 
210c7fd2ed0Sgs150176 /*
211c7fd2ed0Sgs150176  * Utility routine to carve a slice off a chunk of allocated memory,
212c7fd2ed0Sgs150176  * updating the chunk descriptor accordingly.  The size of the slice
213c7fd2ed0Sgs150176  * is given by the product of the <qty> and <size> parameters.
214c7fd2ed0Sgs150176  */
215c7fd2ed0Sgs150176 static void
216c7fd2ed0Sgs150176 rge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
217c7fd2ed0Sgs150176 	uint32_t qty, uint32_t size)
218c7fd2ed0Sgs150176 {
219c7fd2ed0Sgs150176 	static uint32_t sequence = 0xbcd5704a;
220c7fd2ed0Sgs150176 	size_t totsize;
221c7fd2ed0Sgs150176 
222c7fd2ed0Sgs150176 	totsize = qty*size;
223c7fd2ed0Sgs150176 	ASSERT(size >= 0);
224c7fd2ed0Sgs150176 	ASSERT(totsize <= chunk->alength);
225c7fd2ed0Sgs150176 
226c7fd2ed0Sgs150176 	*slice = *chunk;
227c7fd2ed0Sgs150176 	slice->nslots = qty;
228c7fd2ed0Sgs150176 	slice->size = size;
229c7fd2ed0Sgs150176 	slice->alength = totsize;
230c7fd2ed0Sgs150176 	slice->token = ++sequence;
231c7fd2ed0Sgs150176 
232c7fd2ed0Sgs150176 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
233c7fd2ed0Sgs150176 	chunk->alength -= totsize;
234c7fd2ed0Sgs150176 	chunk->offset += totsize;
235c7fd2ed0Sgs150176 	chunk->cookie.dmac_laddress += totsize;
236c7fd2ed0Sgs150176 	chunk->cookie.dmac_size -= totsize;
237c7fd2ed0Sgs150176 }
238c7fd2ed0Sgs150176 
239c7fd2ed0Sgs150176 static int
240c7fd2ed0Sgs150176 rge_alloc_bufs(rge_t *rgep)
241c7fd2ed0Sgs150176 {
242c7fd2ed0Sgs150176 	size_t txdescsize;
243c7fd2ed0Sgs150176 	size_t rxdescsize;
244c7fd2ed0Sgs150176 	int err;
245c7fd2ed0Sgs150176 
246c7fd2ed0Sgs150176 	/*
247c7fd2ed0Sgs150176 	 * Allocate memory & handle for packet statistics
248c7fd2ed0Sgs150176 	 */
249c7fd2ed0Sgs150176 	err = rge_alloc_dma_mem(rgep,
250c7fd2ed0Sgs150176 	    RGE_STATS_DUMP_SIZE,
251c7fd2ed0Sgs150176 	    &dma_attr_desc,
252c7fd2ed0Sgs150176 	    &rge_desc_accattr,
253c7fd2ed0Sgs150176 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
254c7fd2ed0Sgs150176 	    &rgep->dma_area_stats);
255c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS)
256c7fd2ed0Sgs150176 		return (DDI_FAILURE);
257c7fd2ed0Sgs150176 	rgep->hw_stats = DMA_VPTR(rgep->dma_area_stats);
258c7fd2ed0Sgs150176 
259c7fd2ed0Sgs150176 	/*
260c7fd2ed0Sgs150176 	 * Allocate memory & handle for Tx descriptor ring
261c7fd2ed0Sgs150176 	 */
262c7fd2ed0Sgs150176 	txdescsize = RGE_SEND_SLOTS * sizeof (rge_bd_t);
263c7fd2ed0Sgs150176 	err = rge_alloc_dma_mem(rgep,
264c7fd2ed0Sgs150176 	    txdescsize,
265c7fd2ed0Sgs150176 	    &dma_attr_desc,
266c7fd2ed0Sgs150176 	    &rge_desc_accattr,
267c7fd2ed0Sgs150176 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
268c7fd2ed0Sgs150176 	    &rgep->dma_area_txdesc);
269c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS)
270c7fd2ed0Sgs150176 		return (DDI_FAILURE);
271c7fd2ed0Sgs150176 
272c7fd2ed0Sgs150176 	/*
273c7fd2ed0Sgs150176 	 * Allocate memory & handle for Rx descriptor ring
274c7fd2ed0Sgs150176 	 */
275c7fd2ed0Sgs150176 	rxdescsize = RGE_RECV_SLOTS * sizeof (rge_bd_t);
276c7fd2ed0Sgs150176 	err = rge_alloc_dma_mem(rgep,
277c7fd2ed0Sgs150176 	    rxdescsize,
278c7fd2ed0Sgs150176 	    &dma_attr_desc,
279c7fd2ed0Sgs150176 	    &rge_desc_accattr,
280c7fd2ed0Sgs150176 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
281c7fd2ed0Sgs150176 	    &rgep->dma_area_rxdesc);
282c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS)
283c7fd2ed0Sgs150176 		return (DDI_FAILURE);
284c7fd2ed0Sgs150176 
285c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
286c7fd2ed0Sgs150176 }
287c7fd2ed0Sgs150176 
288c7fd2ed0Sgs150176 /*
289c7fd2ed0Sgs150176  * rge_free_bufs() -- free descriptors/buffers allocated for this
290c7fd2ed0Sgs150176  * device instance.
291c7fd2ed0Sgs150176  */
292c7fd2ed0Sgs150176 static void
293c7fd2ed0Sgs150176 rge_free_bufs(rge_t *rgep)
294c7fd2ed0Sgs150176 {
295c7fd2ed0Sgs150176 	rge_free_dma_mem(&rgep->dma_area_stats);
296c7fd2ed0Sgs150176 	rge_free_dma_mem(&rgep->dma_area_txdesc);
297c7fd2ed0Sgs150176 	rge_free_dma_mem(&rgep->dma_area_rxdesc);
298c7fd2ed0Sgs150176 }
299c7fd2ed0Sgs150176 
300c7fd2ed0Sgs150176 /*
301c7fd2ed0Sgs150176  * ========== Transmit and receive ring reinitialisation ==========
302c7fd2ed0Sgs150176  */
303c7fd2ed0Sgs150176 
304c7fd2ed0Sgs150176 /*
305c7fd2ed0Sgs150176  * These <reinit> routines each reset the rx/tx rings to an initial
306c7fd2ed0Sgs150176  * state, assuming that the corresponding <init> routine has already
307c7fd2ed0Sgs150176  * been called exactly once.
308c7fd2ed0Sgs150176  */
309c7fd2ed0Sgs150176 static void
310c7fd2ed0Sgs150176 rge_reinit_send_ring(rge_t *rgep)
311c7fd2ed0Sgs150176 {
312c7fd2ed0Sgs150176 	sw_sbd_t *ssbdp;
313c7fd2ed0Sgs150176 	rge_bd_t *bdp;
314c7fd2ed0Sgs150176 	uint32_t slot;
315c7fd2ed0Sgs150176 
316c7fd2ed0Sgs150176 	/*
317c7fd2ed0Sgs150176 	 * re-init send ring
318c7fd2ed0Sgs150176 	 */
319c7fd2ed0Sgs150176 	DMA_ZERO(rgep->tx_desc);
320c7fd2ed0Sgs150176 	ssbdp = rgep->sw_sbds;
321c7fd2ed0Sgs150176 	bdp = rgep->tx_ring;
322c7fd2ed0Sgs150176 	for (slot = 0; slot < RGE_SEND_SLOTS; slot++) {
323c7fd2ed0Sgs150176 		bdp->host_buf_addr =
324c7fd2ed0Sgs150176 		    RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress);
325c7fd2ed0Sgs150176 		bdp->host_buf_addr_hi =
326c7fd2ed0Sgs150176 		    RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress >> 32);
327c7fd2ed0Sgs150176 		/* last BD in Tx ring */
328c7fd2ed0Sgs150176 		if (slot == (RGE_SEND_SLOTS - 1))
329c7fd2ed0Sgs150176 			bdp->flags_len = RGE_BSWAP_32(BD_FLAG_EOR);
330c7fd2ed0Sgs150176 		ssbdp++;
331c7fd2ed0Sgs150176 		bdp++;
332c7fd2ed0Sgs150176 	}
333c7fd2ed0Sgs150176 	DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
334c7fd2ed0Sgs150176 	rgep->tx_next = 0;
335c7fd2ed0Sgs150176 	rgep->tc_next = 0;
336c7fd2ed0Sgs150176 	rgep->tc_tail = 0;
337c7fd2ed0Sgs150176 	rgep->tx_flow = 0;
338c7fd2ed0Sgs150176 	rgep->tx_free = RGE_SEND_SLOTS;
339c7fd2ed0Sgs150176 }
340c7fd2ed0Sgs150176 
341c7fd2ed0Sgs150176 static void
342c7fd2ed0Sgs150176 rge_reinit_recv_ring(rge_t *rgep)
343c7fd2ed0Sgs150176 {
344c7fd2ed0Sgs150176 	rge_bd_t *bdp;
345c7fd2ed0Sgs150176 	sw_rbd_t *srbdp;
346c7fd2ed0Sgs150176 	dma_area_t *pbuf;
347c7fd2ed0Sgs150176 	uint32_t slot;
348c7fd2ed0Sgs150176 
349c7fd2ed0Sgs150176 	/*
350c7fd2ed0Sgs150176 	 * re-init receive ring
351c7fd2ed0Sgs150176 	 */
352c7fd2ed0Sgs150176 	DMA_ZERO(rgep->rx_desc);
353c7fd2ed0Sgs150176 	srbdp = rgep->sw_rbds;
354c7fd2ed0Sgs150176 	bdp = rgep->rx_ring;
355c7fd2ed0Sgs150176 	for (slot = 0; slot < RGE_RECV_SLOTS; slot++) {
356c7fd2ed0Sgs150176 		pbuf = &srbdp->rx_buf->pbuf;
357c7fd2ed0Sgs150176 		bdp->host_buf_addr =
358aa817493Sgs150176 		    RGE_BSWAP_32(pbuf->cookie.dmac_laddress + rgep->head_room);
359c7fd2ed0Sgs150176 		bdp->host_buf_addr_hi =
360c7fd2ed0Sgs150176 		    RGE_BSWAP_32(pbuf->cookie.dmac_laddress >> 32);
361c7fd2ed0Sgs150176 		bdp->flags_len = RGE_BSWAP_32(BD_FLAG_HW_OWN |
362aa817493Sgs150176 		    (rgep->rxbuf_size - rgep->head_room));
363c7fd2ed0Sgs150176 		/* last BD in Tx ring */
364c7fd2ed0Sgs150176 		if (slot == (RGE_RECV_SLOTS - 1))
365c7fd2ed0Sgs150176 			bdp->flags_len |= RGE_BSWAP_32(BD_FLAG_EOR);
366c7fd2ed0Sgs150176 		srbdp++;
367c7fd2ed0Sgs150176 		bdp++;
368c7fd2ed0Sgs150176 	}
369c7fd2ed0Sgs150176 	DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV);
370c7fd2ed0Sgs150176 	rgep->watchdog = 0;
371c7fd2ed0Sgs150176 	rgep->rx_next = 0;
372c7fd2ed0Sgs150176 }
373c7fd2ed0Sgs150176 
374c7fd2ed0Sgs150176 static void
375c7fd2ed0Sgs150176 rge_reinit_buf_ring(rge_t *rgep)
376c7fd2ed0Sgs150176 {
377aa817493Sgs150176 
378aa817493Sgs150176 	if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY)
379aa817493Sgs150176 		return;
380aa817493Sgs150176 
381c7fd2ed0Sgs150176 	/*
382aa817493Sgs150176 	 * If all the up-sending buffers haven't been returned to driver,
383aa817493Sgs150176 	 * use bcopy() only in rx process.
384c7fd2ed0Sgs150176 	 */
385c7fd2ed0Sgs150176 	if (rgep->rx_free != RGE_BUF_SLOTS)
386c7fd2ed0Sgs150176 		rgep->rx_bcopy = B_TRUE;
387c7fd2ed0Sgs150176 }
388c7fd2ed0Sgs150176 
389c7fd2ed0Sgs150176 static void
390c7fd2ed0Sgs150176 rge_reinit_rings(rge_t *rgep)
391c7fd2ed0Sgs150176 {
392c7fd2ed0Sgs150176 	rge_reinit_send_ring(rgep);
393c7fd2ed0Sgs150176 	rge_reinit_recv_ring(rgep);
394c7fd2ed0Sgs150176 	rge_reinit_buf_ring(rgep);
395c7fd2ed0Sgs150176 }
396c7fd2ed0Sgs150176 
397c7fd2ed0Sgs150176 static void
398aa817493Sgs150176 rge_fini_send_ring(rge_t *rgep)
399aa817493Sgs150176 {
400aa817493Sgs150176 	sw_sbd_t *ssbdp;
401aa817493Sgs150176 	uint32_t slot;
402aa817493Sgs150176 
403aa817493Sgs150176 	ssbdp = rgep->sw_sbds;
404aa817493Sgs150176 	for (slot = 0; slot < RGE_SEND_SLOTS; ++slot) {
405aa817493Sgs150176 		rge_free_dma_mem(&ssbdp->pbuf);
406aa817493Sgs150176 		ssbdp++;
407aa817493Sgs150176 	}
408aa817493Sgs150176 
409aa817493Sgs150176 	kmem_free(rgep->sw_sbds, RGE_SEND_SLOTS * sizeof (sw_sbd_t));
410aa817493Sgs150176 	rgep->sw_sbds = NULL;
411aa817493Sgs150176 }
412aa817493Sgs150176 
413aa817493Sgs150176 static void
414aa817493Sgs150176 rge_fini_recv_ring(rge_t *rgep)
415aa817493Sgs150176 {
416aa817493Sgs150176 	sw_rbd_t *srbdp;
417aa817493Sgs150176 	uint32_t slot;
418aa817493Sgs150176 
419aa817493Sgs150176 	srbdp = rgep->sw_rbds;
420aa817493Sgs150176 	for (slot = 0; slot < RGE_RECV_SLOTS; ++srbdp, ++slot) {
421aa817493Sgs150176 		if (srbdp->rx_buf) {
422aa817493Sgs150176 			if (srbdp->rx_buf->mp != NULL) {
423aa817493Sgs150176 				freemsg(srbdp->rx_buf->mp);
424aa817493Sgs150176 				srbdp->rx_buf->mp = NULL;
425aa817493Sgs150176 			}
426aa817493Sgs150176 			rge_free_dma_mem(&srbdp->rx_buf->pbuf);
427aa817493Sgs150176 			kmem_free(srbdp->rx_buf, sizeof (dma_buf_t));
428aa817493Sgs150176 			srbdp->rx_buf = NULL;
429aa817493Sgs150176 		}
430aa817493Sgs150176 	}
431aa817493Sgs150176 
432aa817493Sgs150176 	kmem_free(rgep->sw_rbds, RGE_RECV_SLOTS * sizeof (sw_rbd_t));
433aa817493Sgs150176 	rgep->sw_rbds = NULL;
434aa817493Sgs150176 }
435aa817493Sgs150176 
436aa817493Sgs150176 static void
437aa817493Sgs150176 rge_fini_buf_ring(rge_t *rgep)
438aa817493Sgs150176 {
439aa817493Sgs150176 	sw_rbd_t *srbdp;
440aa817493Sgs150176 	uint32_t slot;
441aa817493Sgs150176 
442aa817493Sgs150176 	if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY)
443aa817493Sgs150176 		return;
444aa817493Sgs150176 
445aa817493Sgs150176 	ASSERT(rgep->rx_free == RGE_BUF_SLOTS);
446aa817493Sgs150176 
447aa817493Sgs150176 	srbdp = rgep->free_srbds;
448aa817493Sgs150176 	for (slot = 0; slot < RGE_BUF_SLOTS; ++srbdp, ++slot) {
449aa817493Sgs150176 		if (srbdp->rx_buf != NULL) {
450aa817493Sgs150176 			if (srbdp->rx_buf->mp != NULL) {
451aa817493Sgs150176 				freemsg(srbdp->rx_buf->mp);
452aa817493Sgs150176 				srbdp->rx_buf->mp = NULL;
453aa817493Sgs150176 			}
454aa817493Sgs150176 			rge_free_dma_mem(&srbdp->rx_buf->pbuf);
455aa817493Sgs150176 			kmem_free(srbdp->rx_buf, sizeof (dma_buf_t));
456aa817493Sgs150176 			srbdp->rx_buf = NULL;
457aa817493Sgs150176 		}
458aa817493Sgs150176 	}
459aa817493Sgs150176 
460aa817493Sgs150176 	kmem_free(rgep->free_srbds, RGE_BUF_SLOTS * sizeof (sw_rbd_t));
461aa817493Sgs150176 	rgep->free_srbds = NULL;
462aa817493Sgs150176 }
463aa817493Sgs150176 
464aa817493Sgs150176 static void
465aa817493Sgs150176 rge_fini_rings(rge_t *rgep)
466aa817493Sgs150176 {
467aa817493Sgs150176 	rge_fini_send_ring(rgep);
468aa817493Sgs150176 	rge_fini_recv_ring(rgep);
469aa817493Sgs150176 	rge_fini_buf_ring(rgep);
470aa817493Sgs150176 }
471aa817493Sgs150176 
472aa817493Sgs150176 static int
473c7fd2ed0Sgs150176 rge_init_send_ring(rge_t *rgep)
474c7fd2ed0Sgs150176 {
475c7fd2ed0Sgs150176 	uint32_t slot;
476c7fd2ed0Sgs150176 	sw_sbd_t *ssbdp;
477c7fd2ed0Sgs150176 	dma_area_t *pbuf;
478aa817493Sgs150176 	dma_area_t desc;
479aa817493Sgs150176 	int err;
480c7fd2ed0Sgs150176 
481c7fd2ed0Sgs150176 	/*
482c7fd2ed0Sgs150176 	 * Allocate the array of s/w Tx Buffer Descriptors
483c7fd2ed0Sgs150176 	 */
484c7fd2ed0Sgs150176 	ssbdp = kmem_zalloc(RGE_SEND_SLOTS*sizeof (*ssbdp), KM_SLEEP);
485c7fd2ed0Sgs150176 	rgep->sw_sbds = ssbdp;
486c7fd2ed0Sgs150176 
487c7fd2ed0Sgs150176 	/*
488c7fd2ed0Sgs150176 	 * Init send ring
489c7fd2ed0Sgs150176 	 */
490c7fd2ed0Sgs150176 	rgep->tx_desc = rgep->dma_area_txdesc;
491c7fd2ed0Sgs150176 	DMA_ZERO(rgep->tx_desc);
492aa817493Sgs150176 	rgep->tx_ring = rgep->tx_desc.mem_va;
493aa817493Sgs150176 
494aa817493Sgs150176 	desc = rgep->tx_desc;
495aa817493Sgs150176 	for (slot = 0; slot < RGE_SEND_SLOTS; slot++) {
496aa817493Sgs150176 		rge_slice_chunk(&ssbdp->desc, &desc, 1, sizeof (rge_bd_t));
497aa817493Sgs150176 
498aa817493Sgs150176 		/*
499aa817493Sgs150176 		 * Allocate memory & handle for Tx buffers
500aa817493Sgs150176 		 */
501c7fd2ed0Sgs150176 		pbuf = &ssbdp->pbuf;
502aa817493Sgs150176 		err = rge_alloc_dma_mem(rgep, rgep->txbuf_size,
503aa817493Sgs150176 		    &dma_attr_buf, &rge_buf_accattr,
504aa817493Sgs150176 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, pbuf);
505aa817493Sgs150176 		if (err != DDI_SUCCESS) {
506aa817493Sgs150176 			rge_error(rgep,
507aa817493Sgs150176 			    "rge_init_send_ring: alloc tx buffer failed");
508aa817493Sgs150176 			rge_fini_send_ring(rgep);
509aa817493Sgs150176 			return (DDI_FAILURE);
510aa817493Sgs150176 		}
511c7fd2ed0Sgs150176 		ssbdp++;
512c7fd2ed0Sgs150176 	}
513aa817493Sgs150176 	ASSERT(desc.alength == 0);
514aa817493Sgs150176 
515c7fd2ed0Sgs150176 	DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
516aa817493Sgs150176 	return (DDI_SUCCESS);
517c7fd2ed0Sgs150176 }
518c7fd2ed0Sgs150176 
519c7fd2ed0Sgs150176 static int
520c7fd2ed0Sgs150176 rge_init_recv_ring(rge_t *rgep)
521c7fd2ed0Sgs150176 {
522c7fd2ed0Sgs150176 	uint32_t slot;
523c7fd2ed0Sgs150176 	sw_rbd_t *srbdp;
524c7fd2ed0Sgs150176 	dma_buf_t *rx_buf;
525c7fd2ed0Sgs150176 	dma_area_t *pbuf;
526aa817493Sgs150176 	int err;
527c7fd2ed0Sgs150176 
528c7fd2ed0Sgs150176 	/*
529c7fd2ed0Sgs150176 	 * Allocate the array of s/w Rx Buffer Descriptors
530c7fd2ed0Sgs150176 	 */
531c7fd2ed0Sgs150176 	srbdp = kmem_zalloc(RGE_RECV_SLOTS*sizeof (*srbdp), KM_SLEEP);
532c7fd2ed0Sgs150176 	rgep->sw_rbds = srbdp;
533c7fd2ed0Sgs150176 
534c7fd2ed0Sgs150176 	/*
535c7fd2ed0Sgs150176 	 * Init receive ring
536c7fd2ed0Sgs150176 	 */
537c7fd2ed0Sgs150176 	rgep->rx_next = 0;
538c7fd2ed0Sgs150176 	rgep->rx_desc = rgep->dma_area_rxdesc;
539c7fd2ed0Sgs150176 	DMA_ZERO(rgep->rx_desc);
540aa817493Sgs150176 	rgep->rx_ring = rgep->rx_desc.mem_va;
541aa817493Sgs150176 
542aa817493Sgs150176 	for (slot = 0; slot < RGE_RECV_SLOTS; slot++) {
543aa817493Sgs150176 		srbdp->rx_buf = rx_buf =
544aa817493Sgs150176 		    kmem_zalloc(sizeof (dma_buf_t), KM_SLEEP);
545aa817493Sgs150176 
546aa817493Sgs150176 		/*
547aa817493Sgs150176 		 * Allocate memory & handle for Rx buffers
548aa817493Sgs150176 		 */
549c7fd2ed0Sgs150176 		pbuf = &rx_buf->pbuf;
550aa817493Sgs150176 		err = rge_alloc_dma_mem(rgep, rgep->rxbuf_size,
551aa817493Sgs150176 		    &dma_attr_buf, &rge_buf_accattr,
552aa817493Sgs150176 		    DDI_DMA_READ | DDI_DMA_STREAMING, pbuf);
553aa817493Sgs150176 		if (err != DDI_SUCCESS) {
554aa817493Sgs150176 			rge_fini_recv_ring(rgep);
555aa817493Sgs150176 			rge_error(rgep,
556aa817493Sgs150176 			    "rge_init_recv_ring: alloc rx buffer failed");
557aa817493Sgs150176 			return (DDI_FAILURE);
558aa817493Sgs150176 		}
559aa817493Sgs150176 
560aa817493Sgs150176 		pbuf->alength -= rgep->head_room;
561aa817493Sgs150176 		pbuf->offset += rgep->head_room;
562aa817493Sgs150176 		if (!(rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY)) {
563c7fd2ed0Sgs150176 			rx_buf->rx_recycle.free_func = rge_rx_recycle;
564c7fd2ed0Sgs150176 			rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf;
565c7fd2ed0Sgs150176 			rx_buf->private = (caddr_t)rgep;
566c7fd2ed0Sgs150176 			rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
567c7fd2ed0Sgs150176 			    rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
568c7fd2ed0Sgs150176 			if (rx_buf->mp == NULL) {
569aa817493Sgs150176 				rge_fini_recv_ring(rgep);
570c7fd2ed0Sgs150176 				rge_problem(rgep,
571c7fd2ed0Sgs150176 				    "rge_init_recv_ring: desballoc() failed");
572c7fd2ed0Sgs150176 				return (DDI_FAILURE);
573c7fd2ed0Sgs150176 			}
574c7fd2ed0Sgs150176 		}
575aa817493Sgs150176 		srbdp++;
576c7fd2ed0Sgs150176 	}
577c7fd2ed0Sgs150176 	DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV);
578c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
579c7fd2ed0Sgs150176 }
580c7fd2ed0Sgs150176 
581c7fd2ed0Sgs150176 static int
582c7fd2ed0Sgs150176 rge_init_buf_ring(rge_t *rgep)
583c7fd2ed0Sgs150176 {
584c7fd2ed0Sgs150176 	uint32_t slot;
585aa817493Sgs150176 	sw_rbd_t *free_srbdp;
586c7fd2ed0Sgs150176 	dma_buf_t *rx_buf;
587c7fd2ed0Sgs150176 	dma_area_t *pbuf;
588aa817493Sgs150176 	int err;
589aa817493Sgs150176 
590aa817493Sgs150176 	if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) {
591aa817493Sgs150176 		rgep->rx_bcopy = B_TRUE;
592aa817493Sgs150176 		return (DDI_SUCCESS);
593aa817493Sgs150176 	}
594c7fd2ed0Sgs150176 
595c7fd2ed0Sgs150176 	/*
596c7fd2ed0Sgs150176 	 * Allocate the array of s/w free Buffer Descriptors
597c7fd2ed0Sgs150176 	 */
598aa817493Sgs150176 	free_srbdp = kmem_zalloc(RGE_BUF_SLOTS*sizeof (*free_srbdp), KM_SLEEP);
599aa817493Sgs150176 	rgep->free_srbds = free_srbdp;
600c7fd2ed0Sgs150176 
601c7fd2ed0Sgs150176 	/*
602c7fd2ed0Sgs150176 	 * Init free buffer ring
603c7fd2ed0Sgs150176 	 */
604c7fd2ed0Sgs150176 	rgep->rc_next = 0;
605c7fd2ed0Sgs150176 	rgep->rf_next = 0;
606c7fd2ed0Sgs150176 	rgep->rx_bcopy = B_FALSE;
607c7fd2ed0Sgs150176 	rgep->rx_free = RGE_BUF_SLOTS;
608aa817493Sgs150176 	for (slot = 0; slot < RGE_BUF_SLOTS; slot++) {
609aa817493Sgs150176 		free_srbdp->rx_buf = rx_buf =
610aa817493Sgs150176 		    kmem_zalloc(sizeof (dma_buf_t), KM_SLEEP);
611aa817493Sgs150176 
612aa817493Sgs150176 		/*
613aa817493Sgs150176 		 * Allocate memory & handle for free Rx buffers
614aa817493Sgs150176 		 */
615c7fd2ed0Sgs150176 		pbuf = &rx_buf->pbuf;
616aa817493Sgs150176 		err = rge_alloc_dma_mem(rgep, rgep->rxbuf_size,
617aa817493Sgs150176 		    &dma_attr_buf, &rge_buf_accattr,
618aa817493Sgs150176 		    DDI_DMA_READ | DDI_DMA_STREAMING, pbuf);
619aa817493Sgs150176 		if (err != DDI_SUCCESS) {
620aa817493Sgs150176 			rge_fini_buf_ring(rgep);
621aa817493Sgs150176 			rge_error(rgep,
622aa817493Sgs150176 			    "rge_init_buf_ring: alloc rx free buffer failed");
623aa817493Sgs150176 			return (DDI_FAILURE);
624aa817493Sgs150176 		}
625aa817493Sgs150176 		pbuf->alength -= rgep->head_room;
626aa817493Sgs150176 		pbuf->offset += rgep->head_room;
627c7fd2ed0Sgs150176 		rx_buf->rx_recycle.free_func = rge_rx_recycle;
628c7fd2ed0Sgs150176 		rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf;
629c7fd2ed0Sgs150176 		rx_buf->private = (caddr_t)rgep;
630c7fd2ed0Sgs150176 		rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
631c7fd2ed0Sgs150176 		    rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
632c7fd2ed0Sgs150176 		if (rx_buf->mp == NULL) {
633aa817493Sgs150176 			rge_fini_buf_ring(rgep);
634c7fd2ed0Sgs150176 			rge_problem(rgep,
635c7fd2ed0Sgs150176 			    "rge_init_buf_ring: desballoc() failed");
636c7fd2ed0Sgs150176 			return (DDI_FAILURE);
637c7fd2ed0Sgs150176 		}
638aa817493Sgs150176 		free_srbdp++;
639c7fd2ed0Sgs150176 	}
640c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
641c7fd2ed0Sgs150176 }
642c7fd2ed0Sgs150176 
643c7fd2ed0Sgs150176 static int
644c7fd2ed0Sgs150176 rge_init_rings(rge_t *rgep)
645c7fd2ed0Sgs150176 {
646c7fd2ed0Sgs150176 	int err;
647c7fd2ed0Sgs150176 
648aa817493Sgs150176 	err = rge_init_send_ring(rgep);
649aa817493Sgs150176 	if (err != DDI_SUCCESS)
650aa817493Sgs150176 		return (DDI_FAILURE);
651aa817493Sgs150176 
652c7fd2ed0Sgs150176 	err = rge_init_recv_ring(rgep);
653aa817493Sgs150176 	if (err != DDI_SUCCESS) {
654aa817493Sgs150176 		rge_fini_send_ring(rgep);
655aa817493Sgs150176 		return (DDI_FAILURE);
656aa817493Sgs150176 	}
657aa817493Sgs150176 
658c7fd2ed0Sgs150176 	err = rge_init_buf_ring(rgep);
659aa817493Sgs150176 	if (err != DDI_SUCCESS) {
660c7fd2ed0Sgs150176 		rge_fini_send_ring(rgep);
661c7fd2ed0Sgs150176 		rge_fini_recv_ring(rgep);
662aa817493Sgs150176 		return (DDI_FAILURE);
663aa817493Sgs150176 	}
664aa817493Sgs150176 
665aa817493Sgs150176 	return (DDI_SUCCESS);
666c7fd2ed0Sgs150176 }
667c7fd2ed0Sgs150176 
668c7fd2ed0Sgs150176 /*
669c7fd2ed0Sgs150176  * ========== Internal state management entry points ==========
670c7fd2ed0Sgs150176  */
671c7fd2ed0Sgs150176 
672c7fd2ed0Sgs150176 #undef	RGE_DBG
673c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_NEMO	/* debug flag for this code	*/
674c7fd2ed0Sgs150176 
675c7fd2ed0Sgs150176 /*
676c7fd2ed0Sgs150176  * These routines provide all the functionality required by the
677c7fd2ed0Sgs150176  * corresponding MAC layer entry points, but don't update the
678c7fd2ed0Sgs150176  * MAC state so they can be called internally without disturbing
679c7fd2ed0Sgs150176  * our record of what NEMO thinks we should be doing ...
680c7fd2ed0Sgs150176  */
681c7fd2ed0Sgs150176 
682c7fd2ed0Sgs150176 /*
683c7fd2ed0Sgs150176  *	rge_reset() -- reset h/w & rings to initial state
684c7fd2ed0Sgs150176  */
685c7fd2ed0Sgs150176 static void
686c7fd2ed0Sgs150176 rge_reset(rge_t *rgep)
687c7fd2ed0Sgs150176 {
688c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
689c7fd2ed0Sgs150176 
690c7fd2ed0Sgs150176 	/*
691c7fd2ed0Sgs150176 	 * Grab all the other mutexes in the world (this should
692c7fd2ed0Sgs150176 	 * ensure no other threads are manipulating driver state)
693c7fd2ed0Sgs150176 	 */
694c7fd2ed0Sgs150176 	mutex_enter(rgep->rx_lock);
695c7fd2ed0Sgs150176 	mutex_enter(rgep->rc_lock);
696c7fd2ed0Sgs150176 	rw_enter(rgep->errlock, RW_WRITER);
697c7fd2ed0Sgs150176 
698c7fd2ed0Sgs150176 	(void) rge_chip_reset(rgep);
699c7fd2ed0Sgs150176 	rge_reinit_rings(rgep);
700c7fd2ed0Sgs150176 	rge_chip_init(rgep);
701c7fd2ed0Sgs150176 
702c7fd2ed0Sgs150176 	/*
703c7fd2ed0Sgs150176 	 * Free the world ...
704c7fd2ed0Sgs150176 	 */
705c7fd2ed0Sgs150176 	rw_exit(rgep->errlock);
706c7fd2ed0Sgs150176 	mutex_exit(rgep->rc_lock);
707c7fd2ed0Sgs150176 	mutex_exit(rgep->rx_lock);
708c7fd2ed0Sgs150176 
709c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_reset($%p) done", (void *)rgep));
710c7fd2ed0Sgs150176 }
711c7fd2ed0Sgs150176 
712c7fd2ed0Sgs150176 /*
713c7fd2ed0Sgs150176  *	rge_stop() -- stop processing, don't reset h/w or rings
714c7fd2ed0Sgs150176  */
715c7fd2ed0Sgs150176 static void
716c7fd2ed0Sgs150176 rge_stop(rge_t *rgep)
717c7fd2ed0Sgs150176 {
718c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
719c7fd2ed0Sgs150176 
720c7fd2ed0Sgs150176 	rge_chip_stop(rgep, B_FALSE);
721c7fd2ed0Sgs150176 
722c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_stop($%p) done", (void *)rgep));
723c7fd2ed0Sgs150176 }
724c7fd2ed0Sgs150176 
725c7fd2ed0Sgs150176 /*
726c7fd2ed0Sgs150176  *	rge_start() -- start transmitting/receiving
727c7fd2ed0Sgs150176  */
728c7fd2ed0Sgs150176 static void
729c7fd2ed0Sgs150176 rge_start(rge_t *rgep)
730c7fd2ed0Sgs150176 {
731c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
732c7fd2ed0Sgs150176 
733c7fd2ed0Sgs150176 	/*
734c7fd2ed0Sgs150176 	 * Start chip processing, including enabling interrupts
735c7fd2ed0Sgs150176 	 */
736c7fd2ed0Sgs150176 	rge_chip_start(rgep);
737c7fd2ed0Sgs150176 	rgep->watchdog = 0;
738c7fd2ed0Sgs150176 }
739c7fd2ed0Sgs150176 
740c7fd2ed0Sgs150176 /*
741c7fd2ed0Sgs150176  * rge_restart - restart transmitting/receiving after error or suspend
742c7fd2ed0Sgs150176  */
743c7fd2ed0Sgs150176 void
744c7fd2ed0Sgs150176 rge_restart(rge_t *rgep)
745c7fd2ed0Sgs150176 {
746c7fd2ed0Sgs150176 	uint32_t i;
747c7fd2ed0Sgs150176 
748c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
749c7fd2ed0Sgs150176 	/*
750c7fd2ed0Sgs150176 	 * Wait for posted buffer to be freed...
751c7fd2ed0Sgs150176 	 */
752c7fd2ed0Sgs150176 	if (!rgep->rx_bcopy) {
753c7fd2ed0Sgs150176 		for (i = 0; i < RXBUFF_FREE_LOOP; i++) {
754c7fd2ed0Sgs150176 			if (rgep->rx_free == RGE_BUF_SLOTS)
755c7fd2ed0Sgs150176 				break;
756c7fd2ed0Sgs150176 			drv_usecwait(1000);
757c7fd2ed0Sgs150176 			RGE_DEBUG(("rge_restart: waiting for rx buf free..."));
758c7fd2ed0Sgs150176 		}
759c7fd2ed0Sgs150176 	}
760c7fd2ed0Sgs150176 	rge_reset(rgep);
761c7fd2ed0Sgs150176 	rgep->stats.chip_reset++;
762c7fd2ed0Sgs150176 	if (rgep->rge_mac_state == RGE_MAC_STARTED) {
763c7fd2ed0Sgs150176 		rge_start(rgep);
764aa817493Sgs150176 		rgep->resched_needed = B_TRUE;
765aa817493Sgs150176 		(void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL);
766c7fd2ed0Sgs150176 	}
767c7fd2ed0Sgs150176 }
768c7fd2ed0Sgs150176 
769c7fd2ed0Sgs150176 
770c7fd2ed0Sgs150176 /*
771c7fd2ed0Sgs150176  * ========== Nemo-required management entry points ==========
772c7fd2ed0Sgs150176  */
773c7fd2ed0Sgs150176 
774c7fd2ed0Sgs150176 #undef	RGE_DBG
775c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_NEMO	/* debug flag for this code	*/
776c7fd2ed0Sgs150176 
777c7fd2ed0Sgs150176 /*
778c7fd2ed0Sgs150176  *	rge_m_stop() -- stop transmitting/receiving
779c7fd2ed0Sgs150176  */
780c7fd2ed0Sgs150176 static void
781c7fd2ed0Sgs150176 rge_m_stop(void *arg)
782c7fd2ed0Sgs150176 {
783c7fd2ed0Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
784c7fd2ed0Sgs150176 	uint32_t i;
785c7fd2ed0Sgs150176 
786c7fd2ed0Sgs150176 	/*
787c7fd2ed0Sgs150176 	 * Just stop processing, then record new MAC state
788c7fd2ed0Sgs150176 	 */
789c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
790c7fd2ed0Sgs150176 	rge_stop(rgep);
791c7fd2ed0Sgs150176 	/*
792c7fd2ed0Sgs150176 	 * Wait for posted buffer to be freed...
793c7fd2ed0Sgs150176 	 */
794c7fd2ed0Sgs150176 	if (!rgep->rx_bcopy) {
795c7fd2ed0Sgs150176 		for (i = 0; i < RXBUFF_FREE_LOOP; i++) {
796c7fd2ed0Sgs150176 			if (rgep->rx_free == RGE_BUF_SLOTS)
797c7fd2ed0Sgs150176 				break;
798c7fd2ed0Sgs150176 			drv_usecwait(1000);
799c7fd2ed0Sgs150176 			RGE_DEBUG(("rge_m_stop: waiting for rx buf free..."));
800c7fd2ed0Sgs150176 		}
801c7fd2ed0Sgs150176 	}
802c7fd2ed0Sgs150176 	rgep->rge_mac_state = RGE_MAC_STOPPED;
803c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_m_stop($%p) done", arg));
804c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
805c7fd2ed0Sgs150176 }
806c7fd2ed0Sgs150176 
807c7fd2ed0Sgs150176 /*
808c7fd2ed0Sgs150176  *	rge_m_start() -- start transmitting/receiving
809c7fd2ed0Sgs150176  */
810c7fd2ed0Sgs150176 static int
811c7fd2ed0Sgs150176 rge_m_start(void *arg)
812c7fd2ed0Sgs150176 {
813c7fd2ed0Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
814c7fd2ed0Sgs150176 
815c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
816c7fd2ed0Sgs150176 
817c7fd2ed0Sgs150176 	/*
818c7fd2ed0Sgs150176 	 * Clear hw/sw statistics
819c7fd2ed0Sgs150176 	 */
820c7fd2ed0Sgs150176 	DMA_ZERO(rgep->dma_area_stats);
821c7fd2ed0Sgs150176 	bzero(&rgep->stats, sizeof (rge_stats_t));
822c7fd2ed0Sgs150176 
823c7fd2ed0Sgs150176 	/*
824c7fd2ed0Sgs150176 	 * Start processing and record new MAC state
825c7fd2ed0Sgs150176 	 */
826c7fd2ed0Sgs150176 	rge_reset(rgep);
827c7fd2ed0Sgs150176 	rge_start(rgep);
828c7fd2ed0Sgs150176 	rgep->rge_mac_state = RGE_MAC_STARTED;
829c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_m_start($%p) done", arg));
830c7fd2ed0Sgs150176 
831c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
832c7fd2ed0Sgs150176 
833c7fd2ed0Sgs150176 	return (0);
834c7fd2ed0Sgs150176 }
835c7fd2ed0Sgs150176 
836c7fd2ed0Sgs150176 /*
837c7fd2ed0Sgs150176  *	rge_m_unicst_set() -- set the physical network address
838c7fd2ed0Sgs150176  */
839c7fd2ed0Sgs150176 static int
840c7fd2ed0Sgs150176 rge_m_unicst(void *arg, const uint8_t *macaddr)
841c7fd2ed0Sgs150176 {
842c7fd2ed0Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
843c7fd2ed0Sgs150176 
844c7fd2ed0Sgs150176 	/*
845c7fd2ed0Sgs150176 	 * Remember the new current address in the driver state
846c7fd2ed0Sgs150176 	 * Sync the chip's idea of the address too ...
847c7fd2ed0Sgs150176 	 */
848c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
849c7fd2ed0Sgs150176 	bcopy(macaddr, rgep->netaddr, ETHERADDRL);
850c7fd2ed0Sgs150176 	rge_chip_sync(rgep, RGE_SET_MAC);
851c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
852c7fd2ed0Sgs150176 
853c7fd2ed0Sgs150176 	return (0);
854c7fd2ed0Sgs150176 }
855c7fd2ed0Sgs150176 
856c7fd2ed0Sgs150176 /*
857c7fd2ed0Sgs150176  * Compute the index of the required bit in the multicast hash map.
858c7fd2ed0Sgs150176  * This must mirror the way the hardware actually does it!
859c7fd2ed0Sgs150176  */
860c7fd2ed0Sgs150176 static uint32_t
861c7fd2ed0Sgs150176 rge_hash_index(const uint8_t *mca)
862c7fd2ed0Sgs150176 {
863aa817493Sgs150176 	uint32_t crc = (uint32_t)RGE_HASH_CRC;
864c7fd2ed0Sgs150176 	uint32_t const POLY = RGE_HASH_POLY;
865c7fd2ed0Sgs150176 	uint32_t msb;
866c7fd2ed0Sgs150176 	int bytes;
867c7fd2ed0Sgs150176 	uchar_t currentbyte;
868c7fd2ed0Sgs150176 	uint32_t index;
869c7fd2ed0Sgs150176 	int bit;
870c7fd2ed0Sgs150176 
871c7fd2ed0Sgs150176 	for (bytes = 0; bytes < ETHERADDRL; bytes++) {
872c7fd2ed0Sgs150176 		currentbyte = mca[bytes];
873c7fd2ed0Sgs150176 		for (bit = 0; bit < 8; bit++) {
874c7fd2ed0Sgs150176 			msb = crc >> 31;
875c7fd2ed0Sgs150176 			crc <<= 1;
876aa817493Sgs150176 			if (msb ^ (currentbyte & 1))
877c7fd2ed0Sgs150176 				crc ^= POLY;
878c7fd2ed0Sgs150176 			currentbyte >>= 1;
879c7fd2ed0Sgs150176 		}
880c7fd2ed0Sgs150176 	}
881c7fd2ed0Sgs150176 	index = crc >> 26;
882aa817493Sgs150176 		/* the index value is between 0 and 63(0x3f) */
883c7fd2ed0Sgs150176 
884c7fd2ed0Sgs150176 	return (index);
885c7fd2ed0Sgs150176 }
886c7fd2ed0Sgs150176 
887c7fd2ed0Sgs150176 /*
888c7fd2ed0Sgs150176  *	rge_m_multicst_add() -- enable/disable a multicast address
889c7fd2ed0Sgs150176  */
890c7fd2ed0Sgs150176 static int
891c7fd2ed0Sgs150176 rge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
892c7fd2ed0Sgs150176 {
893c7fd2ed0Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
894c7fd2ed0Sgs150176 	struct ether_addr *addr;
895c7fd2ed0Sgs150176 	uint32_t index;
896aa817493Sgs150176 	uint32_t reg;
897aa817493Sgs150176 	uint8_t *hashp;
898c7fd2ed0Sgs150176 
899c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
900c7fd2ed0Sgs150176 	hashp = rgep->mcast_hash;
901c7fd2ed0Sgs150176 	addr = (struct ether_addr *)mca;
902aa817493Sgs150176 	/*
903aa817493Sgs150176 	 * Calculate the Multicast address hash index value
904aa817493Sgs150176 	 *	Normally, the position of MAR0-MAR7 is
905aa817493Sgs150176 	 *	MAR0: offset 0x08, ..., MAR7: offset 0x0F.
906aa817493Sgs150176 	 *
907aa817493Sgs150176 	 *	For pcie chipset, the position of MAR0-MAR7 is
908aa817493Sgs150176 	 *	different from others:
909aa817493Sgs150176 	 *	MAR0: offset 0x0F, ..., MAR7: offset 0x08.
910aa817493Sgs150176 	 */
911c7fd2ed0Sgs150176 	index = rge_hash_index(addr->ether_addr_octet);
912aa817493Sgs150176 	if (rgep->chipid.is_pcie)
913aa817493Sgs150176 		reg = (~(index / RGE_MCAST_NUM)) & 0x7;
914aa817493Sgs150176 	else
915aa817493Sgs150176 		reg = index / RGE_MCAST_NUM;
916c7fd2ed0Sgs150176 
917c7fd2ed0Sgs150176 	if (add) {
918c7fd2ed0Sgs150176 		if (rgep->mcast_refs[index]++) {
919c7fd2ed0Sgs150176 			mutex_exit(rgep->genlock);
920c7fd2ed0Sgs150176 			return (0);
921c7fd2ed0Sgs150176 		}
922aa817493Sgs150176 		hashp[reg] |= 1 << (index % RGE_MCAST_NUM);
923c7fd2ed0Sgs150176 	} else {
924c7fd2ed0Sgs150176 		if (--rgep->mcast_refs[index]) {
925c7fd2ed0Sgs150176 			mutex_exit(rgep->genlock);
926c7fd2ed0Sgs150176 			return (0);
927c7fd2ed0Sgs150176 		}
928aa817493Sgs150176 		hashp[reg] &= ~ (1 << (index % RGE_MCAST_NUM));
929c7fd2ed0Sgs150176 	}
930c7fd2ed0Sgs150176 
931c7fd2ed0Sgs150176 	/*
932c7fd2ed0Sgs150176 	 * Set multicast register
933c7fd2ed0Sgs150176 	 */
934c7fd2ed0Sgs150176 	rge_chip_sync(rgep, RGE_SET_MUL);
935c7fd2ed0Sgs150176 
936c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
937c7fd2ed0Sgs150176 	return (0);
938c7fd2ed0Sgs150176 }
939c7fd2ed0Sgs150176 
940c7fd2ed0Sgs150176 /*
941c7fd2ed0Sgs150176  * rge_m_promisc() -- set or reset promiscuous mode on the board
942c7fd2ed0Sgs150176  *
943c7fd2ed0Sgs150176  *	Program the hardware to enable/disable promiscuous and/or
944c7fd2ed0Sgs150176  *	receive-all-multicast modes.
945c7fd2ed0Sgs150176  */
946c7fd2ed0Sgs150176 static int
947c7fd2ed0Sgs150176 rge_m_promisc(void *arg, boolean_t on)
948c7fd2ed0Sgs150176 {
949c7fd2ed0Sgs150176 	rge_t *rgep = arg;
950c7fd2ed0Sgs150176 
951c7fd2ed0Sgs150176 	/*
952c7fd2ed0Sgs150176 	 * Store MAC layer specified mode and pass to chip layer to update h/w
953c7fd2ed0Sgs150176 	 */
954c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
955c7fd2ed0Sgs150176 
956c7fd2ed0Sgs150176 	if (rgep->promisc == on) {
957c7fd2ed0Sgs150176 		mutex_exit(rgep->genlock);
958c7fd2ed0Sgs150176 		return (0);
959c7fd2ed0Sgs150176 	}
960c7fd2ed0Sgs150176 	rgep->promisc = on;
961c7fd2ed0Sgs150176 	rge_chip_sync(rgep, RGE_SET_PROMISC);
962c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_m_promisc_set($%p) done", arg));
963c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
964c7fd2ed0Sgs150176 	return (0);
965c7fd2ed0Sgs150176 }
966c7fd2ed0Sgs150176 
967c7fd2ed0Sgs150176 /*
968c7fd2ed0Sgs150176  * Loopback ioctl code
969c7fd2ed0Sgs150176  */
970c7fd2ed0Sgs150176 
971c7fd2ed0Sgs150176 static lb_property_t loopmodes[] = {
972c7fd2ed0Sgs150176 	{ normal,	"normal",	RGE_LOOP_NONE		},
973c7fd2ed0Sgs150176 	{ internal,	"PHY",		RGE_LOOP_INTERNAL_PHY	},
974c7fd2ed0Sgs150176 	{ internal,	"MAC",		RGE_LOOP_INTERNAL_MAC	}
975c7fd2ed0Sgs150176 };
976c7fd2ed0Sgs150176 
977c7fd2ed0Sgs150176 static enum ioc_reply
978c7fd2ed0Sgs150176 rge_set_loop_mode(rge_t *rgep, uint32_t mode)
979c7fd2ed0Sgs150176 {
980c7fd2ed0Sgs150176 	/*
981c7fd2ed0Sgs150176 	 * If the mode isn't being changed, there's nothing to do ...
982c7fd2ed0Sgs150176 	 */
983c7fd2ed0Sgs150176 	if (mode == rgep->param_loop_mode)
984c7fd2ed0Sgs150176 		return (IOC_ACK);
985c7fd2ed0Sgs150176 
986c7fd2ed0Sgs150176 	/*
987c7fd2ed0Sgs150176 	 * Validate the requested mode and prepare a suitable message
988c7fd2ed0Sgs150176 	 * to explain the link down/up cycle that the change will
989c7fd2ed0Sgs150176 	 * probably induce ...
990c7fd2ed0Sgs150176 	 */
991c7fd2ed0Sgs150176 	switch (mode) {
992c7fd2ed0Sgs150176 	default:
993c7fd2ed0Sgs150176 		return (IOC_INVAL);
994c7fd2ed0Sgs150176 
995c7fd2ed0Sgs150176 	case RGE_LOOP_NONE:
996c7fd2ed0Sgs150176 	case RGE_LOOP_INTERNAL_PHY:
997c7fd2ed0Sgs150176 	case RGE_LOOP_INTERNAL_MAC:
998c7fd2ed0Sgs150176 		break;
999c7fd2ed0Sgs150176 	}
1000c7fd2ed0Sgs150176 
1001c7fd2ed0Sgs150176 	/*
1002c7fd2ed0Sgs150176 	 * All OK; tell the caller to reprogram
1003c7fd2ed0Sgs150176 	 * the PHY and/or MAC for the new mode ...
1004c7fd2ed0Sgs150176 	 */
1005c7fd2ed0Sgs150176 	rgep->param_loop_mode = mode;
1006c7fd2ed0Sgs150176 	return (IOC_RESTART_ACK);
1007c7fd2ed0Sgs150176 }
1008c7fd2ed0Sgs150176 
1009c7fd2ed0Sgs150176 static enum ioc_reply
1010c7fd2ed0Sgs150176 rge_loop_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
1011c7fd2ed0Sgs150176 {
1012c7fd2ed0Sgs150176 	lb_info_sz_t *lbsp;
1013c7fd2ed0Sgs150176 	lb_property_t *lbpp;
1014c7fd2ed0Sgs150176 	uint32_t *lbmp;
1015c7fd2ed0Sgs150176 	int cmd;
1016c7fd2ed0Sgs150176 
1017c7fd2ed0Sgs150176 	_NOTE(ARGUNUSED(wq))
1018c7fd2ed0Sgs150176 
1019c7fd2ed0Sgs150176 	/*
1020c7fd2ed0Sgs150176 	 * Validate format of ioctl
1021c7fd2ed0Sgs150176 	 */
1022c7fd2ed0Sgs150176 	if (mp->b_cont == NULL)
1023c7fd2ed0Sgs150176 		return (IOC_INVAL);
1024c7fd2ed0Sgs150176 
1025c7fd2ed0Sgs150176 	cmd = iocp->ioc_cmd;
1026c7fd2ed0Sgs150176 	switch (cmd) {
1027c7fd2ed0Sgs150176 	default:
1028c7fd2ed0Sgs150176 		/* NOTREACHED */
1029c7fd2ed0Sgs150176 		rge_error(rgep, "rge_loop_ioctl: invalid cmd 0x%x", cmd);
1030c7fd2ed0Sgs150176 		return (IOC_INVAL);
1031c7fd2ed0Sgs150176 
1032c7fd2ed0Sgs150176 	case LB_GET_INFO_SIZE:
1033c7fd2ed0Sgs150176 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
1034c7fd2ed0Sgs150176 			return (IOC_INVAL);
1035c7fd2ed0Sgs150176 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
1036c7fd2ed0Sgs150176 		*lbsp = sizeof (loopmodes);
1037c7fd2ed0Sgs150176 		return (IOC_REPLY);
1038c7fd2ed0Sgs150176 
1039c7fd2ed0Sgs150176 	case LB_GET_INFO:
1040c7fd2ed0Sgs150176 		if (iocp->ioc_count != sizeof (loopmodes))
1041c7fd2ed0Sgs150176 			return (IOC_INVAL);
1042c7fd2ed0Sgs150176 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
1043c7fd2ed0Sgs150176 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
1044c7fd2ed0Sgs150176 		return (IOC_REPLY);
1045c7fd2ed0Sgs150176 
1046c7fd2ed0Sgs150176 	case LB_GET_MODE:
1047c7fd2ed0Sgs150176 		if (iocp->ioc_count != sizeof (uint32_t))
1048c7fd2ed0Sgs150176 			return (IOC_INVAL);
1049c7fd2ed0Sgs150176 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
1050c7fd2ed0Sgs150176 		*lbmp = rgep->param_loop_mode;
1051c7fd2ed0Sgs150176 		return (IOC_REPLY);
1052c7fd2ed0Sgs150176 
1053c7fd2ed0Sgs150176 	case LB_SET_MODE:
1054c7fd2ed0Sgs150176 		if (iocp->ioc_count != sizeof (uint32_t))
1055c7fd2ed0Sgs150176 			return (IOC_INVAL);
1056c7fd2ed0Sgs150176 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
1057c7fd2ed0Sgs150176 		return (rge_set_loop_mode(rgep, *lbmp));
1058c7fd2ed0Sgs150176 	}
1059c7fd2ed0Sgs150176 }
1060c7fd2ed0Sgs150176 
1061c7fd2ed0Sgs150176 /*
1062c7fd2ed0Sgs150176  * Specific rge IOCTLs, the MAC layer handles the generic ones.
1063c7fd2ed0Sgs150176  */
1064c7fd2ed0Sgs150176 static void
1065c7fd2ed0Sgs150176 rge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1066c7fd2ed0Sgs150176 {
1067c7fd2ed0Sgs150176 	rge_t *rgep = arg;
1068c7fd2ed0Sgs150176 	struct iocblk *iocp;
1069c7fd2ed0Sgs150176 	enum ioc_reply status;
1070c7fd2ed0Sgs150176 	boolean_t need_privilege;
1071c7fd2ed0Sgs150176 	int err;
1072c7fd2ed0Sgs150176 	int cmd;
1073c7fd2ed0Sgs150176 
1074c7fd2ed0Sgs150176 	/*
1075c7fd2ed0Sgs150176 	 * Validate the command before bothering with the mutex ...
1076c7fd2ed0Sgs150176 	 */
1077c7fd2ed0Sgs150176 	iocp = (struct iocblk *)mp->b_rptr;
1078c7fd2ed0Sgs150176 	iocp->ioc_error = 0;
1079c7fd2ed0Sgs150176 	need_privilege = B_TRUE;
1080c7fd2ed0Sgs150176 	cmd = iocp->ioc_cmd;
1081c7fd2ed0Sgs150176 	switch (cmd) {
1082c7fd2ed0Sgs150176 	default:
1083c7fd2ed0Sgs150176 		miocnak(wq, mp, 0, EINVAL);
1084c7fd2ed0Sgs150176 		return;
1085c7fd2ed0Sgs150176 
1086c7fd2ed0Sgs150176 	case RGE_MII_READ:
1087c7fd2ed0Sgs150176 	case RGE_MII_WRITE:
1088c7fd2ed0Sgs150176 	case RGE_DIAG:
1089c7fd2ed0Sgs150176 	case RGE_PEEK:
1090c7fd2ed0Sgs150176 	case RGE_POKE:
1091c7fd2ed0Sgs150176 	case RGE_PHY_RESET:
1092c7fd2ed0Sgs150176 	case RGE_SOFT_RESET:
1093c7fd2ed0Sgs150176 	case RGE_HARD_RESET:
1094c7fd2ed0Sgs150176 		break;
1095c7fd2ed0Sgs150176 
1096c7fd2ed0Sgs150176 	case LB_GET_INFO_SIZE:
1097c7fd2ed0Sgs150176 	case LB_GET_INFO:
1098c7fd2ed0Sgs150176 	case LB_GET_MODE:
1099c7fd2ed0Sgs150176 		need_privilege = B_FALSE;
1100c7fd2ed0Sgs150176 		/* FALLTHRU */
1101c7fd2ed0Sgs150176 	case LB_SET_MODE:
1102c7fd2ed0Sgs150176 		break;
1103c7fd2ed0Sgs150176 
1104c7fd2ed0Sgs150176 	case ND_GET:
1105c7fd2ed0Sgs150176 		need_privilege = B_FALSE;
1106c7fd2ed0Sgs150176 		/* FALLTHRU */
1107c7fd2ed0Sgs150176 	case ND_SET:
1108c7fd2ed0Sgs150176 		break;
1109c7fd2ed0Sgs150176 	}
1110c7fd2ed0Sgs150176 
1111c7fd2ed0Sgs150176 	if (need_privilege) {
1112c7fd2ed0Sgs150176 		/*
1113aa817493Sgs150176 		 * Check for specific net_config privilege
1114c7fd2ed0Sgs150176 		 */
1115c7fd2ed0Sgs150176 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1116c7fd2ed0Sgs150176 		if (err != 0) {
1117c7fd2ed0Sgs150176 			miocnak(wq, mp, 0, err);
1118c7fd2ed0Sgs150176 			return;
1119c7fd2ed0Sgs150176 		}
1120c7fd2ed0Sgs150176 	}
1121c7fd2ed0Sgs150176 
1122c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
1123c7fd2ed0Sgs150176 
1124c7fd2ed0Sgs150176 	switch (cmd) {
1125c7fd2ed0Sgs150176 	default:
1126c7fd2ed0Sgs150176 		_NOTE(NOTREACHED)
1127c7fd2ed0Sgs150176 		status = IOC_INVAL;
1128c7fd2ed0Sgs150176 		break;
1129c7fd2ed0Sgs150176 
1130c7fd2ed0Sgs150176 	case RGE_MII_READ:
1131c7fd2ed0Sgs150176 	case RGE_MII_WRITE:
1132c7fd2ed0Sgs150176 	case RGE_DIAG:
1133c7fd2ed0Sgs150176 	case RGE_PEEK:
1134c7fd2ed0Sgs150176 	case RGE_POKE:
1135c7fd2ed0Sgs150176 	case RGE_PHY_RESET:
1136c7fd2ed0Sgs150176 	case RGE_SOFT_RESET:
1137c7fd2ed0Sgs150176 	case RGE_HARD_RESET:
1138c7fd2ed0Sgs150176 		status = rge_chip_ioctl(rgep, wq, mp, iocp);
1139c7fd2ed0Sgs150176 		break;
1140c7fd2ed0Sgs150176 
1141c7fd2ed0Sgs150176 	case LB_GET_INFO_SIZE:
1142c7fd2ed0Sgs150176 	case LB_GET_INFO:
1143c7fd2ed0Sgs150176 	case LB_GET_MODE:
1144c7fd2ed0Sgs150176 	case LB_SET_MODE:
1145c7fd2ed0Sgs150176 		status = rge_loop_ioctl(rgep, wq, mp, iocp);
1146c7fd2ed0Sgs150176 		break;
1147c7fd2ed0Sgs150176 
1148c7fd2ed0Sgs150176 	case ND_GET:
1149c7fd2ed0Sgs150176 	case ND_SET:
1150c7fd2ed0Sgs150176 		status = rge_nd_ioctl(rgep, wq, mp, iocp);
1151c7fd2ed0Sgs150176 		break;
1152c7fd2ed0Sgs150176 	}
1153c7fd2ed0Sgs150176 
1154c7fd2ed0Sgs150176 	/*
1155c7fd2ed0Sgs150176 	 * Do we need to reprogram the PHY and/or the MAC?
1156c7fd2ed0Sgs150176 	 * Do it now, while we still have the mutex.
1157c7fd2ed0Sgs150176 	 *
1158c7fd2ed0Sgs150176 	 * Note: update the PHY first, 'cos it controls the
1159c7fd2ed0Sgs150176 	 * speed/duplex parameters that the MAC code uses.
1160c7fd2ed0Sgs150176 	 */
1161c7fd2ed0Sgs150176 	switch (status) {
1162c7fd2ed0Sgs150176 	case IOC_RESTART_REPLY:
1163c7fd2ed0Sgs150176 	case IOC_RESTART_ACK:
1164c7fd2ed0Sgs150176 		rge_phy_update(rgep);
1165c7fd2ed0Sgs150176 		break;
1166c7fd2ed0Sgs150176 	}
1167c7fd2ed0Sgs150176 
1168c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1169c7fd2ed0Sgs150176 
1170c7fd2ed0Sgs150176 	/*
1171c7fd2ed0Sgs150176 	 * Finally, decide how to reply
1172c7fd2ed0Sgs150176 	 */
1173c7fd2ed0Sgs150176 	switch (status) {
1174c7fd2ed0Sgs150176 	default:
1175c7fd2ed0Sgs150176 	case IOC_INVAL:
1176c7fd2ed0Sgs150176 		/*
1177c7fd2ed0Sgs150176 		 * Error, reply with a NAK and EINVAL or the specified error
1178c7fd2ed0Sgs150176 		 */
1179c7fd2ed0Sgs150176 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
1180c7fd2ed0Sgs150176 		    EINVAL : iocp->ioc_error);
1181c7fd2ed0Sgs150176 		break;
1182c7fd2ed0Sgs150176 
1183c7fd2ed0Sgs150176 	case IOC_DONE:
1184c7fd2ed0Sgs150176 		/*
1185c7fd2ed0Sgs150176 		 * OK, reply already sent
1186c7fd2ed0Sgs150176 		 */
1187c7fd2ed0Sgs150176 		break;
1188c7fd2ed0Sgs150176 
1189c7fd2ed0Sgs150176 	case IOC_RESTART_ACK:
1190c7fd2ed0Sgs150176 	case IOC_ACK:
1191c7fd2ed0Sgs150176 		/*
1192c7fd2ed0Sgs150176 		 * OK, reply with an ACK
1193c7fd2ed0Sgs150176 		 */
1194c7fd2ed0Sgs150176 		miocack(wq, mp, 0, 0);
1195c7fd2ed0Sgs150176 		break;
1196c7fd2ed0Sgs150176 
1197c7fd2ed0Sgs150176 	case IOC_RESTART_REPLY:
1198c7fd2ed0Sgs150176 	case IOC_REPLY:
1199c7fd2ed0Sgs150176 		/*
1200c7fd2ed0Sgs150176 		 * OK, send prepared reply as ACK or NAK
1201c7fd2ed0Sgs150176 		 */
1202c7fd2ed0Sgs150176 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
1203c7fd2ed0Sgs150176 		    M_IOCACK : M_IOCNAK;
1204c7fd2ed0Sgs150176 		qreply(wq, mp);
1205c7fd2ed0Sgs150176 		break;
1206c7fd2ed0Sgs150176 	}
1207c7fd2ed0Sgs150176 }
1208c7fd2ed0Sgs150176 
1209c7fd2ed0Sgs150176 static void
1210c7fd2ed0Sgs150176 rge_m_resources(void *arg)
1211c7fd2ed0Sgs150176 {
1212c7fd2ed0Sgs150176 	rge_t *rgep = arg;
1213c7fd2ed0Sgs150176 	mac_rx_fifo_t mrf;
1214c7fd2ed0Sgs150176 
1215c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
1216c7fd2ed0Sgs150176 
1217c7fd2ed0Sgs150176 	/*
1218c7fd2ed0Sgs150176 	 * Register Rx rings as resources and save mac
1219c7fd2ed0Sgs150176 	 * resource id for future reference
1220c7fd2ed0Sgs150176 	 */
1221c7fd2ed0Sgs150176 	mrf.mrf_type = MAC_RX_FIFO;
1222c7fd2ed0Sgs150176 	mrf.mrf_blank = rge_chip_blank;
1223c7fd2ed0Sgs150176 	mrf.mrf_arg = (void *)rgep;
1224c7fd2ed0Sgs150176 	mrf.mrf_normal_blank_time = RGE_RX_INT_TIME;
1225c7fd2ed0Sgs150176 	mrf.mrf_normal_pkt_count = RGE_RX_INT_PKTS;
1226ba2e4443Sseb 	rgep->handle = mac_resource_add(rgep->mh, (mac_resource_t *)&mrf);
1227c7fd2ed0Sgs150176 
1228c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1229c7fd2ed0Sgs150176 }
1230c7fd2ed0Sgs150176 
1231ba2e4443Sseb /* ARGSUSED */
1232ba2e4443Sseb static boolean_t
1233ba2e4443Sseb rge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
1234ba2e4443Sseb {
1235ba2e4443Sseb 	switch (cap) {
1236ba2e4443Sseb 	case MAC_CAPAB_HCKSUM: {
1237ba2e4443Sseb 		uint32_t *hcksum_txflags = cap_data;
1238ba2e4443Sseb 		*hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
1239ba2e4443Sseb 		break;
1240ba2e4443Sseb 	}
1241ba2e4443Sseb 	case MAC_CAPAB_POLL:
1242ba2e4443Sseb 		/*
1243ba2e4443Sseb 		 * There's nothing for us to fill in, simply returning
1244ba2e4443Sseb 		 * B_TRUE stating that we support polling is sufficient.
1245ba2e4443Sseb 		 */
1246ba2e4443Sseb 		break;
1247ba2e4443Sseb 	default:
1248ba2e4443Sseb 		return (B_FALSE);
1249ba2e4443Sseb 	}
1250ba2e4443Sseb 	return (B_TRUE);
1251ba2e4443Sseb }
1252ba2e4443Sseb 
1253c7fd2ed0Sgs150176 /*
1254aa817493Sgs150176  * ============ Init MSI/Fixed Interrupt routines ==============
1255aa817493Sgs150176  */
1256aa817493Sgs150176 
1257aa817493Sgs150176 /*
1258aa817493Sgs150176  * rge_add_intrs:
1259aa817493Sgs150176  *
1260aa817493Sgs150176  * Register FIXED or MSI interrupts.
1261aa817493Sgs150176  */
1262aa817493Sgs150176 static int
1263aa817493Sgs150176 rge_add_intrs(rge_t *rgep, int intr_type)
1264aa817493Sgs150176 {
1265aa817493Sgs150176 	dev_info_t *dip = rgep->devinfo;
1266aa817493Sgs150176 	int avail;
1267aa817493Sgs150176 	int actual;
1268aa817493Sgs150176 	int intr_size;
1269aa817493Sgs150176 	int count;
1270aa817493Sgs150176 	int i, j;
1271aa817493Sgs150176 	int ret;
1272aa817493Sgs150176 
1273aa817493Sgs150176 	/* Get number of interrupts */
1274aa817493Sgs150176 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
1275aa817493Sgs150176 	if ((ret != DDI_SUCCESS) || (count == 0)) {
1276aa817493Sgs150176 		rge_error(rgep, "ddi_intr_get_nintrs() failure, ret: %d, "
1277aa817493Sgs150176 		    "count: %d", ret, count);
1278aa817493Sgs150176 		return (DDI_FAILURE);
1279aa817493Sgs150176 	}
1280aa817493Sgs150176 
1281aa817493Sgs150176 	/* Get number of available interrupts */
1282aa817493Sgs150176 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
1283aa817493Sgs150176 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
1284aa817493Sgs150176 		rge_error(rgep, "ddi_intr_get_navail() failure, "
1285aa817493Sgs150176 		    "ret: %d, avail: %d\n", ret, avail);
1286aa817493Sgs150176 		return (DDI_FAILURE);
1287aa817493Sgs150176 	}
1288aa817493Sgs150176 
1289aa817493Sgs150176 	/* Allocate an array of interrupt handles */
1290aa817493Sgs150176 	intr_size = count * sizeof (ddi_intr_handle_t);
1291aa817493Sgs150176 	rgep->htable = kmem_alloc(intr_size, KM_SLEEP);
1292aa817493Sgs150176 	rgep->intr_rqst = count;
1293aa817493Sgs150176 
1294aa817493Sgs150176 	/* Call ddi_intr_alloc() */
1295aa817493Sgs150176 	ret = ddi_intr_alloc(dip, rgep->htable, intr_type, 0,
1296aa817493Sgs150176 	    count, &actual, DDI_INTR_ALLOC_NORMAL);
1297aa817493Sgs150176 	if (ret != DDI_SUCCESS || actual == 0) {
1298aa817493Sgs150176 		rge_error(rgep, "ddi_intr_alloc() failed %d\n", ret);
1299aa817493Sgs150176 		kmem_free(rgep->htable, intr_size);
1300aa817493Sgs150176 		return (DDI_FAILURE);
1301aa817493Sgs150176 	}
1302aa817493Sgs150176 	if (actual < count) {
1303aa817493Sgs150176 		rge_log(rgep, "ddi_intr_alloc() Requested: %d, Received: %d\n",
1304aa817493Sgs150176 		    count, actual);
1305aa817493Sgs150176 	}
1306aa817493Sgs150176 	rgep->intr_cnt = actual;
1307aa817493Sgs150176 
1308aa817493Sgs150176 	/*
1309aa817493Sgs150176 	 * Get priority for first msi, assume remaining are all the same
1310aa817493Sgs150176 	 */
1311aa817493Sgs150176 	if ((ret = ddi_intr_get_pri(rgep->htable[0], &rgep->intr_pri)) !=
1312aa817493Sgs150176 	    DDI_SUCCESS) {
1313aa817493Sgs150176 		rge_error(rgep, "ddi_intr_get_pri() failed %d\n", ret);
1314aa817493Sgs150176 		/* Free already allocated intr */
1315aa817493Sgs150176 		for (i = 0; i < actual; i++) {
1316aa817493Sgs150176 			(void) ddi_intr_free(rgep->htable[i]);
1317aa817493Sgs150176 		}
1318aa817493Sgs150176 		kmem_free(rgep->htable, intr_size);
1319aa817493Sgs150176 		return (DDI_FAILURE);
1320aa817493Sgs150176 	}
1321aa817493Sgs150176 
1322aa817493Sgs150176 	/* Test for high level mutex */
1323aa817493Sgs150176 	if (rgep->intr_pri >= ddi_intr_get_hilevel_pri()) {
1324aa817493Sgs150176 		rge_error(rgep, "rge_add_intrs:"
1325aa817493Sgs150176 		    "Hi level interrupt not supported");
1326aa817493Sgs150176 		for (i = 0; i < actual; i++)
1327aa817493Sgs150176 			(void) ddi_intr_free(rgep->htable[i]);
1328aa817493Sgs150176 		kmem_free(rgep->htable, intr_size);
1329aa817493Sgs150176 		return (DDI_FAILURE);
1330aa817493Sgs150176 	}
1331aa817493Sgs150176 
1332aa817493Sgs150176 	/* Call ddi_intr_add_handler() */
1333aa817493Sgs150176 	for (i = 0; i < actual; i++) {
1334aa817493Sgs150176 		if ((ret = ddi_intr_add_handler(rgep->htable[i], rge_intr,
1335aa817493Sgs150176 		    (caddr_t)rgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
1336aa817493Sgs150176 			rge_error(rgep, "ddi_intr_add_handler() "
1337aa817493Sgs150176 			    "failed %d\n", ret);
1338aa817493Sgs150176 			/* Remove already added intr */
1339aa817493Sgs150176 			for (j = 0; j < i; j++)
1340aa817493Sgs150176 				(void) ddi_intr_remove_handler(rgep->htable[j]);
1341aa817493Sgs150176 			/* Free already allocated intr */
1342aa817493Sgs150176 			for (i = 0; i < actual; i++) {
1343aa817493Sgs150176 				(void) ddi_intr_free(rgep->htable[i]);
1344aa817493Sgs150176 			}
1345aa817493Sgs150176 			kmem_free(rgep->htable, intr_size);
1346aa817493Sgs150176 			return (DDI_FAILURE);
1347aa817493Sgs150176 		}
1348aa817493Sgs150176 	}
1349aa817493Sgs150176 
1350aa817493Sgs150176 	if ((ret = ddi_intr_get_cap(rgep->htable[0], &rgep->intr_cap))
1351aa817493Sgs150176 	    != DDI_SUCCESS) {
1352aa817493Sgs150176 		rge_error(rgep, "ddi_intr_get_cap() failed %d\n", ret);
1353aa817493Sgs150176 		for (i = 0; i < actual; i++) {
1354aa817493Sgs150176 			(void) ddi_intr_remove_handler(rgep->htable[i]);
1355aa817493Sgs150176 			(void) ddi_intr_free(rgep->htable[i]);
1356aa817493Sgs150176 		}
1357aa817493Sgs150176 		kmem_free(rgep->htable, intr_size);
1358aa817493Sgs150176 		return (DDI_FAILURE);
1359aa817493Sgs150176 	}
1360aa817493Sgs150176 
1361aa817493Sgs150176 	return (DDI_SUCCESS);
1362aa817493Sgs150176 }
1363aa817493Sgs150176 
1364aa817493Sgs150176 /*
1365aa817493Sgs150176  * rge_rem_intrs:
1366aa817493Sgs150176  *
1367aa817493Sgs150176  * Unregister FIXED or MSI interrupts
1368aa817493Sgs150176  */
1369aa817493Sgs150176 static void
1370aa817493Sgs150176 rge_rem_intrs(rge_t *rgep)
1371aa817493Sgs150176 {
1372aa817493Sgs150176 	int i;
1373aa817493Sgs150176 
1374aa817493Sgs150176 	/* Disable all interrupts */
1375aa817493Sgs150176 	if (rgep->intr_cap & DDI_INTR_FLAG_BLOCK) {
1376aa817493Sgs150176 		/* Call ddi_intr_block_disable() */
1377aa817493Sgs150176 		(void) ddi_intr_block_disable(rgep->htable, rgep->intr_cnt);
1378aa817493Sgs150176 	} else {
1379aa817493Sgs150176 		for (i = 0; i < rgep->intr_cnt; i++) {
1380aa817493Sgs150176 			(void) ddi_intr_disable(rgep->htable[i]);
1381aa817493Sgs150176 		}
1382aa817493Sgs150176 	}
1383aa817493Sgs150176 
1384aa817493Sgs150176 	/* Call ddi_intr_remove_handler() */
1385aa817493Sgs150176 	for (i = 0; i < rgep->intr_cnt; i++) {
1386aa817493Sgs150176 		(void) ddi_intr_remove_handler(rgep->htable[i]);
1387aa817493Sgs150176 		(void) ddi_intr_free(rgep->htable[i]);
1388aa817493Sgs150176 	}
1389aa817493Sgs150176 
1390aa817493Sgs150176 	kmem_free(rgep->htable, rgep->intr_rqst * sizeof (ddi_intr_handle_t));
1391aa817493Sgs150176 }
1392aa817493Sgs150176 
1393aa817493Sgs150176 /*
1394c7fd2ed0Sgs150176  * ========== Per-instance setup/teardown code ==========
1395c7fd2ed0Sgs150176  */
1396c7fd2ed0Sgs150176 
1397c7fd2ed0Sgs150176 #undef	RGE_DBG
1398c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_INIT	/* debug flag for this code	*/
1399c7fd2ed0Sgs150176 
1400c7fd2ed0Sgs150176 static void
1401c7fd2ed0Sgs150176 rge_unattach(rge_t *rgep)
1402c7fd2ed0Sgs150176 {
1403c7fd2ed0Sgs150176 	/*
1404c7fd2ed0Sgs150176 	 * Flag that no more activity may be initiated
1405c7fd2ed0Sgs150176 	 */
1406c7fd2ed0Sgs150176 	rgep->progress &= ~PROGRESS_READY;
1407c7fd2ed0Sgs150176 	rgep->rge_mac_state = RGE_MAC_UNATTACH;
1408c7fd2ed0Sgs150176 
1409c7fd2ed0Sgs150176 	/*
1410c7fd2ed0Sgs150176 	 * Quiesce the PHY and MAC (leave it reset but still powered).
1411c7fd2ed0Sgs150176 	 * Clean up and free all RGE data structures
1412c7fd2ed0Sgs150176 	 */
1413dd4eeefdSeota 	if (rgep->periodic_id != NULL) {
1414dd4eeefdSeota 		ddi_periodic_delete(rgep->periodic_id);
1415dd4eeefdSeota 		rgep->periodic_id = NULL;
1416c7fd2ed0Sgs150176 	}
1417c7fd2ed0Sgs150176 
1418c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_KSTATS)
1419c7fd2ed0Sgs150176 		rge_fini_kstats(rgep);
1420c7fd2ed0Sgs150176 
1421c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_PHY)
1422c7fd2ed0Sgs150176 		(void) rge_phy_reset(rgep);
1423c7fd2ed0Sgs150176 
1424aa817493Sgs150176 	if (rgep->progress & PROGRESS_INIT) {
1425c7fd2ed0Sgs150176 		mutex_enter(rgep->genlock);
1426c7fd2ed0Sgs150176 		(void) rge_chip_reset(rgep);
1427c7fd2ed0Sgs150176 		mutex_exit(rgep->genlock);
1428c7fd2ed0Sgs150176 		rge_fini_rings(rgep);
1429aa817493Sgs150176 	}
1430aa817493Sgs150176 
1431aa817493Sgs150176 	if (rgep->progress & PROGRESS_INTR) {
1432aa817493Sgs150176 		rge_rem_intrs(rgep);
1433c7fd2ed0Sgs150176 		mutex_destroy(rgep->rc_lock);
1434c7fd2ed0Sgs150176 		mutex_destroy(rgep->rx_lock);
1435c7fd2ed0Sgs150176 		mutex_destroy(rgep->tc_lock);
1436c7fd2ed0Sgs150176 		mutex_destroy(rgep->tx_lock);
1437c7fd2ed0Sgs150176 		rw_destroy(rgep->errlock);
1438c7fd2ed0Sgs150176 		mutex_destroy(rgep->genlock);
1439c7fd2ed0Sgs150176 	}
1440c7fd2ed0Sgs150176 
1441c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_FACTOTUM)
1442aa817493Sgs150176 		(void) ddi_intr_remove_softint(rgep->factotum_hdl);
1443c7fd2ed0Sgs150176 
1444c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_RESCHED)
1445aa817493Sgs150176 		(void) ddi_intr_remove_softint(rgep->resched_hdl);
1446c7fd2ed0Sgs150176 
1447c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_NDD)
1448c7fd2ed0Sgs150176 		rge_nd_cleanup(rgep);
1449c7fd2ed0Sgs150176 
1450*dfc2d53eSmx205022 	rge_free_bufs(rgep);
1451*dfc2d53eSmx205022 
1452c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_REGS)
1453c7fd2ed0Sgs150176 		ddi_regs_map_free(&rgep->io_handle);
1454c7fd2ed0Sgs150176 
1455c7fd2ed0Sgs150176 	if (rgep->progress & PROGRESS_CFG)
1456c7fd2ed0Sgs150176 		pci_config_teardown(&rgep->cfg_handle);
1457c7fd2ed0Sgs150176 
1458c7fd2ed0Sgs150176 	ddi_remove_minor_node(rgep->devinfo, NULL);
1459c7fd2ed0Sgs150176 	kmem_free(rgep, sizeof (*rgep));
1460c7fd2ed0Sgs150176 }
1461c7fd2ed0Sgs150176 
1462c7fd2ed0Sgs150176 static int
1463c7fd2ed0Sgs150176 rge_resume(dev_info_t *devinfo)
1464c7fd2ed0Sgs150176 {
1465c7fd2ed0Sgs150176 	rge_t *rgep;			/* Our private data	*/
1466c7fd2ed0Sgs150176 	chip_id_t *cidp;
1467c7fd2ed0Sgs150176 	chip_id_t chipid;
1468c7fd2ed0Sgs150176 
1469c7fd2ed0Sgs150176 	rgep = ddi_get_driver_private(devinfo);
1470c7fd2ed0Sgs150176 	if (rgep == NULL)
1471c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1472c7fd2ed0Sgs150176 
1473c7fd2ed0Sgs150176 	/*
1474c7fd2ed0Sgs150176 	 * Refuse to resume if the data structures aren't consistent
1475c7fd2ed0Sgs150176 	 */
1476c7fd2ed0Sgs150176 	if (rgep->devinfo != devinfo)
1477c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1478c7fd2ed0Sgs150176 
1479c7fd2ed0Sgs150176 	/*
1480c7fd2ed0Sgs150176 	 * Read chip ID & set up config space command register(s)
1481c7fd2ed0Sgs150176 	 * Refuse to resume if the chip has changed its identity!
1482c7fd2ed0Sgs150176 	 */
1483c7fd2ed0Sgs150176 	cidp = &rgep->chipid;
1484c7fd2ed0Sgs150176 	rge_chip_cfg_init(rgep, &chipid);
1485c7fd2ed0Sgs150176 	if (chipid.vendor != cidp->vendor)
1486c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1487c7fd2ed0Sgs150176 	if (chipid.device != cidp->device)
1488c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1489c7fd2ed0Sgs150176 	if (chipid.revision != cidp->revision)
1490c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1491c7fd2ed0Sgs150176 
1492c7fd2ed0Sgs150176 	/*
1493c7fd2ed0Sgs150176 	 * All OK, reinitialise h/w & kick off NEMO scheduling
1494c7fd2ed0Sgs150176 	 */
1495c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
1496c7fd2ed0Sgs150176 	rge_restart(rgep);
1497c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1498c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
1499c7fd2ed0Sgs150176 }
1500c7fd2ed0Sgs150176 
1501c7fd2ed0Sgs150176 
1502c7fd2ed0Sgs150176 /*
1503c7fd2ed0Sgs150176  * attach(9E) -- Attach a device to the system
1504c7fd2ed0Sgs150176  *
1505c7fd2ed0Sgs150176  * Called once for each board successfully probed.
1506c7fd2ed0Sgs150176  */
1507c7fd2ed0Sgs150176 static int
1508c7fd2ed0Sgs150176 rge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
1509c7fd2ed0Sgs150176 {
1510c7fd2ed0Sgs150176 	rge_t *rgep;			/* Our private data	*/
1511ba2e4443Sseb 	mac_register_t *macp;
1512c7fd2ed0Sgs150176 	chip_id_t *cidp;
1513aa817493Sgs150176 	int intr_types;
1514c7fd2ed0Sgs150176 	caddr_t regs;
1515c7fd2ed0Sgs150176 	int instance;
1516aa817493Sgs150176 	int i;
1517c7fd2ed0Sgs150176 	int err;
1518c7fd2ed0Sgs150176 
1519c7fd2ed0Sgs150176 	/*
1520c7fd2ed0Sgs150176 	 * we don't support high level interrupts in the driver
1521c7fd2ed0Sgs150176 	 */
1522c7fd2ed0Sgs150176 	if (ddi_intr_hilevel(devinfo, 0) != 0) {
1523c7fd2ed0Sgs150176 		cmn_err(CE_WARN,
1524c7fd2ed0Sgs150176 		    "rge_attach -- unsupported high level interrupt");
1525c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1526c7fd2ed0Sgs150176 	}
1527c7fd2ed0Sgs150176 
1528c7fd2ed0Sgs150176 	instance = ddi_get_instance(devinfo);
1529c7fd2ed0Sgs150176 	RGE_GTRACE(("rge_attach($%p, %d) instance %d",
1530c7fd2ed0Sgs150176 	    (void *)devinfo, cmd, instance));
1531c7fd2ed0Sgs150176 	RGE_BRKPT(NULL, "rge_attach");
1532c7fd2ed0Sgs150176 
1533c7fd2ed0Sgs150176 	switch (cmd) {
1534c7fd2ed0Sgs150176 	default:
1535c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1536c7fd2ed0Sgs150176 
1537c7fd2ed0Sgs150176 	case DDI_RESUME:
1538c7fd2ed0Sgs150176 		return (rge_resume(devinfo));
1539c7fd2ed0Sgs150176 
1540c7fd2ed0Sgs150176 	case DDI_ATTACH:
1541c7fd2ed0Sgs150176 		break;
1542c7fd2ed0Sgs150176 	}
1543c7fd2ed0Sgs150176 
1544c7fd2ed0Sgs150176 	rgep = kmem_zalloc(sizeof (*rgep), KM_SLEEP);
1545c7fd2ed0Sgs150176 	ddi_set_driver_private(devinfo, rgep);
1546c7fd2ed0Sgs150176 	rgep->devinfo = devinfo;
1547c7fd2ed0Sgs150176 
1548c7fd2ed0Sgs150176 	/*
1549c7fd2ed0Sgs150176 	 * Initialize more fields in RGE private data
1550c7fd2ed0Sgs150176 	 */
1551aa817493Sgs150176 	rgep->rge_mac_state = RGE_MAC_ATTACH;
1552c7fd2ed0Sgs150176 	rgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
1553c7fd2ed0Sgs150176 	    DDI_PROP_DONTPASS, debug_propname, rge_debug);
1554aa817493Sgs150176 	rgep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
1555aa817493Sgs150176 	    DDI_PROP_DONTPASS, mtu_propname, ETHERMTU);
1556aa817493Sgs150176 	rgep->msi_enable = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
1557aa817493Sgs150176 	    DDI_PROP_DONTPASS, msi_propname, B_TRUE);
1558c7fd2ed0Sgs150176 	(void) snprintf(rgep->ifname, sizeof (rgep->ifname), "%s%d",
1559c7fd2ed0Sgs150176 	    RGE_DRIVER_NAME, instance);
1560c7fd2ed0Sgs150176 
1561c7fd2ed0Sgs150176 	/*
1562c7fd2ed0Sgs150176 	 * Map config space registers
1563c7fd2ed0Sgs150176 	 * Read chip ID & set up config space command register(s)
1564c7fd2ed0Sgs150176 	 *
1565c7fd2ed0Sgs150176 	 * Note: this leaves the chip accessible by Memory Space
1566c7fd2ed0Sgs150176 	 * accesses, but with interrupts and Bus Mastering off.
1567c7fd2ed0Sgs150176 	 * This should ensure that nothing untoward will happen
1568c7fd2ed0Sgs150176 	 * if it has been left active by the (net-)bootloader.
1569c7fd2ed0Sgs150176 	 * We'll re-enable Bus Mastering once we've reset the chip,
1570c7fd2ed0Sgs150176 	 * and allow interrupts only when everything else is set up.
1571c7fd2ed0Sgs150176 	 */
1572c7fd2ed0Sgs150176 	err = pci_config_setup(devinfo, &rgep->cfg_handle);
1573c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
1574c7fd2ed0Sgs150176 		rge_problem(rgep, "pci_config_setup() failed");
1575c7fd2ed0Sgs150176 		goto attach_fail;
1576c7fd2ed0Sgs150176 	}
1577c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_CFG;
1578c7fd2ed0Sgs150176 	cidp = &rgep->chipid;
1579c7fd2ed0Sgs150176 	bzero(cidp, sizeof (*cidp));
1580c7fd2ed0Sgs150176 	rge_chip_cfg_init(rgep, cidp);
1581c7fd2ed0Sgs150176 
1582c7fd2ed0Sgs150176 	/*
1583c7fd2ed0Sgs150176 	 * Map operating registers
1584c7fd2ed0Sgs150176 	 */
1585c7fd2ed0Sgs150176 	err = ddi_regs_map_setup(devinfo, 1, &regs,
1586c7fd2ed0Sgs150176 	    0, 0, &rge_reg_accattr, &rgep->io_handle);
1587c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
1588c7fd2ed0Sgs150176 		rge_problem(rgep, "ddi_regs_map_setup() failed");
1589c7fd2ed0Sgs150176 		goto attach_fail;
1590c7fd2ed0Sgs150176 	}
1591c7fd2ed0Sgs150176 	rgep->io_regs = regs;
1592c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_REGS;
1593c7fd2ed0Sgs150176 
1594c7fd2ed0Sgs150176 	/*
1595c7fd2ed0Sgs150176 	 * Characterise the device, so we know its requirements.
1596c7fd2ed0Sgs150176 	 * Then allocate the appropriate TX and RX descriptors & buffers.
1597c7fd2ed0Sgs150176 	 */
1598c7fd2ed0Sgs150176 	rge_chip_ident(rgep);
1599c7fd2ed0Sgs150176 	err = rge_alloc_bufs(rgep);
1600c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
1601c7fd2ed0Sgs150176 		rge_problem(rgep, "DMA buffer allocation failed");
1602c7fd2ed0Sgs150176 		goto attach_fail;
1603c7fd2ed0Sgs150176 	}
1604c7fd2ed0Sgs150176 
1605c7fd2ed0Sgs150176 	/*
1606*dfc2d53eSmx205022 	 * Register NDD-tweakable parameters
1607*dfc2d53eSmx205022 	 */
1608*dfc2d53eSmx205022 	if (rge_nd_init(rgep)) {
1609*dfc2d53eSmx205022 		rge_problem(rgep, "rge_nd_init() failed");
1610*dfc2d53eSmx205022 		goto attach_fail;
1611*dfc2d53eSmx205022 	}
1612*dfc2d53eSmx205022 	rgep->progress |= PROGRESS_NDD;
1613*dfc2d53eSmx205022 
1614*dfc2d53eSmx205022 	/*
1615c7fd2ed0Sgs150176 	 * Add the softint handlers:
1616c7fd2ed0Sgs150176 	 *
1617c7fd2ed0Sgs150176 	 * Both of these handlers are used to avoid restrictions on the
1618c7fd2ed0Sgs150176 	 * context and/or mutexes required for some operations.  In
1619c7fd2ed0Sgs150176 	 * particular, the hardware interrupt handler and its subfunctions
1620c7fd2ed0Sgs150176 	 * can detect a number of conditions that we don't want to handle
1621c7fd2ed0Sgs150176 	 * in that context or with that set of mutexes held.  So, these
1622c7fd2ed0Sgs150176 	 * softints are triggered instead:
1623c7fd2ed0Sgs150176 	 *
1624c7fd2ed0Sgs150176 	 * the <resched> softint is triggered if if we have previously
1625c7fd2ed0Sgs150176 	 * had to refuse to send a packet because of resource shortage
1626c7fd2ed0Sgs150176 	 * (we've run out of transmit buffers), but the send completion
1627c7fd2ed0Sgs150176 	 * interrupt handler has now detected that more buffers have
1628c7fd2ed0Sgs150176 	 * become available.
1629c7fd2ed0Sgs150176 	 *
1630c7fd2ed0Sgs150176 	 * the <factotum> is triggered if the h/w interrupt handler
1631c7fd2ed0Sgs150176 	 * sees the <link state changed> or <error> bits in the status
1632c7fd2ed0Sgs150176 	 * block.  It's also triggered periodically to poll the link
1633c7fd2ed0Sgs150176 	 * state, just in case we aren't getting link status change
1634c7fd2ed0Sgs150176 	 * interrupts ...
1635c7fd2ed0Sgs150176 	 */
1636aa817493Sgs150176 	err = ddi_intr_add_softint(devinfo, &rgep->resched_hdl,
1637aa817493Sgs150176 	    DDI_INTR_SOFTPRI_MIN, rge_reschedule, (caddr_t)rgep);
1638c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
1639aa817493Sgs150176 		rge_problem(rgep, "ddi_intr_add_softint() failed");
1640c7fd2ed0Sgs150176 		goto attach_fail;
1641c7fd2ed0Sgs150176 	}
1642c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_RESCHED;
1643aa817493Sgs150176 	err = ddi_intr_add_softint(devinfo, &rgep->factotum_hdl,
1644aa817493Sgs150176 	    DDI_INTR_SOFTPRI_MIN, rge_chip_factotum, (caddr_t)rgep);
1645c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
1646aa817493Sgs150176 		rge_problem(rgep, "ddi_intr_add_softint() failed");
1647c7fd2ed0Sgs150176 		goto attach_fail;
1648c7fd2ed0Sgs150176 	}
1649c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_FACTOTUM;
1650c7fd2ed0Sgs150176 
1651c7fd2ed0Sgs150176 	/*
1652aa817493Sgs150176 	 * Get supported interrupt types
1653c7fd2ed0Sgs150176 	 */
1654aa817493Sgs150176 	if (ddi_intr_get_supported_types(devinfo, &intr_types)
1655aa817493Sgs150176 	    != DDI_SUCCESS) {
1656aa817493Sgs150176 		rge_error(rgep, "ddi_intr_get_supported_types failed\n");
1657c7fd2ed0Sgs150176 		goto attach_fail;
1658c7fd2ed0Sgs150176 	}
1659aa817493Sgs150176 
1660aa817493Sgs150176 	/*
1661aa817493Sgs150176 	 * Add the h/w interrupt handler and initialise mutexes
1662aa817493Sgs150176 	 */
1663aa817493Sgs150176 	if ((intr_types & DDI_INTR_TYPE_MSI) && rgep->msi_enable) {
1664aa817493Sgs150176 		if (rge_add_intrs(rgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
1665aa817493Sgs150176 			rge_error(rgep, "MSI registration failed, "
1666aa817493Sgs150176 			    "trying FIXED interrupt type\n");
1667aa817493Sgs150176 		} else {
1668aa817493Sgs150176 			rge_log(rgep, "Using MSI interrupt type\n");
1669aa817493Sgs150176 			rgep->intr_type = DDI_INTR_TYPE_MSI;
1670c7fd2ed0Sgs150176 			rgep->progress |= PROGRESS_INTR;
1671aa817493Sgs150176 		}
1672aa817493Sgs150176 	}
1673aa817493Sgs150176 	if (!(rgep->progress & PROGRESS_INTR) &&
1674aa817493Sgs150176 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
1675aa817493Sgs150176 		if (rge_add_intrs(rgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
1676aa817493Sgs150176 			rge_error(rgep, "FIXED interrupt "
1677aa817493Sgs150176 			    "registration failed\n");
1678aa817493Sgs150176 			goto attach_fail;
1679aa817493Sgs150176 		}
1680aa817493Sgs150176 		rge_log(rgep, "Using FIXED interrupt type\n");
1681aa817493Sgs150176 		rgep->intr_type = DDI_INTR_TYPE_FIXED;
1682aa817493Sgs150176 		rgep->progress |= PROGRESS_INTR;
1683aa817493Sgs150176 	}
1684aa817493Sgs150176 	if (!(rgep->progress & PROGRESS_INTR)) {
1685aa817493Sgs150176 		rge_error(rgep, "No interrupts registered\n");
1686aa817493Sgs150176 		goto attach_fail;
1687aa817493Sgs150176 	}
1688aa817493Sgs150176 	mutex_init(rgep->genlock, NULL, MUTEX_DRIVER,
1689aa817493Sgs150176 	    DDI_INTR_PRI(rgep->intr_pri));
1690aa817493Sgs150176 	rw_init(rgep->errlock, NULL, RW_DRIVER,
1691aa817493Sgs150176 	    DDI_INTR_PRI(rgep->intr_pri));
1692aa817493Sgs150176 	mutex_init(rgep->tx_lock, NULL, MUTEX_DRIVER,
1693aa817493Sgs150176 	    DDI_INTR_PRI(rgep->intr_pri));
1694aa817493Sgs150176 	mutex_init(rgep->tc_lock, NULL, MUTEX_DRIVER,
1695aa817493Sgs150176 	    DDI_INTR_PRI(rgep->intr_pri));
1696aa817493Sgs150176 	mutex_init(rgep->rx_lock, NULL, MUTEX_DRIVER,
1697aa817493Sgs150176 	    DDI_INTR_PRI(rgep->intr_pri));
1698aa817493Sgs150176 	mutex_init(rgep->rc_lock, NULL, MUTEX_DRIVER,
1699aa817493Sgs150176 	    DDI_INTR_PRI(rgep->intr_pri));
1700c7fd2ed0Sgs150176 
1701c7fd2ed0Sgs150176 	/*
1702c7fd2ed0Sgs150176 	 * Initialize rings
1703c7fd2ed0Sgs150176 	 */
1704c7fd2ed0Sgs150176 	err = rge_init_rings(rgep);
1705c7fd2ed0Sgs150176 	if (err != DDI_SUCCESS) {
1706c7fd2ed0Sgs150176 		rge_problem(rgep, "rge_init_rings() failed");
1707c7fd2ed0Sgs150176 		goto attach_fail;
1708c7fd2ed0Sgs150176 	}
1709aa817493Sgs150176 	rgep->progress |= PROGRESS_INIT;
1710aa817493Sgs150176 
1711aa817493Sgs150176 	/*
1712aa817493Sgs150176 	 * Now that mutex locks are initialized, enable interrupts.
1713aa817493Sgs150176 	 */
1714aa817493Sgs150176 	if (rgep->intr_cap & DDI_INTR_FLAG_BLOCK) {
1715aa817493Sgs150176 		/* Call ddi_intr_block_enable() for MSI interrupts */
1716aa817493Sgs150176 		(void) ddi_intr_block_enable(rgep->htable, rgep->intr_cnt);
1717aa817493Sgs150176 	} else {
1718aa817493Sgs150176 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
1719aa817493Sgs150176 		for (i = 0; i < rgep->intr_cnt; i++) {
1720aa817493Sgs150176 			(void) ddi_intr_enable(rgep->htable[i]);
1721aa817493Sgs150176 		}
1722aa817493Sgs150176 	}
1723c7fd2ed0Sgs150176 
1724c7fd2ed0Sgs150176 	/*
1725c7fd2ed0Sgs150176 	 * Initialise link state variables
1726c7fd2ed0Sgs150176 	 * Stop, reset & reinitialise the chip.
1727c7fd2ed0Sgs150176 	 * Initialise the (internal) PHY.
1728c7fd2ed0Sgs150176 	 */
1729c7fd2ed0Sgs150176 	rgep->param_link_up = LINK_STATE_UNKNOWN;
1730c7fd2ed0Sgs150176 
1731c7fd2ed0Sgs150176 	/*
1732c7fd2ed0Sgs150176 	 * Reset chip & rings to initial state; also reset address
1733c7fd2ed0Sgs150176 	 * filtering, promiscuity, loopback mode.
1734c7fd2ed0Sgs150176 	 */
1735c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
1736c7fd2ed0Sgs150176 	(void) rge_chip_reset(rgep);
1737c7fd2ed0Sgs150176 	rge_chip_sync(rgep, RGE_GET_MAC);
1738c7fd2ed0Sgs150176 	bzero(rgep->mcast_hash, sizeof (rgep->mcast_hash));
1739c7fd2ed0Sgs150176 	bzero(rgep->mcast_refs, sizeof (rgep->mcast_refs));
1740c7fd2ed0Sgs150176 	rgep->promisc = B_FALSE;
1741c7fd2ed0Sgs150176 	rgep->param_loop_mode = RGE_LOOP_NONE;
1742c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1743c7fd2ed0Sgs150176 	rge_phy_init(rgep);
1744c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_PHY;
1745c7fd2ed0Sgs150176 
1746c7fd2ed0Sgs150176 	/*
1747c7fd2ed0Sgs150176 	 * Create & initialise named kstats
1748c7fd2ed0Sgs150176 	 */
1749c7fd2ed0Sgs150176 	rge_init_kstats(rgep, instance);
1750c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_KSTATS;
1751c7fd2ed0Sgs150176 
1752ba2e4443Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
1753ba2e4443Sseb 		goto attach_fail;
1754ba2e4443Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1755ba2e4443Sseb 	macp->m_driver = rgep;
1756c7fd2ed0Sgs150176 	macp->m_dip = devinfo;
1757ba2e4443Sseb 	macp->m_src_addr = rgep->netaddr;
1758ba2e4443Sseb 	macp->m_callbacks = &rge_m_callbacks;
1759ba2e4443Sseb 	macp->m_min_sdu = 0;
1760aa817493Sgs150176 	macp->m_max_sdu = rgep->default_mtu;
1761c7fd2ed0Sgs150176 
1762c7fd2ed0Sgs150176 	/*
1763c7fd2ed0Sgs150176 	 * Finally, we're ready to register ourselves with the MAC layer
1764c7fd2ed0Sgs150176 	 * interface; if this succeeds, we're all ready to start()
1765c7fd2ed0Sgs150176 	 */
1766ba2e4443Sseb 	err = mac_register(macp, &rgep->mh);
1767ba2e4443Sseb 	mac_free(macp);
1768ba2e4443Sseb 	if (err != 0)
1769c7fd2ed0Sgs150176 		goto attach_fail;
1770c7fd2ed0Sgs150176 
1771dd4eeefdSeota 	/*
1772dd4eeefdSeota 	 * Register a periodical handler.
1773dd4eeefdSeota 	 * reg_chip_cyclic() is invoked in kernel context.
1774dd4eeefdSeota 	 */
1775dd4eeefdSeota 	rgep->periodic_id = ddi_periodic_add(rge_chip_cyclic, rgep,
1776dd4eeefdSeota 	    RGE_CYCLIC_PERIOD, DDI_IPL_0);
1777c7fd2ed0Sgs150176 
1778c7fd2ed0Sgs150176 	rgep->progress |= PROGRESS_READY;
1779c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
1780c7fd2ed0Sgs150176 
1781c7fd2ed0Sgs150176 attach_fail:
1782c7fd2ed0Sgs150176 	rge_unattach(rgep);
1783c7fd2ed0Sgs150176 	return (DDI_FAILURE);
1784c7fd2ed0Sgs150176 }
1785c7fd2ed0Sgs150176 
1786c7fd2ed0Sgs150176 /*
1787c7fd2ed0Sgs150176  *	rge_suspend() -- suspend transmit/receive for powerdown
1788c7fd2ed0Sgs150176  */
1789c7fd2ed0Sgs150176 static int
1790c7fd2ed0Sgs150176 rge_suspend(rge_t *rgep)
1791c7fd2ed0Sgs150176 {
1792c7fd2ed0Sgs150176 	/*
1793c7fd2ed0Sgs150176 	 * Stop processing and idle (powerdown) the PHY ...
1794c7fd2ed0Sgs150176 	 */
1795c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
1796c7fd2ed0Sgs150176 	rge_stop(rgep);
1797c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1798c7fd2ed0Sgs150176 
1799c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
1800c7fd2ed0Sgs150176 }
1801c7fd2ed0Sgs150176 
1802c7fd2ed0Sgs150176 /*
1803c7fd2ed0Sgs150176  * detach(9E) -- Detach a device from the system
1804c7fd2ed0Sgs150176  */
1805c7fd2ed0Sgs150176 static int
1806c7fd2ed0Sgs150176 rge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
1807c7fd2ed0Sgs150176 {
1808c7fd2ed0Sgs150176 	rge_t *rgep;
1809c7fd2ed0Sgs150176 
1810c7fd2ed0Sgs150176 	RGE_GTRACE(("rge_detach($%p, %d)", (void *)devinfo, cmd));
1811c7fd2ed0Sgs150176 
1812c7fd2ed0Sgs150176 	rgep = ddi_get_driver_private(devinfo);
1813c7fd2ed0Sgs150176 
1814c7fd2ed0Sgs150176 	switch (cmd) {
1815c7fd2ed0Sgs150176 	default:
1816c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1817c7fd2ed0Sgs150176 
1818c7fd2ed0Sgs150176 	case DDI_SUSPEND:
1819c7fd2ed0Sgs150176 		return (rge_suspend(rgep));
1820c7fd2ed0Sgs150176 
1821c7fd2ed0Sgs150176 	case DDI_DETACH:
1822c7fd2ed0Sgs150176 		break;
1823c7fd2ed0Sgs150176 	}
1824c7fd2ed0Sgs150176 
1825c7fd2ed0Sgs150176 	/*
1826c7fd2ed0Sgs150176 	 * If there is any posted buffer, the driver should reject to be
1827c7fd2ed0Sgs150176 	 * detached. Need notice upper layer to release them.
1828c7fd2ed0Sgs150176 	 */
1829aa817493Sgs150176 	if (!(rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) &&
1830aa817493Sgs150176 	    rgep->rx_free != RGE_BUF_SLOTS)
1831c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1832c7fd2ed0Sgs150176 
1833c7fd2ed0Sgs150176 	/*
1834c7fd2ed0Sgs150176 	 * Unregister from the MAC layer subsystem.  This can fail, in
1835c7fd2ed0Sgs150176 	 * particular if there are DLPI style-2 streams still open -
1836c7fd2ed0Sgs150176 	 * in which case we just return failure without shutting
1837c7fd2ed0Sgs150176 	 * down chip operations.
1838c7fd2ed0Sgs150176 	 */
1839ba2e4443Sseb 	if (mac_unregister(rgep->mh) != 0)
1840c7fd2ed0Sgs150176 		return (DDI_FAILURE);
1841c7fd2ed0Sgs150176 
1842c7fd2ed0Sgs150176 	/*
1843c7fd2ed0Sgs150176 	 * All activity stopped, so we can clean up & exit
1844c7fd2ed0Sgs150176 	 */
1845c7fd2ed0Sgs150176 	rge_unattach(rgep);
1846c7fd2ed0Sgs150176 	return (DDI_SUCCESS);
1847c7fd2ed0Sgs150176 }
1848c7fd2ed0Sgs150176 
1849c7fd2ed0Sgs150176 
1850c7fd2ed0Sgs150176 /*
1851c7fd2ed0Sgs150176  * ========== Module Loading Data & Entry Points ==========
1852c7fd2ed0Sgs150176  */
1853c7fd2ed0Sgs150176 
1854c7fd2ed0Sgs150176 #undef	RGE_DBG
1855c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_INIT	/* debug flag for this code	*/
1856c7fd2ed0Sgs150176 DDI_DEFINE_STREAM_OPS(rge_dev_ops, nulldev, nulldev, rge_attach, rge_detach,
1857c7fd2ed0Sgs150176     nodev, NULL, D_MP, NULL);
1858c7fd2ed0Sgs150176 
1859c7fd2ed0Sgs150176 static struct modldrv rge_modldrv = {
1860c7fd2ed0Sgs150176 	&mod_driverops,		/* Type of module.  This one is a driver */
1861c7fd2ed0Sgs150176 	rge_ident,		/* short description */
1862c7fd2ed0Sgs150176 	&rge_dev_ops		/* driver specific ops */
1863c7fd2ed0Sgs150176 };
1864c7fd2ed0Sgs150176 
1865c7fd2ed0Sgs150176 static struct modlinkage modlinkage = {
1866c7fd2ed0Sgs150176 	MODREV_1, (void *)&rge_modldrv, NULL
1867c7fd2ed0Sgs150176 };
1868c7fd2ed0Sgs150176 
1869c7fd2ed0Sgs150176 
1870c7fd2ed0Sgs150176 int
1871c7fd2ed0Sgs150176 _info(struct modinfo *modinfop)
1872c7fd2ed0Sgs150176 {
1873c7fd2ed0Sgs150176 	return (mod_info(&modlinkage, modinfop));
1874c7fd2ed0Sgs150176 }
1875c7fd2ed0Sgs150176 
1876c7fd2ed0Sgs150176 int
1877c7fd2ed0Sgs150176 _init(void)
1878c7fd2ed0Sgs150176 {
1879c7fd2ed0Sgs150176 	int status;
1880c7fd2ed0Sgs150176 
1881c7fd2ed0Sgs150176 	mac_init_ops(&rge_dev_ops, "rge");
1882c7fd2ed0Sgs150176 	status = mod_install(&modlinkage);
1883c7fd2ed0Sgs150176 	if (status == DDI_SUCCESS)
1884c7fd2ed0Sgs150176 		mutex_init(rge_log_mutex, NULL, MUTEX_DRIVER, NULL);
1885c7fd2ed0Sgs150176 	else
1886c7fd2ed0Sgs150176 		mac_fini_ops(&rge_dev_ops);
1887c7fd2ed0Sgs150176 
1888c7fd2ed0Sgs150176 	return (status);
1889c7fd2ed0Sgs150176 }
1890c7fd2ed0Sgs150176 
1891c7fd2ed0Sgs150176 int
1892c7fd2ed0Sgs150176 _fini(void)
1893c7fd2ed0Sgs150176 {
1894c7fd2ed0Sgs150176 	int status;
1895c7fd2ed0Sgs150176 
1896c7fd2ed0Sgs150176 	status = mod_remove(&modlinkage);
1897c7fd2ed0Sgs150176 	if (status == DDI_SUCCESS) {
1898c7fd2ed0Sgs150176 		mac_fini_ops(&rge_dev_ops);
1899c7fd2ed0Sgs150176 		mutex_destroy(rge_log_mutex);
1900c7fd2ed0Sgs150176 	}
1901c7fd2ed0Sgs150176 	return (status);
1902c7fd2ed0Sgs150176 }
1903