xref: /onnv-gate/usr/src/uts/common/io/rge/rge_main.c (revision 2311:2d86e52dcdf0)
1744Sgs150176 /*
2744Sgs150176  * CDDL HEADER START
3744Sgs150176  *
4744Sgs150176  * The contents of this file are subject to the terms of the
5*2311Sseb  * Common Development and Distribution License (the "License").
6*2311Sseb  * You may not use this file except in compliance with the License.
7744Sgs150176  *
8744Sgs150176  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9744Sgs150176  * or http://www.opensolaris.org/os/licensing.
10744Sgs150176  * See the License for the specific language governing permissions
11744Sgs150176  * and limitations under the License.
12744Sgs150176  *
13744Sgs150176  * When distributing Covered Code, include this CDDL HEADER in each
14744Sgs150176  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15744Sgs150176  * If applicable, add the following below this CDDL HEADER, with the
16744Sgs150176  * fields enclosed by brackets "[]" replaced with your own identifying
17744Sgs150176  * information: Portions Copyright [yyyy] [name of copyright owner]
18744Sgs150176  *
19744Sgs150176  * CDDL HEADER END
20744Sgs150176  */
21744Sgs150176 /*
22*2311Sseb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23744Sgs150176  * Use is subject to license terms.
24744Sgs150176  */
25744Sgs150176 
26744Sgs150176 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27744Sgs150176 
28744Sgs150176 #include "rge.h"
29744Sgs150176 
30744Sgs150176 /*
31744Sgs150176  * This is the string displayed by modinfo, etc.
32744Sgs150176  * Make sure you keep the version ID up to date!
33744Sgs150176  */
34744Sgs150176 static char rge_ident[] = "Realtek Gigabit Ethernet Driver v%I%";
35744Sgs150176 
36744Sgs150176 /*
37744Sgs150176  * Used for buffers allocated by ddi_dma_mem_alloc()
38744Sgs150176  */
39744Sgs150176 static ddi_dma_attr_t dma_attr_buf = {
40744Sgs150176 	DMA_ATTR_V0,		/* dma_attr version */
41744Sgs150176 	(uint32_t)0,		/* dma_attr_addr_lo */
42744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
43744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_count_max */
44744Sgs150176 	(uint32_t)16,		/* dma_attr_align */
45744Sgs150176 	0xFFFFFFFF,		/* dma_attr_burstsizes */
46744Sgs150176 	1,			/* dma_attr_minxfer */
47744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
48744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_seg */
49744Sgs150176 	1,			/* dma_attr_sgllen */
50744Sgs150176 	1,			/* dma_attr_granular */
51744Sgs150176 	0,			/* dma_attr_flags */
52744Sgs150176 };
53744Sgs150176 
54744Sgs150176 /*
55744Sgs150176  * Used for BDs allocated by ddi_dma_mem_alloc()
56744Sgs150176  */
57744Sgs150176 static ddi_dma_attr_t dma_attr_desc = {
58744Sgs150176 	DMA_ATTR_V0,		/* dma_attr version */
59744Sgs150176 	(uint32_t)0,		/* dma_attr_addr_lo */
60744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
61744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_count_max */
62744Sgs150176 	(uint32_t)256,		/* dma_attr_align */
63744Sgs150176 	0xFFFFFFFF,		/* dma_attr_burstsizes */
64744Sgs150176 	1,			/* dma_attr_minxfer */
65744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
66744Sgs150176 	(uint32_t)0xFFFFFFFF,	/* dma_attr_seg */
67744Sgs150176 	1,			/* dma_attr_sgllen */
68744Sgs150176 	1,			/* dma_attr_granular */
69744Sgs150176 	0,			/* dma_attr_flags */
70744Sgs150176 };
71744Sgs150176 
72744Sgs150176 /*
73744Sgs150176  * PIO access attributes for registers
74744Sgs150176  */
75744Sgs150176 static ddi_device_acc_attr_t rge_reg_accattr = {
76744Sgs150176 	DDI_DEVICE_ATTR_V0,
77744Sgs150176 	DDI_STRUCTURE_LE_ACC,
78744Sgs150176 	DDI_STRICTORDER_ACC,
79744Sgs150176 	DDI_DEFAULT_ACC
80744Sgs150176 };
81744Sgs150176 
82744Sgs150176 /*
83744Sgs150176  * DMA access attributes for descriptors
84744Sgs150176  */
85744Sgs150176 static ddi_device_acc_attr_t rge_desc_accattr = {
86744Sgs150176 	DDI_DEVICE_ATTR_V0,
87744Sgs150176 	DDI_NEVERSWAP_ACC,
88744Sgs150176 	DDI_STRICTORDER_ACC,
89744Sgs150176 	DDI_DEFAULT_ACC
90744Sgs150176 };
91744Sgs150176 
92744Sgs150176 /*
93744Sgs150176  * DMA access attributes for data
94744Sgs150176  */
95744Sgs150176 static ddi_device_acc_attr_t rge_buf_accattr = {
96744Sgs150176 	DDI_DEVICE_ATTR_V0,
97744Sgs150176 	DDI_NEVERSWAP_ACC,
98744Sgs150176 	DDI_STRICTORDER_ACC,
99744Sgs150176 	DDI_DEFAULT_ACC
100744Sgs150176 };
101744Sgs150176 
102744Sgs150176 /*
103744Sgs150176  * Property names
104744Sgs150176  */
105744Sgs150176 static char debug_propname[] = "rge-debug-flags";
106744Sgs150176 
107*2311Sseb static int		rge_m_start(void *);
108*2311Sseb static void		rge_m_stop(void *);
109*2311Sseb static int		rge_m_promisc(void *, boolean_t);
110*2311Sseb static int		rge_m_multicst(void *, boolean_t, const uint8_t *);
111*2311Sseb static int		rge_m_unicst(void *, const uint8_t *);
112*2311Sseb static void		rge_m_resources(void *);
113*2311Sseb static void		rge_m_ioctl(void *, queue_t *, mblk_t *);
114*2311Sseb static boolean_t	rge_m_getcapab(void *, mac_capab_t, void *);
115*2311Sseb 
116*2311Sseb #define	RGE_M_CALLBACK_FLAGS	(MC_RESOURCES | MC_IOCTL | MC_GETCAPAB)
117*2311Sseb 
118*2311Sseb static mac_callbacks_t rge_m_callbacks = {
119*2311Sseb 	RGE_M_CALLBACK_FLAGS,
120*2311Sseb 	rge_m_stat,
121*2311Sseb 	rge_m_start,
122*2311Sseb 	rge_m_stop,
123*2311Sseb 	rge_m_promisc,
124*2311Sseb 	rge_m_multicst,
125*2311Sseb 	rge_m_unicst,
126*2311Sseb 	rge_m_tx,
127*2311Sseb 	rge_m_resources,
128*2311Sseb 	rge_m_ioctl,
129*2311Sseb 	rge_m_getcapab
130*2311Sseb };
131744Sgs150176 
132744Sgs150176 /*
133744Sgs150176  * Allocate an area of memory and a DMA handle for accessing it
134744Sgs150176  */
135744Sgs150176 static int
136744Sgs150176 rge_alloc_dma_mem(rge_t *rgep, size_t memsize, ddi_dma_attr_t *dma_attr_p,
137744Sgs150176 	ddi_device_acc_attr_t *acc_attr_p, uint_t dma_flags, dma_area_t *dma_p)
138744Sgs150176 {
139744Sgs150176 	caddr_t vaddr;
140744Sgs150176 	int err;
141744Sgs150176 
142744Sgs150176 	/*
143744Sgs150176 	 * Allocate handle
144744Sgs150176 	 */
145744Sgs150176 	err = ddi_dma_alloc_handle(rgep->devinfo, dma_attr_p,
146744Sgs150176 		    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
147744Sgs150176 	if (err != DDI_SUCCESS) {
148744Sgs150176 		dma_p->dma_hdl = NULL;
149744Sgs150176 		return (DDI_FAILURE);
150744Sgs150176 	}
151744Sgs150176 
152744Sgs150176 	/*
153744Sgs150176 	 * Allocate memory
154744Sgs150176 	 */
155744Sgs150176 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
156744Sgs150176 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
157744Sgs150176 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
158744Sgs150176 	if (err != DDI_SUCCESS) {
159744Sgs150176 		ddi_dma_free_handle(&dma_p->dma_hdl);
160744Sgs150176 		dma_p->dma_hdl = NULL;
161744Sgs150176 		dma_p->acc_hdl = NULL;
162744Sgs150176 		return (DDI_FAILURE);
163744Sgs150176 	}
164744Sgs150176 
165744Sgs150176 	/*
166744Sgs150176 	 * Bind the two together
167744Sgs150176 	 */
168744Sgs150176 	dma_p->mem_va = vaddr;
169744Sgs150176 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
170744Sgs150176 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
171744Sgs150176 	    &dma_p->cookie, &dma_p->ncookies);
172744Sgs150176 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) {
173744Sgs150176 		ddi_dma_mem_free(&dma_p->acc_hdl);
174744Sgs150176 		ddi_dma_free_handle(&dma_p->dma_hdl);
175744Sgs150176 		dma_p->acc_hdl = NULL;
176744Sgs150176 		dma_p->dma_hdl = NULL;
177744Sgs150176 		return (DDI_FAILURE);
178744Sgs150176 	}
179744Sgs150176 
180744Sgs150176 	dma_p->nslots = ~0U;
181744Sgs150176 	dma_p->size = ~0U;
182744Sgs150176 	dma_p->token = ~0U;
183744Sgs150176 	dma_p->offset = 0;
184744Sgs150176 	return (DDI_SUCCESS);
185744Sgs150176 }
186744Sgs150176 
187744Sgs150176 /*
188744Sgs150176  * Free one allocated area of DMAable memory
189744Sgs150176  */
190744Sgs150176 static void
191744Sgs150176 rge_free_dma_mem(dma_area_t *dma_p)
192744Sgs150176 {
193744Sgs150176 	if (dma_p->dma_hdl != NULL) {
194744Sgs150176 		if (dma_p->ncookies) {
195744Sgs150176 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
196744Sgs150176 			dma_p->ncookies = 0;
197744Sgs150176 		}
198744Sgs150176 		ddi_dma_free_handle(&dma_p->dma_hdl);
199744Sgs150176 		dma_p->dma_hdl = NULL;
200744Sgs150176 	}
201744Sgs150176 
202744Sgs150176 	if (dma_p->acc_hdl != NULL) {
203744Sgs150176 		ddi_dma_mem_free(&dma_p->acc_hdl);
204744Sgs150176 		dma_p->acc_hdl = NULL;
205744Sgs150176 	}
206744Sgs150176 }
207744Sgs150176 
208744Sgs150176 /*
209744Sgs150176  * Utility routine to carve a slice off a chunk of allocated memory,
210744Sgs150176  * updating the chunk descriptor accordingly.  The size of the slice
211744Sgs150176  * is given by the product of the <qty> and <size> parameters.
212744Sgs150176  */
213744Sgs150176 static void
214744Sgs150176 rge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
215744Sgs150176 	uint32_t qty, uint32_t size)
216744Sgs150176 {
217744Sgs150176 	static uint32_t sequence = 0xbcd5704a;
218744Sgs150176 	size_t totsize;
219744Sgs150176 
220744Sgs150176 	totsize = qty*size;
221744Sgs150176 	ASSERT(size >= 0);
222744Sgs150176 	ASSERT(totsize <= chunk->alength);
223744Sgs150176 
224744Sgs150176 	*slice = *chunk;
225744Sgs150176 	slice->nslots = qty;
226744Sgs150176 	slice->size = size;
227744Sgs150176 	slice->alength = totsize;
228744Sgs150176 	slice->token = ++sequence;
229744Sgs150176 
230744Sgs150176 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
231744Sgs150176 	chunk->alength -= totsize;
232744Sgs150176 	chunk->offset += totsize;
233744Sgs150176 	chunk->cookie.dmac_laddress += totsize;
234744Sgs150176 	chunk->cookie.dmac_size -= totsize;
235744Sgs150176 }
236744Sgs150176 
237744Sgs150176 
238744Sgs150176 static int
239744Sgs150176 rge_alloc_bufs(rge_t *rgep)
240744Sgs150176 {
241744Sgs150176 	size_t txdescsize;
242744Sgs150176 	size_t rxdescsize;
243744Sgs150176 	size_t txbuffsize;
244744Sgs150176 	size_t rxbuffsize;
245744Sgs150176 	size_t freebuffsize;
246744Sgs150176 	int split;
247744Sgs150176 	int err;
248744Sgs150176 
249744Sgs150176 	/*
250744Sgs150176 	 * Allocate memory & handle for packet statistics
251744Sgs150176 	 */
252744Sgs150176 	err = rge_alloc_dma_mem(rgep,
253744Sgs150176 	    RGE_STATS_DUMP_SIZE,
254744Sgs150176 	    &dma_attr_desc,
255744Sgs150176 	    &rge_desc_accattr,
256744Sgs150176 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
257744Sgs150176 	    &rgep->dma_area_stats);
258744Sgs150176 	if (err != DDI_SUCCESS)
259744Sgs150176 		return (DDI_FAILURE);
260744Sgs150176 	rgep->hw_stats = DMA_VPTR(rgep->dma_area_stats);
261744Sgs150176 
262744Sgs150176 	/*
263744Sgs150176 	 * Allocate memory & handle for Tx descriptor ring
264744Sgs150176 	 */
265744Sgs150176 	txdescsize = RGE_SEND_SLOTS * sizeof (rge_bd_t);
266744Sgs150176 	err = rge_alloc_dma_mem(rgep,
267744Sgs150176 	    txdescsize,
268744Sgs150176 	    &dma_attr_desc,
269744Sgs150176 	    &rge_desc_accattr,
270744Sgs150176 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
271744Sgs150176 	    &rgep->dma_area_txdesc);
272744Sgs150176 	if (err != DDI_SUCCESS)
273744Sgs150176 		return (DDI_FAILURE);
274744Sgs150176 
275744Sgs150176 	/*
276744Sgs150176 	 * Allocate memory & handle for Rx descriptor ring
277744Sgs150176 	 */
278744Sgs150176 	rxdescsize = RGE_RECV_SLOTS * sizeof (rge_bd_t);
279744Sgs150176 	err = rge_alloc_dma_mem(rgep,
280744Sgs150176 	    rxdescsize,
281744Sgs150176 	    &dma_attr_desc,
282744Sgs150176 	    &rge_desc_accattr,
283744Sgs150176 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
284744Sgs150176 	    &rgep->dma_area_rxdesc);
285744Sgs150176 	if (err != DDI_SUCCESS)
286744Sgs150176 		return (DDI_FAILURE);
287744Sgs150176 
288744Sgs150176 	/*
289744Sgs150176 	 * Allocate memory & handle for Tx buffers
290744Sgs150176 	 */
291744Sgs150176 	txbuffsize = RGE_SEND_SLOTS * rgep->txbuf_size;
292744Sgs150176 	ASSERT((txbuffsize % RGE_SPLIT) == 0);
293744Sgs150176 	for (split = 0; split < RGE_SPLIT; ++split) {
294744Sgs150176 		err = rge_alloc_dma_mem(rgep,
295744Sgs150176 		    txbuffsize/RGE_SPLIT,
296744Sgs150176 		    &dma_attr_buf,
297744Sgs150176 		    &rge_buf_accattr,
298744Sgs150176 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
299744Sgs150176 		    &rgep->dma_area_txbuf[split]);
300744Sgs150176 		if (err != DDI_SUCCESS)
301744Sgs150176 			return (DDI_FAILURE);
302744Sgs150176 	}
303744Sgs150176 
304744Sgs150176 	/*
305744Sgs150176 	 * Allocate memory & handle for Rx buffers
306744Sgs150176 	 */
307744Sgs150176 	rxbuffsize = RGE_RECV_SLOTS * rgep->rxbuf_size;
308744Sgs150176 	ASSERT((rxbuffsize % RGE_SPLIT) == 0);
309744Sgs150176 	for (split = 0; split < RGE_SPLIT; ++split) {
310744Sgs150176 		err = rge_alloc_dma_mem(rgep,
311744Sgs150176 		    rxbuffsize/RGE_SPLIT,
312744Sgs150176 		    &dma_attr_buf,
313744Sgs150176 		    &rge_buf_accattr,
314744Sgs150176 		    DDI_DMA_READ | DDI_DMA_STREAMING,
315744Sgs150176 		    &rgep->dma_area_rxbuf[split]);
316744Sgs150176 		if (err != DDI_SUCCESS)
317744Sgs150176 			return (DDI_FAILURE);
318744Sgs150176 	}
319744Sgs150176 
320744Sgs150176 	/*
321744Sgs150176 	 * Allocate memory & handle for free Rx buffers
322744Sgs150176 	 */
323744Sgs150176 	freebuffsize = RGE_BUF_SLOTS * rgep->rxbuf_size;
324744Sgs150176 	ASSERT((freebuffsize % RGE_SPLIT) == 0);
325744Sgs150176 	for (split = 0; split < RGE_SPLIT; ++split) {
326744Sgs150176 		err = rge_alloc_dma_mem(rgep,
327744Sgs150176 		    freebuffsize/RGE_SPLIT,
328744Sgs150176 		    &dma_attr_buf,
329744Sgs150176 		    &rge_buf_accattr,
330744Sgs150176 		    DDI_DMA_READ | DDI_DMA_STREAMING,
331744Sgs150176 		    &rgep->dma_area_freebuf[split]);
332744Sgs150176 		if (err != DDI_SUCCESS)
333744Sgs150176 			return (DDI_FAILURE);
334744Sgs150176 	}
335744Sgs150176 
336744Sgs150176 	return (DDI_SUCCESS);
337744Sgs150176 }
338744Sgs150176 
339744Sgs150176 /*
340744Sgs150176  * rge_free_bufs() -- free descriptors/buffers allocated for this
341744Sgs150176  * device instance.
342744Sgs150176  */
343744Sgs150176 static void
344744Sgs150176 rge_free_bufs(rge_t *rgep)
345744Sgs150176 {
346744Sgs150176 	int i;
347744Sgs150176 
348744Sgs150176 	rge_free_dma_mem(&rgep->dma_area_stats);
349744Sgs150176 	rge_free_dma_mem(&rgep->dma_area_txdesc);
350744Sgs150176 	rge_free_dma_mem(&rgep->dma_area_rxdesc);
351744Sgs150176 	for (i = 0; i < RGE_SPLIT; i++) {
352744Sgs150176 		rge_free_dma_mem(&rgep->dma_area_txbuf[i]);
353744Sgs150176 		rge_free_dma_mem(&rgep->dma_area_rxbuf[i]);
354744Sgs150176 		rge_free_dma_mem(&rgep->dma_area_freebuf[i]);
355744Sgs150176 	}
356744Sgs150176 }
357744Sgs150176 
358744Sgs150176 /*
359744Sgs150176  * ========== Transmit and receive ring reinitialisation ==========
360744Sgs150176  */
361744Sgs150176 
362744Sgs150176 /*
363744Sgs150176  * These <reinit> routines each reset the rx/tx rings to an initial
364744Sgs150176  * state, assuming that the corresponding <init> routine has already
365744Sgs150176  * been called exactly once.
366744Sgs150176  */
367744Sgs150176 static void
368744Sgs150176 rge_reinit_send_ring(rge_t *rgep)
369744Sgs150176 {
370744Sgs150176 	sw_sbd_t *ssbdp;
371744Sgs150176 	rge_bd_t *bdp;
372744Sgs150176 	uint32_t slot;
373744Sgs150176 
374744Sgs150176 	/*
375744Sgs150176 	 * re-init send ring
376744Sgs150176 	 */
377744Sgs150176 	DMA_ZERO(rgep->tx_desc);
378744Sgs150176 	ssbdp = rgep->sw_sbds;
379744Sgs150176 	bdp = rgep->tx_ring;
380744Sgs150176 	for (slot = 0; slot < RGE_SEND_SLOTS; slot++) {
381744Sgs150176 		bdp->host_buf_addr =
382744Sgs150176 		    RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress);
383744Sgs150176 		bdp->host_buf_addr_hi =
384744Sgs150176 		    RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress >> 32);
385744Sgs150176 		/* last BD in Tx ring */
386744Sgs150176 		if (slot == (RGE_SEND_SLOTS - 1))
387744Sgs150176 			bdp->flags_len = RGE_BSWAP_32(BD_FLAG_EOR);
388744Sgs150176 		ssbdp++;
389744Sgs150176 		bdp++;
390744Sgs150176 	}
391744Sgs150176 	DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
392744Sgs150176 	rgep->tx_next = 0;
393744Sgs150176 	rgep->tc_next = 0;
394744Sgs150176 	rgep->tc_tail = 0;
395744Sgs150176 	rgep->tx_flow = 0;
396744Sgs150176 	rgep->tx_free = RGE_SEND_SLOTS;
397744Sgs150176 }
398744Sgs150176 
399744Sgs150176 static void
400744Sgs150176 rge_reinit_recv_ring(rge_t *rgep)
401744Sgs150176 {
402744Sgs150176 	rge_bd_t *bdp;
403744Sgs150176 	sw_rbd_t *srbdp;
404744Sgs150176 	dma_area_t *pbuf;
405744Sgs150176 	uint32_t slot;
406744Sgs150176 
407744Sgs150176 	/*
408744Sgs150176 	 * re-init receive ring
409744Sgs150176 	 */
410744Sgs150176 	DMA_ZERO(rgep->rx_desc);
411744Sgs150176 	srbdp = rgep->sw_rbds;
412744Sgs150176 	bdp = rgep->rx_ring;
413744Sgs150176 	for (slot = 0; slot < RGE_RECV_SLOTS; slot++) {
414744Sgs150176 		pbuf = &srbdp->rx_buf->pbuf;
415744Sgs150176 		bdp->host_buf_addr =
416744Sgs150176 		    RGE_BSWAP_32(pbuf->cookie.dmac_laddress + RGE_HEADROOM);
417744Sgs150176 		bdp->host_buf_addr_hi =
418744Sgs150176 		    RGE_BSWAP_32(pbuf->cookie.dmac_laddress >> 32);
419744Sgs150176 		bdp->flags_len = RGE_BSWAP_32(BD_FLAG_HW_OWN |
420744Sgs150176 		    (rgep->rxbuf_size - RGE_HEADROOM));
421744Sgs150176 		/* last BD in Tx ring */
422744Sgs150176 		if (slot == (RGE_RECV_SLOTS - 1))
423744Sgs150176 			bdp->flags_len |= RGE_BSWAP_32(BD_FLAG_EOR);
424744Sgs150176 		srbdp++;
425744Sgs150176 		bdp++;
426744Sgs150176 	}
427744Sgs150176 	DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV);
428744Sgs150176 	rgep->watchdog = 0;
429744Sgs150176 	rgep->rx_next = 0;
430744Sgs150176 }
431744Sgs150176 
432744Sgs150176 static void
433744Sgs150176 rge_reinit_buf_ring(rge_t *rgep)
434744Sgs150176 {
435744Sgs150176 	/*
436744Sgs150176 	 * re-init free buffer ring
437744Sgs150176 	 */
438744Sgs150176 	rgep->rc_next = 0;
439744Sgs150176 	rgep->rf_next = 0;
440744Sgs150176 	if (rgep->rx_free != RGE_BUF_SLOTS)
441744Sgs150176 		rgep->rx_bcopy = B_TRUE;
442744Sgs150176 }
443744Sgs150176 
444744Sgs150176 static void
445744Sgs150176 rge_reinit_rings(rge_t *rgep)
446744Sgs150176 {
447744Sgs150176 	rge_reinit_send_ring(rgep);
448744Sgs150176 	rge_reinit_recv_ring(rgep);
449744Sgs150176 	rge_reinit_buf_ring(rgep);
450744Sgs150176 }
451744Sgs150176 
452744Sgs150176 static void
453744Sgs150176 rge_init_send_ring(rge_t *rgep)
454744Sgs150176 {
455744Sgs150176 	uint32_t slot;
456744Sgs150176 	uint32_t split;
457744Sgs150176 	rge_bd_t *bdp;
458744Sgs150176 	sw_sbd_t *ssbdp;
459744Sgs150176 	dma_area_t buf_chunk;
460744Sgs150176 	dma_area_t *pbuf;
461744Sgs150176 
462744Sgs150176 	/*
463744Sgs150176 	 * Allocate the array of s/w Tx Buffer Descriptors
464744Sgs150176 	 */
465744Sgs150176 	ssbdp = kmem_zalloc(RGE_SEND_SLOTS*sizeof (*ssbdp), KM_SLEEP);
466744Sgs150176 	rgep->sw_sbds = ssbdp;
467744Sgs150176 
468744Sgs150176 	/*
469744Sgs150176 	 * Init send ring
470744Sgs150176 	 */
471744Sgs150176 	rgep->tx_next = 0;
472744Sgs150176 	rgep->tc_next = 0;
473744Sgs150176 	rgep->tc_tail = 0;
474744Sgs150176 	rgep->tx_flow = 0;
475744Sgs150176 	rgep->tx_free = RGE_SEND_SLOTS;
476744Sgs150176 	rgep->tx_desc = rgep->dma_area_txdesc;
477744Sgs150176 	DMA_ZERO(rgep->tx_desc);
478744Sgs150176 	bdp = rgep->tx_desc.mem_va;
479744Sgs150176 	rgep->tx_ring = bdp;
480744Sgs150176 	for (split = 0; split < RGE_SPLIT; split++) {
481744Sgs150176 		buf_chunk = rgep->dma_area_txbuf[split];
482744Sgs150176 		for (slot = 0; slot < RGE_SEND_SLOTS/RGE_SPLIT; slot++) {
483744Sgs150176 			rge_slice_chunk(&ssbdp->desc, &rgep->dma_area_txdesc,
484744Sgs150176 			    1, sizeof (rge_bd_t));
485744Sgs150176 			pbuf = &ssbdp->pbuf;
486744Sgs150176 			rge_slice_chunk(pbuf, &buf_chunk, 1, rgep->txbuf_size);
487744Sgs150176 			bdp->host_buf_addr =
488744Sgs150176 			    RGE_BSWAP_32(pbuf->cookie.dmac_laddress);
489744Sgs150176 			bdp->host_buf_addr_hi =
490744Sgs150176 			    RGE_BSWAP_32(pbuf->cookie.dmac_laddress >> 32);
491744Sgs150176 			/* last BD in Tx ring */
492744Sgs150176 			if (split == (RGE_SPLIT - 1) &&
493744Sgs150176 			    slot == (RGE_SEND_SLOTS/RGE_SPLIT -1))
494744Sgs150176 				bdp->flags_len |= RGE_BSWAP_32(BD_FLAG_EOR);
495744Sgs150176 			ssbdp++;
496744Sgs150176 			bdp++;
497744Sgs150176 		}
498744Sgs150176 	}
499744Sgs150176 	DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
500744Sgs150176 }
501744Sgs150176 
502744Sgs150176 static int
503744Sgs150176 rge_init_recv_ring(rge_t *rgep)
504744Sgs150176 {
505744Sgs150176 	uint32_t slot;
506744Sgs150176 	uint32_t split;
507744Sgs150176 	rge_bd_t *bdp;
508744Sgs150176 	sw_rbd_t *srbdp;
509744Sgs150176 	dma_buf_t *rx_buf;
510744Sgs150176 	dma_area_t buf_chunk;
511744Sgs150176 	dma_area_t *pbuf;
512744Sgs150176 
513744Sgs150176 	/*
514744Sgs150176 	 * Allocate the array of s/w Rx Buffer Descriptors
515744Sgs150176 	 */
516744Sgs150176 	srbdp = kmem_zalloc(RGE_RECV_SLOTS*sizeof (*srbdp), KM_SLEEP);
517744Sgs150176 	rx_buf = kmem_zalloc(RGE_RECV_SLOTS*sizeof (*rx_buf), KM_SLEEP);
518744Sgs150176 	rgep->sw_rbds = srbdp;
519744Sgs150176 	rgep->sw_rbuf = rx_buf;
520744Sgs150176 
521744Sgs150176 	/*
522744Sgs150176 	 * Init receive ring
523744Sgs150176 	 */
524744Sgs150176 	rgep->rx_next = 0;
525744Sgs150176 	rgep->rx_desc = rgep->dma_area_rxdesc;
526744Sgs150176 	DMA_ZERO(rgep->rx_desc);
527744Sgs150176 	bdp = rgep->rx_desc.mem_va;
528744Sgs150176 	rgep->rx_ring = bdp;
529744Sgs150176 	for (split = 0; split < RGE_SPLIT; split++) {
530744Sgs150176 		buf_chunk = rgep->dma_area_rxbuf[split];
531744Sgs150176 		for (slot = 0; slot < RGE_RECV_SLOTS/RGE_SPLIT; slot++) {
532744Sgs150176 			srbdp->rx_buf = rx_buf;
533744Sgs150176 			pbuf = &rx_buf->pbuf;
534744Sgs150176 			rge_slice_chunk(pbuf, &buf_chunk, 1, rgep->rxbuf_size);
535744Sgs150176 			pbuf->alength -= RGE_HEADROOM;
536744Sgs150176 			pbuf->offset += RGE_HEADROOM;
537744Sgs150176 			rx_buf->rx_recycle.free_func = rge_rx_recycle;
538744Sgs150176 			rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf;
539744Sgs150176 			rx_buf->private = (caddr_t)rgep;
540744Sgs150176 			rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
541744Sgs150176 			    rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
542744Sgs150176 			if (rx_buf->mp == NULL) {
543744Sgs150176 				rge_problem(rgep,
544744Sgs150176 				    "rge_init_recv_ring: desballoc() failed");
545744Sgs150176 				return (DDI_FAILURE);
546744Sgs150176 			}
547744Sgs150176 
548744Sgs150176 			bdp->host_buf_addr = RGE_BSWAP_32(RGE_HEADROOM +
549744Sgs150176 			    pbuf->cookie.dmac_laddress);
550744Sgs150176 			bdp->host_buf_addr_hi =
551744Sgs150176 			    RGE_BSWAP_32(pbuf->cookie.dmac_laddress >> 32);
552744Sgs150176 			bdp->flags_len = RGE_BSWAP_32(BD_FLAG_HW_OWN |
553744Sgs150176 			    (rgep->rxbuf_size - RGE_HEADROOM));
554744Sgs150176 			/* last BD in Rx ring */
555744Sgs150176 			if (split == (RGE_SPLIT - 1) &&
556744Sgs150176 			    slot == (RGE_RECV_SLOTS/RGE_SPLIT -1))
557744Sgs150176 				bdp->flags_len |= RGE_BSWAP_32(BD_FLAG_EOR);
558744Sgs150176 			srbdp++;
559744Sgs150176 			bdp++;
560744Sgs150176 			rx_buf++;
561744Sgs150176 		}
562744Sgs150176 	}
563744Sgs150176 	DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV);
564744Sgs150176 	return (DDI_SUCCESS);
565744Sgs150176 }
566744Sgs150176 
567744Sgs150176 static int
568744Sgs150176 rge_init_buf_ring(rge_t *rgep)
569744Sgs150176 {
570744Sgs150176 	uint32_t slot;
571744Sgs150176 	uint32_t split;
572744Sgs150176 	sw_rbd_t *free_rbdp;
573744Sgs150176 	dma_buf_t *rx_buf;
574744Sgs150176 	dma_area_t buf_chunk;
575744Sgs150176 	dma_area_t *pbuf;
576744Sgs150176 
577744Sgs150176 	/*
578744Sgs150176 	 * Allocate the array of s/w free Buffer Descriptors
579744Sgs150176 	 */
580744Sgs150176 	free_rbdp = kmem_zalloc(RGE_BUF_SLOTS*sizeof (*free_rbdp), KM_SLEEP);
581744Sgs150176 	rx_buf = kmem_zalloc(RGE_BUF_SLOTS*sizeof (*rx_buf), KM_SLEEP);
582744Sgs150176 	rgep->free_rbds = free_rbdp;
583744Sgs150176 	rgep->sw_freebuf = rx_buf;
584744Sgs150176 
585744Sgs150176 	/*
586744Sgs150176 	 * Init free buffer ring
587744Sgs150176 	 */
588744Sgs150176 	rgep->rc_next = 0;
589744Sgs150176 	rgep->rf_next = 0;
590744Sgs150176 	rgep->rx_bcopy = B_FALSE;
591744Sgs150176 	rgep->rx_free = RGE_BUF_SLOTS;
592744Sgs150176 	for (split = 0; split < RGE_SPLIT; split++) {
593744Sgs150176 		buf_chunk = rgep->dma_area_freebuf[split];
594744Sgs150176 		for (slot = 0; slot < RGE_BUF_SLOTS/RGE_SPLIT; slot++) {
595744Sgs150176 			free_rbdp->rx_buf = rx_buf;
596744Sgs150176 			pbuf = &rx_buf->pbuf;
597744Sgs150176 			rge_slice_chunk(pbuf, &buf_chunk, 1, rgep->rxbuf_size);
598744Sgs150176 			pbuf->alength -= RGE_HEADROOM;
599744Sgs150176 			pbuf->offset += RGE_HEADROOM;
600744Sgs150176 			rx_buf->rx_recycle.free_func = rge_rx_recycle;
601744Sgs150176 			rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf;
602744Sgs150176 			rx_buf->private = (caddr_t)rgep;
603744Sgs150176 			rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
604744Sgs150176 			    rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
605744Sgs150176 			if (rx_buf->mp == NULL) {
606744Sgs150176 				rge_problem(rgep,
607744Sgs150176 				    "rge_init_buf_ring: desballoc() failed");
608744Sgs150176 				return (DDI_FAILURE);
609744Sgs150176 			}
610744Sgs150176 			free_rbdp++;
611744Sgs150176 			rx_buf++;
612744Sgs150176 		}
613744Sgs150176 	}
614744Sgs150176 	return (DDI_SUCCESS);
615744Sgs150176 }
616744Sgs150176 
617744Sgs150176 static int
618744Sgs150176 rge_init_rings(rge_t *rgep)
619744Sgs150176 {
620744Sgs150176 	int err;
621744Sgs150176 
622744Sgs150176 	rge_init_send_ring(rgep);
623744Sgs150176 	err = rge_init_recv_ring(rgep);
624744Sgs150176 	err = rge_init_buf_ring(rgep);
625744Sgs150176 	return (err);
626744Sgs150176 }
627744Sgs150176 
628744Sgs150176 static void
629744Sgs150176 rge_fini_send_ring(rge_t *rgep)
630744Sgs150176 {
631744Sgs150176 	kmem_free(rgep->sw_sbds, RGE_SEND_SLOTS * sizeof (sw_sbd_t));
632744Sgs150176 }
633744Sgs150176 
634744Sgs150176 static void
635744Sgs150176 rge_fini_recv_ring(rge_t *rgep)
636744Sgs150176 {
637744Sgs150176 	dma_buf_t *rx_buf = rgep->sw_rbuf;
638744Sgs150176 	uint32_t slot;
639744Sgs150176 
640744Sgs150176 	for (slot = 0; slot < RGE_RECV_SLOTS; slot++, rx_buf++)
641744Sgs150176 		freemsg(rx_buf->mp);
642744Sgs150176 	kmem_free(rgep->sw_rbuf, RGE_RECV_SLOTS * sizeof (dma_buf_t));
643744Sgs150176 	kmem_free(rgep->sw_rbds, RGE_RECV_SLOTS * sizeof (sw_rbd_t));
644744Sgs150176 }
645744Sgs150176 
646744Sgs150176 static void
647744Sgs150176 rge_fini_buf_ring(rge_t *rgep)
648744Sgs150176 {
649744Sgs150176 	dma_buf_t *rx_buf = rgep->sw_freebuf;
650744Sgs150176 	uint32_t slot;
651744Sgs150176 
652744Sgs150176 	for (slot = 0; slot < RGE_BUF_SLOTS; slot++, rx_buf++)
653744Sgs150176 		freemsg(rx_buf->mp);
654744Sgs150176 	kmem_free(rgep->sw_freebuf, RGE_BUF_SLOTS * sizeof (dma_buf_t));
655744Sgs150176 	kmem_free(rgep->free_rbds, RGE_BUF_SLOTS * sizeof (sw_rbd_t));
656744Sgs150176 }
657744Sgs150176 
658744Sgs150176 static void
659744Sgs150176 rge_fini_rings(rge_t *rgep)
660744Sgs150176 {
661744Sgs150176 	rge_fini_send_ring(rgep);
662744Sgs150176 	rge_fini_recv_ring(rgep);
663744Sgs150176 	rge_fini_buf_ring(rgep);
664744Sgs150176 }
665744Sgs150176 
666744Sgs150176 /*
667744Sgs150176  * ========== Internal state management entry points ==========
668744Sgs150176  */
669744Sgs150176 
670744Sgs150176 #undef	RGE_DBG
671744Sgs150176 #define	RGE_DBG		RGE_DBG_NEMO	/* debug flag for this code	*/
672744Sgs150176 
673744Sgs150176 /*
674744Sgs150176  * These routines provide all the functionality required by the
675744Sgs150176  * corresponding MAC layer entry points, but don't update the
676744Sgs150176  * MAC state so they can be called internally without disturbing
677744Sgs150176  * our record of what NEMO thinks we should be doing ...
678744Sgs150176  */
679744Sgs150176 
680744Sgs150176 /*
681744Sgs150176  *	rge_reset() -- reset h/w & rings to initial state
682744Sgs150176  */
683744Sgs150176 static void
684744Sgs150176 rge_reset(rge_t *rgep)
685744Sgs150176 {
686744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
687744Sgs150176 
688744Sgs150176 	/*
689744Sgs150176 	 * Grab all the other mutexes in the world (this should
690744Sgs150176 	 * ensure no other threads are manipulating driver state)
691744Sgs150176 	 */
692744Sgs150176 	mutex_enter(rgep->rx_lock);
693744Sgs150176 	mutex_enter(rgep->rc_lock);
694744Sgs150176 	rw_enter(rgep->errlock, RW_WRITER);
695744Sgs150176 
696744Sgs150176 	(void) rge_chip_reset(rgep);
697744Sgs150176 	rge_reinit_rings(rgep);
698744Sgs150176 	rge_chip_init(rgep);
699744Sgs150176 
700744Sgs150176 	/*
701744Sgs150176 	 * Free the world ...
702744Sgs150176 	 */
703744Sgs150176 	rw_exit(rgep->errlock);
704744Sgs150176 	mutex_exit(rgep->rc_lock);
705744Sgs150176 	mutex_exit(rgep->rx_lock);
706744Sgs150176 
707744Sgs150176 	RGE_DEBUG(("rge_reset($%p) done", (void *)rgep));
708744Sgs150176 }
709744Sgs150176 
710744Sgs150176 /*
711744Sgs150176  *	rge_stop() -- stop processing, don't reset h/w or rings
712744Sgs150176  */
713744Sgs150176 static void
714744Sgs150176 rge_stop(rge_t *rgep)
715744Sgs150176 {
716744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
717744Sgs150176 
718744Sgs150176 	rge_chip_stop(rgep, B_FALSE);
719744Sgs150176 
720744Sgs150176 	RGE_DEBUG(("rge_stop($%p) done", (void *)rgep));
721744Sgs150176 }
722744Sgs150176 
723744Sgs150176 /*
724744Sgs150176  *	rge_start() -- start transmitting/receiving
725744Sgs150176  */
726744Sgs150176 static void
727744Sgs150176 rge_start(rge_t *rgep)
728744Sgs150176 {
729744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
730744Sgs150176 
731744Sgs150176 	/*
732744Sgs150176 	 * Start chip processing, including enabling interrupts
733744Sgs150176 	 */
734744Sgs150176 	rge_chip_start(rgep);
735744Sgs150176 	rgep->watchdog = 0;
736744Sgs150176 }
737744Sgs150176 
738744Sgs150176 /*
739744Sgs150176  * rge_restart - restart transmitting/receiving after error or suspend
740744Sgs150176  */
741744Sgs150176 void
742744Sgs150176 rge_restart(rge_t *rgep)
743744Sgs150176 {
744744Sgs150176 	uint32_t i;
745744Sgs150176 
746744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
747744Sgs150176 	/*
748744Sgs150176 	 * Wait for posted buffer to be freed...
749744Sgs150176 	 */
750744Sgs150176 	if (!rgep->rx_bcopy) {
751744Sgs150176 		for (i = 0; i < RXBUFF_FREE_LOOP; i++) {
752744Sgs150176 			if (rgep->rx_free == RGE_BUF_SLOTS)
753744Sgs150176 				break;
754744Sgs150176 			drv_usecwait(1000);
755744Sgs150176 			RGE_DEBUG(("rge_restart: waiting for rx buf free..."));
756744Sgs150176 		}
757744Sgs150176 	}
758744Sgs150176 	rge_reset(rgep);
759744Sgs150176 	rgep->stats.chip_reset++;
760744Sgs150176 	if (rgep->rge_mac_state == RGE_MAC_STARTED) {
761744Sgs150176 		rge_start(rgep);
762744Sgs150176 		ddi_trigger_softintr(rgep->resched_id);
763744Sgs150176 	}
764744Sgs150176 }
765744Sgs150176 
766744Sgs150176 
767744Sgs150176 /*
768744Sgs150176  * ========== Nemo-required management entry points ==========
769744Sgs150176  */
770744Sgs150176 
771744Sgs150176 #undef	RGE_DBG
772744Sgs150176 #define	RGE_DBG		RGE_DBG_NEMO	/* debug flag for this code	*/
773744Sgs150176 
774744Sgs150176 /*
775744Sgs150176  *	rge_m_stop() -- stop transmitting/receiving
776744Sgs150176  */
777744Sgs150176 static void
778744Sgs150176 rge_m_stop(void *arg)
779744Sgs150176 {
780744Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
781744Sgs150176 	uint32_t i;
782744Sgs150176 
783744Sgs150176 	/*
784744Sgs150176 	 * Just stop processing, then record new MAC state
785744Sgs150176 	 */
786744Sgs150176 	mutex_enter(rgep->genlock);
787744Sgs150176 	rge_stop(rgep);
788744Sgs150176 	rgep->link_up_msg = rgep->link_down_msg = " (stopped)";
789744Sgs150176 	/*
790744Sgs150176 	 * Wait for posted buffer to be freed...
791744Sgs150176 	 */
792744Sgs150176 	if (!rgep->rx_bcopy) {
793744Sgs150176 		for (i = 0; i < RXBUFF_FREE_LOOP; i++) {
794744Sgs150176 			if (rgep->rx_free == RGE_BUF_SLOTS)
795744Sgs150176 				break;
796744Sgs150176 			drv_usecwait(1000);
797744Sgs150176 			RGE_DEBUG(("rge_m_stop: waiting for rx buf free..."));
798744Sgs150176 		}
799744Sgs150176 	}
800744Sgs150176 	rgep->rge_mac_state = RGE_MAC_STOPPED;
801744Sgs150176 	RGE_DEBUG(("rge_m_stop($%p) done", arg));
802744Sgs150176 	mutex_exit(rgep->genlock);
803744Sgs150176 }
804744Sgs150176 
805744Sgs150176 /*
806744Sgs150176  *	rge_m_start() -- start transmitting/receiving
807744Sgs150176  */
808744Sgs150176 static int
809744Sgs150176 rge_m_start(void *arg)
810744Sgs150176 {
811744Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
812744Sgs150176 
813744Sgs150176 	mutex_enter(rgep->genlock);
814744Sgs150176 
815744Sgs150176 	/*
816744Sgs150176 	 * Clear hw/sw statistics
817744Sgs150176 	 */
818744Sgs150176 	DMA_ZERO(rgep->dma_area_stats);
819744Sgs150176 	bzero(&rgep->stats, sizeof (rge_stats_t));
820744Sgs150176 
821744Sgs150176 	/*
822744Sgs150176 	 * Start processing and record new MAC state
823744Sgs150176 	 */
824744Sgs150176 	rge_reset(rgep);
825744Sgs150176 	rgep->link_up_msg = rgep->link_down_msg = " (initialized)";
826744Sgs150176 	rge_start(rgep);
827744Sgs150176 	rgep->rge_mac_state = RGE_MAC_STARTED;
828744Sgs150176 	RGE_DEBUG(("rge_m_start($%p) done", arg));
829744Sgs150176 
830744Sgs150176 	mutex_exit(rgep->genlock);
831744Sgs150176 
832744Sgs150176 	return (0);
833744Sgs150176 }
834744Sgs150176 
835744Sgs150176 /*
836744Sgs150176  *	rge_m_unicst_set() -- set the physical network address
837744Sgs150176  */
838744Sgs150176 static int
839744Sgs150176 rge_m_unicst(void *arg, const uint8_t *macaddr)
840744Sgs150176 {
841744Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
842744Sgs150176 
843744Sgs150176 	/*
844744Sgs150176 	 * Remember the new current address in the driver state
845744Sgs150176 	 * Sync the chip's idea of the address too ...
846744Sgs150176 	 */
847744Sgs150176 	mutex_enter(rgep->genlock);
848744Sgs150176 	bcopy(macaddr, rgep->netaddr, ETHERADDRL);
849744Sgs150176 	rge_chip_sync(rgep, RGE_SET_MAC);
850744Sgs150176 	mutex_exit(rgep->genlock);
851744Sgs150176 
852744Sgs150176 	return (0);
853744Sgs150176 }
854744Sgs150176 
855744Sgs150176 /*
856744Sgs150176  * Compute the index of the required bit in the multicast hash map.
857744Sgs150176  * This must mirror the way the hardware actually does it!
858744Sgs150176  */
859744Sgs150176 static uint32_t
860744Sgs150176 rge_hash_index(const uint8_t *mca)
861744Sgs150176 {
862744Sgs150176 	uint32_t crc = (ulong_t)RGE_HASH_CRC;
863744Sgs150176 	uint32_t const POLY = RGE_HASH_POLY;
864744Sgs150176 	uint32_t msb;
865744Sgs150176 	int bytes;
866744Sgs150176 	uchar_t currentbyte;
867744Sgs150176 	uint32_t index;
868744Sgs150176 	int bit;
869744Sgs150176 
870744Sgs150176 	for (bytes = 0; bytes < ETHERADDRL; bytes++) {
871744Sgs150176 		currentbyte = mca[bytes];
872744Sgs150176 		for (bit = 0; bit < 8; bit++) {
873744Sgs150176 			msb = crc >> 31;
874744Sgs150176 			crc <<= 1;
875744Sgs150176 			if (msb ^ (currentbyte & 1)) {
876744Sgs150176 				crc ^= POLY;
877744Sgs150176 				crc |= 0x00000001;
878744Sgs150176 			}
879744Sgs150176 			currentbyte >>= 1;
880744Sgs150176 		}
881744Sgs150176 	}
882744Sgs150176 	index = crc >> 26;
883744Sgs150176 
884744Sgs150176 	return (index);
885744Sgs150176 }
886744Sgs150176 
887744Sgs150176 /*
888744Sgs150176  *	rge_m_multicst_add() -- enable/disable a multicast address
889744Sgs150176  */
890744Sgs150176 static int
891744Sgs150176 rge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
892744Sgs150176 {
893744Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
894744Sgs150176 	struct ether_addr *addr;
895744Sgs150176 	uint32_t index;
896744Sgs150176 	uint32_t *hashp;
897744Sgs150176 
898744Sgs150176 	mutex_enter(rgep->genlock);
899744Sgs150176 	hashp = rgep->mcast_hash;
900744Sgs150176 	addr = (struct ether_addr *)mca;
901744Sgs150176 	index = rge_hash_index(addr->ether_addr_octet);
902744Sgs150176 			/* index value is between 0 and 63 */
903744Sgs150176 
904744Sgs150176 	if (add) {
905744Sgs150176 		if (rgep->mcast_refs[index]++) {
906744Sgs150176 			mutex_exit(rgep->genlock);
907744Sgs150176 			return (0);
908744Sgs150176 		}
909744Sgs150176 		hashp[index/32] |= 1<< (index % 32);
910744Sgs150176 	} else {
911744Sgs150176 		if (--rgep->mcast_refs[index]) {
912744Sgs150176 			mutex_exit(rgep->genlock);
913744Sgs150176 			return (0);
914744Sgs150176 		}
915744Sgs150176 		hashp[index/32] &= ~(1<< (index % 32));
916744Sgs150176 	}
917744Sgs150176 
918744Sgs150176 	/*
919744Sgs150176 	 * Set multicast register
920744Sgs150176 	 */
921744Sgs150176 	rge_chip_sync(rgep, RGE_SET_MUL);
922744Sgs150176 
923744Sgs150176 	mutex_exit(rgep->genlock);
924744Sgs150176 	return (0);
925744Sgs150176 }
926744Sgs150176 
927744Sgs150176 /*
928744Sgs150176  * rge_m_promisc() -- set or reset promiscuous mode on the board
929744Sgs150176  *
930744Sgs150176  *	Program the hardware to enable/disable promiscuous and/or
931744Sgs150176  *	receive-all-multicast modes.
932744Sgs150176  */
933744Sgs150176 static int
934744Sgs150176 rge_m_promisc(void *arg, boolean_t on)
935744Sgs150176 {
936744Sgs150176 	rge_t *rgep = arg;
937744Sgs150176 
938744Sgs150176 	/*
939744Sgs150176 	 * Store MAC layer specified mode and pass to chip layer to update h/w
940744Sgs150176 	 */
941744Sgs150176 	mutex_enter(rgep->genlock);
942744Sgs150176 
943744Sgs150176 	if (rgep->promisc == on) {
944744Sgs150176 		mutex_exit(rgep->genlock);
945744Sgs150176 		return (0);
946744Sgs150176 	}
947744Sgs150176 	rgep->promisc = on;
948744Sgs150176 	rge_chip_sync(rgep, RGE_SET_PROMISC);
949744Sgs150176 	RGE_DEBUG(("rge_m_promisc_set($%p) done", arg));
950744Sgs150176 	mutex_exit(rgep->genlock);
951744Sgs150176 	return (0);
952744Sgs150176 }
953744Sgs150176 
954744Sgs150176 /*
955744Sgs150176  * Loopback ioctl code
956744Sgs150176  */
957744Sgs150176 
958744Sgs150176 static lb_property_t loopmodes[] = {
959744Sgs150176 	{ normal,	"normal",	RGE_LOOP_NONE		},
960744Sgs150176 	{ internal,	"PHY",		RGE_LOOP_INTERNAL_PHY	},
961744Sgs150176 	{ internal,	"MAC",		RGE_LOOP_INTERNAL_MAC	}
962744Sgs150176 };
963744Sgs150176 
964744Sgs150176 static enum ioc_reply
965744Sgs150176 rge_set_loop_mode(rge_t *rgep, uint32_t mode)
966744Sgs150176 {
967744Sgs150176 	const char *msg;
968744Sgs150176 
969744Sgs150176 	/*
970744Sgs150176 	 * If the mode isn't being changed, there's nothing to do ...
971744Sgs150176 	 */
972744Sgs150176 	if (mode == rgep->param_loop_mode)
973744Sgs150176 		return (IOC_ACK);
974744Sgs150176 
975744Sgs150176 	/*
976744Sgs150176 	 * Validate the requested mode and prepare a suitable message
977744Sgs150176 	 * to explain the link down/up cycle that the change will
978744Sgs150176 	 * probably induce ...
979744Sgs150176 	 */
980744Sgs150176 	switch (mode) {
981744Sgs150176 	default:
982744Sgs150176 		return (IOC_INVAL);
983744Sgs150176 
984744Sgs150176 	case RGE_LOOP_NONE:
985744Sgs150176 		msg = " (loopback disabled)";
986744Sgs150176 		break;
987744Sgs150176 
988744Sgs150176 	case RGE_LOOP_INTERNAL_PHY:
989744Sgs150176 		msg = " (PHY internal loopback selected)";
990744Sgs150176 		break;
991744Sgs150176 
992744Sgs150176 	case RGE_LOOP_INTERNAL_MAC:
993744Sgs150176 		msg = " (MAC internal loopback selected)";
994744Sgs150176 		break;
995744Sgs150176 	}
996744Sgs150176 
997744Sgs150176 	/*
998744Sgs150176 	 * All OK; tell the caller to reprogram
999744Sgs150176 	 * the PHY and/or MAC for the new mode ...
1000744Sgs150176 	 */
1001744Sgs150176 	rgep->link_down_msg = rgep->link_up_msg = msg;
1002744Sgs150176 	rgep->param_loop_mode = mode;
1003744Sgs150176 	return (IOC_RESTART_ACK);
1004744Sgs150176 }
1005744Sgs150176 
1006744Sgs150176 static enum ioc_reply
1007744Sgs150176 rge_loop_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
1008744Sgs150176 {
1009744Sgs150176 	lb_info_sz_t *lbsp;
1010744Sgs150176 	lb_property_t *lbpp;
1011744Sgs150176 	uint32_t *lbmp;
1012744Sgs150176 	int cmd;
1013744Sgs150176 
1014744Sgs150176 	_NOTE(ARGUNUSED(wq))
1015744Sgs150176 
1016744Sgs150176 	/*
1017744Sgs150176 	 * Validate format of ioctl
1018744Sgs150176 	 */
1019744Sgs150176 	if (mp->b_cont == NULL)
1020744Sgs150176 		return (IOC_INVAL);
1021744Sgs150176 
1022744Sgs150176 	cmd = iocp->ioc_cmd;
1023744Sgs150176 	switch (cmd) {
1024744Sgs150176 	default:
1025744Sgs150176 		/* NOTREACHED */
1026744Sgs150176 		rge_error(rgep, "rge_loop_ioctl: invalid cmd 0x%x", cmd);
1027744Sgs150176 		return (IOC_INVAL);
1028744Sgs150176 
1029744Sgs150176 	case LB_GET_INFO_SIZE:
1030744Sgs150176 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
1031744Sgs150176 			return (IOC_INVAL);
1032744Sgs150176 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
1033744Sgs150176 		*lbsp = sizeof (loopmodes);
1034744Sgs150176 		return (IOC_REPLY);
1035744Sgs150176 
1036744Sgs150176 	case LB_GET_INFO:
1037744Sgs150176 		if (iocp->ioc_count != sizeof (loopmodes))
1038744Sgs150176 			return (IOC_INVAL);
1039744Sgs150176 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
1040744Sgs150176 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
1041744Sgs150176 		return (IOC_REPLY);
1042744Sgs150176 
1043744Sgs150176 	case LB_GET_MODE:
1044744Sgs150176 		if (iocp->ioc_count != sizeof (uint32_t))
1045744Sgs150176 			return (IOC_INVAL);
1046744Sgs150176 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
1047744Sgs150176 		*lbmp = rgep->param_loop_mode;
1048744Sgs150176 		return (IOC_REPLY);
1049744Sgs150176 
1050744Sgs150176 	case LB_SET_MODE:
1051744Sgs150176 		if (iocp->ioc_count != sizeof (uint32_t))
1052744Sgs150176 			return (IOC_INVAL);
1053744Sgs150176 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
1054744Sgs150176 		return (rge_set_loop_mode(rgep, *lbmp));
1055744Sgs150176 	}
1056744Sgs150176 }
1057744Sgs150176 
1058744Sgs150176 /*
1059744Sgs150176  * Specific rge IOCTLs, the MAC layer handles the generic ones.
1060744Sgs150176  */
1061744Sgs150176 static void
1062744Sgs150176 rge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1063744Sgs150176 {
1064744Sgs150176 	rge_t *rgep = arg;
1065744Sgs150176 	struct iocblk *iocp;
1066744Sgs150176 	enum ioc_reply status;
1067744Sgs150176 	boolean_t need_privilege;
1068744Sgs150176 	int err;
1069744Sgs150176 	int cmd;
1070744Sgs150176 
1071744Sgs150176 	/*
1072744Sgs150176 	 * Validate the command before bothering with the mutex ...
1073744Sgs150176 	 */
1074744Sgs150176 	iocp = (struct iocblk *)mp->b_rptr;
1075744Sgs150176 	iocp->ioc_error = 0;
1076744Sgs150176 	need_privilege = B_TRUE;
1077744Sgs150176 	cmd = iocp->ioc_cmd;
1078744Sgs150176 	switch (cmd) {
1079744Sgs150176 	default:
1080744Sgs150176 		miocnak(wq, mp, 0, EINVAL);
1081744Sgs150176 		return;
1082744Sgs150176 
1083744Sgs150176 	case RGE_MII_READ:
1084744Sgs150176 	case RGE_MII_WRITE:
1085744Sgs150176 	case RGE_DIAG:
1086744Sgs150176 	case RGE_PEEK:
1087744Sgs150176 	case RGE_POKE:
1088744Sgs150176 	case RGE_PHY_RESET:
1089744Sgs150176 	case RGE_SOFT_RESET:
1090744Sgs150176 	case RGE_HARD_RESET:
1091744Sgs150176 		break;
1092744Sgs150176 
1093744Sgs150176 	case LB_GET_INFO_SIZE:
1094744Sgs150176 	case LB_GET_INFO:
1095744Sgs150176 	case LB_GET_MODE:
1096744Sgs150176 		need_privilege = B_FALSE;
1097744Sgs150176 		/* FALLTHRU */
1098744Sgs150176 	case LB_SET_MODE:
1099744Sgs150176 		break;
1100744Sgs150176 
1101744Sgs150176 	case ND_GET:
1102744Sgs150176 		need_privilege = B_FALSE;
1103744Sgs150176 		/* FALLTHRU */
1104744Sgs150176 	case ND_SET:
1105744Sgs150176 		break;
1106744Sgs150176 	}
1107744Sgs150176 
1108744Sgs150176 	if (need_privilege) {
1109744Sgs150176 		/*
1110744Sgs150176 		 * Check for specific net_config privilege on Solaris 10+.
1111744Sgs150176 		 * Otherwise just check for root access ...
1112744Sgs150176 		 */
1113744Sgs150176 		if (secpolicy_net_config != NULL)
1114744Sgs150176 			err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1115744Sgs150176 		else
1116744Sgs150176 			err = drv_priv(iocp->ioc_cr);
1117744Sgs150176 		if (err != 0) {
1118744Sgs150176 			miocnak(wq, mp, 0, err);
1119744Sgs150176 			return;
1120744Sgs150176 		}
1121744Sgs150176 	}
1122744Sgs150176 
1123744Sgs150176 	mutex_enter(rgep->genlock);
1124744Sgs150176 
1125744Sgs150176 	switch (cmd) {
1126744Sgs150176 	default:
1127744Sgs150176 		_NOTE(NOTREACHED)
1128744Sgs150176 		status = IOC_INVAL;
1129744Sgs150176 		break;
1130744Sgs150176 
1131744Sgs150176 	case RGE_MII_READ:
1132744Sgs150176 	case RGE_MII_WRITE:
1133744Sgs150176 	case RGE_DIAG:
1134744Sgs150176 	case RGE_PEEK:
1135744Sgs150176 	case RGE_POKE:
1136744Sgs150176 	case RGE_PHY_RESET:
1137744Sgs150176 	case RGE_SOFT_RESET:
1138744Sgs150176 	case RGE_HARD_RESET:
1139744Sgs150176 		status = rge_chip_ioctl(rgep, wq, mp, iocp);
1140744Sgs150176 		break;
1141744Sgs150176 
1142744Sgs150176 	case LB_GET_INFO_SIZE:
1143744Sgs150176 	case LB_GET_INFO:
1144744Sgs150176 	case LB_GET_MODE:
1145744Sgs150176 	case LB_SET_MODE:
1146744Sgs150176 		status = rge_loop_ioctl(rgep, wq, mp, iocp);
1147744Sgs150176 		break;
1148744Sgs150176 
1149744Sgs150176 	case ND_GET:
1150744Sgs150176 	case ND_SET:
1151744Sgs150176 		status = rge_nd_ioctl(rgep, wq, mp, iocp);
1152744Sgs150176 		break;
1153744Sgs150176 	}
1154744Sgs150176 
1155744Sgs150176 	/*
1156744Sgs150176 	 * Do we need to reprogram the PHY and/or the MAC?
1157744Sgs150176 	 * Do it now, while we still have the mutex.
1158744Sgs150176 	 *
1159744Sgs150176 	 * Note: update the PHY first, 'cos it controls the
1160744Sgs150176 	 * speed/duplex parameters that the MAC code uses.
1161744Sgs150176 	 */
1162744Sgs150176 	switch (status) {
1163744Sgs150176 	case IOC_RESTART_REPLY:
1164744Sgs150176 	case IOC_RESTART_ACK:
1165744Sgs150176 		rge_phy_update(rgep);
1166744Sgs150176 		break;
1167744Sgs150176 	}
1168744Sgs150176 
1169744Sgs150176 	mutex_exit(rgep->genlock);
1170744Sgs150176 
1171744Sgs150176 	/*
1172744Sgs150176 	 * Finally, decide how to reply
1173744Sgs150176 	 */
1174744Sgs150176 	switch (status) {
1175744Sgs150176 	default:
1176744Sgs150176 	case IOC_INVAL:
1177744Sgs150176 		/*
1178744Sgs150176 		 * Error, reply with a NAK and EINVAL or the specified error
1179744Sgs150176 		 */
1180744Sgs150176 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
1181744Sgs150176 			EINVAL : iocp->ioc_error);
1182744Sgs150176 		break;
1183744Sgs150176 
1184744Sgs150176 	case IOC_DONE:
1185744Sgs150176 		/*
1186744Sgs150176 		 * OK, reply already sent
1187744Sgs150176 		 */
1188744Sgs150176 		break;
1189744Sgs150176 
1190744Sgs150176 	case IOC_RESTART_ACK:
1191744Sgs150176 	case IOC_ACK:
1192744Sgs150176 		/*
1193744Sgs150176 		 * OK, reply with an ACK
1194744Sgs150176 		 */
1195744Sgs150176 		miocack(wq, mp, 0, 0);
1196744Sgs150176 		break;
1197744Sgs150176 
1198744Sgs150176 	case IOC_RESTART_REPLY:
1199744Sgs150176 	case IOC_REPLY:
1200744Sgs150176 		/*
1201744Sgs150176 		 * OK, send prepared reply as ACK or NAK
1202744Sgs150176 		 */
1203744Sgs150176 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
1204744Sgs150176 			M_IOCACK : M_IOCNAK;
1205744Sgs150176 		qreply(wq, mp);
1206744Sgs150176 		break;
1207744Sgs150176 	}
1208744Sgs150176 }
1209744Sgs150176 
1210744Sgs150176 static void
1211744Sgs150176 rge_m_resources(void *arg)
1212744Sgs150176 {
1213744Sgs150176 	rge_t *rgep = arg;
1214744Sgs150176 	mac_rx_fifo_t mrf;
1215744Sgs150176 
1216744Sgs150176 	mutex_enter(rgep->genlock);
1217744Sgs150176 
1218744Sgs150176 	/*
1219744Sgs150176 	 * Register Rx rings as resources and save mac
1220744Sgs150176 	 * resource id for future reference
1221744Sgs150176 	 */
1222744Sgs150176 	mrf.mrf_type = MAC_RX_FIFO;
1223744Sgs150176 	mrf.mrf_blank = rge_chip_blank;
1224744Sgs150176 	mrf.mrf_arg = (void *)rgep;
1225744Sgs150176 	mrf.mrf_normal_blank_time = RGE_RX_INT_TIME;
1226744Sgs150176 	mrf.mrf_normal_pkt_count = RGE_RX_INT_PKTS;
1227*2311Sseb 	rgep->handle = mac_resource_add(rgep->mh, (mac_resource_t *)&mrf);
1228744Sgs150176 
1229744Sgs150176 	mutex_exit(rgep->genlock);
1230744Sgs150176 }
1231744Sgs150176 
1232*2311Sseb /* ARGSUSED */
1233*2311Sseb static boolean_t
1234*2311Sseb rge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
1235*2311Sseb {
1236*2311Sseb 	switch (cap) {
1237*2311Sseb 	case MAC_CAPAB_HCKSUM: {
1238*2311Sseb 		uint32_t *hcksum_txflags = cap_data;
1239*2311Sseb 		*hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
1240*2311Sseb 		break;
1241*2311Sseb 	}
1242*2311Sseb 	case MAC_CAPAB_POLL:
1243*2311Sseb 		/*
1244*2311Sseb 		 * There's nothing for us to fill in, simply returning
1245*2311Sseb 		 * B_TRUE stating that we support polling is sufficient.
1246*2311Sseb 		 */
1247*2311Sseb 		break;
1248*2311Sseb 	default:
1249*2311Sseb 		return (B_FALSE);
1250*2311Sseb 	}
1251*2311Sseb 	return (B_TRUE);
1252*2311Sseb }
1253*2311Sseb 
1254744Sgs150176 /*
1255744Sgs150176  * ========== Per-instance setup/teardown code ==========
1256744Sgs150176  */
1257744Sgs150176 
1258744Sgs150176 #undef	RGE_DBG
1259744Sgs150176 #define	RGE_DBG		RGE_DBG_INIT	/* debug flag for this code	*/
1260744Sgs150176 
1261744Sgs150176 static void
1262744Sgs150176 rge_unattach(rge_t *rgep)
1263744Sgs150176 {
1264744Sgs150176 	/*
1265744Sgs150176 	 * Flag that no more activity may be initiated
1266744Sgs150176 	 */
1267744Sgs150176 	rgep->progress &= ~PROGRESS_READY;
1268744Sgs150176 	rgep->rge_mac_state = RGE_MAC_UNATTACH;
1269744Sgs150176 
1270744Sgs150176 	/*
1271744Sgs150176 	 * Quiesce the PHY and MAC (leave it reset but still powered).
1272744Sgs150176 	 * Clean up and free all RGE data structures
1273744Sgs150176 	 */
1274744Sgs150176 	if (rgep->cyclic_id) {
1275744Sgs150176 		mutex_enter(&cpu_lock);
1276744Sgs150176 		cyclic_remove(rgep->cyclic_id);
1277744Sgs150176 		mutex_exit(&cpu_lock);
1278744Sgs150176 	}
1279744Sgs150176 
1280744Sgs150176 	if (rgep->progress & PROGRESS_KSTATS)
1281744Sgs150176 		rge_fini_kstats(rgep);
1282744Sgs150176 
1283744Sgs150176 	if (rgep->progress & PROGRESS_PHY)
1284744Sgs150176 		(void) rge_phy_reset(rgep);
1285744Sgs150176 
1286744Sgs150176 	if (rgep->progress & PROGRESS_INTR) {
1287744Sgs150176 		mutex_enter(rgep->genlock);
1288744Sgs150176 		(void) rge_chip_reset(rgep);
1289744Sgs150176 		mutex_exit(rgep->genlock);
1290744Sgs150176 		ddi_remove_intr(rgep->devinfo, 0, rgep->iblk);
1291744Sgs150176 		rge_fini_rings(rgep);
1292744Sgs150176 		mutex_destroy(rgep->rc_lock);
1293744Sgs150176 		mutex_destroy(rgep->rx_lock);
1294744Sgs150176 		mutex_destroy(rgep->tc_lock);
1295744Sgs150176 		mutex_destroy(rgep->tx_lock);
1296744Sgs150176 		rw_destroy(rgep->errlock);
1297744Sgs150176 		mutex_destroy(rgep->genlock);
1298744Sgs150176 	}
1299744Sgs150176 
1300744Sgs150176 	if (rgep->progress & PROGRESS_FACTOTUM)
1301744Sgs150176 		ddi_remove_softintr(rgep->factotum_id);
1302744Sgs150176 
1303744Sgs150176 	if (rgep->progress & PROGRESS_RESCHED)
1304744Sgs150176 		ddi_remove_softintr(rgep->resched_id);
1305744Sgs150176 
1306744Sgs150176 	rge_free_bufs(rgep);
1307744Sgs150176 
1308744Sgs150176 	if (rgep->progress & PROGRESS_NDD)
1309744Sgs150176 		rge_nd_cleanup(rgep);
1310744Sgs150176 
1311744Sgs150176 	if (rgep->progress & PROGRESS_REGS)
1312744Sgs150176 		ddi_regs_map_free(&rgep->io_handle);
1313744Sgs150176 
1314744Sgs150176 	if (rgep->progress & PROGRESS_CFG)
1315744Sgs150176 		pci_config_teardown(&rgep->cfg_handle);
1316744Sgs150176 
1317744Sgs150176 	ddi_remove_minor_node(rgep->devinfo, NULL);
1318744Sgs150176 	kmem_free(rgep, sizeof (*rgep));
1319744Sgs150176 }
1320744Sgs150176 
1321744Sgs150176 static int
1322744Sgs150176 rge_resume(dev_info_t *devinfo)
1323744Sgs150176 {
1324744Sgs150176 	rge_t *rgep;			/* Our private data	*/
1325744Sgs150176 	chip_id_t *cidp;
1326744Sgs150176 	chip_id_t chipid;
1327744Sgs150176 
1328744Sgs150176 	rgep = ddi_get_driver_private(devinfo);
1329744Sgs150176 	if (rgep == NULL)
1330744Sgs150176 		return (DDI_FAILURE);
1331744Sgs150176 
1332744Sgs150176 	/*
1333744Sgs150176 	 * Refuse to resume if the data structures aren't consistent
1334744Sgs150176 	 */
1335744Sgs150176 	if (rgep->devinfo != devinfo)
1336744Sgs150176 		return (DDI_FAILURE);
1337744Sgs150176 
1338744Sgs150176 	/*
1339744Sgs150176 	 * Read chip ID & set up config space command register(s)
1340744Sgs150176 	 * Refuse to resume if the chip has changed its identity!
1341744Sgs150176 	 */
1342744Sgs150176 	cidp = &rgep->chipid;
1343744Sgs150176 	rge_chip_cfg_init(rgep, &chipid);
1344744Sgs150176 	if (chipid.vendor != cidp->vendor)
1345744Sgs150176 		return (DDI_FAILURE);
1346744Sgs150176 	if (chipid.device != cidp->device)
1347744Sgs150176 		return (DDI_FAILURE);
1348744Sgs150176 	if (chipid.revision != cidp->revision)
1349744Sgs150176 		return (DDI_FAILURE);
1350744Sgs150176 
1351744Sgs150176 	/*
1352744Sgs150176 	 * All OK, reinitialise h/w & kick off NEMO scheduling
1353744Sgs150176 	 */
1354744Sgs150176 	mutex_enter(rgep->genlock);
1355744Sgs150176 	rge_restart(rgep);
1356744Sgs150176 	mutex_exit(rgep->genlock);
1357744Sgs150176 	return (DDI_SUCCESS);
1358744Sgs150176 }
1359744Sgs150176 
1360744Sgs150176 
1361744Sgs150176 /*
1362744Sgs150176  * attach(9E) -- Attach a device to the system
1363744Sgs150176  *
1364744Sgs150176  * Called once for each board successfully probed.
1365744Sgs150176  */
1366744Sgs150176 static int
1367744Sgs150176 rge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
1368744Sgs150176 {
1369744Sgs150176 	rge_t *rgep;			/* Our private data	*/
1370*2311Sseb 	mac_register_t *macp;
1371744Sgs150176 	chip_id_t *cidp;
1372744Sgs150176 	cyc_handler_t cychand;
1373744Sgs150176 	cyc_time_t cyctime;
1374744Sgs150176 	caddr_t regs;
1375744Sgs150176 	int instance;
1376744Sgs150176 	int err;
1377744Sgs150176 
1378744Sgs150176 	/*
1379744Sgs150176 	 * we don't support high level interrupts in the driver
1380744Sgs150176 	 */
1381744Sgs150176 	if (ddi_intr_hilevel(devinfo, 0) != 0) {
1382744Sgs150176 		cmn_err(CE_WARN,
1383744Sgs150176 		    "rge_attach -- unsupported high level interrupt");
1384744Sgs150176 		return (DDI_FAILURE);
1385744Sgs150176 	}
1386744Sgs150176 
1387744Sgs150176 	instance = ddi_get_instance(devinfo);
1388744Sgs150176 	RGE_GTRACE(("rge_attach($%p, %d) instance %d",
1389744Sgs150176 		(void *)devinfo, cmd, instance));
1390744Sgs150176 	RGE_BRKPT(NULL, "rge_attach");
1391744Sgs150176 
1392744Sgs150176 	switch (cmd) {
1393744Sgs150176 	default:
1394744Sgs150176 		return (DDI_FAILURE);
1395744Sgs150176 
1396744Sgs150176 	case DDI_RESUME:
1397744Sgs150176 		return (rge_resume(devinfo));
1398744Sgs150176 
1399744Sgs150176 	case DDI_ATTACH:
1400744Sgs150176 		break;
1401744Sgs150176 	}
1402744Sgs150176 
1403744Sgs150176 	rgep = kmem_zalloc(sizeof (*rgep), KM_SLEEP);
1404744Sgs150176 	ddi_set_driver_private(devinfo, rgep);
1405744Sgs150176 	rgep->devinfo = devinfo;
1406744Sgs150176 
1407744Sgs150176 	/*
1408744Sgs150176 	 * Initialize more fields in RGE private data
1409744Sgs150176 	 */
1410744Sgs150176 	rgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
1411744Sgs150176 		DDI_PROP_DONTPASS, debug_propname, rge_debug);
1412744Sgs150176 	(void) snprintf(rgep->ifname, sizeof (rgep->ifname), "%s%d",
1413744Sgs150176 		RGE_DRIVER_NAME, instance);
1414744Sgs150176 
1415744Sgs150176 	/*
1416744Sgs150176 	 * Map config space registers
1417744Sgs150176 	 * Read chip ID & set up config space command register(s)
1418744Sgs150176 	 *
1419744Sgs150176 	 * Note: this leaves the chip accessible by Memory Space
1420744Sgs150176 	 * accesses, but with interrupts and Bus Mastering off.
1421744Sgs150176 	 * This should ensure that nothing untoward will happen
1422744Sgs150176 	 * if it has been left active by the (net-)bootloader.
1423744Sgs150176 	 * We'll re-enable Bus Mastering once we've reset the chip,
1424744Sgs150176 	 * and allow interrupts only when everything else is set up.
1425744Sgs150176 	 */
1426744Sgs150176 	err = pci_config_setup(devinfo, &rgep->cfg_handle);
1427744Sgs150176 	if (err != DDI_SUCCESS) {
1428744Sgs150176 		rge_problem(rgep, "pci_config_setup() failed");
1429744Sgs150176 		goto attach_fail;
1430744Sgs150176 	}
1431744Sgs150176 	rgep->progress |= PROGRESS_CFG;
1432744Sgs150176 	cidp = &rgep->chipid;
1433744Sgs150176 	bzero(cidp, sizeof (*cidp));
1434744Sgs150176 	rge_chip_cfg_init(rgep, cidp);
1435744Sgs150176 
1436744Sgs150176 	/*
1437744Sgs150176 	 * Map operating registers
1438744Sgs150176 	 */
1439744Sgs150176 	err = ddi_regs_map_setup(devinfo, 1, &regs,
1440744Sgs150176 	    0, 0, &rge_reg_accattr, &rgep->io_handle);
1441744Sgs150176 	if (err != DDI_SUCCESS) {
1442744Sgs150176 		rge_problem(rgep, "ddi_regs_map_setup() failed");
1443744Sgs150176 		goto attach_fail;
1444744Sgs150176 	}
1445744Sgs150176 	rgep->io_regs = regs;
1446744Sgs150176 	rgep->progress |= PROGRESS_REGS;
1447744Sgs150176 
1448744Sgs150176 	/*
1449744Sgs150176 	 * Register NDD-tweakable parameters
1450744Sgs150176 	 */
1451744Sgs150176 	if (rge_nd_init(rgep)) {
1452744Sgs150176 		rge_problem(rgep, "rge_nd_init() failed");
1453744Sgs150176 		goto attach_fail;
1454744Sgs150176 	}
1455744Sgs150176 	rgep->progress |= PROGRESS_NDD;
1456744Sgs150176 
1457744Sgs150176 	/*
1458744Sgs150176 	 * Characterise the device, so we know its requirements.
1459744Sgs150176 	 * Then allocate the appropriate TX and RX descriptors & buffers.
1460744Sgs150176 	 */
1461744Sgs150176 	rge_chip_ident(rgep);
1462744Sgs150176 	err = rge_alloc_bufs(rgep);
1463744Sgs150176 	if (err != DDI_SUCCESS) {
1464744Sgs150176 		rge_problem(rgep, "DMA buffer allocation failed");
1465744Sgs150176 		goto attach_fail;
1466744Sgs150176 	}
1467744Sgs150176 
1468744Sgs150176 	/*
1469744Sgs150176 	 * Add the softint handlers:
1470744Sgs150176 	 *
1471744Sgs150176 	 * Both of these handlers are used to avoid restrictions on the
1472744Sgs150176 	 * context and/or mutexes required for some operations.  In
1473744Sgs150176 	 * particular, the hardware interrupt handler and its subfunctions
1474744Sgs150176 	 * can detect a number of conditions that we don't want to handle
1475744Sgs150176 	 * in that context or with that set of mutexes held.  So, these
1476744Sgs150176 	 * softints are triggered instead:
1477744Sgs150176 	 *
1478744Sgs150176 	 * the <resched> softint is triggered if if we have previously
1479744Sgs150176 	 * had to refuse to send a packet because of resource shortage
1480744Sgs150176 	 * (we've run out of transmit buffers), but the send completion
1481744Sgs150176 	 * interrupt handler has now detected that more buffers have
1482744Sgs150176 	 * become available.
1483744Sgs150176 	 *
1484744Sgs150176 	 * the <factotum> is triggered if the h/w interrupt handler
1485744Sgs150176 	 * sees the <link state changed> or <error> bits in the status
1486744Sgs150176 	 * block.  It's also triggered periodically to poll the link
1487744Sgs150176 	 * state, just in case we aren't getting link status change
1488744Sgs150176 	 * interrupts ...
1489744Sgs150176 	 */
1490744Sgs150176 	err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &rgep->resched_id,
1491744Sgs150176 		NULL, NULL, rge_reschedule, (caddr_t)rgep);
1492744Sgs150176 	if (err != DDI_SUCCESS) {
1493744Sgs150176 		rge_problem(rgep, "ddi_add_softintr() failed");
1494744Sgs150176 		goto attach_fail;
1495744Sgs150176 	}
1496744Sgs150176 	rgep->progress |= PROGRESS_RESCHED;
1497744Sgs150176 	err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &rgep->factotum_id,
1498744Sgs150176 		NULL, NULL, rge_chip_factotum, (caddr_t)rgep);
1499744Sgs150176 	if (err != DDI_SUCCESS) {
1500744Sgs150176 		rge_problem(rgep, "ddi_add_softintr() failed");
1501744Sgs150176 		goto attach_fail;
1502744Sgs150176 	}
1503744Sgs150176 	rgep->progress |= PROGRESS_FACTOTUM;
1504744Sgs150176 
1505744Sgs150176 	/*
1506744Sgs150176 	 * Add the h/w interrupt handler and initialise mutexes
1507744Sgs150176 	 */
1508744Sgs150176 	err = ddi_add_intr(devinfo, 0, &rgep->iblk, NULL,
1509744Sgs150176 		rge_intr, (caddr_t)rgep);
1510744Sgs150176 	if (err != DDI_SUCCESS) {
1511744Sgs150176 		rge_problem(rgep, "ddi_add_intr() failed");
1512744Sgs150176 		goto attach_fail;
1513744Sgs150176 	}
1514744Sgs150176 	mutex_init(rgep->genlock, NULL, MUTEX_DRIVER, rgep->iblk);
1515744Sgs150176 	rw_init(rgep->errlock, NULL, RW_DRIVER, rgep->iblk);
1516744Sgs150176 	mutex_init(rgep->tx_lock, NULL, MUTEX_DRIVER, rgep->iblk);
1517744Sgs150176 	mutex_init(rgep->tc_lock, NULL, MUTEX_DRIVER, rgep->iblk);
1518744Sgs150176 	mutex_init(rgep->rx_lock, NULL, MUTEX_DRIVER, rgep->iblk);
1519744Sgs150176 	mutex_init(rgep->rc_lock, NULL, MUTEX_DRIVER, rgep->iblk);
1520744Sgs150176 	rgep->progress |= PROGRESS_INTR;
1521744Sgs150176 
1522744Sgs150176 	/*
1523744Sgs150176 	 * Initialize rings
1524744Sgs150176 	 */
1525744Sgs150176 	err = rge_init_rings(rgep);
1526744Sgs150176 	if (err != DDI_SUCCESS) {
1527744Sgs150176 		rge_problem(rgep, "rge_init_rings() failed");
1528744Sgs150176 		goto attach_fail;
1529744Sgs150176 	}
1530744Sgs150176 
1531744Sgs150176 	/*
1532744Sgs150176 	 * Initialise link state variables
1533744Sgs150176 	 * Stop, reset & reinitialise the chip.
1534744Sgs150176 	 * Initialise the (internal) PHY.
1535744Sgs150176 	 */
1536744Sgs150176 	rgep->param_link_up = LINK_STATE_UNKNOWN;
1537744Sgs150176 	rgep->link_up_msg = rgep->link_down_msg = " (initialised)";
1538744Sgs150176 
1539744Sgs150176 	/*
1540744Sgs150176 	 * Reset chip & rings to initial state; also reset address
1541744Sgs150176 	 * filtering, promiscuity, loopback mode.
1542744Sgs150176 	 */
1543744Sgs150176 	mutex_enter(rgep->genlock);
1544744Sgs150176 	(void) rge_chip_reset(rgep);
1545744Sgs150176 	rge_chip_sync(rgep, RGE_GET_MAC);
1546744Sgs150176 	bzero(rgep->mcast_hash, sizeof (rgep->mcast_hash));
1547744Sgs150176 	bzero(rgep->mcast_refs, sizeof (rgep->mcast_refs));
1548744Sgs150176 	rgep->promisc = B_FALSE;
1549744Sgs150176 	rgep->param_loop_mode = RGE_LOOP_NONE;
1550744Sgs150176 	mutex_exit(rgep->genlock);
1551744Sgs150176 	rge_phy_init(rgep);
1552744Sgs150176 	rgep->progress |= PROGRESS_PHY;
1553744Sgs150176 
1554744Sgs150176 	/*
1555744Sgs150176 	 * Create & initialise named kstats
1556744Sgs150176 	 */
1557744Sgs150176 	rge_init_kstats(rgep, instance);
1558744Sgs150176 	rgep->progress |= PROGRESS_KSTATS;
1559744Sgs150176 
1560*2311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
1561*2311Sseb 		goto attach_fail;
1562*2311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1563*2311Sseb 	macp->m_driver = rgep;
1564744Sgs150176 	macp->m_dip = devinfo;
1565*2311Sseb 	macp->m_src_addr = rgep->netaddr;
1566*2311Sseb 	macp->m_callbacks = &rge_m_callbacks;
1567*2311Sseb 	macp->m_min_sdu = 0;
1568*2311Sseb 	macp->m_max_sdu = rgep->param_default_mtu;
1569744Sgs150176 
1570744Sgs150176 	/*
1571744Sgs150176 	 * Finally, we're ready to register ourselves with the MAC layer
1572744Sgs150176 	 * interface; if this succeeds, we're all ready to start()
1573744Sgs150176 	 */
1574*2311Sseb 	err = mac_register(macp, &rgep->mh);
1575*2311Sseb 	mac_free(macp);
1576*2311Sseb 	if (err != 0)
1577744Sgs150176 		goto attach_fail;
1578744Sgs150176 
1579744Sgs150176 	cychand.cyh_func = rge_chip_cyclic;
1580744Sgs150176 	cychand.cyh_arg = rgep;
1581744Sgs150176 	cychand.cyh_level = CY_LOCK_LEVEL;
1582744Sgs150176 	cyctime.cyt_when = 0;
1583744Sgs150176 	cyctime.cyt_interval = RGE_CYCLIC_PERIOD;
1584744Sgs150176 	mutex_enter(&cpu_lock);
1585744Sgs150176 	rgep->cyclic_id = cyclic_add(&cychand, &cyctime);
1586744Sgs150176 	mutex_exit(&cpu_lock);
1587744Sgs150176 
1588744Sgs150176 	rgep->progress |= PROGRESS_READY;
1589744Sgs150176 	return (DDI_SUCCESS);
1590744Sgs150176 
1591744Sgs150176 attach_fail:
1592744Sgs150176 	rge_unattach(rgep);
1593744Sgs150176 	return (DDI_FAILURE);
1594744Sgs150176 }
1595744Sgs150176 
1596744Sgs150176 /*
1597744Sgs150176  *	rge_suspend() -- suspend transmit/receive for powerdown
1598744Sgs150176  */
1599744Sgs150176 static int
1600744Sgs150176 rge_suspend(rge_t *rgep)
1601744Sgs150176 {
1602744Sgs150176 	/*
1603744Sgs150176 	 * Stop processing and idle (powerdown) the PHY ...
1604744Sgs150176 	 */
1605744Sgs150176 	mutex_enter(rgep->genlock);
1606744Sgs150176 	rge_stop(rgep);
1607744Sgs150176 	mutex_exit(rgep->genlock);
1608744Sgs150176 
1609744Sgs150176 	return (DDI_SUCCESS);
1610744Sgs150176 }
1611744Sgs150176 
1612744Sgs150176 /*
1613744Sgs150176  * detach(9E) -- Detach a device from the system
1614744Sgs150176  */
1615744Sgs150176 static int
1616744Sgs150176 rge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
1617744Sgs150176 {
1618744Sgs150176 	rge_t *rgep;
1619744Sgs150176 
1620744Sgs150176 	RGE_GTRACE(("rge_detach($%p, %d)", (void *)devinfo, cmd));
1621744Sgs150176 
1622744Sgs150176 	rgep = ddi_get_driver_private(devinfo);
1623744Sgs150176 
1624744Sgs150176 	switch (cmd) {
1625744Sgs150176 	default:
1626744Sgs150176 		return (DDI_FAILURE);
1627744Sgs150176 
1628744Sgs150176 	case DDI_SUSPEND:
1629744Sgs150176 		return (rge_suspend(rgep));
1630744Sgs150176 
1631744Sgs150176 	case DDI_DETACH:
1632744Sgs150176 		break;
1633744Sgs150176 	}
1634744Sgs150176 
1635744Sgs150176 	/*
1636744Sgs150176 	 * If there is any posted buffer, the driver should reject to be
1637744Sgs150176 	 * detached. Need notice upper layer to release them.
1638744Sgs150176 	 */
1639744Sgs150176 	if (rgep->rx_free != RGE_BUF_SLOTS)
1640744Sgs150176 		return (DDI_FAILURE);
1641744Sgs150176 
1642744Sgs150176 	/*
1643744Sgs150176 	 * Unregister from the MAC layer subsystem.  This can fail, in
1644744Sgs150176 	 * particular if there are DLPI style-2 streams still open -
1645744Sgs150176 	 * in which case we just return failure without shutting
1646744Sgs150176 	 * down chip operations.
1647744Sgs150176 	 */
1648*2311Sseb 	if (mac_unregister(rgep->mh) != 0)
1649744Sgs150176 		return (DDI_FAILURE);
1650744Sgs150176 
1651744Sgs150176 	/*
1652744Sgs150176 	 * All activity stopped, so we can clean up & exit
1653744Sgs150176 	 */
1654744Sgs150176 	rge_unattach(rgep);
1655744Sgs150176 	return (DDI_SUCCESS);
1656744Sgs150176 }
1657744Sgs150176 
1658744Sgs150176 
1659744Sgs150176 /*
1660744Sgs150176  * ========== Module Loading Data & Entry Points ==========
1661744Sgs150176  */
1662744Sgs150176 
1663744Sgs150176 #undef	RGE_DBG
1664744Sgs150176 #define	RGE_DBG		RGE_DBG_INIT	/* debug flag for this code	*/
1665744Sgs150176 DDI_DEFINE_STREAM_OPS(rge_dev_ops, nulldev, nulldev, rge_attach, rge_detach,
1666744Sgs150176     nodev, NULL, D_MP, NULL);
1667744Sgs150176 
1668744Sgs150176 static struct modldrv rge_modldrv = {
1669744Sgs150176 	&mod_driverops,		/* Type of module.  This one is a driver */
1670744Sgs150176 	rge_ident,		/* short description */
1671744Sgs150176 	&rge_dev_ops		/* driver specific ops */
1672744Sgs150176 };
1673744Sgs150176 
1674744Sgs150176 static struct modlinkage modlinkage = {
1675744Sgs150176 	MODREV_1, (void *)&rge_modldrv, NULL
1676744Sgs150176 };
1677744Sgs150176 
1678744Sgs150176 
1679744Sgs150176 int
1680744Sgs150176 _info(struct modinfo *modinfop)
1681744Sgs150176 {
1682744Sgs150176 	return (mod_info(&modlinkage, modinfop));
1683744Sgs150176 }
1684744Sgs150176 
1685744Sgs150176 int
1686744Sgs150176 _init(void)
1687744Sgs150176 {
1688744Sgs150176 	int status;
1689744Sgs150176 
1690744Sgs150176 	mac_init_ops(&rge_dev_ops, "rge");
1691744Sgs150176 	status = mod_install(&modlinkage);
1692744Sgs150176 	if (status == DDI_SUCCESS)
1693744Sgs150176 		mutex_init(rge_log_mutex, NULL, MUTEX_DRIVER, NULL);
1694744Sgs150176 	else
1695744Sgs150176 		mac_fini_ops(&rge_dev_ops);
1696744Sgs150176 
1697744Sgs150176 	return (status);
1698744Sgs150176 }
1699744Sgs150176 
1700744Sgs150176 int
1701744Sgs150176 _fini(void)
1702744Sgs150176 {
1703744Sgs150176 	int status;
1704744Sgs150176 
1705744Sgs150176 	status = mod_remove(&modlinkage);
1706744Sgs150176 	if (status == DDI_SUCCESS) {
1707744Sgs150176 		mac_fini_ops(&rge_dev_ops);
1708744Sgs150176 		mutex_destroy(rge_log_mutex);
1709744Sgs150176 	}
1710744Sgs150176 	return (status);
1711744Sgs150176 }
1712