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