xref: /illumos-gate/usr/src/uts/common/io/atge/atge_l1c.c (revision 5e8715b9)
1*5e8715b9SGary Mills /*
2*5e8715b9SGary Mills  * CDDL HEADER START
3*5e8715b9SGary Mills  *
4*5e8715b9SGary Mills  * The contents of this file are subject to the terms of the
5*5e8715b9SGary Mills  * Common Development and Distribution License (the "License").
6*5e8715b9SGary Mills  * You may not use this file except in compliance with the License.
7*5e8715b9SGary Mills  *
8*5e8715b9SGary Mills  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5e8715b9SGary Mills  * or http://www.opensolaris.org/os/licensing.
10*5e8715b9SGary Mills  * See the License for the specific language governing permissions
11*5e8715b9SGary Mills  * and limitations under the License.
12*5e8715b9SGary Mills  *
13*5e8715b9SGary Mills  * When distributing Covered Code, include this CDDL HEADER in each
14*5e8715b9SGary Mills  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5e8715b9SGary Mills  * If applicable, add the following below this CDDL HEADER, with the
16*5e8715b9SGary Mills  * fields enclosed by brackets "[]" replaced with your own identifying
17*5e8715b9SGary Mills  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5e8715b9SGary Mills  *
19*5e8715b9SGary Mills  * CDDL HEADER END
20*5e8715b9SGary Mills  */
21*5e8715b9SGary Mills 
22*5e8715b9SGary Mills /*
23*5e8715b9SGary Mills  * Copyright (c) 2012 Gary Mills
24*5e8715b9SGary Mills  *
25*5e8715b9SGary Mills  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26*5e8715b9SGary Mills  * Use is subject to license terms.
27*5e8715b9SGary Mills  */
28*5e8715b9SGary Mills /*
29*5e8715b9SGary Mills  * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
30*5e8715b9SGary Mills  * All rights reserved.
31*5e8715b9SGary Mills  *
32*5e8715b9SGary Mills  * Redistribution and use in source and binary forms, with or without
33*5e8715b9SGary Mills  * modification, are permitted provided that the following conditions
34*5e8715b9SGary Mills  * are met:
35*5e8715b9SGary Mills  * 1. Redistributions of source code must retain the above copyright
36*5e8715b9SGary Mills  *    notice unmodified, this list of conditions, and the following
37*5e8715b9SGary Mills  *    disclaimer.
38*5e8715b9SGary Mills  * 2. Redistributions in binary form must reproduce the above copyright
39*5e8715b9SGary Mills  *    notice, this list of conditions and the following disclaimer in the
40*5e8715b9SGary Mills  *    documentation and/or other materials provided with the distribution.
41*5e8715b9SGary Mills  *
42*5e8715b9SGary Mills  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43*5e8715b9SGary Mills  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44*5e8715b9SGary Mills  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45*5e8715b9SGary Mills  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46*5e8715b9SGary Mills  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47*5e8715b9SGary Mills  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48*5e8715b9SGary Mills  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49*5e8715b9SGary Mills  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50*5e8715b9SGary Mills  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51*5e8715b9SGary Mills  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52*5e8715b9SGary Mills  * SUCH DAMAGE.
53*5e8715b9SGary Mills  */
54*5e8715b9SGary Mills 
55*5e8715b9SGary Mills #include <sys/types.h>
56*5e8715b9SGary Mills #include <sys/stream.h>
57*5e8715b9SGary Mills #include <sys/strsun.h>
58*5e8715b9SGary Mills #include <sys/stat.h>
59*5e8715b9SGary Mills #include <sys/modctl.h>
60*5e8715b9SGary Mills #include <sys/ethernet.h>
61*5e8715b9SGary Mills #include <sys/debug.h>
62*5e8715b9SGary Mills #include <sys/conf.h>
63*5e8715b9SGary Mills #include <sys/mii.h>
64*5e8715b9SGary Mills #include <sys/miiregs.h>
65*5e8715b9SGary Mills #include <sys/sysmacros.h>
66*5e8715b9SGary Mills #include <sys/dditypes.h>
67*5e8715b9SGary Mills #include <sys/ddi.h>
68*5e8715b9SGary Mills #include <sys/sunddi.h>
69*5e8715b9SGary Mills #include <sys/byteorder.h>
70*5e8715b9SGary Mills #include <sys/note.h>
71*5e8715b9SGary Mills #include <sys/vlan.h>
72*5e8715b9SGary Mills #include <sys/stream.h>
73*5e8715b9SGary Mills 
74*5e8715b9SGary Mills #include "atge.h"
75*5e8715b9SGary Mills #include "atge_l1c_reg.h"
76*5e8715b9SGary Mills #include "atge_cmn_reg.h"
77*5e8715b9SGary Mills 
78*5e8715b9SGary Mills static ddi_dma_attr_t atge_l1c_dma_attr_tx_desc = {
79*5e8715b9SGary Mills 	DMA_ATTR_V0,		/* dma_attr_version */
80*5e8715b9SGary Mills 	0,			/* dma_attr_addr_lo */
81*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_addr_hi */
82*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_count_max */
83*5e8715b9SGary Mills 	L1C_TX_RING_ALIGN,	/* dma_attr_align */
84*5e8715b9SGary Mills 	0x0000fffc,		/* dma_attr_burstsizes */
85*5e8715b9SGary Mills 	1,			/* dma_attr_minxfer */
86*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_maxxfer */
87*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_seg */
88*5e8715b9SGary Mills 	1,			/* dma_attr_sgllen */
89*5e8715b9SGary Mills 	1,			/* dma_attr_granular */
90*5e8715b9SGary Mills 	0			/* dma_attr_flags */
91*5e8715b9SGary Mills };
92*5e8715b9SGary Mills 
93*5e8715b9SGary Mills static ddi_dma_attr_t atge_l1c_dma_attr_rx_desc = {
94*5e8715b9SGary Mills 	DMA_ATTR_V0,		/* dma_attr_version */
95*5e8715b9SGary Mills 	0,			/* dma_attr_addr_lo */
96*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_addr_hi */
97*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_count_max */
98*5e8715b9SGary Mills 	L1C_RX_RING_ALIGN,	/* dma_attr_align */
99*5e8715b9SGary Mills 	0x0000fffc,		/* dma_attr_burstsizes */
100*5e8715b9SGary Mills 	1,			/* dma_attr_minxfer */
101*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_maxxfer */
102*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_seg */
103*5e8715b9SGary Mills 	1,			/* dma_attr_sgllen */
104*5e8715b9SGary Mills 	1,			/* dma_attr_granular */
105*5e8715b9SGary Mills 	0			/* dma_attr_flags */
106*5e8715b9SGary Mills };
107*5e8715b9SGary Mills 
108*5e8715b9SGary Mills static ddi_dma_attr_t atge_l1c_dma_attr_cmb = {
109*5e8715b9SGary Mills 	DMA_ATTR_V0,		/* dma_attr_version */
110*5e8715b9SGary Mills 	0,			/* dma_attr_addr_lo */
111*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_addr_hi */
112*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_count_max */
113*5e8715b9SGary Mills 	L1C_CMB_ALIGN,		/* dma_attr_align */
114*5e8715b9SGary Mills 	0x0000fffc,		/* dma_attr_burstsizes */
115*5e8715b9SGary Mills 	1,			/* dma_attr_minxfer */
116*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_maxxfer */
117*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_seg */
118*5e8715b9SGary Mills 	1,			/* dma_attr_sgllen */
119*5e8715b9SGary Mills 	1,			/* dma_attr_granular */
120*5e8715b9SGary Mills 	0			/* dma_attr_flags */
121*5e8715b9SGary Mills };
122*5e8715b9SGary Mills 
123*5e8715b9SGary Mills static ddi_dma_attr_t atge_l1c_dma_attr_smb = {
124*5e8715b9SGary Mills 	DMA_ATTR_V0,		/* dma_attr_version */
125*5e8715b9SGary Mills 	0,			/* dma_attr_addr_lo */
126*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_addr_hi */
127*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_count_max */
128*5e8715b9SGary Mills 	L1C_SMB_ALIGN,		/* dma_attr_align */
129*5e8715b9SGary Mills 	0x0000fffc,		/* dma_attr_burstsizes */
130*5e8715b9SGary Mills 	1,			/* dma_attr_minxfer */
131*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_maxxfer */
132*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_seg */
133*5e8715b9SGary Mills 	1,			/* dma_attr_sgllen */
134*5e8715b9SGary Mills 	1,			/* dma_attr_granular */
135*5e8715b9SGary Mills 	0			/* dma_attr_flags */
136*5e8715b9SGary Mills };
137*5e8715b9SGary Mills 
138*5e8715b9SGary Mills static ddi_dma_attr_t atge_l1c_dma_attr_rr = {
139*5e8715b9SGary Mills 	DMA_ATTR_V0,		/* dma_attr_version */
140*5e8715b9SGary Mills 	0,			/* dma_attr_addr_lo */
141*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_addr_hi */
142*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_count_max */
143*5e8715b9SGary Mills 	L1C_RR_RING_ALIGN,	/* dma_attr_align */
144*5e8715b9SGary Mills 	0x0000fffc,		/* dma_attr_burstsizes */
145*5e8715b9SGary Mills 	1,			/* dma_attr_minxfer */
146*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_maxxfer */
147*5e8715b9SGary Mills 	0x0000ffffffffull,	/* dma_attr_seg */
148*5e8715b9SGary Mills 	1,			/* dma_attr_sgllen */
149*5e8715b9SGary Mills 	1,			/* dma_attr_granular */
150*5e8715b9SGary Mills 	0			/* dma_attr_flags */
151*5e8715b9SGary Mills };
152*5e8715b9SGary Mills 
153*5e8715b9SGary Mills int
atge_l1c_alloc_dma(atge_t * atgep)154*5e8715b9SGary Mills atge_l1c_alloc_dma(atge_t *atgep)
155*5e8715b9SGary Mills {
156*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
157*5e8715b9SGary Mills 	atge_dma_t *dma;
158*5e8715b9SGary Mills 	int err;
159*5e8715b9SGary Mills 
160*5e8715b9SGary Mills 	l1c = kmem_zalloc(sizeof (atge_l1c_data_t), KM_SLEEP);
161*5e8715b9SGary Mills 	atgep->atge_private_data = l1c;
162*5e8715b9SGary Mills 
163*5e8715b9SGary Mills 	/*
164*5e8715b9SGary Mills 	 * Allocate TX ring descriptor.
165*5e8715b9SGary Mills 	 */
166*5e8715b9SGary Mills 	atgep->atge_tx_buf_len = atgep->atge_mtu +
167*5e8715b9SGary Mills 	    sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL;
168*5e8715b9SGary Mills 	atgep->atge_tx_ring = kmem_alloc(sizeof (atge_ring_t), KM_SLEEP);
169*5e8715b9SGary Mills 	atgep->atge_tx_ring->r_atge = atgep;
170*5e8715b9SGary Mills 	atgep->atge_tx_ring->r_desc_ring = NULL;
171*5e8715b9SGary Mills 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_tx_desc,
172*5e8715b9SGary Mills 	    ATGE_TX_RING_SZ, DDI_DMA_RDWR);
173*5e8715b9SGary Mills 	if (dma == NULL) {
174*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed for TX"
175*5e8715b9SGary Mills 		    " desc ring");
176*5e8715b9SGary Mills 		return (DDI_FAILURE);
177*5e8715b9SGary Mills 	}
178*5e8715b9SGary Mills 	atgep->atge_tx_ring->r_desc_ring = dma;
179*5e8715b9SGary Mills 
180*5e8715b9SGary Mills 	/*
181*5e8715b9SGary Mills 	 * Allocate DMA buffers for TX ring.
182*5e8715b9SGary Mills 	 */
183*5e8715b9SGary Mills 	err = atge_alloc_buffers(atgep->atge_tx_ring, ATGE_TX_RING_CNT,
184*5e8715b9SGary Mills 	    atgep->atge_tx_buf_len, DDI_DMA_WRITE);
185*5e8715b9SGary Mills 	if (err != DDI_SUCCESS) {
186*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed for"
187*5e8715b9SGary Mills 		    " TX Ring");
188*5e8715b9SGary Mills 		return (err);
189*5e8715b9SGary Mills 	}
190*5e8715b9SGary Mills 
191*5e8715b9SGary Mills 	/*
192*5e8715b9SGary Mills 	 * Allocate RX ring.
193*5e8715b9SGary Mills 	 */
194*5e8715b9SGary Mills 	atgep->atge_rx_buf_len = atgep->atge_mtu +
195*5e8715b9SGary Mills 	    sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL;
196*5e8715b9SGary Mills 	l1c->atge_rx_ring = kmem_alloc(sizeof (atge_ring_t), KM_SLEEP);
197*5e8715b9SGary Mills 	l1c->atge_rx_ring->r_atge = atgep;
198*5e8715b9SGary Mills 	l1c->atge_rx_ring->r_desc_ring = NULL;
199*5e8715b9SGary Mills 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_rx_desc,
200*5e8715b9SGary Mills 	    L1C_RX_RING_SZ, DDI_DMA_RDWR);
201*5e8715b9SGary Mills 	if (dma == NULL) {
202*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed"
203*5e8715b9SGary Mills 		    " for RX Ring");
204*5e8715b9SGary Mills 		return (DDI_FAILURE);
205*5e8715b9SGary Mills 	}
206*5e8715b9SGary Mills 	l1c->atge_rx_ring->r_desc_ring = dma;
207*5e8715b9SGary Mills 
208*5e8715b9SGary Mills 	/*
209*5e8715b9SGary Mills 	 * Allocate DMA buffers for RX ring.
210*5e8715b9SGary Mills 	 */
211*5e8715b9SGary Mills 	err = atge_alloc_buffers(l1c->atge_rx_ring, L1C_RX_RING_CNT,
212*5e8715b9SGary Mills 	    atgep->atge_rx_buf_len, DDI_DMA_READ);
213*5e8715b9SGary Mills 	if (err != DDI_SUCCESS) {
214*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed for"
215*5e8715b9SGary Mills 		    " RX buffers");
216*5e8715b9SGary Mills 		return (err);
217*5e8715b9SGary Mills 	}
218*5e8715b9SGary Mills 
219*5e8715b9SGary Mills 	/*
220*5e8715b9SGary Mills 	 * Allocate CMB used for fetching interrupt status data.
221*5e8715b9SGary Mills 	 */
222*5e8715b9SGary Mills 	ATGE_DB(("%s: %s() L1C_CMB_BLOCK_SZ : 0x%x", atgep->atge_name,
223*5e8715b9SGary Mills 	    __func__, L1C_CMB_BLOCK_SZ));
224*5e8715b9SGary Mills 
225*5e8715b9SGary Mills 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_cmb,
226*5e8715b9SGary Mills 	    L1C_CMB_BLOCK_SZ, DDI_DMA_RDWR);
227*5e8715b9SGary Mills 	l1c->atge_l1c_cmb = dma;
228*5e8715b9SGary Mills 	if (dma == NULL) {
229*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed for CMB");
230*5e8715b9SGary Mills 		return (DDI_FAILURE);
231*5e8715b9SGary Mills 	}
232*5e8715b9SGary Mills 
233*5e8715b9SGary Mills 	/*
234*5e8715b9SGary Mills 	 * RR ring (Return Ring for RX and TX).
235*5e8715b9SGary Mills 	 */
236*5e8715b9SGary Mills 	ATGE_DB(("%s: %s() L1C_RR_RING_SZ : 0x%x", atgep->atge_name,
237*5e8715b9SGary Mills 	    __func__, L1C_RR_RING_SZ));
238*5e8715b9SGary Mills 
239*5e8715b9SGary Mills 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_rr,
240*5e8715b9SGary Mills 	    L1C_RR_RING_SZ, DDI_DMA_RDWR);
241*5e8715b9SGary Mills 	l1c->atge_l1c_rr = dma;
242*5e8715b9SGary Mills 	if (dma == NULL) {
243*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed"
244*5e8715b9SGary Mills 		    " for RX RR ring");
245*5e8715b9SGary Mills 		return (DDI_FAILURE);
246*5e8715b9SGary Mills 	}
247*5e8715b9SGary Mills 
248*5e8715b9SGary Mills 	/*
249*5e8715b9SGary Mills 	 * SMB for statistics.
250*5e8715b9SGary Mills 	 */
251*5e8715b9SGary Mills 	ATGE_DB(("%s: %s() L1C_SMB_BLOCK_SZ : 0x%x", atgep->atge_name,
252*5e8715b9SGary Mills 	    __func__, L1C_SMB_BLOCK_SZ));
253*5e8715b9SGary Mills 
254*5e8715b9SGary Mills 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_smb,
255*5e8715b9SGary Mills 	    L1C_SMB_BLOCK_SZ, DDI_DMA_RDWR);
256*5e8715b9SGary Mills 	l1c->atge_l1c_smb = dma;
257*5e8715b9SGary Mills 	if (dma == NULL) {
258*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "DMA allocation failed for SMB");
259*5e8715b9SGary Mills 		return (DDI_FAILURE);
260*5e8715b9SGary Mills 	}
261*5e8715b9SGary Mills 
262*5e8715b9SGary Mills 	atgep->atge_hw_stats = kmem_zalloc(sizeof (atge_l1c_smb_t), KM_SLEEP);
263*5e8715b9SGary Mills 
264*5e8715b9SGary Mills 	return (DDI_SUCCESS);
265*5e8715b9SGary Mills }
266*5e8715b9SGary Mills 
267*5e8715b9SGary Mills void
atge_l1c_free_dma(atge_t * atgep)268*5e8715b9SGary Mills atge_l1c_free_dma(atge_t *atgep)
269*5e8715b9SGary Mills {
270*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
271*5e8715b9SGary Mills 
272*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
273*5e8715b9SGary Mills 
274*5e8715b9SGary Mills 	/*
275*5e8715b9SGary Mills 	 * Free TX ring.
276*5e8715b9SGary Mills 	 */
277*5e8715b9SGary Mills 	if (atgep->atge_tx_ring != NULL) {
278*5e8715b9SGary Mills 		atge_free_buffers(atgep->atge_tx_ring,  ATGE_TX_RING_CNT);
279*5e8715b9SGary Mills 
280*5e8715b9SGary Mills 		if (atgep->atge_tx_ring->r_desc_ring != NULL) {
281*5e8715b9SGary Mills 			atge_free_a_dma_blk(atgep->atge_tx_ring->r_desc_ring);
282*5e8715b9SGary Mills 		}
283*5e8715b9SGary Mills 
284*5e8715b9SGary Mills 		kmem_free(atgep->atge_tx_ring, sizeof (atge_ring_t));
285*5e8715b9SGary Mills 		atgep->atge_tx_ring = NULL;
286*5e8715b9SGary Mills 	}
287*5e8715b9SGary Mills 
288*5e8715b9SGary Mills 	if (l1c && l1c->atge_l1c_cmb != NULL) {
289*5e8715b9SGary Mills 		atge_free_a_dma_blk(l1c->atge_l1c_cmb);
290*5e8715b9SGary Mills 		l1c->atge_l1c_cmb = NULL;
291*5e8715b9SGary Mills 	}
292*5e8715b9SGary Mills 
293*5e8715b9SGary Mills 	if (l1c && l1c->atge_l1c_rr != NULL) {
294*5e8715b9SGary Mills 		atge_free_a_dma_blk(l1c->atge_l1c_rr);
295*5e8715b9SGary Mills 		l1c->atge_l1c_rr = NULL;
296*5e8715b9SGary Mills 	}
297*5e8715b9SGary Mills 
298*5e8715b9SGary Mills 	if (l1c && l1c->atge_l1c_smb != NULL) {
299*5e8715b9SGary Mills 		atge_free_a_dma_blk(l1c->atge_l1c_smb);
300*5e8715b9SGary Mills 		l1c->atge_l1c_smb = NULL;
301*5e8715b9SGary Mills 	}
302*5e8715b9SGary Mills 
303*5e8715b9SGary Mills 	/*
304*5e8715b9SGary Mills 	 * Free RX ring.
305*5e8715b9SGary Mills 	 */
306*5e8715b9SGary Mills 	if (l1c && l1c->atge_rx_ring != NULL) {
307*5e8715b9SGary Mills 		atge_free_buffers(l1c->atge_rx_ring,  L1C_RX_RING_CNT);
308*5e8715b9SGary Mills 
309*5e8715b9SGary Mills 		if (l1c->atge_rx_ring->r_desc_ring != NULL) {
310*5e8715b9SGary Mills 			atge_free_a_dma_blk(l1c->atge_rx_ring->r_desc_ring);
311*5e8715b9SGary Mills 		}
312*5e8715b9SGary Mills 
313*5e8715b9SGary Mills 		kmem_free(l1c->atge_rx_ring, sizeof (atge_ring_t));
314*5e8715b9SGary Mills 		l1c->atge_rx_ring = NULL;
315*5e8715b9SGary Mills 	}
316*5e8715b9SGary Mills 
317*5e8715b9SGary Mills 	/*
318*5e8715b9SGary Mills 	 * Free the memory allocated for gathering hw stats.
319*5e8715b9SGary Mills 	 */
320*5e8715b9SGary Mills 	if (atgep->atge_hw_stats != NULL) {
321*5e8715b9SGary Mills 		kmem_free(atgep->atge_hw_stats, sizeof (atge_l1c_smb_t));
322*5e8715b9SGary Mills 		atgep->atge_hw_stats = NULL;
323*5e8715b9SGary Mills 	}
324*5e8715b9SGary Mills 
325*5e8715b9SGary Mills 	/*
326*5e8715b9SGary Mills 	 * Free the private area.
327*5e8715b9SGary Mills 	 */
328*5e8715b9SGary Mills 	if (l1c != NULL) {
329*5e8715b9SGary Mills 		kmem_free(l1c, sizeof (atge_l1c_data_t));
330*5e8715b9SGary Mills 		atgep->atge_private_data = NULL;
331*5e8715b9SGary Mills 	}
332*5e8715b9SGary Mills }
333*5e8715b9SGary Mills 
334*5e8715b9SGary Mills void
atge_l1c_init_rx_ring(atge_t * atgep)335*5e8715b9SGary Mills atge_l1c_init_rx_ring(atge_t *atgep)
336*5e8715b9SGary Mills {
337*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
338*5e8715b9SGary Mills 	atge_dma_t *dma;
339*5e8715b9SGary Mills 	l1c_rx_desc_t *rx;
340*5e8715b9SGary Mills 	int i;
341*5e8715b9SGary Mills 
342*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
343*5e8715b9SGary Mills 	l1c->atge_rx_ring->r_consumer = L1C_RX_RING_CNT - 1;
344*5e8715b9SGary Mills 	dma = l1c->atge_rx_ring->r_desc_ring;
345*5e8715b9SGary Mills 	bzero(dma->addr, L1C_RX_RING_SZ);
346*5e8715b9SGary Mills 
347*5e8715b9SGary Mills 	for (i = 0; i < L1C_RX_RING_CNT; i++) {
348*5e8715b9SGary Mills 		rx = (l1c_rx_desc_t *)(dma->addr +
349*5e8715b9SGary Mills 		    (i * sizeof (l1c_rx_desc_t)));
350*5e8715b9SGary Mills 
351*5e8715b9SGary Mills 		ATGE_PUT64(dma, &rx->addr,
352*5e8715b9SGary Mills 		    l1c->atge_rx_ring->r_buf_tbl[i]->cookie.dmac_laddress);
353*5e8715b9SGary Mills 		/* No length field. */
354*5e8715b9SGary Mills 	}
355*5e8715b9SGary Mills 
356*5e8715b9SGary Mills 	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
357*5e8715b9SGary Mills 	/* Let controller know availability of new Rx buffers. */
358*5e8715b9SGary Mills 	OUTL(atgep, ATGE_MBOX_RD0_PROD_IDX, l1c->atge_rx_ring->r_consumer);
359*5e8715b9SGary Mills }
360*5e8715b9SGary Mills 
361*5e8715b9SGary Mills void
atge_l1c_init_tx_ring(atge_t * atgep)362*5e8715b9SGary Mills atge_l1c_init_tx_ring(atge_t *atgep)
363*5e8715b9SGary Mills {
364*5e8715b9SGary Mills 	atgep->atge_tx_ring->r_producer = 0;
365*5e8715b9SGary Mills 	atgep->atge_tx_ring->r_consumer = 0;
366*5e8715b9SGary Mills 	atgep->atge_tx_ring->r_avail_desc = ATGE_TX_RING_CNT;
367*5e8715b9SGary Mills 
368*5e8715b9SGary Mills 	bzero(atgep->atge_tx_ring->r_desc_ring->addr, ATGE_TX_RING_SZ);
369*5e8715b9SGary Mills 	DMA_SYNC(atgep->atge_tx_ring->r_desc_ring, 0, 0, DDI_DMA_SYNC_FORDEV);
370*5e8715b9SGary Mills }
371*5e8715b9SGary Mills 
372*5e8715b9SGary Mills void
atge_l1c_init_rr_ring(atge_t * atgep)373*5e8715b9SGary Mills atge_l1c_init_rr_ring(atge_t *atgep)
374*5e8715b9SGary Mills {
375*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
376*5e8715b9SGary Mills 	atge_dma_t *dma;
377*5e8715b9SGary Mills 
378*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
379*5e8715b9SGary Mills 	l1c->atge_l1c_rr_consumers = 0;
380*5e8715b9SGary Mills 
381*5e8715b9SGary Mills 	dma = l1c->atge_l1c_rr;
382*5e8715b9SGary Mills 	bzero(dma->addr, L1C_RR_RING_SZ);
383*5e8715b9SGary Mills 	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
384*5e8715b9SGary Mills }
385*5e8715b9SGary Mills 
386*5e8715b9SGary Mills void
atge_l1c_init_smb(atge_t * atgep)387*5e8715b9SGary Mills atge_l1c_init_smb(atge_t *atgep)
388*5e8715b9SGary Mills {
389*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
390*5e8715b9SGary Mills 	atge_dma_t *dma;
391*5e8715b9SGary Mills 
392*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
393*5e8715b9SGary Mills 	dma = l1c->atge_l1c_smb;
394*5e8715b9SGary Mills 	bzero(dma->addr, L1C_SMB_BLOCK_SZ);
395*5e8715b9SGary Mills 	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
396*5e8715b9SGary Mills }
397*5e8715b9SGary Mills 
398*5e8715b9SGary Mills void
atge_l1c_init_cmb(atge_t * atgep)399*5e8715b9SGary Mills atge_l1c_init_cmb(atge_t *atgep)
400*5e8715b9SGary Mills {
401*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
402*5e8715b9SGary Mills 	atge_dma_t *dma;
403*5e8715b9SGary Mills 
404*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
405*5e8715b9SGary Mills 	dma = l1c->atge_l1c_cmb;
406*5e8715b9SGary Mills 	bzero(dma->addr, L1C_CMB_BLOCK_SZ);
407*5e8715b9SGary Mills 	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
408*5e8715b9SGary Mills }
409*5e8715b9SGary Mills 
410*5e8715b9SGary Mills void
atge_l1c_program_dma(atge_t * atgep)411*5e8715b9SGary Mills atge_l1c_program_dma(atge_t *atgep)
412*5e8715b9SGary Mills {
413*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
414*5e8715b9SGary Mills 	atge_ring_t *r;
415*5e8715b9SGary Mills 	uint32_t reg;
416*5e8715b9SGary Mills 
417*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
418*5e8715b9SGary Mills 
419*5e8715b9SGary Mills 	/*
420*5e8715b9SGary Mills 	 * Clear WOL status and disable all WOL feature as WOL
421*5e8715b9SGary Mills 	 * would interfere Rx operation under normal environments.
422*5e8715b9SGary Mills 	 */
423*5e8715b9SGary Mills 	(void) INL(atgep, ATGE_WOL_CFG);
424*5e8715b9SGary Mills 	OUTL(atgep, ATGE_WOL_CFG, 0);
425*5e8715b9SGary Mills 
426*5e8715b9SGary Mills 	/* TX */
427*5e8715b9SGary Mills 	r = atgep->atge_tx_ring;
428*5e8715b9SGary Mills 	OUTL(atgep, L1C_TX_BASE_ADDR_HI,
429*5e8715b9SGary Mills 	    ATGE_ADDR_HI(r->r_desc_ring->cookie.dmac_laddress));
430*5e8715b9SGary Mills 	OUTL(atgep, L1C_TDL_HEAD_ADDR_LO,
431*5e8715b9SGary Mills 	    ATGE_ADDR_LO(r->r_desc_ring->cookie.dmac_laddress));
432*5e8715b9SGary Mills 	/* We don't use high priority ring. */
433*5e8715b9SGary Mills 	OUTL(atgep, L1C_TDH_HEAD_ADDR_LO, 0);
434*5e8715b9SGary Mills 
435*5e8715b9SGary Mills 	/* RX */
436*5e8715b9SGary Mills 	r = l1c->atge_rx_ring;
437*5e8715b9SGary Mills 	OUTL(atgep, L1C_RX_BASE_ADDR_HI,
438*5e8715b9SGary Mills 	    ATGE_ADDR_HI(r->r_desc_ring->cookie.dmac_laddress));
439*5e8715b9SGary Mills 	OUTL(atgep, L1C_RD0_HEAD_ADDR_LO,
440*5e8715b9SGary Mills 	    ATGE_ADDR_LO(r->r_desc_ring->cookie.dmac_laddress));
441*5e8715b9SGary Mills 	/* We use one Rx ring. */
442*5e8715b9SGary Mills 	OUTL(atgep, L1C_RD1_HEAD_ADDR_LO, 0);
443*5e8715b9SGary Mills 	OUTL(atgep, L1C_RD2_HEAD_ADDR_LO, 0);
444*5e8715b9SGary Mills 	OUTL(atgep, L1C_RD3_HEAD_ADDR_LO, 0);
445*5e8715b9SGary Mills 
446*5e8715b9SGary Mills 	/* RR Ring */
447*5e8715b9SGary Mills 	/*
448*5e8715b9SGary Mills 	 * Let hardware split jumbo frames into alc_max_buf_sized chunks.
449*5e8715b9SGary Mills 	 * if it do not fit the buffer size. Rx return descriptor holds
450*5e8715b9SGary Mills 	 * a counter that indicates how many fragments were made by the
451*5e8715b9SGary Mills 	 * hardware. The buffer size should be multiple of 8 bytes.
452*5e8715b9SGary Mills 	 * Since hardware has limit on the size of buffer size, always
453*5e8715b9SGary Mills 	 * use the maximum value.
454*5e8715b9SGary Mills 	 * For strict-alignment architectures make sure to reduce buffer
455*5e8715b9SGary Mills 	 * size by 8 bytes to make room for alignment fixup.
456*5e8715b9SGary Mills 	 */
457*5e8715b9SGary Mills 	OUTL(atgep, L1C_RX_BUF_SIZE, RX_BUF_SIZE_MAX); /* XXX */
458*5e8715b9SGary Mills 
459*5e8715b9SGary Mills 	/* Set Rx return descriptor base addresses. */
460*5e8715b9SGary Mills 	OUTL(atgep, L1C_RRD0_HEAD_ADDR_LO,
461*5e8715b9SGary Mills 	    ATGE_ADDR_LO(l1c->atge_l1c_rr->cookie.dmac_laddress));
462*5e8715b9SGary Mills 	/* We use one Rx return ring. */
463*5e8715b9SGary Mills 	OUTL(atgep, L1C_RRD1_HEAD_ADDR_LO, 0);
464*5e8715b9SGary Mills 	OUTL(atgep, L1C_RRD2_HEAD_ADDR_LO, 0);
465*5e8715b9SGary Mills 	OUTL(atgep, L1C_RRD3_HEAD_ADDR_LO, 0);
466*5e8715b9SGary Mills 
467*5e8715b9SGary Mills 	/* CMB */
468*5e8715b9SGary Mills 	OUTL(atgep, L1C_CMB_BASE_ADDR_LO,
469*5e8715b9SGary Mills 	    ATGE_ADDR_LO(l1c->atge_l1c_cmb->cookie.dmac_laddress));
470*5e8715b9SGary Mills 
471*5e8715b9SGary Mills 	/* SMB */
472*5e8715b9SGary Mills 	OUTL(atgep, L1C_SMB_BASE_ADDR_HI,
473*5e8715b9SGary Mills 	    ATGE_ADDR_HI(l1c->atge_l1c_smb->cookie.dmac_laddress));
474*5e8715b9SGary Mills 	OUTL(atgep, L1C_SMB_BASE_ADDR_LO,
475*5e8715b9SGary Mills 	    ATGE_ADDR_LO(l1c->atge_l1c_smb->cookie.dmac_laddress));
476*5e8715b9SGary Mills 
477*5e8715b9SGary Mills 	/*
478*5e8715b9SGary Mills 	 * Set RX return ring (RR) counter.
479*5e8715b9SGary Mills 	 */
480*5e8715b9SGary Mills 	/* Set Rx descriptor counter. */
481*5e8715b9SGary Mills 	OUTL(atgep, L1C_RD_RING_CNT,
482*5e8715b9SGary Mills 	    (L1C_RX_RING_CNT << RD_RING_CNT_SHIFT) & RD_RING_CNT_MASK);
483*5e8715b9SGary Mills 	/* Set Rx return descriptor counter. */
484*5e8715b9SGary Mills 	OUTL(atgep, L1C_RRD_RING_CNT,
485*5e8715b9SGary Mills 	    (L1C_RR_RING_CNT << RRD_RING_CNT_SHIFT) & RRD_RING_CNT_MASK);
486*5e8715b9SGary Mills 
487*5e8715b9SGary Mills 	/*
488*5e8715b9SGary Mills 	 * Set TX descriptor counter.
489*5e8715b9SGary Mills 	 */
490*5e8715b9SGary Mills 	OUTL(atgep, L1C_TD_RING_CNT,
491*5e8715b9SGary Mills 	    (ATGE_TX_RING_CNT << TD_RING_CNT_SHIFT) & TD_RING_CNT_MASK);
492*5e8715b9SGary Mills 
493*5e8715b9SGary Mills 	switch (ATGE_DID(atgep)) {
494*5e8715b9SGary Mills 	case ATGE_CHIP_AR8152V1_DEV_ID:
495*5e8715b9SGary Mills 		/* Reconfigure SRAM - Vendor magic. */
496*5e8715b9SGary Mills 		OUTL(atgep, L1C_SRAM_RX_FIFO_LEN, 0x000002A0);
497*5e8715b9SGary Mills 		OUTL(atgep, L1C_SRAM_TX_FIFO_LEN, 0x00000100);
498*5e8715b9SGary Mills 		OUTL(atgep, L1C_SRAM_RX_FIFO_ADDR, 0x029F0000);
499*5e8715b9SGary Mills 		OUTL(atgep, L1C_SRAM_RD_ADDR, 0x02BF02A0);
500*5e8715b9SGary Mills 		OUTL(atgep, L1C_SRAM_TX_FIFO_ADDR, 0x03BF02C0);
501*5e8715b9SGary Mills 		OUTL(atgep, L1C_SRAM_TRD_ADDR, 0x03DF03C0);
502*5e8715b9SGary Mills 		OUTL(atgep, L1C_TXF_WATER_MARK, 0x00000000);
503*5e8715b9SGary Mills 		OUTL(atgep, L1C_RD_DMA_CFG, 0x00000000);
504*5e8715b9SGary Mills 		break;
505*5e8715b9SGary Mills 	}
506*5e8715b9SGary Mills 
507*5e8715b9SGary Mills 	/*
508*5e8715b9SGary Mills 	 * Inform hardware that we have loaded DMA registers.
509*5e8715b9SGary Mills 	 */
510*5e8715b9SGary Mills 	OUTL(atgep, ATGE_DMA_BLOCK, DMA_BLOCK_LOAD);
511*5e8715b9SGary Mills 
512*5e8715b9SGary Mills 	/* Configure interrupt moderation timer. */
513*5e8715b9SGary Mills 	reg = ATGE_USECS(atgep->atge_int_rx_mod) << IM_TIMER_RX_SHIFT;
514*5e8715b9SGary Mills 	reg |= ATGE_USECS(atgep->atge_int_tx_mod) << IM_TIMER_TX_SHIFT;
515*5e8715b9SGary Mills 	OUTL(atgep, ATGE_IM_TIMER, reg);
516*5e8715b9SGary Mills 	/*
517*5e8715b9SGary Mills 	 * We don't want to automatic interrupt clear as task queue
518*5e8715b9SGary Mills 	 * for the interrupt should know interrupt status.
519*5e8715b9SGary Mills 	 */
520*5e8715b9SGary Mills 	reg = 0;
521*5e8715b9SGary Mills 	if (ATGE_USECS(atgep->atge_int_rx_mod) != 0)
522*5e8715b9SGary Mills 		reg |= MASTER_IM_RX_TIMER_ENB;
523*5e8715b9SGary Mills 	if (ATGE_USECS(atgep->atge_int_tx_mod) != 0)
524*5e8715b9SGary Mills 		reg |= MASTER_IM_TX_TIMER_ENB;
525*5e8715b9SGary Mills 	OUTL(atgep, ATGE_MASTER_CFG, reg);
526*5e8715b9SGary Mills }
527*5e8715b9SGary Mills 
528*5e8715b9SGary Mills void
atge_l1c_clear_stats(atge_t * atgep)529*5e8715b9SGary Mills atge_l1c_clear_stats(atge_t *atgep)
530*5e8715b9SGary Mills {
531*5e8715b9SGary Mills 	atge_l1c_smb_t smb;
532*5e8715b9SGary Mills 	uint32_t *reg;
533*5e8715b9SGary Mills 	int i;
534*5e8715b9SGary Mills 
535*5e8715b9SGary Mills 	/*
536*5e8715b9SGary Mills 	 * Clear RX stats first.
537*5e8715b9SGary Mills 	 */
538*5e8715b9SGary Mills 	i = 0;
539*5e8715b9SGary Mills 	reg = &smb.rx_frames;
540*5e8715b9SGary Mills 	while (reg++ <= &smb.rx_pkts_filtered) {
541*5e8715b9SGary Mills 		(void) INL(atgep, ATGE_RX_MIB_BASE + i);
542*5e8715b9SGary Mills 		i += sizeof (uint32_t);
543*5e8715b9SGary Mills 	}
544*5e8715b9SGary Mills 
545*5e8715b9SGary Mills 	/*
546*5e8715b9SGary Mills 	 * Clear TX stats.
547*5e8715b9SGary Mills 	 */
548*5e8715b9SGary Mills 	i = 0;
549*5e8715b9SGary Mills 	reg = &smb.tx_frames;
550*5e8715b9SGary Mills 	while (reg++ <= &smb.tx_mcast_bytes) {
551*5e8715b9SGary Mills 		(void) INL(atgep, ATGE_TX_MIB_BASE + i);
552*5e8715b9SGary Mills 		i += sizeof (uint32_t);
553*5e8715b9SGary Mills 	}
554*5e8715b9SGary Mills }
555*5e8715b9SGary Mills 
556*5e8715b9SGary Mills void
atge_l1c_gather_stats(atge_t * atgep)557*5e8715b9SGary Mills atge_l1c_gather_stats(atge_t *atgep)
558*5e8715b9SGary Mills {
559*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
560*5e8715b9SGary Mills 	atge_dma_t *dma;
561*5e8715b9SGary Mills 	atge_l1c_smb_t *stat;
562*5e8715b9SGary Mills 	atge_l1c_smb_t *smb;
563*5e8715b9SGary Mills 
564*5e8715b9SGary Mills 	ASSERT(atgep != NULL);
565*5e8715b9SGary Mills 
566*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
567*5e8715b9SGary Mills 	dma = l1c->atge_l1c_smb;
568*5e8715b9SGary Mills 	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORKERNEL);
569*5e8715b9SGary Mills 	stat = (atge_l1c_smb_t *)atgep->atge_hw_stats;
570*5e8715b9SGary Mills 	smb = (atge_l1c_smb_t *)dma->addr;
571*5e8715b9SGary Mills 
572*5e8715b9SGary Mills 	/* Rx stats. */
573*5e8715b9SGary Mills 	stat->rx_frames += smb->rx_frames;
574*5e8715b9SGary Mills 	stat->rx_bcast_frames += smb->rx_bcast_frames;
575*5e8715b9SGary Mills 	stat->rx_mcast_frames += smb->rx_mcast_frames;
576*5e8715b9SGary Mills 	stat->rx_pause_frames += smb->rx_pause_frames;
577*5e8715b9SGary Mills 	stat->rx_control_frames += smb->rx_control_frames;
578*5e8715b9SGary Mills 	stat->rx_crcerrs += smb->rx_crcerrs;
579*5e8715b9SGary Mills 	stat->rx_lenerrs += smb->rx_lenerrs;
580*5e8715b9SGary Mills 	stat->rx_bytes += smb->rx_bytes;
581*5e8715b9SGary Mills 	stat->rx_runts += smb->rx_runts;
582*5e8715b9SGary Mills 	stat->rx_fragments += smb->rx_fragments;
583*5e8715b9SGary Mills 	stat->rx_pkts_64 += smb->rx_pkts_64;
584*5e8715b9SGary Mills 	stat->rx_pkts_65_127 += smb->rx_pkts_65_127;
585*5e8715b9SGary Mills 	stat->rx_pkts_128_255 += smb->rx_pkts_128_255;
586*5e8715b9SGary Mills 	stat->rx_pkts_256_511 += smb->rx_pkts_256_511;
587*5e8715b9SGary Mills 	stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023;
588*5e8715b9SGary Mills 	stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518;
589*5e8715b9SGary Mills 	stat->rx_pkts_1519_max += smb->rx_pkts_1519_max;
590*5e8715b9SGary Mills 	stat->rx_pkts_truncated += smb->rx_pkts_truncated;
591*5e8715b9SGary Mills 	stat->rx_fifo_oflows += smb->rx_fifo_oflows;
592*5e8715b9SGary Mills 	stat->rx_alignerrs += smb->rx_alignerrs;
593*5e8715b9SGary Mills 	stat->rx_bcast_bytes += smb->rx_bcast_bytes;
594*5e8715b9SGary Mills 	stat->rx_mcast_bytes += smb->rx_mcast_bytes;
595*5e8715b9SGary Mills 	stat->rx_pkts_filtered += smb->rx_pkts_filtered;
596*5e8715b9SGary Mills 
597*5e8715b9SGary Mills 	/* Tx stats. */
598*5e8715b9SGary Mills 	stat->tx_frames += smb->tx_frames;
599*5e8715b9SGary Mills 	stat->tx_bcast_frames += smb->tx_bcast_frames;
600*5e8715b9SGary Mills 	stat->tx_mcast_frames += smb->tx_mcast_frames;
601*5e8715b9SGary Mills 	stat->tx_pause_frames += smb->tx_pause_frames;
602*5e8715b9SGary Mills 	stat->tx_excess_defer += smb->tx_excess_defer;
603*5e8715b9SGary Mills 	stat->tx_control_frames += smb->tx_control_frames;
604*5e8715b9SGary Mills 	stat->tx_deferred += smb->tx_deferred;
605*5e8715b9SGary Mills 	stat->tx_bytes += smb->tx_bytes;
606*5e8715b9SGary Mills 	stat->tx_pkts_64 += smb->tx_pkts_64;
607*5e8715b9SGary Mills 	stat->tx_pkts_65_127 += smb->tx_pkts_65_127;
608*5e8715b9SGary Mills 	stat->tx_pkts_128_255 += smb->tx_pkts_128_255;
609*5e8715b9SGary Mills 	stat->tx_pkts_256_511 += smb->tx_pkts_256_511;
610*5e8715b9SGary Mills 	stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023;
611*5e8715b9SGary Mills 	stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518;
612*5e8715b9SGary Mills 	stat->tx_pkts_1519_max += smb->tx_pkts_1519_max;
613*5e8715b9SGary Mills 	stat->tx_single_colls += smb->tx_single_colls;
614*5e8715b9SGary Mills 	stat->tx_multi_colls += smb->tx_multi_colls;
615*5e8715b9SGary Mills 	stat->tx_late_colls += smb->tx_late_colls;
616*5e8715b9SGary Mills 	stat->tx_excess_colls += smb->tx_excess_colls;
617*5e8715b9SGary Mills 	stat->tx_underrun += smb->tx_underrun;
618*5e8715b9SGary Mills 	stat->tx_desc_underrun += smb->tx_desc_underrun;
619*5e8715b9SGary Mills 	stat->tx_lenerrs += smb->tx_lenerrs;
620*5e8715b9SGary Mills 	stat->tx_pkts_truncated += smb->tx_pkts_truncated;
621*5e8715b9SGary Mills 	stat->tx_bcast_bytes += smb->tx_bcast_bytes;
622*5e8715b9SGary Mills 	stat->tx_mcast_bytes += smb->tx_mcast_bytes;
623*5e8715b9SGary Mills 
624*5e8715b9SGary Mills 	/*
625*5e8715b9SGary Mills 	 * Update global counters in atge_t.
626*5e8715b9SGary Mills 	 */
627*5e8715b9SGary Mills 	atgep->atge_brdcstrcv += smb->rx_bcast_frames;
628*5e8715b9SGary Mills 	atgep->atge_multircv += smb->rx_mcast_frames;
629*5e8715b9SGary Mills 	atgep->atge_multixmt += smb->tx_mcast_frames;
630*5e8715b9SGary Mills 	atgep->atge_brdcstxmt += smb->tx_bcast_frames;
631*5e8715b9SGary Mills 
632*5e8715b9SGary Mills 	atgep->atge_align_errors += smb->rx_alignerrs;
633*5e8715b9SGary Mills 	atgep->atge_fcs_errors += smb->rx_crcerrs;
634*5e8715b9SGary Mills 	atgep->atge_defer_xmts += smb->tx_deferred;
635*5e8715b9SGary Mills 	atgep->atge_first_collisions += smb->tx_single_colls;
636*5e8715b9SGary Mills 	atgep->atge_multi_collisions += smb->tx_multi_colls * 2;
637*5e8715b9SGary Mills 	atgep->atge_tx_late_collisions += smb->tx_late_colls;
638*5e8715b9SGary Mills 	atgep->atge_ex_collisions += smb->tx_excess_colls;
639*5e8715b9SGary Mills 	atgep->atge_toolong_errors += smb->rx_lenerrs;
640*5e8715b9SGary Mills 	atgep->atge_overflow += smb->rx_fifo_oflows;
641*5e8715b9SGary Mills 	atgep->atge_underflow += (smb->tx_underrun + smb->tx_desc_underrun);
642*5e8715b9SGary Mills 	atgep->atge_runt += smb->rx_runts;
643*5e8715b9SGary Mills 
644*5e8715b9SGary Mills 
645*5e8715b9SGary Mills 	atgep->atge_collisions += smb->tx_single_colls +
646*5e8715b9SGary Mills 	    smb->tx_multi_colls * 2 + smb->tx_late_colls;
647*5e8715b9SGary Mills 
648*5e8715b9SGary Mills 	/*
649*5e8715b9SGary Mills 	 * tx_pkts_truncated counter looks suspicious. It constantly
650*5e8715b9SGary Mills 	 * increments with no sign of Tx errors. Hence we don't factor it.
651*5e8715b9SGary Mills 	 */
652*5e8715b9SGary Mills 	atgep->atge_macxmt_errors += smb->tx_late_colls + smb->tx_underrun;
653*5e8715b9SGary Mills 
654*5e8715b9SGary Mills 	atgep->atge_macrcv_errors += smb->rx_crcerrs + smb->rx_lenerrs +
655*5e8715b9SGary Mills 	    smb->rx_runts + smb->rx_pkts_truncated +
656*5e8715b9SGary Mills 	    smb->rx_alignerrs;
657*5e8715b9SGary Mills 
658*5e8715b9SGary Mills 	smb->updated = 0;
659*5e8715b9SGary Mills 	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
660*5e8715b9SGary Mills }
661*5e8715b9SGary Mills 
662*5e8715b9SGary Mills void
atge_l1c_stop_tx_mac(atge_t * atgep)663*5e8715b9SGary Mills atge_l1c_stop_tx_mac(atge_t *atgep)
664*5e8715b9SGary Mills {
665*5e8715b9SGary Mills 	uint32_t reg;
666*5e8715b9SGary Mills 	int t;
667*5e8715b9SGary Mills 
668*5e8715b9SGary Mills 	ATGE_DB(("%s: %s() called", atgep->atge_name, __func__));
669*5e8715b9SGary Mills 
670*5e8715b9SGary Mills 	reg = INL(atgep, ATGE_MAC_CFG);
671*5e8715b9SGary Mills 	if ((reg & ATGE_CFG_TX_ENB) != 0) {
672*5e8715b9SGary Mills 		reg &= ~ATGE_CFG_TX_ENB;
673*5e8715b9SGary Mills 		OUTL(atgep, ATGE_MAC_CFG, reg);
674*5e8715b9SGary Mills 	}
675*5e8715b9SGary Mills 
676*5e8715b9SGary Mills 	/* Stop TX DMA engine. */
677*5e8715b9SGary Mills 	reg = INL(atgep, ATGE_DMA_CFG);
678*5e8715b9SGary Mills 	if ((reg & DMA_CFG_RD_ENB) != 0) {
679*5e8715b9SGary Mills 		reg &= ~DMA_CFG_RD_ENB;
680*5e8715b9SGary Mills 		OUTL(atgep, ATGE_DMA_CFG, reg);
681*5e8715b9SGary Mills 	}
682*5e8715b9SGary Mills 
683*5e8715b9SGary Mills 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
684*5e8715b9SGary Mills 		if ((INL(atgep, ATGE_IDLE_STATUS) &
685*5e8715b9SGary Mills 		    (IDLE_STATUS_TXMAC | IDLE_STATUS_DMARD)) == 0)
686*5e8715b9SGary Mills 			break;
687*5e8715b9SGary Mills 
688*5e8715b9SGary Mills 		drv_usecwait(10);
689*5e8715b9SGary Mills 	}
690*5e8715b9SGary Mills 
691*5e8715b9SGary Mills 	if (t == 0) {
692*5e8715b9SGary Mills 		/* This should be an FMA event. */
693*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, "stopping TX DMA Engine timeout");
694*5e8715b9SGary Mills 	}
695*5e8715b9SGary Mills }
696*5e8715b9SGary Mills 
697*5e8715b9SGary Mills void
atge_l1c_stop_rx_mac(atge_t * atgep)698*5e8715b9SGary Mills atge_l1c_stop_rx_mac(atge_t *atgep)
699*5e8715b9SGary Mills {
700*5e8715b9SGary Mills 	uint32_t reg;
701*5e8715b9SGary Mills 	int t;
702*5e8715b9SGary Mills 
703*5e8715b9SGary Mills 	ATGE_DB(("%s: %s() called", atgep->atge_name, __func__));
704*5e8715b9SGary Mills 
705*5e8715b9SGary Mills 	reg = INL(atgep, ATGE_MAC_CFG);
706*5e8715b9SGary Mills 	if ((reg & ATGE_CFG_RX_ENB) != 0) {
707*5e8715b9SGary Mills 		reg &= ~ATGE_CFG_RX_ENB;
708*5e8715b9SGary Mills 		OUTL(atgep, ATGE_MAC_CFG, reg);
709*5e8715b9SGary Mills 	}
710*5e8715b9SGary Mills 
711*5e8715b9SGary Mills 	/* Stop RX DMA engine. */
712*5e8715b9SGary Mills 	reg = INL(atgep, ATGE_DMA_CFG);
713*5e8715b9SGary Mills 	if ((reg & DMA_CFG_WR_ENB) != 0) {
714*5e8715b9SGary Mills 		reg &= ~DMA_CFG_WR_ENB;
715*5e8715b9SGary Mills 		OUTL(atgep, ATGE_DMA_CFG, reg);
716*5e8715b9SGary Mills 	}
717*5e8715b9SGary Mills 
718*5e8715b9SGary Mills 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
719*5e8715b9SGary Mills 		if ((INL(atgep, ATGE_IDLE_STATUS) &
720*5e8715b9SGary Mills 		    (IDLE_STATUS_RXMAC | IDLE_STATUS_DMAWR)) == 0)
721*5e8715b9SGary Mills 			break;
722*5e8715b9SGary Mills 		drv_usecwait(10);
723*5e8715b9SGary Mills 	}
724*5e8715b9SGary Mills 
725*5e8715b9SGary Mills 	if (t == 0) {
726*5e8715b9SGary Mills 		/* This should be an FMA event. */
727*5e8715b9SGary Mills 		atge_error(atgep->atge_dip, " stopping RX DMA Engine timeout");
728*5e8715b9SGary Mills 	}
729*5e8715b9SGary Mills }
730*5e8715b9SGary Mills 
731*5e8715b9SGary Mills /*
732*5e8715b9SGary Mills  * Receives (consumes) packets.
733*5e8715b9SGary Mills  */
734*5e8715b9SGary Mills static mblk_t *
atge_l1c_rx(atge_t * atgep)735*5e8715b9SGary Mills atge_l1c_rx(atge_t *atgep)
736*5e8715b9SGary Mills {
737*5e8715b9SGary Mills 	atge_l1c_data_t *l1c;
738*5e8715b9SGary Mills 	mblk_t *mp = NULL, *rx_head = NULL, *rx_tail = NULL;
739*5e8715b9SGary Mills 	l1c_rx_rdesc_t *rx_rr;
740*5e8715b9SGary Mills 	uint32_t rdinfo, status, totlen, pktlen, slotlen;
741*5e8715b9SGary Mills 	int nsegs, rx_cons = 0, cnt;
742*5e8715b9SGary Mills 	atge_dma_t *buf;
743*5e8715b9SGary Mills 	uchar_t *bufp;
744*5e8715b9SGary Mills 	int sync = 0;
745*5e8715b9SGary Mills 
746*5e8715b9SGary Mills 	l1c = atgep->atge_private_data;
747*5e8715b9SGary Mills 	ASSERT(l1c != NULL);
748*5e8715b9SGary Mills 
749*5e8715b9SGary Mills 	DMA_SYNC(l1c->atge_l1c_rr, 0, 0, DDI_DMA_SYNC_FORKERNEL);
750*5e8715b9SGary Mills 	for (;;) {
751*5e8715b9SGary Mills 		rx_rr = (l1c_rx_rdesc_t *)(l1c->atge_l1c_rr->addr +
752*5e8715b9SGary Mills 		    (l1c->atge_l1c_rr_consumers * sizeof (l1c_rx_rdesc_t)));
753*5e8715b9SGary Mills 
754*5e8715b9SGary Mills 		rdinfo = ATGE_GET32(l1c->atge_l1c_rr, &rx_rr->rdinfo);
755*5e8715b9SGary Mills 		status = ATGE_GET32(l1c->atge_l1c_rr, &rx_rr->status);
756*5e8715b9SGary Mills 
757*5e8715b9SGary Mills 		rx_cons = L1C_RRD_RD_IDX(rdinfo);
758*5e8715b9SGary Mills 		nsegs = L1C_RRD_RD_CNT(rdinfo);
759*5e8715b9SGary Mills 		totlen = L1C_RRD_BYTES(status);
760*5e8715b9SGary Mills 
761*5e8715b9SGary Mills 		ATGE_DB(("%s: %s() PKT -- rdinfo : 0x%x,"
762*5e8715b9SGary Mills 		    "status : 0x%x, totlen : %d,"
763*5e8715b9SGary Mills 		    " rx_cons : %d, nsegs : %d", atgep->atge_name, __func__,
764*5e8715b9SGary Mills 		    rdinfo, status, totlen, rx_cons, nsegs));
765*5e8715b9SGary Mills 
766*5e8715b9SGary Mills 		if ((status & L1C_RRD_VALID) == 0) {
767*5e8715b9SGary Mills 			break;
768*5e8715b9SGary Mills 		}
769*5e8715b9SGary Mills 
770*5e8715b9SGary Mills 		if ((status & (L1C_RRD_ERR_CRC | L1C_RRD_ERR_ALIGN |
771*5e8715b9SGary Mills 		    L1C_RRD_ERR_TRUNC | L1C_RRD_ERR_RUNT |
772*5e8715b9SGary Mills 		    L1C_RRD_ERR_ICMP | L1C_RRD_ERR_LENGTH)) != 0) {
773*5e8715b9SGary Mills 			atge_error(atgep->atge_dip, "errored pkt");
774*5e8715b9SGary Mills 
775*5e8715b9SGary Mills 			l1c->atge_rx_ring->r_consumer += nsegs;
776*5e8715b9SGary Mills 			l1c->atge_rx_ring->r_consumer %= L1C_RX_RING_CNT;
777*5e8715b9SGary Mills 			break;
778*5e8715b9SGary Mills 		}
779*5e8715b9SGary Mills 
780*5e8715b9SGary Mills 		ASSERT(rx_cons >= 0 && rx_cons <= L1C_RX_RING_CNT);
781*5e8715b9SGary Mills 
782*5e8715b9SGary Mills 		mp = allocb(totlen + L1C_HEADROOM, BPRI_MED);
783*5e8715b9SGary Mills 		if (mp != NULL) {
784*5e8715b9SGary Mills 			mp->b_rptr += L1C_HEADROOM;
785*5e8715b9SGary Mills 			bufp = mp->b_rptr;
786*5e8715b9SGary Mills 			mp->b_wptr = bufp + totlen;
787*5e8715b9SGary Mills 			mp->b_next = NULL;
788*5e8715b9SGary Mills 
789*5e8715b9SGary Mills 			atgep->atge_ipackets++;
790*5e8715b9SGary Mills 			atgep->atge_rbytes += totlen;
791*5e8715b9SGary Mills 
792*5e8715b9SGary Mills 			/*
793*5e8715b9SGary Mills 			 * If there are more than one segments, then the first
794*5e8715b9SGary Mills 			 * segment should be of size MTU. We couldn't verify
795*5e8715b9SGary Mills 			 * this as our driver does not support changing MTU
796*5e8715b9SGary Mills 			 * or Jumbo Frames.
797*5e8715b9SGary Mills 			 */
798*5e8715b9SGary Mills 			if (nsegs > 1) {
799*5e8715b9SGary Mills 				slotlen = atgep->atge_mtu;
800*5e8715b9SGary Mills 			} else {
801*5e8715b9SGary Mills 				slotlen = totlen;
802*5e8715b9SGary Mills 			}
803*5e8715b9SGary Mills 		} else {
804*5e8715b9SGary Mills 			ATGE_DB(("%s: %s() PKT mp == NULL totlen : %d",
805*5e8715b9SGary Mills 			    atgep->atge_name, __func__, totlen));
806*5e8715b9SGary Mills 
807*5e8715b9SGary Mills 			if (slotlen > atgep->atge_rx_buf_len) {
808*5e8715b9SGary Mills 				atgep->atge_toolong_errors++;
809*5e8715b9SGary Mills 			} else if (mp == NULL) {
810*5e8715b9SGary Mills 				atgep->atge_norcvbuf++;
811*5e8715b9SGary Mills 			}
812*5e8715b9SGary Mills 
813*5e8715b9SGary Mills 			rx_rr->status = 0;
814*5e8715b9SGary Mills 			break;
815*5e8715b9SGary Mills 		}
816*5e8715b9SGary Mills 
817*5e8715b9SGary Mills 		for (cnt = 0, pktlen = 0; cnt < nsegs; cnt++) {
818*5e8715b9SGary Mills 			buf = l1c->atge_rx_ring->r_buf_tbl[rx_cons];
819*5e8715b9SGary Mills 
820*5e8715b9SGary Mills 			slotlen = min(atgep->atge_max_frame_size, totlen);
821*5e8715b9SGary Mills 
822*5e8715b9SGary Mills 			bcopy(buf->addr, (bufp + pktlen), slotlen);
823*5e8715b9SGary Mills 			pktlen += slotlen;
824*5e8715b9SGary Mills 			totlen -= slotlen;
825*5e8715b9SGary Mills 
826*5e8715b9SGary Mills 			ATGE_DB(("%s: %s() len : %d, rxcons : %d, pktlen : %d",
827*5e8715b9SGary Mills 			    atgep->atge_name, __func__, slotlen, rx_cons,
828*5e8715b9SGary Mills 			    pktlen));
829*5e8715b9SGary Mills 
830*5e8715b9SGary Mills 			ATGE_INC_SLOT(rx_cons, L1C_RX_RING_CNT);
831*5e8715b9SGary Mills 		}
832*5e8715b9SGary Mills 
833*5e8715b9SGary Mills 		if (rx_tail == NULL) {
834*5e8715b9SGary Mills 			rx_head = rx_tail = mp;
835*5e8715b9SGary Mills 		} else {
836*5e8715b9SGary Mills 			rx_tail->b_next = mp;
837*5e8715b9SGary Mills 			rx_tail = mp;
838*5e8715b9SGary Mills 		}
839*5e8715b9SGary Mills 
840*5e8715b9SGary Mills 		if (cnt != nsegs) {
841*5e8715b9SGary Mills 			l1c->atge_rx_ring->r_consumer += nsegs;
842*5e8715b9SGary Mills 			l1c->atge_rx_ring->r_consumer %= L1C_RX_RING_CNT;
843*5e8715b9SGary Mills 		} else {
844*5e8715b9SGary Mills 			l1c->atge_rx_ring->r_consumer = rx_cons;
845*5e8715b9SGary Mills 		}
846*5e8715b9SGary Mills 
847*5e8715b9SGary Mills 		/*
848*5e8715b9SGary Mills 		 * Tell the chip that this RR can be reused.
849*5e8715b9SGary Mills 		 */
850*5e8715b9SGary Mills 		rx_rr->status = 0;
851*5e8715b9SGary Mills 
852*5e8715b9SGary Mills 		ATGE_INC_SLOT(l1c->atge_l1c_rr_consumers, L1C_RR_RING_CNT);
853*5e8715b9SGary Mills 		sync++;
854*5e8715b9SGary Mills 	}
855*5e8715b9SGary Mills 
856*5e8715b9SGary Mills 	if (sync) {
857*5e8715b9SGary Mills 		DMA_SYNC(l1c->atge_rx_ring->r_desc_ring, 0, 0,
858*5e8715b9SGary Mills 		    DDI_DMA_SYNC_FORDEV);
859*5e8715b9SGary Mills 
860*5e8715b9SGary Mills 		DMA_SYNC(l1c->atge_l1c_rr, 0, 0, DDI_DMA_SYNC_FORDEV);
861*5e8715b9SGary Mills 		/*
862*5e8715b9SGary Mills 		 * Let controller know availability of new Rx buffers.
863*5e8715b9SGary Mills 		 */
864*5e8715b9SGary Mills 		OUTL(atgep, ATGE_MBOX_RD0_PROD_IDX,
865*5e8715b9SGary Mills 		    l1c->atge_rx_ring->r_consumer);
866*5e8715b9SGary Mills 
867*5e8715b9SGary Mills 		ATGE_DB(("%s: %s() PKT Recved -> r_consumer : %d, rx_cons : %d"
868*5e8715b9SGary Mills 		    " atge_l1c_rr_consumers : %d",
869*5e8715b9SGary Mills 		    atgep->atge_name, __func__, l1c->atge_rx_ring->r_consumer,
870*5e8715b9SGary Mills 		    rx_cons, l1c->atge_l1c_rr_consumers));
871*5e8715b9SGary Mills 	}
872*5e8715b9SGary Mills 
873*5e8715b9SGary Mills 
874*5e8715b9SGary Mills 	return (rx_head);
875*5e8715b9SGary Mills }
876*5e8715b9SGary Mills 
877*5e8715b9SGary Mills /*
878*5e8715b9SGary Mills  * The interrupt handler for L1C chip.
879*5e8715b9SGary Mills  */
880*5e8715b9SGary Mills /*ARGSUSED*/
881*5e8715b9SGary Mills uint_t
atge_l1c_interrupt(caddr_t arg1,caddr_t arg2)882*5e8715b9SGary Mills atge_l1c_interrupt(caddr_t arg1, caddr_t arg2)
883*5e8715b9SGary Mills {
884*5e8715b9SGary Mills 	atge_t *atgep = (void *)arg1;
885*5e8715b9SGary Mills 	mblk_t *rx_head = NULL;
886*5e8715b9SGary Mills 	uint32_t status;
887*5e8715b9SGary Mills 	int resched = 0;
888*5e8715b9SGary Mills 
889*5e8715b9SGary Mills 	ASSERT(atgep != NULL);
890*5e8715b9SGary Mills 
891*5e8715b9SGary Mills 	mutex_enter(&atgep->atge_intr_lock);
892*5e8715b9SGary Mills 
893*5e8715b9SGary Mills 	if (atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
894*5e8715b9SGary Mills 		mutex_exit(&atgep->atge_intr_lock);
895*5e8715b9SGary Mills 		return (DDI_INTR_UNCLAIMED);
896*5e8715b9SGary Mills 	}
897*5e8715b9SGary Mills 
898*5e8715b9SGary Mills 	status = INL(atgep, ATGE_INTR_STATUS);
899*5e8715b9SGary Mills 	if (status == 0 || (status & atgep->atge_intrs) == 0) {
900*5e8715b9SGary Mills 		mutex_exit(&atgep->atge_intr_lock);
901*5e8715b9SGary Mills 
902*5e8715b9SGary Mills 		if (atgep->atge_flags & ATGE_FIXED_TYPE)
903*5e8715b9SGary Mills 			return (DDI_INTR_UNCLAIMED);
904*5e8715b9SGary Mills 
905*5e8715b9SGary Mills 		return (DDI_INTR_CLAIMED);
906*5e8715b9SGary Mills 	}
907*5e8715b9SGary Mills 
908*5e8715b9SGary Mills 	ATGE_DB(("%s: %s() entry status : %x",
909*5e8715b9SGary Mills 	    atgep->atge_name, __func__, status));
910*5e8715b9SGary Mills 
911*5e8715b9SGary Mills 	/*
912*5e8715b9SGary Mills 	 * Disable interrupts.
913*5e8715b9SGary Mills 	 */
914*5e8715b9SGary Mills 	if (status & L1C_INTR_GPHY) {
915*5e8715b9SGary Mills 		/* clear PHY interrupt source before we ack interrupts */
916*5e8715b9SGary Mills 		(void) atge_mii_read(atgep,
917*5e8715b9SGary Mills 		    atgep->atge_phyaddr, ATGE_ISR_ACK_GPHY);
918*5e8715b9SGary Mills 	}
919*5e8715b9SGary Mills 
920*5e8715b9SGary Mills 	OUTL(atgep, ATGE_INTR_STATUS, status | L1C_INTR_DIS_INT);
921*5e8715b9SGary Mills 	FLUSH(atgep, ATGE_INTR_STATUS);
922*5e8715b9SGary Mills 
923*5e8715b9SGary Mills 	/*
924*5e8715b9SGary Mills 	 * Check if chip is running, only then do the work.
925*5e8715b9SGary Mills 	 */
926*5e8715b9SGary Mills 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
927*5e8715b9SGary Mills 		atge_l1c_data_t *l1c;
928*5e8715b9SGary Mills 
929*5e8715b9SGary Mills 		l1c = atgep->atge_private_data;
930*5e8715b9SGary Mills 
931*5e8715b9SGary Mills 		ATGE_DB(("%s: %s() atge_l1c_intr_status : %x, "
932*5e8715b9SGary Mills 		    "atge_l1c_rx_prod_cons : %d, atge_l1c_tx_prod_cons : %d"
933*5e8715b9SGary Mills 		    " atge_l1c_rr_consumers : %d",
934*5e8715b9SGary Mills 		    atgep->atge_name, __func__, l1c->atge_l1c_intr_status,
935*5e8715b9SGary Mills 		    l1c->atge_l1c_rx_prod_cons, l1c->atge_l1c_tx_prod_cons,
936*5e8715b9SGary Mills 		    l1c->atge_l1c_rr_consumers));
937*5e8715b9SGary Mills 
938*5e8715b9SGary Mills 		if (status & L1C_INTR_SMB)
939*5e8715b9SGary Mills 			atge_l1c_gather_stats(atgep);
940*5e8715b9SGary Mills 
941*5e8715b9SGary Mills 		/*
942*5e8715b9SGary Mills 		 * Check for errors.
943*5e8715b9SGary Mills 		 */
944*5e8715b9SGary Mills 		if (status & (L1C_INTR_DMA_RD_TO_RST |
945*5e8715b9SGary Mills 		    L1C_INTR_DMA_WR_TO_RST | L1C_INTR_TXQ_TO_RST)) {
946*5e8715b9SGary Mills 			/* This should be an FMA event. */
947*5e8715b9SGary Mills 			atge_error(atgep->atge_dip,
948*5e8715b9SGary Mills 			    "L1C chip detected a fatal error, "
949*5e8715b9SGary Mills 			    "interrupt status: %x", status);
950*5e8715b9SGary Mills 
951*5e8715b9SGary Mills 			if (status & L1C_INTR_DMA_RD_TO_RST) {
952*5e8715b9SGary Mills 				atge_error(atgep->atge_dip,
953*5e8715b9SGary Mills 				    "DMA read error");
954*5e8715b9SGary Mills 			}
955*5e8715b9SGary Mills 			if (status & L1C_INTR_DMA_WR_TO_RST) {
956*5e8715b9SGary Mills 				atge_error(atgep->atge_dip,
957*5e8715b9SGary Mills 				    "DMA write error");
958*5e8715b9SGary Mills 			}
959*5e8715b9SGary Mills 			if (status & L1C_INTR_TXQ_TO_RST) {
960*5e8715b9SGary Mills 				atge_error(atgep->atge_dip,
961*5e8715b9SGary Mills 				    "Transmit queue error");
962*5e8715b9SGary Mills 			}
963*5e8715b9SGary Mills 
964*5e8715b9SGary Mills 			/* This should be an FMA event. */
965*5e8715b9SGary Mills 			atge_device_stop(atgep);
966*5e8715b9SGary Mills 			/*
967*5e8715b9SGary Mills 			 * Device has failed fatally.
968*5e8715b9SGary Mills 			 * It will not be restarted by the driver.
969*5e8715b9SGary Mills 			 */
970*5e8715b9SGary Mills 			goto done;
971*5e8715b9SGary Mills 
972*5e8715b9SGary Mills 		}
973*5e8715b9SGary Mills 
974*5e8715b9SGary Mills 		rx_head = atge_l1c_rx(atgep);
975*5e8715b9SGary Mills 		if (status & L1C_INTR_TX_PKT) {
976*5e8715b9SGary Mills 			int cons;
977*5e8715b9SGary Mills 
978*5e8715b9SGary Mills 			mutex_enter(&atgep->atge_tx_lock);
979*5e8715b9SGary Mills 			cons = INL(atgep, ATGE_MBOX_TD_CONS_IDX) >> 16;
980*5e8715b9SGary Mills 			atge_tx_reclaim(atgep, cons);
981*5e8715b9SGary Mills 			if (atgep->atge_tx_resched) {
982*5e8715b9SGary Mills 				atgep->atge_tx_resched = 0;
983*5e8715b9SGary Mills 				resched = 1;
984*5e8715b9SGary Mills 			}
985*5e8715b9SGary Mills 
986*5e8715b9SGary Mills 			mutex_exit(&atgep->atge_tx_lock);
987*5e8715b9SGary Mills 		}
988*5e8715b9SGary Mills 	}
989*5e8715b9SGary Mills 
990*5e8715b9SGary Mills 	/* Re-enable interrupts. */
991*5e8715b9SGary Mills 	OUTL(atgep, ATGE_INTR_STATUS, 0);
992*5e8715b9SGary Mills 
993*5e8715b9SGary Mills done:
994*5e8715b9SGary Mills 	mutex_exit(&atgep->atge_intr_lock);
995*5e8715b9SGary Mills 
996*5e8715b9SGary Mills 	if (status & L1C_INTR_GPHY) {
997*5e8715b9SGary Mills 		/* link down */
998*5e8715b9SGary Mills 		ATGE_DB(("%s: %s() MII_CHECK Performed",
999*5e8715b9SGary Mills 		    atgep->atge_name, __func__));
1000*5e8715b9SGary Mills 		mii_check(atgep->atge_mii);
1001*5e8715b9SGary Mills 	}
1002*5e8715b9SGary Mills 
1003*5e8715b9SGary Mills 	/*
1004*5e8715b9SGary Mills 	 * Pass the list of packets received from chip to MAC layer.
1005*5e8715b9SGary Mills 	 */
1006*5e8715b9SGary Mills 	if (rx_head) {
1007*5e8715b9SGary Mills 		mac_rx(atgep->atge_mh, 0, rx_head);
1008*5e8715b9SGary Mills 	}
1009*5e8715b9SGary Mills 
1010*5e8715b9SGary Mills 	/*
1011*5e8715b9SGary Mills 	 * Let MAC start sending pkts if the downstream was asked to pause.
1012*5e8715b9SGary Mills 	 */
1013*5e8715b9SGary Mills 	if (resched)
1014*5e8715b9SGary Mills 		mac_tx_update(atgep->atge_mh);
1015*5e8715b9SGary Mills 
1016*5e8715b9SGary Mills 	return (DDI_INTR_CLAIMED);
1017*5e8715b9SGary Mills }
1018*5e8715b9SGary Mills 
1019*5e8715b9SGary Mills void
atge_l1c_send_packet(atge_ring_t * r)1020*5e8715b9SGary Mills atge_l1c_send_packet(atge_ring_t *r)
1021*5e8715b9SGary Mills {
1022*5e8715b9SGary Mills 	atge_t *atgep;
1023*5e8715b9SGary Mills 
1024*5e8715b9SGary Mills 	atgep = r->r_atge;
1025*5e8715b9SGary Mills 
1026*5e8715b9SGary Mills 	mutex_enter(&atgep->atge_mbox_lock);
1027*5e8715b9SGary Mills 	/* Sync descriptors. */
1028*5e8715b9SGary Mills 	DMA_SYNC(atgep->atge_tx_ring->r_desc_ring, 0, 0, DDI_DMA_SYNC_FORDEV);
1029*5e8715b9SGary Mills 	/* Kick. Assume we're using normal Tx priority queue. */
1030*5e8715b9SGary Mills 	OUTL(atgep, ATGE_MBOX_TD_PROD_IDX,
1031*5e8715b9SGary Mills 	    (atgep->atge_tx_ring->r_producer << MBOX_TD_PROD_LO_IDX_SHIFT) &
1032*5e8715b9SGary Mills 	    MBOX_TD_PROD_LO_IDX_MASK);
1033*5e8715b9SGary Mills 	mutex_exit(&atgep->atge_mbox_lock);
1034*5e8715b9SGary Mills }
1035