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