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 "regs.h" 28 #include "fpga_defs.h" 29 30 #define MAC_CSR_INTERFACE_GMII 0x0 31 #define MAC_CSR_INTERFACE_TBI 0x1 32 #define MAC_CSR_INTERFACE_MII 0x2 33 #define MAC_CSR_INTERFACE_RMII 0x3 34 35 /* Chelsio's MAC statistics. */ 36 struct mac_statistics { 37 38 /* Transmit */ 39 u32 TxFramesTransmittedOK; 40 u32 TxReserved1; 41 u32 TxReserved2; 42 u32 TxOctetsTransmittedOK; 43 u32 TxFramesWithDeferredXmissions; 44 u32 TxLateCollisions; 45 u32 TxFramesAbortedDueToXSCollisions; 46 u32 TxFramesLostDueToIntMACXmitError; 47 u32 TxReserved3; 48 u32 TxMulticastFrameXmittedOK; 49 u32 TxBroadcastFramesXmittedOK; 50 u32 TxFramesWithExcessiveDeferral; 51 u32 TxPAUSEMACCtrlFramesTransmitted; 52 53 /* Receive */ 54 u32 RxFramesReceivedOK; 55 u32 RxFrameCheckSequenceErrors; 56 u32 RxAlignmentErrors; 57 u32 RxOctetsReceivedOK; 58 u32 RxFramesLostDueToIntMACRcvError; 59 u32 RxMulticastFramesReceivedOK; 60 u32 RxBroadcastFramesReceivedOK; 61 u32 RxInRangeLengthErrors; 62 u32 RxTxOutOfRangeLengthField; 63 u32 RxFrameTooLongErrors; 64 u32 RxPAUSEMACCtrlFramesReceived; 65 }; 66 67 static int static_aPorts[] = { 68 FPGA_GMAC_INTERRUPT_PORT0, 69 FPGA_GMAC_INTERRUPT_PORT1, 70 FPGA_GMAC_INTERRUPT_PORT2, 71 FPGA_GMAC_INTERRUPT_PORT3 72 }; 73 74 struct _cmac_instance { 75 u32 index; 76 }; 77 78 static int mac_intr_enable(struct cmac *mac) 79 { 80 u32 mac_intr; 81 82 if (t1_is_asic(mac->adapter)) { 83 /* ASIC */ 84 /*EMPTY*/ 85 /* We don't use the on chip MAC for ASIC products. */ 86 } else { 87 /* FPGA */ 88 89 /* Set parent gmac interrupt. */ 90 mac_intr = t1_read_reg_4(mac->adapter, A_PL_ENABLE); 91 mac_intr |= FPGA_PCIX_INTERRUPT_GMAC; 92 t1_write_reg_4(mac->adapter, A_PL_ENABLE, mac_intr); 93 94 mac_intr = t1_read_reg_4(mac->adapter, 95 FPGA_GMAC_ADDR_INTERRUPT_ENABLE); 96 mac_intr |= static_aPorts[mac->instance->index]; 97 t1_write_reg_4(mac->adapter, 98 FPGA_GMAC_ADDR_INTERRUPT_ENABLE, mac_intr); 99 } 100 101 return (0); 102 } 103 104 static int mac_intr_disable(struct cmac *mac) 105 { 106 u32 mac_intr; 107 108 if (t1_is_asic(mac->adapter)) { 109 /* ASIC */ 110 /*EMPTY*/ 111 /* We don't use the on chip MAC for ASIC products. */ 112 } else { 113 /* FPGA */ 114 115 /* Set parent gmac interrupt. */ 116 mac_intr = t1_read_reg_4(mac->adapter, A_PL_ENABLE); 117 mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC; 118 t1_write_reg_4(mac->adapter, A_PL_ENABLE, mac_intr); 119 120 mac_intr = t1_read_reg_4(mac->adapter, 121 FPGA_GMAC_ADDR_INTERRUPT_ENABLE); 122 mac_intr &= ~(static_aPorts[mac->instance->index]); 123 t1_write_reg_4(mac->adapter, 124 FPGA_GMAC_ADDR_INTERRUPT_ENABLE, mac_intr); 125 } 126 127 return (0); 128 } 129 130 static int mac_intr_clear(struct cmac *mac) 131 { 132 u32 mac_intr; 133 134 if (t1_is_asic(mac->adapter)) { 135 /* ASIC */ 136 /*EMPTY*/ 137 /* We don't use the on chip MAC for ASIC products. */ 138 } else { 139 /* FPGA */ 140 141 /* Set parent gmac interrupt. */ 142 t1_write_reg_4(mac->adapter, A_PL_CAUSE, 143 FPGA_PCIX_INTERRUPT_GMAC); 144 145 mac_intr = t1_read_reg_4(mac->adapter, 146 FPGA_GMAC_ADDR_INTERRUPT_CAUSE); 147 mac_intr |= (static_aPorts[mac->instance->index]); 148 t1_write_reg_4(mac->adapter, 149 FPGA_GMAC_ADDR_INTERRUPT_CAUSE, mac_intr); 150 } 151 152 return (0); 153 } 154 155 static int mac_get_address(struct cmac *mac, u8 addr[6]) 156 { 157 u32 data32_lo, data32_hi; 158 159 data32_lo = t1_read_reg_4(mac->adapter, 160 MAC_REG_IDLO(mac->instance->index)); 161 data32_hi = t1_read_reg_4(mac->adapter, 162 MAC_REG_IDHI(mac->instance->index)); 163 164 addr[0] = (u8) ((data32_hi >> 8) & 0xFF); 165 addr[1] = (u8) ((data32_hi) & 0xFF); 166 addr[2] = (u8) ((data32_lo >> 24) & 0xFF); 167 addr[3] = (u8) ((data32_lo >> 16) & 0xFF); 168 addr[4] = (u8) ((data32_lo >> 8) & 0xFF); 169 addr[5] = (u8) ((data32_lo) & 0xFF); 170 return (0); 171 } 172 173 static int mac_reset(struct cmac *mac) 174 { 175 u32 data32; 176 int mac_in_reset, time_out = 100; 177 int idx = mac->instance->index; 178 179 data32 = t1_read_reg_4(mac->adapter, MAC_REG_CSR(idx)); 180 t1_write_reg_4(mac->adapter, MAC_REG_CSR(idx), 181 data32 | F_MAC_RESET); 182 183 do { 184 data32 = t1_read_reg_4(mac->adapter, 185 MAC_REG_CSR(idx)); 186 mac_in_reset = data32 & F_MAC_RESET; 187 if (mac_in_reset) 188 DELAY_US(1); 189 } while (mac_in_reset && --time_out); 190 191 if (mac_in_reset) { 192 CH_ERR("%s: MAC %d reset timed out\n", 193 adapter_name(mac->adapter), idx); 194 return (2); 195 } 196 197 return (0); 198 } 199 200 static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) 201 { 202 u32 val; 203 204 val = t1_read_reg_4(mac->adapter, 205 MAC_REG_CSR(mac->instance->index)); 206 val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE); 207 val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0); 208 val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0); 209 t1_write_reg_4(mac->adapter, 210 MAC_REG_CSR(mac->instance->index), val); 211 212 return (0); 213 } 214 215 static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, 216 int fc) 217 { 218 u32 data32; 219 220 data32 = t1_read_reg_4(mac->adapter, 221 MAC_REG_CSR(mac->instance->index)); 222 data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) | 223 V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE | 224 F_MAC_RX_PAUSE_ENABLE); 225 226 switch (speed) { 227 case SPEED_10: 228 case SPEED_100: 229 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII); 230 data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1); 231 break; 232 case SPEED_1000: 233 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII); 234 data32 |= V_MAC_SPEED(2); 235 break; 236 } 237 238 if (duplex >= 0) 239 data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF); 240 241 if (fc >= 0) { 242 data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0); 243 data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0); 244 } 245 246 t1_write_reg_4(mac->adapter, 247 MAC_REG_CSR(mac->instance->index), data32); 248 return (0); 249 } 250 251 static int mac_enable(struct cmac *mac, int which) 252 { 253 u32 val; 254 255 val = t1_read_reg_4(mac->adapter, 256 MAC_REG_CSR(mac->instance->index)); 257 if (which & MAC_DIRECTION_RX) 258 val |= F_MAC_RX_ENABLE; 259 if (which & MAC_DIRECTION_TX) 260 val |= F_MAC_TX_ENABLE; 261 t1_write_reg_4(mac->adapter, 262 MAC_REG_CSR(mac->instance->index), val); 263 return (0); 264 } 265 266 static int mac_disable(struct cmac *mac, int which) 267 { 268 u32 val; 269 270 val = t1_read_reg_4(mac->adapter, 271 MAC_REG_CSR(mac->instance->index)); 272 if (which & MAC_DIRECTION_RX) 273 val &= ~F_MAC_RX_ENABLE; 274 if (which & MAC_DIRECTION_TX) 275 val &= ~F_MAC_TX_ENABLE; 276 t1_write_reg_4(mac->adapter, 277 MAC_REG_CSR(mac->instance->index), val); 278 return (0); 279 } 280 281 int 282 mac_set_ifs(struct cmac *mac, u32 mode) 283 { 284 t1_write_reg_4(mac->adapter, 285 MAC_REG_IFS(mac->instance->index), mode); 286 287 return (0); 288 } 289 290 int 291 mac_enable_isl(struct cmac *mac) 292 { 293 u32 data32 = t1_read_reg_4(mac->adapter, 294 MAC_REG_CSR(mac->instance->index)); 295 data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE; 296 t1_write_reg_4(mac->adapter, 297 MAC_REG_CSR(mac->instance->index), data32); 298 299 return (0); 300 } 301 302 static int mac_set_mtu(struct cmac *mac, int mtu) 303 { 304 if (mtu > 9600) 305 return (-EINVAL); 306 t1_write_reg_4(mac->adapter, 307 MAC_REG_LARGEFRAMELENGTH(mac->instance->index), 308 mtu + 14 + 4); 309 return (0); 310 } 311 312 /* ARGSUSED */ 313 static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 314 int flag) 315 { 316 struct mac_statistics st; 317 u32 *p = (u32 *) & st, i; 318 319 t1_write_reg_4(mac->adapter, 320 MAC_REG_RMCNT(mac->instance->index), 0); 321 for (i = 0; i < sizeof (st) / sizeof (u32); i++) 322 *p++ = t1_read_reg_4(mac->adapter, 323 MAC_REG_RMDATA(mac->instance->index)); 324 325 /* XXX convert stats */ 326 return (&mac->stats); 327 } 328 329 static void mac_destroy(struct cmac *mac) 330 { 331 t1_os_free((void *)mac, sizeof (*mac) + sizeof (cmac_instance)); 332 } 333 334 #ifdef C99_NOT_SUPPORTED 335 static struct cmac_ops chelsio_mac_ops = { 336 mac_destroy, 337 mac_reset, 338 mac_intr_enable, 339 mac_intr_disable, 340 mac_intr_clear, 341 NULL, 342 mac_enable, 343 mac_disable, 344 NULL, 345 NULL, 346 mac_set_mtu, 347 mac_set_rx_mode, 348 mac_set_speed_duplex_fc, 349 NULL, 350 mac_update_statistics, 351 mac_get_address, 352 NULL 353 }; 354 #else 355 static struct cmac_ops chelsio_mac_ops = { 356 .destroy = mac_destroy, 357 .reset = mac_reset, 358 .interrupt_enable = mac_intr_enable, 359 .interrupt_disable = mac_intr_disable, 360 .interrupt_clear = mac_intr_clear, 361 .enable = mac_enable, 362 .disable = mac_disable, 363 .set_mtu = mac_set_mtu, 364 .set_rx_mode = mac_set_rx_mode, 365 .set_speed_duplex_fc = mac_set_speed_duplex_fc, 366 .macaddress_get = mac_get_address, 367 .statistics_update = mac_update_statistics, 368 }; 369 #endif 370 371 static struct cmac *mac_create(adapter_t *adapter, int index) 372 { 373 struct cmac *mac; 374 u32 data32; 375 376 if (index >= 4) 377 return (NULL); 378 379 mac = t1_os_malloc_wait_zero(sizeof (*mac) + sizeof (cmac_instance)); 380 if (!mac) 381 return (NULL); 382 383 mac->ops = &chelsio_mac_ops; 384 mac->instance = (cmac_instance *) (mac + 1); 385 386 mac->instance->index = index; 387 mac->adapter = adapter; 388 389 data32 = t1_read_reg_4(adapter, MAC_REG_CSR(mac->instance->index)); 390 data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC | 391 F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE); 392 data32 |= F_MAC_JUMBO_ENABLE; 393 t1_write_reg_4(adapter, MAC_REG_CSR(mac->instance->index), data32); 394 395 /* Initialize the random backoff seed. */ 396 data32 = 0x55aa + (3 * index); 397 t1_write_reg_4(adapter, 398 MAC_REG_GMRANDBACKOFFSEED(mac->instance->index), data32); 399 400 /* Check to see if the mac address needs to be set manually. */ 401 data32 = t1_read_reg_4(adapter, MAC_REG_IDLO(mac->instance->index)); 402 if (data32 == 0 || data32 == 0xffffffff) { 403 /* 404 * Add a default MAC address if we can't read one. 405 */ 406 t1_write_reg_4(adapter, MAC_REG_IDLO(mac->instance->index), 407 0x43FFFFFF - index); 408 t1_write_reg_4(adapter, MAC_REG_IDHI(mac->instance->index), 409 0x0007); 410 } 411 412 (void) mac_set_mtu(mac, 1500); 413 return (mac); 414 } 415 416 struct gmac t1_chelsio_mac_ops = { 417 0, 418 mac_create 419 }; 420