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