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