xref: /illumos-gate/usr/src/uts/common/io/atge/atge_l1e.c (revision 5e8715b9)
1015a6ef6SSaurabh Misra /*
2015a6ef6SSaurabh Misra  * CDDL HEADER START
3015a6ef6SSaurabh Misra  *
4015a6ef6SSaurabh Misra  * The contents of this file are subject to the terms of the
5015a6ef6SSaurabh Misra  * Common Development and Distribution License (the "License").
6015a6ef6SSaurabh Misra  * You may not use this file except in compliance with the License.
7015a6ef6SSaurabh Misra  *
8015a6ef6SSaurabh Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9015a6ef6SSaurabh Misra  * or http://www.opensolaris.org/os/licensing.
10015a6ef6SSaurabh Misra  * See the License for the specific language governing permissions
11015a6ef6SSaurabh Misra  * and limitations under the License.
12015a6ef6SSaurabh Misra  *
13015a6ef6SSaurabh Misra  * When distributing Covered Code, include this CDDL HEADER in each
14015a6ef6SSaurabh Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15015a6ef6SSaurabh Misra  * If applicable, add the following below this CDDL HEADER, with the
16015a6ef6SSaurabh Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17015a6ef6SSaurabh Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18015a6ef6SSaurabh Misra  *
19015a6ef6SSaurabh Misra  * CDDL HEADER END
20015a6ef6SSaurabh Misra  */
21015a6ef6SSaurabh Misra 
22015a6ef6SSaurabh Misra /*
23*5e8715b9SGary Mills  * Copyright (c) 2012 Gary Mills
24*5e8715b9SGary Mills  *
25015a6ef6SSaurabh Misra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26015a6ef6SSaurabh Misra  * Use is subject to license terms.
27015a6ef6SSaurabh Misra  */
28015a6ef6SSaurabh Misra 
29015a6ef6SSaurabh Misra #include <sys/types.h>
30015a6ef6SSaurabh Misra #include <sys/stream.h>
31015a6ef6SSaurabh Misra #include <sys/strsun.h>
32015a6ef6SSaurabh Misra #include <sys/stat.h>
33015a6ef6SSaurabh Misra #include <sys/modctl.h>
34015a6ef6SSaurabh Misra #include <sys/ethernet.h>
35015a6ef6SSaurabh Misra #include <sys/debug.h>
36015a6ef6SSaurabh Misra #include <sys/conf.h>
37015a6ef6SSaurabh Misra #include <sys/mii.h>
38015a6ef6SSaurabh Misra #include <sys/miiregs.h>
39015a6ef6SSaurabh Misra #include <sys/sysmacros.h>
40015a6ef6SSaurabh Misra #include <sys/dditypes.h>
41015a6ef6SSaurabh Misra #include <sys/ddi.h>
42015a6ef6SSaurabh Misra #include <sys/sunddi.h>
43015a6ef6SSaurabh Misra #include <sys/byteorder.h>
44015a6ef6SSaurabh Misra #include <sys/note.h>
45015a6ef6SSaurabh Misra #include <sys/vlan.h>
46015a6ef6SSaurabh Misra #include <sys/stream.h>
47015a6ef6SSaurabh Misra 
48015a6ef6SSaurabh Misra #include "atge.h"
49015a6ef6SSaurabh Misra #include "atge_l1e_reg.h"
50015a6ef6SSaurabh Misra #include "atge_cmn_reg.h"
51015a6ef6SSaurabh Misra 
52015a6ef6SSaurabh Misra /*
53015a6ef6SSaurabh Misra  * L1E specfic functions.
54015a6ef6SSaurabh Misra  */
55015a6ef6SSaurabh Misra void	atge_l1e_device_reset(atge_t *);
56015a6ef6SSaurabh Misra void	atge_l1e_stop_rx_mac(atge_t *);
57015a6ef6SSaurabh Misra void	atge_l1e_stop_tx_mac(atge_t *);
58015a6ef6SSaurabh Misra 
59015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_l1e_dma_attr_tx_desc = {
60015a6ef6SSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
61015a6ef6SSaurabh Misra 	0,			/* dma_attr_addr_lo */
62015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_addr_hi */
63015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_count_max */
64015a6ef6SSaurabh Misra 	L1E_TX_RING_ALIGN,	/* dma_attr_align */
65015a6ef6SSaurabh Misra 	0x0000fffc,		/* dma_attr_burstsizes */
66015a6ef6SSaurabh Misra 	1,			/* dma_attr_minxfer */
67015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_maxxfer */
68015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_seg */
69015a6ef6SSaurabh Misra 	1,			/* dma_attr_sgllen */
70015a6ef6SSaurabh Misra 	1,			/* dma_attr_granular */
71015a6ef6SSaurabh Misra 	0			/* dma_attr_flags */
72015a6ef6SSaurabh Misra };
73015a6ef6SSaurabh Misra 
74015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_l1e_dma_attr_rx_desc = {
75015a6ef6SSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
76015a6ef6SSaurabh Misra 	0,			/* dma_attr_addr_lo */
77015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_addr_hi */
78015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_count_max */
79015a6ef6SSaurabh Misra 	L1E_RX_PAGE_ALIGN,	/* dma_attr_align */
80015a6ef6SSaurabh Misra 	0x0000fffc,		/* dma_attr_burstsizes */
81015a6ef6SSaurabh Misra 	1,			/* dma_attr_minxfer */
82015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_maxxfer */
83015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_seg */
84015a6ef6SSaurabh Misra 	1,			/* dma_attr_sgllen */
85015a6ef6SSaurabh Misra 	1,			/* dma_attr_granular */
86015a6ef6SSaurabh Misra 	0			/* dma_attr_flags */
87015a6ef6SSaurabh Misra };
88015a6ef6SSaurabh Misra 
89015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_l1e_dma_attr_cmb = {
90015a6ef6SSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
91015a6ef6SSaurabh Misra 	0,			/* dma_attr_addr_lo */
92015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_addr_hi */
93015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_count_max */
94015a6ef6SSaurabh Misra 	L1E_CMB_ALIGN,		/* dma_attr_align */
95015a6ef6SSaurabh Misra 	0x0000fffc,		/* dma_attr_burstsizes */
96015a6ef6SSaurabh Misra 	1,			/* dma_attr_minxfer */
97015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_maxxfer */
98015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_seg */
99015a6ef6SSaurabh Misra 	1,			/* dma_attr_sgllen */
100015a6ef6SSaurabh Misra 	1,			/* dma_attr_granular */
101015a6ef6SSaurabh Misra 	0			/* dma_attr_flags */
102015a6ef6SSaurabh Misra };
103015a6ef6SSaurabh Misra 
104015a6ef6SSaurabh Misra void	atge_l1e_rx_next_pkt(atge_t *, uint32_t);
105015a6ef6SSaurabh Misra 
106015a6ef6SSaurabh Misra void
atge_rx_desc_free(atge_t * atgep)107015a6ef6SSaurabh Misra atge_rx_desc_free(atge_t *atgep)
108015a6ef6SSaurabh Misra {
109015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e;
110015a6ef6SSaurabh Misra 	atge_dma_t *dma;
111015a6ef6SSaurabh Misra 	int pages;
112015a6ef6SSaurabh Misra 
113015a6ef6SSaurabh Misra 	l1e = (atge_l1e_data_t *)atgep->atge_private_data;
114015a6ef6SSaurabh Misra 	if (l1e == NULL)
115015a6ef6SSaurabh Misra 		return;
116015a6ef6SSaurabh Misra 
117015a6ef6SSaurabh Misra 	if (l1e->atge_l1e_rx_page == NULL)
118015a6ef6SSaurabh Misra 		return;
119015a6ef6SSaurabh Misra 
120015a6ef6SSaurabh Misra 	for (pages = 0; pages < L1E_RX_PAGES; pages++) {
121015a6ef6SSaurabh Misra 		dma = l1e->atge_l1e_rx_page[pages];
122015a6ef6SSaurabh Misra 		if (dma != NULL) {
123015a6ef6SSaurabh Misra 			(void) ddi_dma_unbind_handle(dma->hdl);
124015a6ef6SSaurabh Misra 			ddi_dma_mem_free(&dma->acchdl);
125015a6ef6SSaurabh Misra 			ddi_dma_free_handle(&dma->hdl);
126015a6ef6SSaurabh Misra 			kmem_free(dma, sizeof (atge_dma_t));
127015a6ef6SSaurabh Misra 		}
128015a6ef6SSaurabh Misra 	}
129015a6ef6SSaurabh Misra 
130015a6ef6SSaurabh Misra 	kmem_free(l1e->atge_l1e_rx_page, L1E_RX_PAGES * sizeof (atge_dma_t *));
131015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_page = NULL;
132015a6ef6SSaurabh Misra }
133015a6ef6SSaurabh Misra 
134015a6ef6SSaurabh Misra int
atge_l1e_alloc_dma(atge_t * atgep)135015a6ef6SSaurabh Misra atge_l1e_alloc_dma(atge_t *atgep)
136015a6ef6SSaurabh Misra {
137015a6ef6SSaurabh Misra 	atge_dma_t *dma;
138015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e;
139015a6ef6SSaurabh Misra 	int err;
140015a6ef6SSaurabh Misra 	int pages;
141015a6ef6SSaurabh Misra 	int guard_size;
142015a6ef6SSaurabh Misra 
143015a6ef6SSaurabh Misra 	l1e = kmem_zalloc(sizeof (atge_l1e_data_t), KM_SLEEP);
144015a6ef6SSaurabh Misra 	atgep->atge_private_data = l1e;
145015a6ef6SSaurabh Misra 
146015a6ef6SSaurabh Misra 	/*
147015a6ef6SSaurabh Misra 	 * Allocate TX ring descriptor.
148015a6ef6SSaurabh Misra 	 */
149015a6ef6SSaurabh Misra 	atgep->atge_tx_buf_len = atgep->atge_mtu +
150015a6ef6SSaurabh Misra 	    sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL;
151015a6ef6SSaurabh Misra 	atgep->atge_tx_ring = kmem_alloc(sizeof (atge_ring_t), KM_SLEEP);
152015a6ef6SSaurabh Misra 	atgep->atge_tx_ring->r_atge = atgep;
153015a6ef6SSaurabh Misra 	atgep->atge_tx_ring->r_desc_ring = NULL;
154015a6ef6SSaurabh Misra 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1e_dma_attr_tx_desc,
1550eb090a7SSaurabh Misra 	    ATGE_TX_RING_SZ, DDI_DMA_RDWR);
156015a6ef6SSaurabh Misra 	if (dma == NULL) {
157015a6ef6SSaurabh Misra 		ATGE_DB(("%s :%s failed",
158015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
1590eb090a7SSaurabh Misra 		return (DDI_FAILURE);
160015a6ef6SSaurabh Misra 	}
161015a6ef6SSaurabh Misra 	atgep->atge_tx_ring->r_desc_ring = dma;
162015a6ef6SSaurabh Misra 
163015a6ef6SSaurabh Misra 	/*
164015a6ef6SSaurabh Misra 	 * Allocate DMA buffers for TX ring.
165015a6ef6SSaurabh Misra 	 */
1660eb090a7SSaurabh Misra 	err = atge_alloc_buffers(atgep->atge_tx_ring, ATGE_TX_RING_CNT,
167015a6ef6SSaurabh Misra 	    atgep->atge_tx_buf_len, DDI_DMA_WRITE);
1680eb090a7SSaurabh Misra 	if (err != DDI_SUCCESS) {
169015a6ef6SSaurabh Misra 		ATGE_DB(("%s :%s() TX buffers failed",
170015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
171015a6ef6SSaurabh Misra 		return (err);
172015a6ef6SSaurabh Misra 	}
173015a6ef6SSaurabh Misra 
174015a6ef6SSaurabh Misra 	/*
175015a6ef6SSaurabh Misra 	 * Allocate RX pages.
176015a6ef6SSaurabh Misra 	 */
177015a6ef6SSaurabh Misra 	atgep->atge_rx_buf_len = atgep->atge_mtu +
178015a6ef6SSaurabh Misra 	    sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL;
179015a6ef6SSaurabh Misra 
180015a6ef6SSaurabh Misra 	if (atgep->atge_flags & ATGE_FLAG_JUMBO)
181015a6ef6SSaurabh Misra 		guard_size = L1E_JUMBO_FRAMELEN;
182015a6ef6SSaurabh Misra 	else
183015a6ef6SSaurabh Misra 		guard_size = L1E_MAX_FRAMELEN;
184015a6ef6SSaurabh Misra 
185015a6ef6SSaurabh Misra 	l1e->atge_l1e_pagesize = ROUNDUP(guard_size + L1E_RX_PAGE_SZ,
186015a6ef6SSaurabh Misra 	    L1E_RX_PAGE_ALIGN);
187015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_page =
188015a6ef6SSaurabh Misra 	    kmem_zalloc(L1E_RX_PAGES * sizeof (atge_dma_t *), KM_SLEEP);
189015a6ef6SSaurabh Misra 
190015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() atge_l1e_pagesize : %d, L1E_RX_PAGE_SZ : %d",
191015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, l1e->atge_l1e_pagesize,
192015a6ef6SSaurabh Misra 	    L1E_RX_PAGE_SZ));
193015a6ef6SSaurabh Misra 
1940eb090a7SSaurabh Misra 	err = DDI_SUCCESS;
195015a6ef6SSaurabh Misra 	for (pages = 0; pages < L1E_RX_PAGES; pages++) {
196015a6ef6SSaurabh Misra 		dma = atge_alloc_a_dma_blk(atgep, &atge_l1e_dma_attr_rx_desc,
197015a6ef6SSaurabh Misra 		    l1e->atge_l1e_pagesize, DDI_DMA_READ);
198015a6ef6SSaurabh Misra 
199015a6ef6SSaurabh Misra 		if (dma == NULL) {
2000eb090a7SSaurabh Misra 			err = DDI_FAILURE;
201015a6ef6SSaurabh Misra 			break;
202015a6ef6SSaurabh Misra 		}
203015a6ef6SSaurabh Misra 
204015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_page[pages] = dma;
205015a6ef6SSaurabh Misra 	}
206015a6ef6SSaurabh Misra 
2070eb090a7SSaurabh Misra 	if (err == DDI_FAILURE) {
208015a6ef6SSaurabh Misra 		ATGE_DB(("%s :%s RX pages failed",
209015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
2100eb090a7SSaurabh Misra 		return (DDI_FAILURE);
211015a6ef6SSaurabh Misra 	}
212015a6ef6SSaurabh Misra 
213015a6ef6SSaurabh Misra 	/*
214015a6ef6SSaurabh Misra 	 * Allocate CMB used for fetching interrupt status data.
215015a6ef6SSaurabh Misra 	 */
216015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() L1E_RX_CMB_SZ : %x", atgep->atge_name,
217015a6ef6SSaurabh Misra 	    __func__, L1E_RX_CMB_SZ));
218015a6ef6SSaurabh Misra 
2190eb090a7SSaurabh Misra 	err = DDI_SUCCESS;
220015a6ef6SSaurabh Misra 	dma = atge_alloc_a_dma_blk(atgep, &atge_l1e_dma_attr_cmb,
221015a6ef6SSaurabh Misra 	    L1E_RX_CMB_SZ * L1E_RX_PAGES, DDI_DMA_RDWR);
222015a6ef6SSaurabh Misra 	if (dma == NULL) {
223015a6ef6SSaurabh Misra 		ATGE_DB(("%s :%s() RX CMB failed",
224015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
2250eb090a7SSaurabh Misra 		return (DDI_FAILURE);
226015a6ef6SSaurabh Misra 	}
227015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_cmb = dma;
228015a6ef6SSaurabh Misra 
2290eb090a7SSaurabh Misra 	if (err == DDI_FAILURE) {
230015a6ef6SSaurabh Misra 		ATGE_DB(("%s :%s() RX CMB failed",
231015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
2320eb090a7SSaurabh Misra 		return (DDI_FAILURE);
233015a6ef6SSaurabh Misra 	}
234015a6ef6SSaurabh Misra 
235015a6ef6SSaurabh Misra 	atgep->atge_hw_stats = kmem_zalloc(sizeof (atge_l1e_smb_t), KM_SLEEP);
236015a6ef6SSaurabh Misra 
2370eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
238015a6ef6SSaurabh Misra }
239015a6ef6SSaurabh Misra 
240015a6ef6SSaurabh Misra void
atge_l1e_free_dma(atge_t * atgep)241015a6ef6SSaurabh Misra atge_l1e_free_dma(atge_t *atgep)
242015a6ef6SSaurabh Misra {
243015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e;
244015a6ef6SSaurabh Misra 
245015a6ef6SSaurabh Misra 	/*
246015a6ef6SSaurabh Misra 	 * Free TX ring.
247015a6ef6SSaurabh Misra 	 */
248015a6ef6SSaurabh Misra 	if (atgep->atge_tx_ring != NULL) {
2490eb090a7SSaurabh Misra 		atge_free_buffers(atgep->atge_tx_ring,  ATGE_TX_RING_CNT);
250015a6ef6SSaurabh Misra 
251015a6ef6SSaurabh Misra 		if (atgep->atge_tx_ring->r_desc_ring != NULL) {
252015a6ef6SSaurabh Misra 			atge_free_a_dma_blk(atgep->atge_tx_ring->r_desc_ring);
253015a6ef6SSaurabh Misra 		}
254015a6ef6SSaurabh Misra 
255015a6ef6SSaurabh Misra 		kmem_free(atgep->atge_tx_ring, sizeof (atge_ring_t));
256015a6ef6SSaurabh Misra 		atgep->atge_tx_ring = NULL;
257015a6ef6SSaurabh Misra 	}
258015a6ef6SSaurabh Misra 
259015a6ef6SSaurabh Misra 	l1e = atgep->atge_private_data;
260015a6ef6SSaurabh Misra 	if (l1e == NULL)
261015a6ef6SSaurabh Misra 		return;
262015a6ef6SSaurabh Misra 
263015a6ef6SSaurabh Misra 	/*
264015a6ef6SSaurabh Misra 	 * Free RX CMB.
265015a6ef6SSaurabh Misra 	 */
266015a6ef6SSaurabh Misra 	if (l1e->atge_l1e_rx_cmb != NULL) {
267015a6ef6SSaurabh Misra 		atge_free_a_dma_blk(l1e->atge_l1e_rx_cmb);
268015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_cmb = NULL;
269015a6ef6SSaurabh Misra 	}
270015a6ef6SSaurabh Misra 
271015a6ef6SSaurabh Misra 	/*
272015a6ef6SSaurabh Misra 	 * Free RX buffers and RX ring.
273015a6ef6SSaurabh Misra 	 */
274015a6ef6SSaurabh Misra 	atge_rx_desc_free(atgep);
275015a6ef6SSaurabh Misra 
276015a6ef6SSaurabh Misra 	/*
277015a6ef6SSaurabh Misra 	 * Free the memory allocated for gathering hw stats.
278015a6ef6SSaurabh Misra 	 */
279015a6ef6SSaurabh Misra 	if (atgep->atge_hw_stats != NULL) {
280015a6ef6SSaurabh Misra 		kmem_free(atgep->atge_hw_stats, sizeof (atge_l1e_smb_t));
281015a6ef6SSaurabh Misra 		atgep->atge_hw_stats = NULL;
282015a6ef6SSaurabh Misra 	}
283015a6ef6SSaurabh Misra }
284015a6ef6SSaurabh Misra 
285015a6ef6SSaurabh Misra void
atge_l1e_init_rx_pages(atge_t * atgep)286015a6ef6SSaurabh Misra atge_l1e_init_rx_pages(atge_t *atgep)
287015a6ef6SSaurabh Misra {
288015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e;
289015a6ef6SSaurabh Misra 	atge_dma_t *dma;
290015a6ef6SSaurabh Misra 	int pages;
291015a6ef6SSaurabh Misra 
292015a6ef6SSaurabh Misra 	ASSERT(atgep != NULL);
293015a6ef6SSaurabh Misra 	l1e = atgep->atge_private_data;
294015a6ef6SSaurabh Misra 
295015a6ef6SSaurabh Misra 	ASSERT(l1e != NULL);
296015a6ef6SSaurabh Misra 
297015a6ef6SSaurabh Misra 	l1e->atge_l1e_proc_max = L1E_RX_PAGE_SZ / ETHERMIN;
298015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_curp = 0;
299015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_seqno = 0;
300015a6ef6SSaurabh Misra 
301015a6ef6SSaurabh Misra 	for (pages = 0; pages < L1E_RX_PAGES; pages++) {
302015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_page_cons = 0;
303015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_page_prods[pages] = 0;
304015a6ef6SSaurabh Misra 
305015a6ef6SSaurabh Misra 
306015a6ef6SSaurabh Misra 		dma = l1e->atge_l1e_rx_page[pages];
307015a6ef6SSaurabh Misra 		ASSERT(dma != NULL);
308015a6ef6SSaurabh Misra 		bzero(dma->addr, l1e->atge_l1e_pagesize);
309015a6ef6SSaurabh Misra 		DMA_SYNC(dma, 0, l1e->atge_l1e_pagesize, DDI_DMA_SYNC_FORDEV);
310015a6ef6SSaurabh Misra 	}
311015a6ef6SSaurabh Misra 
312015a6ef6SSaurabh Misra 	dma = l1e->atge_l1e_rx_cmb;
313015a6ef6SSaurabh Misra 	ASSERT(dma != NULL);
314015a6ef6SSaurabh Misra 	bzero(dma->addr, L1E_RX_CMB_SZ * L1E_RX_PAGES);
315015a6ef6SSaurabh Misra 	DMA_SYNC(dma, 0, L1E_RX_CMB_SZ * L1E_RX_PAGES, DDI_DMA_SYNC_FORDEV);
316015a6ef6SSaurabh Misra }
317015a6ef6SSaurabh Misra 
318015a6ef6SSaurabh Misra void
atge_l1e_init_tx_ring(atge_t * atgep)319015a6ef6SSaurabh Misra atge_l1e_init_tx_ring(atge_t *atgep)
320015a6ef6SSaurabh Misra {
321015a6ef6SSaurabh Misra 	ASSERT(atgep != NULL);
322015a6ef6SSaurabh Misra 	ASSERT(atgep->atge_tx_ring != NULL);
323015a6ef6SSaurabh Misra 	ASSERT(atgep->atge_tx_ring->r_desc_ring != NULL);
324015a6ef6SSaurabh Misra 
325015a6ef6SSaurabh Misra 	atgep->atge_tx_ring->r_producer = 0;
326015a6ef6SSaurabh Misra 	atgep->atge_tx_ring->r_consumer = 0;
3270eb090a7SSaurabh Misra 	atgep->atge_tx_ring->r_avail_desc = ATGE_TX_RING_CNT;
328015a6ef6SSaurabh Misra 
3290eb090a7SSaurabh Misra 	bzero(atgep->atge_tx_ring->r_desc_ring->addr, ATGE_TX_RING_SZ);
330015a6ef6SSaurabh Misra 
3310eb090a7SSaurabh Misra 	DMA_SYNC(atgep->atge_tx_ring->r_desc_ring, 0, ATGE_TX_RING_SZ,
332015a6ef6SSaurabh Misra 	    DDI_DMA_SYNC_FORDEV);
333015a6ef6SSaurabh Misra }
334015a6ef6SSaurabh Misra 
335015a6ef6SSaurabh Misra void
atge_l1e_program_dma(atge_t * atgep)336015a6ef6SSaurabh Misra atge_l1e_program_dma(atge_t *atgep)
337015a6ef6SSaurabh Misra {
338015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e;
339015a6ef6SSaurabh Misra 	uint64_t paddr;
340015a6ef6SSaurabh Misra 	uint32_t reg;
341015a6ef6SSaurabh Misra 
342015a6ef6SSaurabh Misra 	l1e = (atge_l1e_data_t *)atgep->atge_private_data;
343015a6ef6SSaurabh Misra 
344015a6ef6SSaurabh Misra 	/*
345015a6ef6SSaurabh Misra 	 * Clear WOL status and disable all WOL feature as WOL
346015a6ef6SSaurabh Misra 	 * would interfere Rx operation under normal environments.
347015a6ef6SSaurabh Misra 	 */
348015a6ef6SSaurabh Misra 	(void) INL(atgep, ATGE_WOL_CFG);
349015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_WOL_CFG, 0);
350015a6ef6SSaurabh Misra 
351015a6ef6SSaurabh Misra 	/*
352015a6ef6SSaurabh Misra 	 * Set Tx descriptor/RXF0/CMB base addresses. They share
353015a6ef6SSaurabh Misra 	 * the same high address part of DMAable region.
354015a6ef6SSaurabh Misra 	 */
355015a6ef6SSaurabh Misra 	paddr = atgep->atge_tx_ring->r_desc_ring->cookie.dmac_laddress;
356015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_DESC_ADDR_HI, ATGE_ADDR_HI(paddr));
357015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_DESC_TPD_ADDR_LO, ATGE_ADDR_LO(paddr));
358015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_DESC_TPD_CNT,
3590eb090a7SSaurabh Misra 	    (ATGE_TX_RING_CNT << DESC_TPD_CNT_SHIFT) & DESC_TPD_CNT_MASK);
360015a6ef6SSaurabh Misra 
361015a6ef6SSaurabh Misra 	/* Set Rx page base address, note we use single queue. */
362015a6ef6SSaurabh Misra 	paddr = l1e->atge_l1e_rx_page[0]->cookie.dmac_laddress;
363015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_RXF0_PAGE0_ADDR_LO, ATGE_ADDR_LO(paddr));
364015a6ef6SSaurabh Misra 	paddr = l1e->atge_l1e_rx_page[1]->cookie.dmac_laddress;
365015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_RXF0_PAGE1_ADDR_LO, ATGE_ADDR_LO(paddr));
366015a6ef6SSaurabh Misra 
367015a6ef6SSaurabh Misra 	/* Set Tx/Rx CMB addresses. */
368015a6ef6SSaurabh Misra 	paddr = l1e->atge_l1e_rx_cmb->cookie.dmac_laddress;
369015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_RXF0_CMB0_ADDR_LO, ATGE_ADDR_LO(paddr));
370015a6ef6SSaurabh Misra 	paddr = l1e->atge_l1e_rx_cmb->cookie.dmac_laddress + sizeof (uint32_t);
371015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_RXF0_CMB1_ADDR_LO, ATGE_ADDR_LO(paddr));
372015a6ef6SSaurabh Misra 
373015a6ef6SSaurabh Misra 	/* Mark RXF0 valid. */
374015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0, RXF_VALID);	/* 0 */
375015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE1, RXF_VALID);	/* 1 */
376015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0 + 2, 0);
377015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0 + 3, 0);
378015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0 + 4, 0);
379015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0 + 5, 0);
380015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0 + 6, 0);
381015a6ef6SSaurabh Misra 	OUTB(atgep, L1E_RXF0_PAGE0 + 6, 0);
382015a6ef6SSaurabh Misra 
383015a6ef6SSaurabh Misra 	/* Set Rx page size, excluding guard frame size. */
384015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_RXF_PAGE_SIZE, L1E_RX_PAGE_SZ);
385015a6ef6SSaurabh Misra 
386015a6ef6SSaurabh Misra 	/* Tell hardware that we're ready to load DMA blocks. */
387015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_DMA_BLOCK, DMA_BLOCK_LOAD);
388015a6ef6SSaurabh Misra 
389015a6ef6SSaurabh Misra 	/* Set Rx/Tx interrupt trigger threshold. */
390015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_INT_TRIG_THRESH, (1 << INT_TRIG_RX_THRESH_SHIFT) |
391015a6ef6SSaurabh Misra 	    (4 << INT_TRIG_TX_THRESH_SHIFT));
392015a6ef6SSaurabh Misra 
393015a6ef6SSaurabh Misra 	/*
394015a6ef6SSaurabh Misra 	 * Set interrupt trigger timer, its purpose and relation
395015a6ef6SSaurabh Misra 	 * with interrupt moderation mechanism is not clear yet.
396015a6ef6SSaurabh Misra 	 */
397015a6ef6SSaurabh Misra 	OUTL(atgep, L1E_INT_TRIG_TIMER,
398015a6ef6SSaurabh Misra 	    ((ATGE_USECS(10) << INT_TRIG_RX_TIMER_SHIFT) |
399015a6ef6SSaurabh Misra 	    (ATGE_USECS(1000) << INT_TRIG_TX_TIMER_SHIFT)));
400015a6ef6SSaurabh Misra 
401015a6ef6SSaurabh Misra 	reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
402015a6ef6SSaurabh Misra 	reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) << IM_TIMER_TX_SHIFT;
403015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_IM_TIMER, reg);
404015a6ef6SSaurabh Misra 
405015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_MASTER_CFG);
406*5e8715b9SGary Mills 	reg &= ~(L1E_MASTER_CHIP_REV_MASK | L1E_MASTER_CHIP_ID_MASK);
407*5e8715b9SGary Mills 	reg &= ~(L1E_MASTER_IM_RX_TIMER_ENB | L1E_MASTER_IM_TX_TIMER_ENB);
408*5e8715b9SGary Mills 	reg |= L1E_MASTER_IM_RX_TIMER_ENB;
409*5e8715b9SGary Mills 	reg |= L1E_MASTER_IM_TX_TIMER_ENB;
410015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MASTER_CFG, reg);
411015a6ef6SSaurabh Misra 
412015a6ef6SSaurabh Misra 	OUTW(atgep, RX_COALSC_PKT_1e, 0);
413015a6ef6SSaurabh Misra 	OUTW(atgep, RX_COALSC_TO_1e, 0);
414015a6ef6SSaurabh Misra 	OUTW(atgep, TX_COALSC_PKT_1e, 1);
415015a6ef6SSaurabh Misra 	OUTW(atgep, TX_COALSC_TO_1e, 4000/2);		/* 4mS */
416015a6ef6SSaurabh Misra }
417015a6ef6SSaurabh Misra 
418015a6ef6SSaurabh Misra mblk_t *
atge_l1e_receive(atge_t * atgep)419015a6ef6SSaurabh Misra atge_l1e_receive(atge_t *atgep)
420015a6ef6SSaurabh Misra {
421015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e;
422015a6ef6SSaurabh Misra 	atge_dma_t *dma_rx_page;
423015a6ef6SSaurabh Misra 	atge_dma_t *dma_rx_cmb;
424015a6ef6SSaurabh Misra 	uint32_t *ptr;
425015a6ef6SSaurabh Misra 	uint32_t cons, current_page;
426015a6ef6SSaurabh Misra 	uchar_t *pageaddr, *bufp;
427015a6ef6SSaurabh Misra 	rx_rs_t	*rs;
428015a6ef6SSaurabh Misra 	int prog;
429015a6ef6SSaurabh Misra 	uint32_t seqno, len, flags;
430015a6ef6SSaurabh Misra 	mblk_t *mp = NULL, *rx_head, *rx_tail;
431015a6ef6SSaurabh Misra 	static uint32_t gen = 0;
432015a6ef6SSaurabh Misra 
433015a6ef6SSaurabh Misra 	l1e = atgep->atge_private_data;
434015a6ef6SSaurabh Misra 
435015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
436015a6ef6SSaurabh Misra 	ASSERT(l1e != NULL);
437015a6ef6SSaurabh Misra 
438015a6ef6SSaurabh Misra 	rx_tail = NULL;
439015a6ef6SSaurabh Misra 	rx_head = NULL;
440015a6ef6SSaurabh Misra 
441015a6ef6SSaurabh Misra 	current_page = l1e->atge_l1e_rx_curp;
442015a6ef6SSaurabh Misra 
443015a6ef6SSaurabh Misra 	/* Sync CMB first */
444015a6ef6SSaurabh Misra 	dma_rx_cmb = l1e->atge_l1e_rx_cmb;
445015a6ef6SSaurabh Misra 	DMA_SYNC(dma_rx_cmb, 0, L1E_RX_CMB_SZ * L1E_RX_PAGES,
446015a6ef6SSaurabh Misra 	    DDI_DMA_SYNC_FORKERNEL);
447015a6ef6SSaurabh Misra 
448015a6ef6SSaurabh Misra 	dma_rx_page = l1e->atge_l1e_rx_page[current_page];
449015a6ef6SSaurabh Misra 
450015a6ef6SSaurabh Misra 	/*
451015a6ef6SSaurabh Misra 	 * Get the producer offset from CMB.
452015a6ef6SSaurabh Misra 	 */
453015a6ef6SSaurabh Misra 	ptr = (void *)dma_rx_cmb->addr;
454015a6ef6SSaurabh Misra 
455015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_page_prods[current_page] =
456015a6ef6SSaurabh Misra 	    ATGE_GET32(dma_rx_cmb, ptr + current_page);
457015a6ef6SSaurabh Misra 
458015a6ef6SSaurabh Misra 	/* Sync current RX Page as well */
459015a6ef6SSaurabh Misra 	DMA_SYNC(dma_rx_page, l1e->atge_l1e_rx_page_cons,
460015a6ef6SSaurabh Misra 	    l1e->atge_l1e_rx_page_prods[current_page], DDI_DMA_SYNC_FORKERNEL);
461015a6ef6SSaurabh Misra 
462015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() prod : %d, cons : %d, curr page : %d, gen : (%d)"
463015a6ef6SSaurabh Misra 	    " cmb[0,1] : %d, %d",
464015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__,
465015a6ef6SSaurabh Misra 	    l1e->atge_l1e_rx_page_prods[current_page],
466015a6ef6SSaurabh Misra 	    l1e->atge_l1e_rx_page_cons, l1e->atge_l1e_rx_curp, gen,
467015a6ef6SSaurabh Misra 	    ATGE_GET32(dma_rx_cmb, ptr), ATGE_GET32(dma_rx_cmb, ptr + 1)));
468015a6ef6SSaurabh Misra 
469015a6ef6SSaurabh Misra 	for (prog = 0; prog <= l1e->atge_l1e_proc_max; prog++) {
470015a6ef6SSaurabh Misra 		cons = l1e->atge_l1e_rx_page_cons;
471015a6ef6SSaurabh Misra 		if (cons >= l1e->atge_l1e_rx_page_prods[l1e->atge_l1e_rx_curp])
472015a6ef6SSaurabh Misra 			break;
473015a6ef6SSaurabh Misra 
474015a6ef6SSaurabh Misra 		dma_rx_page = l1e->atge_l1e_rx_page[l1e->atge_l1e_rx_curp];
475015a6ef6SSaurabh Misra 		pageaddr = (uchar_t *)dma_rx_page->addr;
476015a6ef6SSaurabh Misra 		pageaddr = pageaddr + cons;
477015a6ef6SSaurabh Misra 		rs = (rx_rs_t *)pageaddr;
478015a6ef6SSaurabh Misra 
479015a6ef6SSaurabh Misra 		seqno = ATGE_GET32(dma_rx_page, &(rs->seqno));
480015a6ef6SSaurabh Misra 		seqno = L1E_RX_SEQNO(seqno);
481015a6ef6SSaurabh Misra 
482015a6ef6SSaurabh Misra 		len = ATGE_GET32(dma_rx_page, &(rs->length));
483015a6ef6SSaurabh Misra 		len = L1E_RX_BYTES(len);
484015a6ef6SSaurabh Misra 
485015a6ef6SSaurabh Misra 		flags = ATGE_GET32(dma_rx_page, &(rs->flags));
486015a6ef6SSaurabh Misra 
487015a6ef6SSaurabh Misra 		if (seqno != l1e->atge_l1e_rx_seqno) {
488015a6ef6SSaurabh Misra 			/*
489015a6ef6SSaurabh Misra 			 * We have not seen this happening but we
490015a6ef6SSaurabh Misra 			 * must restart the chip if that happens.
491015a6ef6SSaurabh Misra 			 */
492015a6ef6SSaurabh Misra 			ATGE_DB(("%s: %s() MISS-MATCH in seqno :%d,"
493015a6ef6SSaurabh Misra 			    " atge_l1e_rx_seqno : %d, length : %d, flags : %x",
494015a6ef6SSaurabh Misra 			    atgep->atge_name, __func__, seqno,
495015a6ef6SSaurabh Misra 			    l1e->atge_l1e_rx_seqno, len, flags));
496015a6ef6SSaurabh Misra 
497015a6ef6SSaurabh Misra 			mutex_enter(&atgep->atge_tx_lock);
498015a6ef6SSaurabh Misra 			atge_device_restart(atgep);
499015a6ef6SSaurabh Misra 			mutex_exit(&atgep->atge_tx_lock);
500015a6ef6SSaurabh Misra 
501015a6ef6SSaurabh Misra 			/*
502015a6ef6SSaurabh Misra 			 * Return all the pkts received before restarting
503015a6ef6SSaurabh Misra 			 * the chip.
504015a6ef6SSaurabh Misra 			 */
505015a6ef6SSaurabh Misra 			return (rx_head);
506015a6ef6SSaurabh Misra 		} else {
507015a6ef6SSaurabh Misra 			l1e->atge_l1e_rx_seqno++;
508015a6ef6SSaurabh Misra 		}
509015a6ef6SSaurabh Misra 
510015a6ef6SSaurabh Misra 		/*
511015a6ef6SSaurabh Misra 		 * We will pass the pkt to upper layer provided it's clear
512015a6ef6SSaurabh Misra 		 * from any error.
513015a6ef6SSaurabh Misra 		 */
514015a6ef6SSaurabh Misra 		if ((flags & L1E_RD_ERROR) != 0) {
515015a6ef6SSaurabh Misra 			if ((flags & (L1E_RD_CRC | L1E_RD_CODE |
516015a6ef6SSaurabh Misra 			    L1E_RD_DRIBBLE | L1E_RD_RUNT | L1E_RD_OFLOW |
517015a6ef6SSaurabh Misra 			    L1E_RD_TRUNC)) != 0) {
518015a6ef6SSaurabh Misra 				ATGE_DB(("%s: %s() ERRORED PKT : %x",
519015a6ef6SSaurabh Misra 				    atgep->atge_name, __func__, flags));
520015a6ef6SSaurabh Misra 				atge_l1e_rx_next_pkt(atgep, len);
521015a6ef6SSaurabh Misra 				atgep->atge_errrcv++;
522015a6ef6SSaurabh Misra 				continue;
523015a6ef6SSaurabh Misra 			}
524015a6ef6SSaurabh Misra 		}
525015a6ef6SSaurabh Misra 
526015a6ef6SSaurabh Misra 		/*
527015a6ef6SSaurabh Misra 		 * So we have received a frame/pkt.
528015a6ef6SSaurabh Misra 		 */
529015a6ef6SSaurabh Misra 		if (len == 0 || len > atgep->atge_rx_buf_len) {
530015a6ef6SSaurabh Misra 			ATGE_DB(("%s: %s() PKT len > error : %d",
531015a6ef6SSaurabh Misra 			    atgep->atge_name, __func__, len));
532015a6ef6SSaurabh Misra 			atge_l1e_rx_next_pkt(atgep, len);
533015a6ef6SSaurabh Misra 			continue;
534015a6ef6SSaurabh Misra 		}
535015a6ef6SSaurabh Misra 
536015a6ef6SSaurabh Misra 		mp = allocb(len + VLAN_TAGSZ, BPRI_MED);
537015a6ef6SSaurabh Misra 		if (mp != NULL) {
538015a6ef6SSaurabh Misra 			mp->b_rptr += VLAN_TAGSZ;
539015a6ef6SSaurabh Misra 			bufp = mp->b_rptr;
540015a6ef6SSaurabh Misra 			mp->b_wptr = bufp + len;
541015a6ef6SSaurabh Misra 			mp->b_next = NULL;
542015a6ef6SSaurabh Misra 
543015a6ef6SSaurabh Misra 			bcopy(pageaddr + sizeof (rx_rs_t), bufp, len);
544015a6ef6SSaurabh Misra 
545015a6ef6SSaurabh Misra 			if (rx_tail == NULL)
546015a6ef6SSaurabh Misra 				rx_head = rx_tail = mp;
547015a6ef6SSaurabh Misra 			else {
548015a6ef6SSaurabh Misra 				rx_tail->b_next = mp;
549015a6ef6SSaurabh Misra 				rx_tail = mp;
550015a6ef6SSaurabh Misra 			}
551015a6ef6SSaurabh Misra 
552015a6ef6SSaurabh Misra 			atgep->atge_ipackets++;
553015a6ef6SSaurabh Misra 			atgep->atge_rbytes += len;
554015a6ef6SSaurabh Misra 		} else {
555015a6ef6SSaurabh Misra 			ATGE_DB(("%s: %s() PKT mp == NULL len : %d",
556015a6ef6SSaurabh Misra 			    atgep->atge_name, __func__, len));
557015a6ef6SSaurabh Misra 
558015a6ef6SSaurabh Misra 			if (len > atgep->atge_rx_buf_len) {
559015a6ef6SSaurabh Misra 				atgep->atge_toolong_errors++;
560015a6ef6SSaurabh Misra 			} else if (mp == NULL) {
561015a6ef6SSaurabh Misra 				atgep->atge_norcvbuf++;
562015a6ef6SSaurabh Misra 			}
563015a6ef6SSaurabh Misra 		}
564015a6ef6SSaurabh Misra 
565015a6ef6SSaurabh Misra 		atge_l1e_rx_next_pkt(atgep, len);
566015a6ef6SSaurabh Misra 
567015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() seqno :%d, atge_l1e_rx_seqno :"
568015a6ef6SSaurabh Misra 		    " %d, length : %d,"
569015a6ef6SSaurabh Misra 		    " flags : %x, cons : %d, prod : %d",
570015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__, seqno,
571015a6ef6SSaurabh Misra 		    l1e->atge_l1e_rx_seqno, len, flags,
572015a6ef6SSaurabh Misra 		    l1e->atge_l1e_rx_page_cons,
573015a6ef6SSaurabh Misra 		    l1e->atge_l1e_rx_page_prods[l1e->atge_l1e_rx_curp]));
574015a6ef6SSaurabh Misra 	}
575015a6ef6SSaurabh Misra 
576015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() receive completed (gen : %d) : cons : %d,"
577015a6ef6SSaurabh Misra 	    " prod :%d, L1E_RX_PAGE_SZ : %d (prog:%d)",
578015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, gen,
579015a6ef6SSaurabh Misra 	    l1e->atge_l1e_rx_page_cons,
580015a6ef6SSaurabh Misra 	    l1e->atge_l1e_rx_page_prods[l1e->atge_l1e_rx_curp],
581015a6ef6SSaurabh Misra 	    L1E_RX_PAGE_SZ, prog));
582015a6ef6SSaurabh Misra 
583015a6ef6SSaurabh Misra 	gen++;
584015a6ef6SSaurabh Misra 	return (rx_head);
585015a6ef6SSaurabh Misra }
586015a6ef6SSaurabh Misra 
587015a6ef6SSaurabh Misra void
atge_l1e_rx_next_pkt(atge_t * atgep,uint32_t len)588015a6ef6SSaurabh Misra atge_l1e_rx_next_pkt(atge_t *atgep, uint32_t len)
589015a6ef6SSaurabh Misra {
590015a6ef6SSaurabh Misra 	atge_l1e_data_t *l1e = atgep->atge_private_data;
591015a6ef6SSaurabh Misra 	atge_dma_t *dma_rx_page;
592015a6ef6SSaurabh Misra 	atge_dma_t *dma_rx_cmb;
593015a6ef6SSaurabh Misra 	int curr = l1e->atge_l1e_rx_curp;
594015a6ef6SSaurabh Misra 	uint32_t *p;
595015a6ef6SSaurabh Misra 
596015a6ef6SSaurabh Misra 	/*
597015a6ef6SSaurabh Misra 	 * Update consumer position.
598015a6ef6SSaurabh Misra 	 */
599015a6ef6SSaurabh Misra 	l1e->atge_l1e_rx_page_cons +=
600015a6ef6SSaurabh Misra 	    ROUNDUP(len + sizeof (rx_rs_t), L1E_RX_PAGE_ALIGN);
601015a6ef6SSaurabh Misra 
602015a6ef6SSaurabh Misra 	/*
603015a6ef6SSaurabh Misra 	 * If we need to flip to the other page. Note that we use only two
604015a6ef6SSaurabh Misra 	 * pages.
605015a6ef6SSaurabh Misra 	 */
606015a6ef6SSaurabh Misra 	if (l1e->atge_l1e_rx_page_cons >= L1E_RX_PAGE_SZ) {
607015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() cons : %d, prod :%d, L1E_RX_PAGE_SZ : %d",
608015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__, l1e->atge_l1e_rx_page_cons,
609015a6ef6SSaurabh Misra 		    l1e->atge_l1e_rx_page_prods[curr], L1E_RX_PAGE_SZ));
610015a6ef6SSaurabh Misra 
611015a6ef6SSaurabh Misra 		/*
612015a6ef6SSaurabh Misra 		 * Clear the producer.
613015a6ef6SSaurabh Misra 		 */
614015a6ef6SSaurabh Misra 		dma_rx_cmb = l1e->atge_l1e_rx_cmb;
615015a6ef6SSaurabh Misra 		p = (void *)dma_rx_cmb->addr;
616015a6ef6SSaurabh Misra 		p = p + curr;
617015a6ef6SSaurabh Misra 		*p = 0;
618015a6ef6SSaurabh Misra 		DMA_SYNC(dma_rx_cmb, curr * L1E_RX_CMB_SZ,
619015a6ef6SSaurabh Misra 		    L1E_RX_CMB_SZ, DDI_DMA_SYNC_FORDEV);
620015a6ef6SSaurabh Misra 
621015a6ef6SSaurabh Misra 		/*
622015a6ef6SSaurabh Misra 		 * Notify the NIC that the current RX page is available again.
623015a6ef6SSaurabh Misra 		 */
624015a6ef6SSaurabh Misra 		OUTB(atgep, L1E_RXF0_PAGE0 + curr, RXF_VALID);
625015a6ef6SSaurabh Misra 
626015a6ef6SSaurabh Misra 		/*
627015a6ef6SSaurabh Misra 		 * End of Rx page reached, let hardware reuse this page.
628015a6ef6SSaurabh Misra 		 */
629015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_page_cons = 0;
630015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_page_prods[curr] = 0;
631015a6ef6SSaurabh Misra 
632015a6ef6SSaurabh Misra 		/*
633015a6ef6SSaurabh Misra 		 * Switch to alternate Rx page.
634015a6ef6SSaurabh Misra 		 */
635015a6ef6SSaurabh Misra 		curr ^= 1;
636015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_curp = curr;
637015a6ef6SSaurabh Misra 
638015a6ef6SSaurabh Misra 		/*
639015a6ef6SSaurabh Misra 		 * Page flipped, sync CMB and then Rx page.
640015a6ef6SSaurabh Misra 		 */
641015a6ef6SSaurabh Misra 		DMA_SYNC(dma_rx_cmb, 0, L1E_RX_PAGES * L1E_RX_CMB_SZ,
642015a6ef6SSaurabh Misra 		    DDI_DMA_SYNC_FORKERNEL);
643015a6ef6SSaurabh Misra 		p = (void *)dma_rx_cmb->addr;
644015a6ef6SSaurabh Misra 		l1e->atge_l1e_rx_page_prods[curr] =
645015a6ef6SSaurabh Misra 		    ATGE_GET32(dma_rx_cmb, p + curr);
646015a6ef6SSaurabh Misra 
647015a6ef6SSaurabh Misra 		dma_rx_page = l1e->atge_l1e_rx_page[curr];
648015a6ef6SSaurabh Misra 		DMA_SYNC(dma_rx_page, 0, l1e->atge_l1e_rx_page_prods[curr],
649015a6ef6SSaurabh Misra 		    DDI_DMA_SYNC_FORKERNEL);
650015a6ef6SSaurabh Misra 
651015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() PAGE FLIPPED -> %d, producer[0,1]: %d, %d",
652015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__, curr,
653015a6ef6SSaurabh Misra 		    ATGE_GET32(dma_rx_cmb, p), ATGE_GET32(dma_rx_cmb, p + 1)));
654015a6ef6SSaurabh Misra 	}
655015a6ef6SSaurabh Misra }
656015a6ef6SSaurabh Misra 
657015a6ef6SSaurabh Misra void
atge_l1e_send_packet(atge_ring_t * r)6580eb090a7SSaurabh Misra atge_l1e_send_packet(atge_ring_t *r)
659015a6ef6SSaurabh Misra {
660015a6ef6SSaurabh Misra 	/*
661015a6ef6SSaurabh Misra 	 * Ask chip to send the packet now.
662015a6ef6SSaurabh Misra 	 */
663015a6ef6SSaurabh Misra 	OUTL(r->r_atge, ATGE_MBOX, r->r_producer);
664015a6ef6SSaurabh Misra }
665015a6ef6SSaurabh Misra 
666015a6ef6SSaurabh Misra void
atge_l1e_clear_stats(atge_t * atgep)667015a6ef6SSaurabh Misra atge_l1e_clear_stats(atge_t *atgep)
668015a6ef6SSaurabh Misra {
669015a6ef6SSaurabh Misra 	atge_l1e_smb_t smb;
670015a6ef6SSaurabh Misra 	uint32_t *reg;
671015a6ef6SSaurabh Misra 	int i;
672015a6ef6SSaurabh Misra 
673015a6ef6SSaurabh Misra 	/*
674015a6ef6SSaurabh Misra 	 * Clear RX stats first.
675015a6ef6SSaurabh Misra 	 */
676015a6ef6SSaurabh Misra 	i = 0;
677015a6ef6SSaurabh Misra 	reg = &smb.rx_frames;
678015a6ef6SSaurabh Misra 	while (reg++ <= &smb.rx_pkts_filtered) {
679015a6ef6SSaurabh Misra 		(void) INL(atgep, L1E_RX_MIB_BASE + i);
680015a6ef6SSaurabh Misra 		i += sizeof (uint32_t);
681015a6ef6SSaurabh Misra 	}
682015a6ef6SSaurabh Misra 
683015a6ef6SSaurabh Misra 	/*
684015a6ef6SSaurabh Misra 	 * Clear TX stats.
685015a6ef6SSaurabh Misra 	 */
686015a6ef6SSaurabh Misra 	i = 0;
687015a6ef6SSaurabh Misra 	reg = &smb.tx_frames;
688015a6ef6SSaurabh Misra 	while (reg++ <= &smb.tx_mcast_bytes) {
689015a6ef6SSaurabh Misra 		(void) INL(atgep, L1E_TX_MIB_BASE + i);
690015a6ef6SSaurabh Misra 		i += sizeof (uint32_t);
691015a6ef6SSaurabh Misra 	}
692015a6ef6SSaurabh Misra }
693015a6ef6SSaurabh Misra 
694015a6ef6SSaurabh Misra void
atge_l1e_gather_stats(atge_t * atgep)695015a6ef6SSaurabh Misra atge_l1e_gather_stats(atge_t *atgep)
696015a6ef6SSaurabh Misra {
697015a6ef6SSaurabh Misra 	atge_l1e_smb_t *stat;
698015a6ef6SSaurabh Misra 	atge_l1e_smb_t *smb;
699015a6ef6SSaurabh Misra 	atge_l1e_smb_t local_smb;
700015a6ef6SSaurabh Misra 	uint32_t *reg;
701015a6ef6SSaurabh Misra 	int i;
702015a6ef6SSaurabh Misra 
703015a6ef6SSaurabh Misra 	ASSERT(atgep != NULL);
704015a6ef6SSaurabh Misra 
705015a6ef6SSaurabh Misra 	stat = (atge_l1e_smb_t *)atgep->atge_hw_stats;
706015a6ef6SSaurabh Misra 
707015a6ef6SSaurabh Misra 	bzero(&local_smb, sizeof (atge_l1e_smb_t));
708015a6ef6SSaurabh Misra 	smb = &local_smb;
709015a6ef6SSaurabh Misra 
710015a6ef6SSaurabh Misra 	/* Read Rx statistics. */
711015a6ef6SSaurabh Misra 	i = 0;
712015a6ef6SSaurabh Misra 	reg = &smb->rx_frames;
713015a6ef6SSaurabh Misra 	while (reg++ <= &smb->rx_pkts_filtered) {
714015a6ef6SSaurabh Misra 		*reg = INL(atgep, L1E_RX_MIB_BASE + i);
715015a6ef6SSaurabh Misra 		i += sizeof (uint32_t);
716015a6ef6SSaurabh Misra 	}
717015a6ef6SSaurabh Misra 
718015a6ef6SSaurabh Misra 	/* Read Tx statistics. */
719015a6ef6SSaurabh Misra 	i = 0;
720015a6ef6SSaurabh Misra 	reg = &smb->tx_frames;
721015a6ef6SSaurabh Misra 	while (reg++ <= &smb->tx_mcast_bytes) {
722015a6ef6SSaurabh Misra 		*reg = INL(atgep, L1E_TX_MIB_BASE + i);
723015a6ef6SSaurabh Misra 		i += sizeof (uint32_t);
724015a6ef6SSaurabh Misra 	}
725015a6ef6SSaurabh Misra 
726015a6ef6SSaurabh Misra 	/*
727015a6ef6SSaurabh Misra 	 * SMB is cleared everytime we read; hence we always do '+='.
728015a6ef6SSaurabh Misra 	 */
729015a6ef6SSaurabh Misra 
730015a6ef6SSaurabh Misra 	/* Rx stats. */
731015a6ef6SSaurabh Misra 	stat->rx_frames += smb->rx_frames;
732015a6ef6SSaurabh Misra 	stat->rx_bcast_frames += smb->rx_bcast_frames;
733015a6ef6SSaurabh Misra 	stat->rx_mcast_frames += smb->rx_mcast_frames;
734015a6ef6SSaurabh Misra 	stat->rx_pause_frames += smb->rx_pause_frames;
735015a6ef6SSaurabh Misra 	stat->rx_control_frames += smb->rx_control_frames;
736015a6ef6SSaurabh Misra 	stat->rx_crcerrs += smb->rx_crcerrs;
737015a6ef6SSaurabh Misra 	stat->rx_lenerrs += smb->rx_lenerrs;
738015a6ef6SSaurabh Misra 	stat->rx_bytes += smb->rx_bytes;
739015a6ef6SSaurabh Misra 	stat->rx_runts += smb->rx_runts;
740015a6ef6SSaurabh Misra 	stat->rx_fragments += smb->rx_fragments;
741015a6ef6SSaurabh Misra 	stat->rx_pkts_64 += smb->rx_pkts_64;
742015a6ef6SSaurabh Misra 	stat->rx_pkts_65_127 += smb->rx_pkts_65_127;
743015a6ef6SSaurabh Misra 	stat->rx_pkts_128_255 += smb->rx_pkts_128_255;
744015a6ef6SSaurabh Misra 	stat->rx_pkts_256_511 += smb->rx_pkts_256_511;
745015a6ef6SSaurabh Misra 	stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023;
746015a6ef6SSaurabh Misra 	stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518;
747015a6ef6SSaurabh Misra 	stat->rx_pkts_1519_max += smb->rx_pkts_1519_max;
748015a6ef6SSaurabh Misra 	stat->rx_pkts_truncated += smb->rx_pkts_truncated;
749015a6ef6SSaurabh Misra 	stat->rx_fifo_oflows += smb->rx_fifo_oflows;
750015a6ef6SSaurabh Misra 	stat->rx_rrs_errs += smb->rx_rrs_errs;
751015a6ef6SSaurabh Misra 	stat->rx_alignerrs += smb->rx_alignerrs;
752015a6ef6SSaurabh Misra 	stat->rx_bcast_bytes += smb->rx_bcast_bytes;
753015a6ef6SSaurabh Misra 	stat->rx_mcast_bytes += smb->rx_mcast_bytes;
754015a6ef6SSaurabh Misra 	stat->rx_pkts_filtered += smb->rx_pkts_filtered;
755015a6ef6SSaurabh Misra 
756015a6ef6SSaurabh Misra 	/* Tx stats. */
757015a6ef6SSaurabh Misra 	stat->tx_frames += smb->tx_frames;
758015a6ef6SSaurabh Misra 	stat->tx_bcast_frames += smb->tx_bcast_frames;
759015a6ef6SSaurabh Misra 	stat->tx_mcast_frames += smb->tx_mcast_frames;
760015a6ef6SSaurabh Misra 	stat->tx_pause_frames += smb->tx_pause_frames;
761015a6ef6SSaurabh Misra 	stat->tx_excess_defer += smb->tx_excess_defer;
762015a6ef6SSaurabh Misra 	stat->tx_control_frames += smb->tx_control_frames;
763015a6ef6SSaurabh Misra 	stat->tx_deferred += smb->tx_deferred;
764015a6ef6SSaurabh Misra 	stat->tx_bytes += smb->tx_bytes;
765015a6ef6SSaurabh Misra 	stat->tx_pkts_64 += smb->tx_pkts_64;
766015a6ef6SSaurabh Misra 	stat->tx_pkts_65_127 += smb->tx_pkts_65_127;
767015a6ef6SSaurabh Misra 	stat->tx_pkts_128_255 += smb->tx_pkts_128_255;
768015a6ef6SSaurabh Misra 	stat->tx_pkts_256_511 += smb->tx_pkts_256_511;
769015a6ef6SSaurabh Misra 	stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023;
770015a6ef6SSaurabh Misra 	stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518;
771015a6ef6SSaurabh Misra 	stat->tx_pkts_1519_max += smb->tx_pkts_1519_max;
772015a6ef6SSaurabh Misra 	stat->tx_single_colls += smb->tx_single_colls;
773015a6ef6SSaurabh Misra 	stat->tx_multi_colls += smb->tx_multi_colls;
774015a6ef6SSaurabh Misra 	stat->tx_late_colls += smb->tx_late_colls;
775015a6ef6SSaurabh Misra 	stat->tx_excess_colls += smb->tx_excess_colls;
776015a6ef6SSaurabh Misra 	stat->tx_abort += smb->tx_abort;
777015a6ef6SSaurabh Misra 	stat->tx_underrun += smb->tx_underrun;
778015a6ef6SSaurabh Misra 	stat->tx_desc_underrun += smb->tx_desc_underrun;
779015a6ef6SSaurabh Misra 	stat->tx_lenerrs += smb->tx_lenerrs;
780015a6ef6SSaurabh Misra 	stat->tx_pkts_truncated += smb->tx_pkts_truncated;
781015a6ef6SSaurabh Misra 	stat->tx_bcast_bytes += smb->tx_bcast_bytes;
782015a6ef6SSaurabh Misra 	stat->tx_mcast_bytes += smb->tx_mcast_bytes;
783015a6ef6SSaurabh Misra 
784015a6ef6SSaurabh Misra 	/*
785015a6ef6SSaurabh Misra 	 * Update global counters in atge_t.
786015a6ef6SSaurabh Misra 	 */
787015a6ef6SSaurabh Misra 	atgep->atge_brdcstrcv += smb->rx_bcast_frames;
788015a6ef6SSaurabh Misra 	atgep->atge_multircv += smb->rx_mcast_frames;
789015a6ef6SSaurabh Misra 	atgep->atge_multixmt += smb->tx_mcast_frames;
790015a6ef6SSaurabh Misra 	atgep->atge_brdcstxmt += smb->tx_bcast_frames;
791015a6ef6SSaurabh Misra 
792015a6ef6SSaurabh Misra 	atgep->atge_align_errors += smb->rx_alignerrs;
793015a6ef6SSaurabh Misra 	atgep->atge_fcs_errors += smb->rx_crcerrs;
794015a6ef6SSaurabh Misra 	atgep->atge_sqe_errors += smb->rx_rrs_errs;
795015a6ef6SSaurabh Misra 	atgep->atge_defer_xmts += smb->tx_deferred;
796015a6ef6SSaurabh Misra 	atgep->atge_first_collisions += smb->tx_single_colls;
797015a6ef6SSaurabh Misra 	atgep->atge_multi_collisions += smb->tx_multi_colls * 2;
798015a6ef6SSaurabh Misra 	atgep->atge_tx_late_collisions += smb->tx_late_colls;
799015a6ef6SSaurabh Misra 	atgep->atge_ex_collisions += smb->tx_excess_colls;
800015a6ef6SSaurabh Misra 	atgep->atge_macxmt_errors += smb->tx_abort;
801015a6ef6SSaurabh Misra 	atgep->atge_toolong_errors += smb->rx_lenerrs;
802015a6ef6SSaurabh Misra 	atgep->atge_overflow += smb->rx_fifo_oflows;
803015a6ef6SSaurabh Misra 	atgep->atge_underflow += (smb->tx_underrun + smb->tx_desc_underrun);
804015a6ef6SSaurabh Misra 	atgep->atge_runt += smb->rx_runts;
805015a6ef6SSaurabh Misra 
806015a6ef6SSaurabh Misra 
807015a6ef6SSaurabh Misra 	atgep->atge_collisions += smb->tx_single_colls +
808015a6ef6SSaurabh Misra 	    smb->tx_multi_colls * 2 + smb->tx_late_colls +
809015a6ef6SSaurabh Misra 	    smb->tx_abort * HDPX_CFG_RETRY_DEFAULT;
810015a6ef6SSaurabh Misra 
811015a6ef6SSaurabh Misra 	/*
812015a6ef6SSaurabh Misra 	 * tx_pkts_truncated counter looks suspicious. It constantly
813015a6ef6SSaurabh Misra 	 * increments with no sign of Tx errors. Hence we don't factor it.
814015a6ef6SSaurabh Misra 	 */
815015a6ef6SSaurabh Misra 	atgep->atge_macxmt_errors += smb->tx_abort + smb->tx_late_colls +
816015a6ef6SSaurabh Misra 	    smb->tx_underrun;
817015a6ef6SSaurabh Misra 
818015a6ef6SSaurabh Misra 	atgep->atge_macrcv_errors += smb->rx_crcerrs + smb->rx_lenerrs +
819015a6ef6SSaurabh Misra 	    smb->rx_runts + smb->rx_pkts_truncated +
820015a6ef6SSaurabh Misra 	    smb->rx_fifo_oflows + smb->rx_rrs_errs +
821015a6ef6SSaurabh Misra 	    smb->rx_alignerrs;
822015a6ef6SSaurabh Misra }
823015a6ef6SSaurabh Misra 
824015a6ef6SSaurabh Misra void
atge_l1e_stop_mac(atge_t * atgep)825015a6ef6SSaurabh Misra atge_l1e_stop_mac(atge_t *atgep)
826015a6ef6SSaurabh Misra {
827015a6ef6SSaurabh Misra 	uint32_t reg;
828015a6ef6SSaurabh Misra 
829015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_MAC_CFG);
830015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() reg : %x", atgep->atge_name, __func__, reg));
831015a6ef6SSaurabh Misra 
832015a6ef6SSaurabh Misra 	if ((reg & (ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB)) != 0) {
833015a6ef6SSaurabh Misra 		reg &= ~ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
834015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_MAC_CFG, reg);
835015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() mac stopped", atgep->atge_name, __func__));
836015a6ef6SSaurabh Misra 	}
837015a6ef6SSaurabh Misra }
8380eb090a7SSaurabh Misra 
8390eb090a7SSaurabh Misra /*
8400eb090a7SSaurabh Misra  * The interrupt handler for L1E/L2E
8410eb090a7SSaurabh Misra  */
8420eb090a7SSaurabh Misra /*ARGSUSED*/
8430eb090a7SSaurabh Misra uint_t
atge_l1e_interrupt(caddr_t arg1,caddr_t arg2)8440eb090a7SSaurabh Misra atge_l1e_interrupt(caddr_t arg1, caddr_t arg2)
8450eb090a7SSaurabh Misra {
8460eb090a7SSaurabh Misra 	atge_t *atgep = (void *)arg1;
8470eb090a7SSaurabh Misra 	mblk_t *rx_head = NULL;
8480eb090a7SSaurabh Misra 	uint32_t status;
8490eb090a7SSaurabh Misra 	int resched = 0;
8500eb090a7SSaurabh Misra 
8510eb090a7SSaurabh Misra 	ASSERT(atgep != NULL);
8520eb090a7SSaurabh Misra 
8530eb090a7SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
8540eb090a7SSaurabh Misra 
8550eb090a7SSaurabh Misra 	if (atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
8560eb090a7SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
8570eb090a7SSaurabh Misra 		return (DDI_INTR_UNCLAIMED);
8580eb090a7SSaurabh Misra 	}
8590eb090a7SSaurabh Misra 
8600eb090a7SSaurabh Misra 	status = INL(atgep, ATGE_INTR_STATUS);
8610eb090a7SSaurabh Misra 	if (status == 0 || (status & atgep->atge_intrs) == 0) {
8620eb090a7SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
8630eb090a7SSaurabh Misra 
8640eb090a7SSaurabh Misra 		if (atgep->atge_flags & ATGE_FIXED_TYPE)
8650eb090a7SSaurabh Misra 			return (DDI_INTR_UNCLAIMED);
8660eb090a7SSaurabh Misra 
8670eb090a7SSaurabh Misra 		return (DDI_INTR_CLAIMED);
8680eb090a7SSaurabh Misra 	}
8690eb090a7SSaurabh Misra 
8700eb090a7SSaurabh Misra 	ATGE_DB(("%s: %s() entry status : %x",
8710eb090a7SSaurabh Misra 	    atgep->atge_name, __func__, status));
8720eb090a7SSaurabh Misra 
8730eb090a7SSaurabh Misra 
8740eb090a7SSaurabh Misra 	/*
8750eb090a7SSaurabh Misra 	 * Disable interrupts.
8760eb090a7SSaurabh Misra 	 */
8770eb090a7SSaurabh Misra 	OUTL(atgep, ATGE_INTR_STATUS, status | INTR_DIS_INT);
8780eb090a7SSaurabh Misra 	FLUSH(atgep, ATGE_INTR_STATUS);
8790eb090a7SSaurabh Misra 
8800eb090a7SSaurabh Misra 	/*
8810eb090a7SSaurabh Misra 	 * Check if chip is running, only then do the work.
8820eb090a7SSaurabh Misra 	 */
8830eb090a7SSaurabh Misra 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
8840eb090a7SSaurabh Misra 		if (status & INTR_SMB) {
8850eb090a7SSaurabh Misra 			atge_l1e_gather_stats(atgep);
8860eb090a7SSaurabh Misra 		}
8870eb090a7SSaurabh Misra 
8880eb090a7SSaurabh Misra 		/*
8890eb090a7SSaurabh Misra 		 * Check for errors.
8900eb090a7SSaurabh Misra 		 */
8910eb090a7SSaurabh Misra 		if (status & L1E_INTR_ERRORS) {
8920eb090a7SSaurabh Misra 			atge_error(atgep->atge_dip,
8930eb090a7SSaurabh Misra 			    "L1E chip found an error intr status : %x",
8940eb090a7SSaurabh Misra 			    status);
8950eb090a7SSaurabh Misra 
8960eb090a7SSaurabh Misra 			if (status &
8970eb090a7SSaurabh Misra 			    (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST)) {
8980eb090a7SSaurabh Misra 				atge_error(atgep->atge_dip, "DMA transfer err");
8990eb090a7SSaurabh Misra 
9000eb090a7SSaurabh Misra 				atge_device_stop(atgep);
9010eb090a7SSaurabh Misra 				goto done;
9020eb090a7SSaurabh Misra 			}
9030eb090a7SSaurabh Misra 
9040eb090a7SSaurabh Misra 			if (status & INTR_TX_FIFO_UNDERRUN) {
9050eb090a7SSaurabh Misra 				atge_error(atgep->atge_dip, "TX FIFO underrun");
9060eb090a7SSaurabh Misra 			}
9070eb090a7SSaurabh Misra 		}
9080eb090a7SSaurabh Misra 
9090eb090a7SSaurabh Misra 		rx_head = atge_l1e_receive(atgep);
9100eb090a7SSaurabh Misra 
9110eb090a7SSaurabh Misra 		if (status & INTR_TX_PKT) {
9120eb090a7SSaurabh Misra 			int cons;
9130eb090a7SSaurabh Misra 
9140eb090a7SSaurabh Misra 			mutex_enter(&atgep->atge_tx_lock);
9150eb090a7SSaurabh Misra 			cons = INW(atgep, L1E_TPD_CONS_IDX);
9160eb090a7SSaurabh Misra 			atge_tx_reclaim(atgep, cons);
9170eb090a7SSaurabh Misra 			if (atgep->atge_tx_resched) {
9180eb090a7SSaurabh Misra 				atgep->atge_tx_resched = 0;
9190eb090a7SSaurabh Misra 				resched = 1;
9200eb090a7SSaurabh Misra 			}
9210eb090a7SSaurabh Misra 
9220eb090a7SSaurabh Misra 			mutex_exit(&atgep->atge_tx_lock);
9230eb090a7SSaurabh Misra 		}
9240eb090a7SSaurabh Misra 	}
9250eb090a7SSaurabh Misra 
9260eb090a7SSaurabh Misra 	/*
9270eb090a7SSaurabh Misra 	 * Enable interrupts.
9280eb090a7SSaurabh Misra 	 */
9290eb090a7SSaurabh Misra 	OUTL(atgep, ATGE_INTR_STATUS, 0);
9300eb090a7SSaurabh Misra 
9310eb090a7SSaurabh Misra done:
9320eb090a7SSaurabh Misra 
9330eb090a7SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
9340eb090a7SSaurabh Misra 
9350eb090a7SSaurabh Misra 	if (status & INTR_GPHY) {
9360eb090a7SSaurabh Misra 		/*
9370eb090a7SSaurabh Misra 		 * Ack interrupts from PHY
9380eb090a7SSaurabh Misra 		 */
9390eb090a7SSaurabh Misra 		(void) atge_mii_read(atgep,
9400eb090a7SSaurabh Misra 		    atgep->atge_phyaddr, ATGE_ISR_ACK_GPHY);
9410eb090a7SSaurabh Misra 
9420eb090a7SSaurabh Misra 		mii_check(atgep->atge_mii);
9430eb090a7SSaurabh Misra 	}
9440eb090a7SSaurabh Misra 
9450eb090a7SSaurabh Misra 	/*
9460eb090a7SSaurabh Misra 	 * Pass the list of packets received from chip to MAC layer.
9470eb090a7SSaurabh Misra 	 */
9480eb090a7SSaurabh Misra 	if (rx_head) {
9490eb090a7SSaurabh Misra 		mac_rx(atgep->atge_mh, 0, rx_head);
9500eb090a7SSaurabh Misra 	}
9510eb090a7SSaurabh Misra 
9520eb090a7SSaurabh Misra 	/*
9530eb090a7SSaurabh Misra 	 * Let MAC start sending pkts if the downstream was asked to pause.
9540eb090a7SSaurabh Misra 	 */
9550eb090a7SSaurabh Misra 	if (resched)
9560eb090a7SSaurabh Misra 		mac_tx_update(atgep->atge_mh);
9570eb090a7SSaurabh Misra 
9580eb090a7SSaurabh Misra 	return (DDI_INTR_CLAIMED);
9590eb090a7SSaurabh Misra }
960