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