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" /* ixf1010.c */ 27 28 #include "gmac.h" 29 #include "elmer0.h" 30 31 /* Update fast changing statistics every 15 seconds */ 32 #define STATS_TICK_SECS 15 33 /* 30 minutes for full statistics update */ 34 #define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) 35 36 /* 37 * The IXF1010 can handle frames up to 16383 bytes but it's optimized for 38 * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this. 39 * This length includes ethernet header and FCS. 40 */ 41 #define MAX_FRAME_SIZE 0x2667 42 43 /* MAC registers */ 44 enum { 45 /* Per-port registers */ 46 REG_MACADDR_LOW = 0, 47 REG_MACADDR_HIGH = 0x4, 48 REG_FDFC_TYPE = 0xC, 49 REG_FC_TX_TIMER_VALUE = 0x1c, 50 REG_IPG_RX_TIME1 = 0x28, 51 REG_IPG_RX_TIME2 = 0x2c, 52 REG_IPG_TX_TIME = 0x30, 53 REG_PAUSE_THRES = 0x38, 54 REG_MAX_FRAME_SIZE = 0x3c, 55 REG_RGMII_SPEED = 0x40, 56 REG_FC_ENABLE = 0x48, 57 REG_DISCARD_CTRL_FRAMES = 0x54, 58 REG_DIVERSE_CONFIG = 0x60, 59 REG_RX_FILTER = 0x64, 60 REG_MC_ADDR_LOW = 0x68, 61 REG_MC_ADDR_HIGH = 0x6c, 62 63 REG_RX_OCTETS_OK = 0x80, 64 REG_RX_OCTETS_BAD = 0x84, 65 REG_RX_UC_PKTS = 0x88, 66 REG_RX_MC_PKTS = 0x8c, 67 REG_RX_BC_PKTS = 0x90, 68 REG_RX_FCS_ERR = 0xb0, 69 REG_RX_TAGGED = 0xb4, 70 REG_RX_DATA_ERR = 0xb8, 71 REG_RX_ALIGN_ERR = 0xbc, 72 REG_RX_LONG_ERR = 0xc0, 73 REG_RX_JABBER_ERR = 0xc4, 74 REG_RX_PAUSE_FRAMES = 0xc8, 75 REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc, 76 REG_RX_VERY_LONG_ERR = 0xd0, 77 REG_RX_RUNT_ERR = 0xd4, 78 REG_RX_SHORT_ERR = 0xd8, 79 REG_RX_SYMBOL_ERR = 0xe4, 80 81 REG_TX_OCTETS_OK = 0x100, 82 REG_TX_OCTETS_BAD = 0x104, 83 REG_TX_UC_PKTS = 0x108, 84 REG_TX_MC_PKTS = 0x10c, 85 REG_TX_BC_PKTS = 0x110, 86 REG_TX_EXCESSIVE_LEN_DROP = 0x14c, 87 REG_TX_UNDERRUN = 0x150, 88 REG_TX_TAGGED = 0x154, 89 REG_TX_PAUSE_FRAMES = 0x15C, 90 91 /* Global registers */ 92 REG_PORT_ENABLE = 0x1400, 93 94 REG_JTAG_ID = 0x1430, 95 96 RX_FIFO_HIGH_WATERMARK_BASE = 0x1600, 97 RX_FIFO_LOW_WATERMARK_BASE = 0x1628, 98 RX_FIFO_FRAMES_REMOVED_BASE = 0x1650, 99 100 REG_RX_ERR_DROP = 0x167c, 101 REG_RX_FIFO_OVERFLOW_EVENT = 0x1680, 102 103 TX_FIFO_HIGH_WATERMARK_BASE = 0x1800, 104 TX_FIFO_LOW_WATERMARK_BASE = 0x1828, 105 TX_FIFO_XFER_THRES_BASE = 0x1850, 106 107 REG_TX_FIFO_OVERFLOW_EVENT = 0x1878, 108 REG_TX_FIFO_OOS_EVENT = 0x1884, 109 110 TX_FIFO_FRAMES_REMOVED_BASE = 0x1888, 111 112 REG_SPI_RX_BURST = 0x1c00, 113 REG_SPI_RX_TRAINING = 0x1c04, 114 REG_SPI_RX_CALENDAR = 0x1c08, 115 REG_SPI_TX_SYNC = 0x1c0c 116 }; 117 118 enum { /* RMON registers */ 119 REG_RxOctetsTotalOK = 0x80, 120 REG_RxOctetsBad = 0x84, 121 REG_RxUCPkts = 0x88, 122 REG_RxMCPkts = 0x8c, 123 REG_RxBCPkts = 0x90, 124 REG_RxJumboPkts = 0xac, 125 REG_RxFCSErrors = 0xb0, 126 REG_RxDataErrors = 0xb8, 127 REG_RxAlignErrors = 0xbc, 128 REG_RxLongErrors = 0xc0, 129 REG_RxJabberErrors = 0xc4, 130 REG_RxPauseMacControlCounter = 0xc8, 131 REG_RxVeryLongErrors = 0xd0, 132 REG_RxRuntErrors = 0xd4, 133 REG_RxShortErrors = 0xd8, 134 REG_RxSequenceErrors = 0xe0, 135 REG_RxSymbolErrors = 0xe4, 136 137 REG_TxOctetsTotalOK = 0x100, 138 REG_TxOctetsBad = 0x104, 139 REG_TxUCPkts = 0x108, 140 REG_TxMCPkts = 0x10c, 141 REG_TxBCPkts = 0x110, 142 REG_TxJumboPkts = 0x12C, 143 REG_TxTotalCollisions = 0x134, 144 REG_TxExcessiveLengthDrop = 0x14c, 145 REG_TxUnderrun = 0x150, 146 REG_TxCRCErrors = 0x158, 147 REG_TxPauseFrames = 0x15c 148 }; 149 150 enum { 151 DIVERSE_CONFIG_PAD_ENABLE = 0x80, 152 DIVERSE_CONFIG_CRC_ADD = 0x40 153 }; 154 155 #define MACREG_BASE 0 156 #define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg)) 157 158 struct _cmac_instance { 159 u32 mac_base; 160 u32 index; 161 u32 version; 162 u32 ticks; 163 }; 164 165 static void disable_port(struct cmac *mac) 166 { 167 u32 val; 168 169 (void) t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val); 170 val &= ~(1 << mac->instance->index); 171 (void) t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val); 172 } 173 174 #define RMON_UPDATE(mac, name, stat_name) \ 175 (void) t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ 176 (mac)->stats.stat_name += val; 177 178 /* 179 * Read the current values of the RMON counters and add them to the cumulative 180 * port statistics. The HW RMON counters are cleared by this operation. 181 */ 182 static void port_stats_update(struct cmac *mac) 183 { 184 u32 val; 185 186 /* Rx stats */ 187 RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); 188 RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad); 189 RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK); 190 RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK); 191 RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK); 192 RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK); 193 RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors); 194 RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors); 195 RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors); 196 RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors); 197 RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames); 198 RMON_UPDATE(mac, RxDataErrors, RxDataErrors); 199 RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors); 200 RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors); 201 RMON_UPDATE(mac, RxShortErrors, RxRuntErrors); 202 RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors); 203 RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); 204 205 /* Tx stats (skip collision stats as we are full-duplex only) */ 206 RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); 207 RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad); 208 RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK); 209 RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK); 210 RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK); 211 RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK); 212 RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames); 213 RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors); 214 RMON_UPDATE(mac, TxUnderrun, TxUnderrun); 215 RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors); 216 } 217 218 /* No-op interrupt operation as this MAC does not support interrupts */ 219 /* ARGSUSED */ 220 static int mac_intr_op(struct cmac *mac) 221 { 222 return 0; 223 } 224 225 /* Expect MAC address to be in network byte order. */ 226 static int mac_set_address(struct cmac *mac, u8 addr[6]) 227 { 228 u32 addr_lo, addr_hi; 229 230 addr_lo = addr[2]; 231 addr_lo = (addr_lo << 8) | addr[3]; 232 addr_lo = (addr_lo << 8) | addr[4]; 233 addr_lo = (addr_lo << 8) | addr[5]; 234 235 addr_hi = addr[0]; 236 addr_hi = (addr_hi << 8) | addr[1]; 237 238 (void) t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo); 239 (void) t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi); 240 return 0; 241 } 242 243 static int mac_get_address(struct cmac *mac, u8 addr[6]) 244 { 245 u32 addr_lo, addr_hi; 246 247 (void) t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo); 248 (void) t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi); 249 250 addr[0] = (u8) (addr_hi >> 8); 251 addr[1] = (u8) addr_hi; 252 addr[2] = (u8) (addr_lo >> 24); 253 addr[3] = (u8) (addr_lo >> 16); 254 addr[4] = (u8) (addr_lo >> 8); 255 addr[5] = (u8) addr_lo; 256 return 0; 257 } 258 259 /* This is intended to reset a port, not the whole MAC */ 260 /* ARGSUSED */ 261 static int mac_reset(struct cmac *mac) 262 { 263 return 0; 264 } 265 266 static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) 267 { 268 u32 val, new_mode; 269 adapter_t *adapter = mac->adapter; 270 u32 addr_lo, addr_hi; 271 u8 *addr; 272 273 (void) t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val); 274 new_mode = val & ~7; 275 if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0) 276 new_mode |= 1; /* only set if version > 0 due to erratum */ 277 if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm) 278 && t1_rx_mode_mc_cnt(rm) <= 1) 279 new_mode |= 2; 280 if (new_mode != val) 281 (void) t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode); 282 switch (t1_rx_mode_mc_cnt(rm)) { 283 case 0: 284 (void) t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0); 285 (void) t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0); 286 break; 287 case 1: 288 addr = t1_get_next_mcaddr(rm); 289 addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | 290 addr[5]; 291 addr_hi = (addr[0] << 8) | addr[1]; 292 (void) t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo); 293 (void) t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi); 294 break; 295 default: 296 break; 297 } 298 return 0; 299 } 300 301 static int mac_set_mtu(struct cmac *mac, int mtu) 302 { 303 /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */ 304 if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL; 305 (void) t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE), 306 mtu + 14 + 4); 307 return 0; 308 } 309 310 static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, 311 int fc) 312 { 313 u32 val; 314 315 if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000) 316 return -1; 317 if (duplex >= 0 && duplex != DUPLEX_FULL) 318 return -1; 319 320 if (speed >= 0) { 321 val = speed == SPEED_100 ? 1 : 2; 322 (void) t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val); 323 } 324 325 (void) t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); 326 val &= ~3; 327 if (fc & PAUSE_RX) 328 val |= 1; 329 if (fc & PAUSE_TX) 330 val |= 2; 331 (void) t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val); 332 return 0; 333 } 334 335 static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex, 336 int *fc) 337 { 338 u32 val; 339 340 if (duplex) 341 *duplex = DUPLEX_FULL; 342 if (speed) { 343 (void) t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED), 344 &val); 345 *speed = (val & 2) ? SPEED_1000 : SPEED_100; 346 } 347 if (fc) { 348 (void) t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); 349 *fc = 0; 350 if (val & 1) 351 *fc |= PAUSE_RX; 352 if (val & 2) 353 *fc |= PAUSE_TX; 354 } 355 return 0; 356 } 357 358 static void enable_port(struct cmac *mac) 359 { 360 u32 val; 361 u32 index = mac->instance->index; 362 adapter_t *adapter = mac->adapter; 363 364 (void) t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val); 365 val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE; 366 (void) t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val); 367 if (mac->instance->version > 0) 368 (void) t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3); 369 else /* Don't enable unicast address filtering due to IXF1010 bug */ 370 (void) t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2); 371 372 (void) t1_tpi_read(adapter, REG_RX_ERR_DROP, &val); 373 val |= (1 << index); 374 (void) t1_tpi_write(adapter, REG_RX_ERR_DROP, val); 375 376 /* 377 * Clear the port RMON registers by adding their current values to the 378 * cumulatice port stats and then clearing the stats. Really. 379 */ 380 port_stats_update(mac); 381 (void) memset(&mac->stats, 0, sizeof(struct cmac_statistics)); 382 mac->instance->ticks = 0; 383 384 (void) t1_tpi_read(adapter, REG_PORT_ENABLE, &val); 385 val |= (1 << index); 386 (void) t1_tpi_write(adapter, REG_PORT_ENABLE, val); 387 388 index <<= 2; 389 if (is_T2(adapter)) { 390 /* T204: set the Fifo water level & threshold */ 391 if (index) index <<= 2; 392 (void) t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740); 393 (void) t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730); 394 (void) t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600); 395 (void) t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0); 396 (void) t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100); 397 } else { 398 /* 399 * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around 400 * Underrun problem. Intel has blessed this solution. 401 */ 402 (void) t1_tpi_write(adapter, 403 TX_FIFO_XFER_THRES_BASE + mac->instance->index * 4, 0x400); 404 } 405 } 406 407 /* IXF1010 ports do not have separate enables for TX and RX */ 408 static int mac_enable(struct cmac *mac, int which) 409 { 410 if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) 411 enable_port(mac); 412 return 0; 413 } 414 415 static int mac_disable(struct cmac *mac, int which) 416 { 417 if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) 418 disable_port(mac); 419 return 0; 420 } 421 422 /* 423 * This function is called periodically to accumulate the current values of the 424 * RMON counters into the port statistics. Since the counters are only 32 bits 425 * some of them can overflow in less than a minute at GigE speeds, so this 426 * function should be called every 30 seconds or so. 427 * 428 * To cut down on reading costs we update only the octet counters at each tick 429 * and do a full update at major ticks, which can be every 30 minutes or more. 430 */ 431 static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 432 int flag) 433 { 434 if (flag == MAC_STATS_UPDATE_FULL || 435 MAJOR_UPDATE_TICKS <= mac->instance->ticks) { 436 port_stats_update(mac); 437 mac->instance->ticks = 0; 438 } else { 439 u32 val; 440 441 RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); 442 RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); 443 mac->instance->ticks++; 444 } 445 return &mac->stats; 446 } 447 448 static void mac_destroy(struct cmac *mac) 449 { 450 t1_os_free((void *)mac, sizeof(*mac) + sizeof(cmac_instance)); 451 } 452 453 #ifdef C99_NOT_SUPPORTED 454 static struct cmac_ops ixf1010_ops = { 455 mac_destroy, 456 mac_reset, 457 mac_intr_op, 458 mac_intr_op, 459 mac_intr_op, 460 NULL, 461 mac_enable, 462 mac_disable, 463 NULL, 464 NULL, 465 mac_set_mtu, 466 mac_set_rx_mode, 467 mac_set_speed_duplex_fc, 468 mac_get_speed_duplex_fc, 469 mac_update_statistics, 470 mac_get_address, 471 mac_set_address 472 }; 473 #else 474 static struct cmac_ops ixf1010_ops = { 475 .destroy = mac_destroy, 476 .reset = mac_reset, 477 .interrupt_enable = mac_intr_op, 478 .interrupt_disable = mac_intr_op, 479 .interrupt_clear = mac_intr_op, 480 .enable = mac_enable, 481 .disable = mac_disable, 482 .set_mtu = mac_set_mtu, 483 .set_rx_mode = mac_set_rx_mode, 484 .set_speed_duplex_fc = mac_set_speed_duplex_fc, 485 .get_speed_duplex_fc = mac_get_speed_duplex_fc, 486 .statistics_update = mac_update_statistics, 487 .macaddress_get = mac_get_address, 488 .macaddress_set = mac_set_address, 489 }; 490 #endif 491 492 static int ixf1010_mac_reset(adapter_t *adapter) 493 { 494 u32 val; 495 496 (void) t1_tpi_read(adapter, A_ELMER0_GPO, &val); 497 if ((val & 1) != 0) { 498 val &= ~1; 499 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 500 DELAY_US(2); 501 } 502 val |= 1; 503 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 504 DELAY_US(2); 505 506 (void) t1_tpi_write(adapter, REG_PORT_ENABLE, 0); 507 return 0; 508 } 509 510 static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index) 511 { 512 struct cmac *mac; 513 u32 val; 514 515 if (index > 9) return NULL; 516 517 mac = t1_os_malloc_wait_zero(sizeof(*mac) + sizeof(cmac_instance)); 518 if (!mac) return NULL; 519 520 mac->ops = &ixf1010_ops; 521 mac->instance = (cmac_instance *)(mac + 1); 522 523 mac->instance->mac_base = MACREG_BASE + (index * 0x200); 524 mac->instance->index = index; 525 mac->adapter = adapter; 526 mac->instance->ticks = 0; 527 528 (void) t1_tpi_read(adapter, REG_JTAG_ID, &val); 529 mac->instance->version = val >> 28; 530 return mac; 531 } 532 533 struct gmac t1_ixf1010_ops = { 534 STATS_TICK_SECS, 535 ixf1010_mac_create, 536 ixf1010_mac_reset 537 }; 538