xref: /illumos-gate/usr/src/uts/common/io/chxge/com/pm3393.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
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) 2003-2005 Chelsio Communications.  All rights reserved.
24  */
25 
26 #include "common.h"
27 #include "regs.h"
28 #include "gmac.h"
29 #include "elmer0.h"
30 #include "suni1x10gexp_regs.h"
31 
32 /* 802.3ae 10Gb/s MDIO Manageable Device(MMD)
33  */
34 #define MMD_RESERVED        0
35 #define MMD_PMAPMD          1
36 #define MMD_WIS             2
37 #define MMD_PCS             3
38 #define MMD_PHY_XGXS        4	/* XGMII Extender Sublayer */
39 #define MMD_DTE_XGXS        5
40 
41 #define PHY_XGXS_CTRL_1     0
42 #define PHY_XGXS_STATUS_1   1
43 
44 #define OFFSET(REG_ADDR)    (REG_ADDR << 2)
45 
46 /* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */
47 #define MAX_FRAME_SIZE  9600
48 
49 #define IPG 12
50 #define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \
51     SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \
52     SUNI1x10GEXP_BITMSK_TXXG_PADEN)
53 #define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \
54     SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP)
55 
56 /* Update statistics every 15 minutes */
57 #define STATS_TICK_SECS (15 * 60)
58 
59 enum {                     /* RMON registers */
60 	RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW,
61 	RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW,
62 	RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW,
63 	RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW,
64 	RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW,
65 	RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW,
66 	RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW,
67 	RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW,
68 	RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW,
69 	RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW,
70 	RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW,
71 	RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW,
72 	RxUndersizedFrames =  SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW,
73 	RxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_25_LOW,
74 	RxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_26_LOW,
75 
76 	TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW,
77 	TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW,
78 	TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW,
79 	TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW,
80 	TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW,
81 	TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW,
82 	TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW,
83 	TxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_51_LOW,
84 	TxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_52_LOW
85 };
86 
87 struct _cmac_instance {
88 	u8 enabled;
89 	u8 fc;
90 	u8 mac_addr[6];
91 };
92 
93 static int pmread(struct cmac *cmac, u32 reg, u32 * data32)
94 {
95 	(void) t1_tpi_read(cmac->adapter, OFFSET(reg), data32);
96 	return 0;
97 }
98 
99 static int pmwrite(struct cmac *cmac, u32 reg, u32 data32)
100 {
101 	(void) t1_tpi_write(cmac->adapter, OFFSET(reg), data32);
102 	return 0;
103 }
104 
105 /* Port reset. */
106 /* ARGSUSED */
107 static int pm3393_reset(struct cmac *cmac)
108 {
109 	return 0;
110 }
111 
112 /*
113  * Enable interrupts for the PM3393
114 
115     1. Enable PM3393 BLOCK interrupts.
116     2. Enable PM3393 Master Interrupt bit(INTE)
117     3. Enable ELMER's PM3393 bit.
118     4. Enable Terminator external interrupt.
119 */
120 static int pm3393_interrupt_enable(struct cmac *cmac)
121 {
122 #if 0
123 	u32 elmer;
124 #endif
125 	u32 pl_intr;
126 
127 	/* PM3393 - Enabling all hardware block interrupts.
128 	 */
129 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff);
130 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff);
131 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff);
132 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff);
133 
134 	/* Don't interrupt on statistics overflow, we are polling */
135 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
136 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
137 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
138 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
139 
140 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff);
141 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff);
142 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff);
143 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff);
144 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff);
145 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff);
146 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff);
147 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff);
148 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff);
149 
150 	/* PM3393 - Global interrupt enable
151 	 */
152 	/* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */
153 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE,
154 		0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ );
155 
156 #if 0
157 	/* ELMER - External chip interrupts.
158 	 */
159 	(void) t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);
160 	elmer |= ELMER0_GP_BIT1;
161 	(void) t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);
162 #endif
163 
164 	/* TERMINATOR - PL_INTERUPTS_EXT */
165 	pl_intr = t1_read_reg_4(cmac->adapter, A_PL_ENABLE);
166 	pl_intr |= F_PL_INTR_EXT;
167 	t1_write_reg_4(cmac->adapter, A_PL_ENABLE, pl_intr);
168 	return 0;
169 }
170 
171 static int pm3393_interrupt_disable(struct cmac *cmac)
172 {
173 	u32 elmer;
174 
175 	/* PM3393 - Enabling HW interrupt blocks. */
176 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0);
177 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0);
178 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0);
179 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0);
180 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
181 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
182 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
183 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
184 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0);
185 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0);
186 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0);
187 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0);
188 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0);
189 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0);
190 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0);
191 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0);
192 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0);
193 
194 	/* PM3393 - Global interrupt enable */
195 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0);
196 
197 	/* ELMER - External chip interrupts. */
198 	(void) t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);
199 	elmer &= ~ELMER0_GP_BIT1;
200 	(void) t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);
201 
202 	/* TERMINATOR - PL_INTERUPTS_EXT */
203 	/* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP
204 	 * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level.
205 	 */
206 
207 	return 0;
208 }
209 
210 static int pm3393_interrupt_clear(struct cmac *cmac)
211 {
212 	u32 elmer;
213 	u32 pl_intr;
214 	u32 val32;
215 
216 	/* PM3393 - Clearing HW interrupt blocks. Note, this assumes
217 	 *          bit WCIMODE=0 for a clear-on-read.
218 	 */
219 	(void) pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32);
220 	(void) pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32);
221 	(void) pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32);
222 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32);
223 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32);
224 	(void) pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32);
225 	(void) pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32);
226 	(void) pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32);
227 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32);
228 	(void) pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32);
229 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32);
230 	(void) pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION,
231 	       &val32);
232 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32);
233 	(void) pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32);
234 
235 	/* PM3393 - Global interrupt status
236 	 */
237 	(void) pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32);
238 
239 	/* ELMER - External chip interrupts.
240 	 */
241 	(void) t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer);
242 	elmer |= ELMER0_GP_BIT1;
243 	(void) t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer);
244 
245 	/* TERMINATOR - PL_INTERUPTS_EXT
246 	 */
247 	pl_intr = t1_read_reg_4(cmac->adapter, A_PL_CAUSE);
248 	pl_intr |= F_PL_INTR_EXT;
249 	t1_write_reg_4(cmac->adapter, A_PL_CAUSE, pl_intr);
250 
251 	return 0;
252 }
253 
254 /* Interrupt handler */
255 static int pm3393_interrupt_handler(struct cmac *cmac)
256 {
257 	u32 master_intr_status;
258 /*
259     1. Read master interrupt register.
260     2. Read BLOCK's interrupt status registers.
261     3. Handle BLOCK interrupts.
262 */
263 	/* Read the master interrupt status register. */
264 	(void) pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS,
265 	       &master_intr_status);
266 	CH_DBG(cmac->adapter, INTR, "PM3393 intr cause 0x%x\n",
267 	       master_intr_status);
268 
269 	/* Handle BLOCK's interrupts. */
270 
271 	if (SUNI1x10GEXP_BITMSK_TOP_PL4IO_INT & master_intr_status) {
272 		/* EMPTY */
273 	}
274 
275 	if (SUNI1x10GEXP_BITMSK_TOP_IRAM_INT & master_intr_status) {
276 		/* EMPTY */
277 	}
278 
279 	if (SUNI1x10GEXP_BITMSK_TOP_ERAM_INT & master_intr_status) {
280 		/* EMPTY */
281 	}
282 
283 	/* SERDES */
284 	if (SUNI1x10GEXP_BITMSK_TOP_XAUI_INT & master_intr_status) {
285 		/* EMPTY */
286 	}
287 
288 	/* MSTAT */
289 	if (SUNI1x10GEXP_BITMSK_TOP_MSTAT_INT & master_intr_status) {
290 		/* EMPTY */
291 	}
292 
293 	/* RXXG */
294 	if (SUNI1x10GEXP_BITMSK_TOP_RXXG_INT & master_intr_status) {
295 		/* EMPTY */
296 	}
297 
298 	/* TXXG */
299 	if (SUNI1x10GEXP_BITMSK_TOP_TXXG_INT & master_intr_status) {
300 		/* EMPTY */
301 	}
302 
303 	/* XRF */
304 	if (SUNI1x10GEXP_BITMSK_TOP_XRF_INT & master_intr_status) {
305 		/* EMPTY */
306 	}
307 
308 	/* XTEF */
309 	if (SUNI1x10GEXP_BITMSK_TOP_XTEF_INT & master_intr_status) {
310 		/* EMPTY */
311 	}
312 
313 	/* MDIO */
314 	if (SUNI1x10GEXP_BITMSK_TOP_MDIO_BUSY_INT & master_intr_status) {
315 		/* Not used. 8000 uses MDIO through Elmer. */
316 		/* EMPTY */
317 	}
318 
319 	/* RXOAM */
320 	if (SUNI1x10GEXP_BITMSK_TOP_RXOAM_INT & master_intr_status) {
321 		/* EMPTY */
322 	}
323 
324 	/* TXOAM */
325 	if (SUNI1x10GEXP_BITMSK_TOP_TXOAM_INT & master_intr_status) {
326 		/* EMPTY */
327 	}
328 
329 	/* IFLX */
330 	if (SUNI1x10GEXP_BITMSK_TOP_IFLX_INT & master_intr_status) {
331 		/* EMPTY */
332 	}
333 
334 	/* EFLX */
335 	if (SUNI1x10GEXP_BITMSK_TOP_EFLX_INT & master_intr_status) {
336 		/* EMPTY */
337 	}
338 
339 	/* PL4ODP */
340 	if (SUNI1x10GEXP_BITMSK_TOP_PL4ODP_INT & master_intr_status) {
341 		/* EMPTY */
342 	}
343 
344 	/* PL4IDU */
345 	if (SUNI1x10GEXP_BITMSK_TOP_PL4IDU_INT & master_intr_status) {
346 		/* EMPTY */
347 	}
348 
349 	/* TBD XXX Lets just clear everything for now */
350 	(void) pm3393_interrupt_clear(cmac);
351 
352 	return 0;
353 }
354 
355 static int pm3393_enable(struct cmac *cmac, int which)
356 {
357 	if (which & MAC_DIRECTION_RX)
358 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1,
359 			(RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN));
360 
361 	if (which & MAC_DIRECTION_TX) {
362 		u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0;
363 
364 		if (cmac->instance->fc & PAUSE_RX)
365 			val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX;
366 		if (cmac->instance->fc & PAUSE_TX)
367 			val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX;
368 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val);
369 	}
370 
371 	cmac->instance->enabled |= which;
372 	return 0;
373 }
374 
375 /* ARGSUSED */
376 static int pm3393_enable_port(struct cmac *cmac, int which)
377 {
378 	/* Clear port statistics */
379 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
380 		SUNI1x10GEXP_BITMSK_MSTAT_CLEAR);
381 	DELAY_US(2);
382 	(void) memset(&cmac->stats, 0, sizeof(struct cmac_statistics));
383 
384 	(void) pm3393_enable(cmac, which);
385 
386 	/*
387 	 * XXX This should be done by the PHY and preferrably not at all.
388 	 * The PHY doesn't give us link status indication on its own so have
389 	 * the link management code query it instead.
390 	 */
391 	{
392 		extern void link_changed(adapter_t *adapter, int port_id);
393 		link_changed(cmac->adapter, 0);
394 	}
395 	return 0;
396 }
397 
398 static int pm3393_disable(struct cmac *cmac, int which)
399 {
400 	if (which & MAC_DIRECTION_RX)
401 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL);
402 	if (which & MAC_DIRECTION_TX)
403 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL);
404 
405 	/*
406 	 * The disable is graceful. Give the PM3393 time.  Can't wait very
407 	 * long here, we may be holding locks.
408 	 */
409 	DELAY_US(20);
410 
411 	cmac->instance->enabled &= ~which;
412 	return 0;
413 }
414 
415 /* ARGSUSED */
416 static int pm3393_loopback_enable(struct cmac *cmac)
417 {
418 	return 0;
419 }
420 
421 /* ARGSUSED */
422 static int pm3393_loopback_disable(struct cmac *cmac)
423 {
424 	return 0;
425 }
426 
427 static int pm3393_set_mtu(struct cmac *cmac, int mtu)
428 {
429 	int enabled = cmac->instance->enabled;
430 
431 	/* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */
432 	mtu += 14 + 4;
433 	if (mtu > MAX_FRAME_SIZE)
434 		return -EINVAL;
435 
436 	/* Disable Rx/Tx MAC before configuring it. */
437 	if (enabled)
438 		(void) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
439 
440 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu);
441 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu);
442 
443 	if (enabled)
444 		(void) pm3393_enable(cmac, enabled);
445 	return 0;
446 }
447 
448 static u32 calc_crc(u8 *b, int len)
449 {
450         int i;
451 	u32 crc = (u32)~0;
452 
453 	/* calculate crc one bit at a time */
454         while (len--) {
455                 crc ^= *b++;
456                 for (i = 0; i < 8; i++) {
457 			if (crc & 0x1)
458 				crc = (crc >> 1) ^ 0xedb88320;
459 			else
460 				crc = (crc >> 1);
461 		}
462         }
463 
464 	/* reverse bits */
465         crc = ((crc >> 4) & 0x0f0f0f0f) | ((crc << 4) & 0xf0f0f0f0);
466         crc = ((crc >> 2) & 0x33333333) | ((crc << 2) & 0xcccccccc);
467         crc = ((crc >> 1) & 0x55555555) | ((crc << 1) & 0xaaaaaaaa);
468 	/* swap bytes */
469         crc = (crc >> 16) | (crc << 16);
470         crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
471 
472         return crc;
473 }
474 
475 static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm)
476 {
477 	int enabled = cmac->instance->enabled & MAC_DIRECTION_RX;
478 	u32 rx_mode;
479 
480 	/* Disable MAC RX before reconfiguring it */
481 	if (enabled)
482 		(void) pm3393_disable(cmac, MAC_DIRECTION_RX);
483 
484 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode);
485 	rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE | SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN);
486 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode);
487 
488         if (t1_rx_mode_promisc(rm)) {
489                 /* Promiscuous mode. */
490 		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE;
491         }
492 	if (t1_rx_mode_allmulti(rm)) {
493                 /* Accept all multicast. */
494 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff);
495 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff);
496 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff);
497 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff);
498 		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
499         } else if (t1_rx_mode_mc_cnt(rm)) {
500                 /* Accept one or more multicast(s). */
501 		u8 *addr;
502 		int bit;
503 		u16 mc_filter[4] = { 0, };
504 
505 		while ((addr = t1_get_next_mcaddr(rm))) {
506 			bit = (calc_crc(addr, ETH_ALEN) >> 23) & 0x3f;	/* bit[23:28] */
507 			mc_filter[bit >> 4] |= 1 << (bit & 0xf);
508 		}
509 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]);
510 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]);
511 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]);
512 		(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]);
513 		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
514         }
515 
516 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode);
517 
518 	if (enabled)
519 		(void) pm3393_enable(cmac, MAC_DIRECTION_RX);
520 
521 	return 0;
522 }
523 
524 static int pm3393_get_speed_duplex_fc(struct cmac *cmac, int *speed,
525 				      int *duplex, int *fc)
526 {
527 	if (speed)
528 		*speed = SPEED_10000;
529 	if (duplex)
530 		*duplex = DUPLEX_FULL;
531 	if (fc)
532 		*fc = cmac->instance->fc;
533 	return 0;
534 }
535 
536 static int pm3393_set_speed_duplex_fc(struct cmac *cmac, int speed, int duplex,
537 				      int fc)
538 {
539 	if (speed >= 0 && speed != SPEED_10000)
540 		return -1;
541 	if (duplex >= 0 && duplex != DUPLEX_FULL)
542 		return -1;
543 	if (fc & ~(PAUSE_TX | PAUSE_RX))
544 		return -1;
545 
546 	if (fc != cmac->instance->fc) {
547 		cmac->instance->fc = (u8) fc;
548 		if (cmac->instance->enabled & MAC_DIRECTION_TX)
549 			(void) pm3393_enable(cmac, MAC_DIRECTION_TX);
550 	}
551 	return 0;
552 }
553 
554 #define RMON_UPDATE(mac, name, stat_name) \
555 	{ \
556 		(void) t1_tpi_read((mac)->adapter, OFFSET(name), &val0);	\
557 		(void) t1_tpi_read((mac)->adapter, OFFSET(((name)+1)), &val1); \
558 		(void) t1_tpi_read((mac)->adapter, OFFSET(((name)+2)), &val2); \
559 		(mac)->stats.stat_name = (u16)val0  | (((u16)val1) << 16) \
560 						   | ((u64)((u8)val2) << 32) \
561 						   | ((mac)->stats.stat_name & (~(u64)0 << 40)); \
562 		if (ro & ((name -  SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)) \
563 			(mac)->stats.stat_name += ((u64)1 << 40); \
564 	}
565 
566 /* ARGSUSED */
567 static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
568 							      int flag)
569 {
570 	u64	ro;
571 	u32	val0, val1, val2, val3;
572 
573 	/* Snap the counters */
574 	(void) pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
575 		SUNI1x10GEXP_BITMSK_MSTAT_SNAP);
576 
577 	/* Counter rollover, clear on read */
578 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0, &val0);
579 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1, &val1);
580 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2, &val2);
581 	(void) pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3, &val3);
582 	ro = (u16)val0 | (((u16)val1) << 16) | ((u64)((u16)val2) << 32)
583 	     | ((u64)((u16)val3) << 48);
584 
585 	/* Rx stats */
586 	RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
587 	RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
588 	RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
589 	RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
590 	RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
591 	RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
592 	RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors, RxInternalMACRcvError);
593 	RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
594 	RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
595 	RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
596 	RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
597 	RMON_UPDATE(mac, RxFragments, RxRuntErrors);
598 	RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
599 
600 	/* Tx stats */
601 	RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
602 	RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError, TxInternalMACXmitError);
603 	RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
604 	RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
605 	RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
606 	RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
607 	RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
608 
609 	return &mac->stats;
610 }
611 
612 static int pm3393_macaddress_get(struct cmac *cmac, u8 mac_addr[6])
613 {
614 	memcpy(mac_addr, cmac->instance->mac_addr, 6);
615 	return 0;
616 }
617 
618 static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
619 {
620 	u32 val, lo, mid, hi, enabled = cmac->instance->enabled;
621 
622 	/*
623 	 * MAC addr: 00:07:43:00:13:09
624 	 *
625 	 * ma[5] = 0x09
626 	 * ma[4] = 0x13
627 	 * ma[3] = 0x00
628 	 * ma[2] = 0x43
629 	 * ma[1] = 0x07
630 	 * ma[0] = 0x00
631 	 *
632 	 * The PM3393 requires byte swapping and reverse order entry
633 	 * when programming MAC addresses:
634 	 *
635 	 * low_bits[15:0]    = ma[1]:ma[0]
636 	 * mid_bits[31:16]   = ma[3]:ma[2]
637 	 * high_bits[47:32]  = ma[5]:ma[4]
638 	 */
639 
640 	/* Store local copy */
641 	memcpy(cmac->instance->mac_addr, ma, 6);
642 
643 	lo = ((u32) ma[1] << 8) | (u32) ma[0];
644 	mid = ((u32) ma[3] << 8) | (u32) ma[2];
645 	hi = ((u32) ma[5] << 8) | (u32) ma[4];
646 
647 	/* Disable Rx/Tx MAC before configuring it. */
648 	if (enabled)
649 		(void) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
650 
651 	/* Set RXXG Station Address */
652 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_15_0, lo);
653 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_31_16, mid);
654 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_47_32, hi);
655 
656 	/* Set TXXG Station Address */
657 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_15_0, lo);
658 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_31_16, mid);
659 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_47_32, hi);
660 
661 	/* Setup Exact Match Filter 1 with our MAC address
662 	 *
663 	 * Must disable exact match filter before configuring it.
664 	 */
665 	(void) pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, &val);
666 	val &= 0xff0f;
667 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
668 
669 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW, lo);
670 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID, mid);
671 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH, hi);
672 
673 	val |= 0x0090;
674 	(void) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
675 
676 	if (enabled)
677 		(void) pm3393_enable(cmac, enabled);
678 	return 0;
679 }
680 
681 static void pm3393_destroy(struct cmac *cmac)
682 {
683 	t1_os_free((void *)cmac, sizeof(*cmac) + sizeof(cmac_instance));
684 }
685 
686 #ifdef C99_NOT_SUPPORTED
687 static struct cmac_ops pm3393_ops = {
688 	pm3393_destroy,
689 	pm3393_reset,
690 	pm3393_interrupt_enable,
691 	pm3393_interrupt_disable,
692 	pm3393_interrupt_clear,
693 	pm3393_interrupt_handler,
694 	pm3393_enable,
695 	pm3393_disable,
696 	pm3393_loopback_enable,
697 	pm3393_loopback_disable,
698 	pm3393_set_mtu,
699 	pm3393_set_rx_mode,
700 	pm3393_set_speed_duplex_fc,
701 	pm3393_get_speed_duplex_fc,
702 	pm3393_update_statistics,
703 	pm3393_macaddress_get,
704 	pm3393_macaddress_set
705 };
706 #else
707 static struct cmac_ops pm3393_ops = {
708 	.destroy                 = pm3393_destroy,
709 	.reset                   = pm3393_reset,
710 	.interrupt_enable        = pm3393_interrupt_enable,
711 	.interrupt_disable       = pm3393_interrupt_disable,
712 	.interrupt_clear         = pm3393_interrupt_clear,
713 	.interrupt_handler       = pm3393_interrupt_handler,
714 	.enable                  = pm3393_enable_port,
715 	.disable                 = pm3393_disable,
716 	.loopback_enable         = pm3393_loopback_enable,
717 	.loopback_disable        = pm3393_loopback_disable,
718 	.set_mtu                 = pm3393_set_mtu,
719 	.set_rx_mode             = pm3393_set_rx_mode,
720 	.get_speed_duplex_fc     = pm3393_get_speed_duplex_fc,
721 	.set_speed_duplex_fc     = pm3393_set_speed_duplex_fc,
722 	.statistics_update       = pm3393_update_statistics,
723 	.macaddress_get          = pm3393_macaddress_get,
724 	.macaddress_set          = pm3393_macaddress_set
725 };
726 #endif
727 
728 /* ARGSUSED */
729 static struct cmac *pm3393_mac_create(adapter_t *adapter, int index)
730 {
731 	struct cmac *cmac;
732 
733 	cmac = t1_os_malloc_wait_zero(sizeof(*cmac) + sizeof(cmac_instance));
734 	if (!cmac)
735 		return NULL;
736 
737 	cmac->ops = &pm3393_ops;
738 	cmac->instance = (cmac_instance *) (cmac + 1);
739 	cmac->adapter = adapter;
740 	cmac->instance->fc = PAUSE_TX | PAUSE_RX;
741 
742 	(void) t1_tpi_write(adapter, OFFSET(0x0001), 0x00008000);
743 	(void) t1_tpi_write(adapter, OFFSET(0x0001), 0x00000000);
744 	(void) t1_tpi_write(adapter, OFFSET(0x2308), 0x00009800);
745 	(void) t1_tpi_write(adapter, OFFSET(0x2305), 0x00001001);   /* PL4IO Enable */
746 	(void) t1_tpi_write(adapter, OFFSET(0x2320), 0x00008800);
747 	(void) t1_tpi_write(adapter, OFFSET(0x2321), 0x00008800);
748 	(void) t1_tpi_write(adapter, OFFSET(0x2322), 0x00008800);
749 	(void) t1_tpi_write(adapter, OFFSET(0x2323), 0x00008800);
750 	(void) t1_tpi_write(adapter, OFFSET(0x2324), 0x00008800);
751 	(void) t1_tpi_write(adapter, OFFSET(0x2325), 0x00008800);
752 	(void) t1_tpi_write(adapter, OFFSET(0x2326), 0x00008800);
753 	(void) t1_tpi_write(adapter, OFFSET(0x2327), 0x00008800);
754 	(void) t1_tpi_write(adapter, OFFSET(0x2328), 0x00008800);
755 	(void) t1_tpi_write(adapter, OFFSET(0x2329), 0x00008800);
756 	(void) t1_tpi_write(adapter, OFFSET(0x232a), 0x00008800);
757 	(void) t1_tpi_write(adapter, OFFSET(0x232b), 0x00008800);
758 	(void) t1_tpi_write(adapter, OFFSET(0x232c), 0x00008800);
759 	(void) t1_tpi_write(adapter, OFFSET(0x232d), 0x00008800);
760 	(void) t1_tpi_write(adapter, OFFSET(0x232e), 0x00008800);
761 	(void) t1_tpi_write(adapter, OFFSET(0x232f), 0x00008800);
762 	(void) t1_tpi_write(adapter, OFFSET(0x230d), 0x00009c00);
763 	(void) t1_tpi_write(adapter, OFFSET(0x2304), 0x00000202);	/* PL4IO Calendar Repetitions */
764 
765 	(void) t1_tpi_write(adapter, OFFSET(0x3200), 0x00008080);	/* EFLX Enable */
766 	(void) t1_tpi_write(adapter, OFFSET(0x3210), 0x00000000);	/* EFLX Channel Deprovision */
767 	(void) t1_tpi_write(adapter, OFFSET(0x3203), 0x00000000);	/* EFLX Low Limit */
768 	(void) t1_tpi_write(adapter, OFFSET(0x3204), 0x00000040);	/* EFLX High Limit */
769 	(void) t1_tpi_write(adapter, OFFSET(0x3205), 0x000002cc);	/* EFLX Almost Full */
770 	(void) t1_tpi_write(adapter, OFFSET(0x3206), 0x00000199);	/* EFLX Almost Empty */
771 	(void) t1_tpi_write(adapter, OFFSET(0x3207), 0x00000240);	/* EFLX Cut Through Threshold */
772 	(void) t1_tpi_write(adapter, OFFSET(0x3202), 0x00000000);	/* EFLX Indirect Register Update */
773 	(void) t1_tpi_write(adapter, OFFSET(0x3210), 0x00000001);	/* EFLX Channel Provision */
774 	(void) t1_tpi_write(adapter, OFFSET(0x3208), 0x0000ffff);	/* EFLX Undocumented */
775 	(void) t1_tpi_write(adapter, OFFSET(0x320a), 0x0000ffff);	/* EFLX Undocumented */
776 	(void) t1_tpi_write(adapter, OFFSET(0x320c), 0x0000ffff);	/* EFLX enable overflow interrupt The other bit are undocumented */
777 	(void) t1_tpi_write(adapter, OFFSET(0x320e), 0x0000ffff);	/* EFLX Undocumented */
778 
779 	(void) t1_tpi_write(adapter, OFFSET(0x2200), 0x0000c000);	/* IFLX Configuration - enable */
780 	(void) t1_tpi_write(adapter, OFFSET(0x2201), 0x00000000);	/* IFLX Channel Deprovision */
781 	(void) t1_tpi_write(adapter, OFFSET(0x220e), 0x00000000);	/* IFLX Low Limit */
782 	(void) t1_tpi_write(adapter, OFFSET(0x220f), 0x00000100);	/* IFLX High Limit */
783 	(void) t1_tpi_write(adapter, OFFSET(0x2210), 0x00000c00);	/* IFLX Almost Full Limit */
784 	(void) t1_tpi_write(adapter, OFFSET(0x2211), 0x00000599);	/* IFLX Almost Empty Limit */
785 	(void) t1_tpi_write(adapter, OFFSET(0x220d), 0x00000000);	/* IFLX Indirect Register Update */
786 	(void) t1_tpi_write(adapter, OFFSET(0x2201), 0x00000001);	/* IFLX Channel Provision */
787 	(void) t1_tpi_write(adapter, OFFSET(0x2203), 0x0000ffff);	/* IFLX Undocumented */
788 	(void) t1_tpi_write(adapter, OFFSET(0x2205), 0x0000ffff);	/* IFLX Undocumented */
789 	(void) t1_tpi_write(adapter, OFFSET(0x2209), 0x0000ffff);	/* IFLX Enable overflow interrupt.  The other bit are undocumented */
790 
791 	(void) t1_tpi_write(adapter, OFFSET(0x2241), 0xfffffffe);	/* PL4MOS Undocumented */
792 	(void) t1_tpi_write(adapter, OFFSET(0x2242), 0x0000ffff);	/* PL4MOS Undocumented */
793 	(void) t1_tpi_write(adapter, OFFSET(0x2243), 0x00000008);	/* PL4MOS Starving Burst Size */
794 	(void) t1_tpi_write(adapter, OFFSET(0x2244), 0x00000008);	/* PL4MOS Hungry Burst Size */
795 	(void) t1_tpi_write(adapter, OFFSET(0x2245), 0x00000008);	/* PL4MOS Transfer Size */
796 	(void) t1_tpi_write(adapter, OFFSET(0x2240), 0x00000005);	/* PL4MOS Disable */
797 
798 	(void) t1_tpi_write(adapter, OFFSET(0x2280), 0x00002103);	/* PL4ODP Training Repeat and SOP rule */
799 	(void) t1_tpi_write(adapter, OFFSET(0x2284), 0x00000000);	/* PL4ODP MAX_T setting */
800 
801 	(void) t1_tpi_write(adapter, OFFSET(0x3280), 0x00000087);	/* PL4IDU Enable data forward, port state machine. Set ALLOW_NON_ZERO_OLB */
802 	(void) t1_tpi_write(adapter, OFFSET(0x3282), 0x0000001f);	/* PL4IDU Enable Dip4 check error interrupts */
803 
804 	(void) t1_tpi_write(adapter, OFFSET(0x3040), 0x0c32);	/* # TXXG Config */
805 	/* For T1 use timer based Mac flow control. */
806 	(void) t1_tpi_write(adapter, OFFSET(0x304d), 0x8000);
807 	(void) t1_tpi_write(adapter, OFFSET(0x2040), 0x059c);	/* # RXXG Config */
808 	(void) t1_tpi_write(adapter, OFFSET(0x2049), 0x0001);	/* # RXXG Cut Through */
809 	(void) t1_tpi_write(adapter, OFFSET(0x2070), 0x0000);	/* # Disable promiscuous mode */
810 
811 	/* Setup Exact Match Filter 0 to allow broadcast packets.
812 	 */
813 	(void) t1_tpi_write(adapter, OFFSET(0x206e), 0x0000);	/* # Disable Match Enable bit */
814 	(void) t1_tpi_write(adapter, OFFSET(0x204a), 0xffff);	/* # low addr */
815 	(void) t1_tpi_write(adapter, OFFSET(0x204b), 0xffff);	/* # mid addr */
816 	(void) t1_tpi_write(adapter, OFFSET(0x204c), 0xffff);	/* # high addr */
817 	(void) t1_tpi_write(adapter, OFFSET(0x206e), 0x0009);	/* # Enable Match Enable bit */
818 
819 	(void) t1_tpi_write(adapter, OFFSET(0x0003), 0x0000);	/* # NO SOP/ PAD_EN setup */
820 	(void) t1_tpi_write(adapter, OFFSET(0x0100), 0x0ff0);	/* # RXEQB disabled */
821 	(void) t1_tpi_write(adapter, OFFSET(0x0101), 0x0f0f);	/* # No Preemphasis */
822 
823 	return cmac;
824 }
825 
826 static int pm3393_mac_reset(adapter_t * adapter)
827 {
828 	u32 val;
829 	u32 x;
830 	u32 is_pl4_reset_finished;
831 	u32 is_pl4_outof_lock;
832 	u32 is_xaui_mabc_pll_locked;
833 	u32 successful_reset;
834 	int i;
835 
836 	/* The following steps are required to properly reset
837 	 * the PM3393. This information is provided in the
838 	 * PM3393 datasheet (Issue 2: November 2002)
839 	 * section 13.1 -- Device Reset.
840 	 *
841 	 * The PM3393 has three types of components that are
842 	 * individually reset:
843 	 *
844 	 * DRESETB      - Digital circuitry
845 	 * PL4_ARESETB  - PL4 analog circuitry
846 	 * XAUI_ARESETB - XAUI bus analog circuitry
847 	 *
848 	 * Steps to reset PM3393 using RSTB pin:
849 	 *
850 	 * 1. Assert RSTB pin low ( write 0 )
851 	 * 2. Wait at least 1ms to initiate a complete initialization of device.
852 	 * 3. Wait until all external clocks and REFSEL are stable.
853 	 * 4. Wait minimum of 1ms. (after external clocks and REFEL are stable)
854 	 * 5. De-assert RSTB ( write 1 )
855 	 * 6. Wait until internal timers to expires after ~14ms.
856 	 *    - Allows analog clock synthesizer(PL4CSU) to stabilize to
857 	 *      selected reference frequency before allowing the digital
858 	 *      portion of the device to operate.
859 	 * 7. Wait at least 200us for XAUI interface to stabilize.
860 	 * 8. Verify the PM3393 came out of reset successfully.
861 	 *    Set successful reset flag if everything worked else try again
862 	 *    a few more times.
863 	 */
864 
865 	successful_reset = 0;
866 	for (i = 0; i < 3 && !successful_reset; i++) {
867 		/* 1 */
868 		(void) t1_tpi_read(adapter, A_ELMER0_GPO, &val);
869 		val &= ~1;
870 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
871 
872 		/* 2 */
873 		DELAY_MS(1);
874 
875 		/* 3 */
876 		DELAY_MS(1);
877 
878 		/* 4 */
879 		DELAY_MS(2 /*1 extra ms for safety */ );
880 
881 		/* 5 */
882 		val |= 1;
883 		(void) t1_tpi_write(adapter, A_ELMER0_GPO, val);
884 
885 		/* 6 */
886 		DELAY_MS(15 /*1 extra ms for safety */ );
887 
888 		/* 7 */
889 		DELAY_MS(1);
890 
891 		/* 8 */
892 
893 		/* Has PL4 analog block come out of reset correctly? */
894 		(void) t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_DEVICE_STATUS), &val);
895 		is_pl4_reset_finished = (val & SUNI1x10GEXP_BITMSK_TOP_EXPIRED);
896 
897 		/* TBD XXX SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL gets locked later in the init sequence
898 		 *         figure out why? */
899 
900 		/* Have all PL4 block clocks locked? */
901 		x = (SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL
902 		     /*| SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL */  |
903 		     SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL |
904 		     SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL |
905 		     SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL);
906 		is_pl4_outof_lock = (val & x);
907 
908 		/* ??? If this fails, might be able to software reset the XAUI part
909 		 *     and try to recover... thus saving us from doing another HW reset */
910 		/* Has the XAUI MABC PLL circuitry stablized? */
911 		is_xaui_mabc_pll_locked =
912 		    (val & SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED);
913 
914 		successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock
915 				    && is_xaui_mabc_pll_locked);
916 
917 		CH_DBG(adapter, HW,
918 		       "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, "
919 		       "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n",
920 		       i, is_pl4_reset_finished, val, is_pl4_outof_lock,
921 		       is_xaui_mabc_pll_locked);
922 	}
923 	return successful_reset ? 0 : 1;
924 }
925 
926 struct gmac t1_pm3393_ops = {
927 	STATS_TICK_SECS,
928 	pm3393_mac_create,
929 	pm3393_mac_reset
930 };
931