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