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
pmread(struct cmac * cmac,u32 reg,u32 * data32)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
pmwrite(struct cmac * cmac,u32 reg,u32 data32)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 */
pm3393_reset(struct cmac * cmac)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 */
pm3393_interrupt_enable(struct cmac * cmac)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
pm3393_interrupt_disable(struct cmac * cmac)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
pm3393_interrupt_clear(struct cmac * cmac)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 */
pm3393_interrupt_handler(struct cmac * cmac)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
pm3393_enable(struct cmac * cmac,int which)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 */
pm3393_enable_port(struct cmac * cmac,int which)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
pm3393_disable(struct cmac * cmac,int which)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 */
pm3393_loopback_enable(struct cmac * cmac)418 static int pm3393_loopback_enable(struct cmac *cmac)
419 {
420 return 0;
421 }
422
423 /* ARGSUSED */
pm3393_loopback_disable(struct cmac * cmac)424 static int pm3393_loopback_disable(struct cmac *cmac)
425 {
426 return 0;
427 }
428
pm3393_set_mtu(struct cmac * cmac,int mtu)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
calc_crc(u8 * b,int len)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
pm3393_set_rx_mode(struct cmac * cmac,struct t1_rx_mode * rm)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
pm3393_get_speed_duplex_fc(struct cmac * cmac,int * speed,int * duplex,int * fc)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
pm3393_set_speed_duplex_fc(struct cmac * cmac,int speed,int duplex,int fc)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 */
pm3393_update_statistics(struct cmac * mac,int flag)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
pm3393_macaddress_get(struct cmac * cmac,u8 mac_addr[6])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
pm3393_macaddress_set(struct cmac * cmac,u8 ma[6])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
pm3393_destroy(struct cmac * cmac)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 */
pm3393_mac_create(adapter_t * adapter,int index)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
pm3393_mac_reset(adapter_t * adapter)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