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