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" /* vsc7321.c */ 27 28 /* Driver for Vitesse VSC7321 (Meigs II) MAC */ 29 30 31 #if 0 32 #ifndef INVARIANTS 33 #define INVARIANTS 34 #endif 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/malloc.h> 39 #include <sys/kernel.h> 40 #include <sys/conf.h> 41 #include <pci/pcivar.h> 42 #include <pci/pcireg.h> 43 #endif 44 45 #include "gmac.h" 46 #include "elmer0.h" 47 #include "vsc7321_reg.h" 48 49 #define DEBUG 1 50 51 struct init_table { 52 u32 addr; 53 u32 data; 54 }; 55 56 static struct cmac_ops vsc7321_ops; 57 58 struct _cmac_instance { 59 u32 mac_base; 60 u32 index; 61 u32 version; 62 }; 63 64 #define INITBLOCK_SLEEP 0xffffffff 65 66 static void vsc_read(adapter_t *adapter, u32 addr, u32 *val) 67 { 68 u32 status, vlo, vhi; 69 70 (void) t1_tpi_read(adapter, (addr << 2) + 4, &vlo); 71 72 do { 73 (void) t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); 74 (void) t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); 75 status = (vhi << 16) | vlo; 76 } while ((status & 1) == 0); 77 78 (void) t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo); 79 (void) t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi); 80 81 *val = (vhi << 16) | vlo; 82 } 83 84 static void vsc_write(adapter_t *adapter, u32 addr, u32 data) 85 { 86 (void) t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF); 87 (void) t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF); 88 } 89 90 /* Hard reset the MAC. This wipes out *all* configuration. */ 91 static void vsc7321_full_reset(adapter_t* adapter) 92 { 93 u32 val; 94 95 (void) t1_tpi_read(adapter, A_ELMER0_GPO, &val); 96 val &= ~1; 97 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 98 DELAY_US(2); 99 val |= 0x80001; /* Turn on SPI4_EN, and the MAC itself */ 100 if (is_10G(adapter)) { 101 val |= 0x40000; /* Enable 10G section */ 102 } else { 103 val |= 0x20000; /* Enable 1G section */ 104 } 105 val &= ~0x800; /* Turn off the red LED */ 106 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 107 DELAY_US(1000); 108 } 109 110 static struct init_table vsc7321_reset[] = { 111 { REG_SW_RESET, 0x80000001 }, 112 { INITBLOCK_SLEEP, 0x64 }, 113 { REG_SW_RESET, 0x00000000 }, 114 { REG_IFACE_MODE, 0x00000000 }, 115 { REG_CRC_CFG, 0x00000020 }, 116 { REG_PLL_CLK_SPEED, 0x00000000 }, 117 { INITBLOCK_SLEEP, 0x0a }, 118 { REG_PLL_CLK_SPEED, 0x000000d4 }, 119 { REG_SPI4_MISC, 0x00040009 }, 120 { REG_SPI4_ING_SETUP2, 0x04040004 }, 121 { REG_SPI4_ING_SETUP0, 0x0011100f }, /* FIXME: Multiport */ 122 { REG_SPI4_EGR_SETUP0, 0x0004100f }, /* FIXME: Multiport */ 123 { REG_SPI4_ING_SETUP1, 0x00100000 }, 124 { REG_AGE_INC(0), 0x00000000 }, 125 { REG_AGE_INC(1), 0x00000000 }, 126 { REG_ING_CONTROL, 0x0a000014 }, /* FIXME: 1G vs 10G */ 127 { REG_EGR_CONTROL, 0xa0010091 }, /* FIXME: 1G vs 10G */ 128 }; 129 130 static struct init_table vsc7321_portinit[4][20] = { 131 { /* Port 0 */ 132 /* FIFO setup */ 133 { REG_TEST(0,0), 0x00000002 }, 134 { REG_TEST(1,0), 0x00000002 }, 135 { REG_TOP_BOTTOM(0,0), 0x00100000 }, 136 { REG_TOP_BOTTOM(1,0), 0x00100000 }, 137 { REG_HIGH_LOW_WM(0,0), 0x0fff0fff }, 138 { REG_HIGH_LOW_WM(1,0), 0x0fff0fff }, 139 { REG_CT_THRHLD(0,0), 0x00000000 }, 140 { REG_CT_THRHLD(1,0), 0x00000000 }, 141 { REG_TEST(0,0), 0x00000000 }, 142 { REG_TEST(1,0), 0x00000000 }, 143 /* Port config */ 144 { REG_MODE_CFG(0), 0x0000054c }, 145 { REG_MAX_LEN(0), 0x000005ee }, 146 { REG_DEV_SETUP(0), 0x00000001 }, 147 { REG_TBI_CONFIG(0), 0x00000000 }, 148 { REG_DEV_SETUP(0), 0x00000046 }, 149 { REG_PAUSE_CFG(0), 0x00000000 }, 150 { REG_NORMALIZER(0), 0x00000064 }, 151 { REG_DENORM(0), 0x00000010 }, 152 }, 153 { /* Port 1 */ 154 /* FIFO setup */ 155 { REG_TEST(0,1), 0x00000002 }, 156 { REG_TEST(1,1), 0x00000002 }, 157 { REG_TOP_BOTTOM(0,1), 0x00100000 }, 158 { REG_TOP_BOTTOM(1,1), 0x00100000 }, 159 { REG_HIGH_LOW_WM(0,1), 0x0fff0fff }, 160 { REG_HIGH_LOW_WM(1,1), 0x0fff0fff }, 161 { REG_CT_THRHLD(0,1), 0x00000000 }, 162 { REG_CT_THRHLD(1,1), 0x00000000 }, 163 { REG_TEST(0,1), 0x00000000 }, 164 { REG_TEST(1,1), 0x00000000 }, 165 /* Port config */ 166 { REG_MODE_CFG(1), 0x0000054c }, 167 { REG_MAX_LEN(1), 0x000005ee }, 168 { REG_DEV_SETUP(1), 0x00000001 }, 169 { REG_TBI_CONFIG(1), 0x00000000 }, 170 { REG_DEV_SETUP(1), 0x00000046 }, 171 { REG_PAUSE_CFG(1), 0x00000000 }, 172 { REG_NORMALIZER(1), 0x00000064 }, 173 { REG_DENORM(1), 0x00000010 }, 174 }, 175 { /* Port 2 */ 176 /* FIFO setup */ 177 { REG_TEST(0,2), 0x00000002 }, 178 { REG_TEST(1,2), 0x00000002 }, 179 { REG_TOP_BOTTOM(0,2), 0x00100000 }, 180 { REG_TOP_BOTTOM(1,2), 0x00100000 }, 181 { REG_HIGH_LOW_WM(0,2), 0x0fff0fff }, 182 { REG_HIGH_LOW_WM(1,2), 0x0fff0fff }, 183 { REG_CT_THRHLD(0,2), 0x00000000 }, 184 { REG_CT_THRHLD(1,2), 0x00000000 }, 185 { REG_TEST(0,2), 0x00000000 }, 186 { REG_TEST(1,2), 0x00000000 }, 187 /* Port config */ 188 { REG_MODE_CFG(2), 0x0000054c }, 189 { REG_MAX_LEN(2), 0x000005ee }, 190 { REG_DEV_SETUP(2), 0x00000001 }, 191 { REG_TBI_CONFIG(2), 0x00000000 }, 192 { REG_DEV_SETUP(2), 0x00000046 }, 193 { REG_PAUSE_CFG(2), 0x00000000 }, 194 { REG_NORMALIZER(2), 0x00000064 }, 195 { REG_DENORM(2), 0x00000010 }, 196 }, 197 { /* Port 3 */ 198 /* FIFO setup */ 199 { REG_TEST(0,3), 0x00000002 }, 200 { REG_TEST(1,3), 0x00000002 }, 201 { REG_TOP_BOTTOM(0,3), 0x00100000 }, 202 { REG_TOP_BOTTOM(1,3), 0x00100000 }, 203 { REG_HIGH_LOW_WM(0,3), 0x0fff0fff }, 204 { REG_HIGH_LOW_WM(1,3), 0x0fff0fff }, 205 { REG_CT_THRHLD(0,3), 0x00000000 }, 206 { REG_CT_THRHLD(1,3), 0x00000000 }, 207 { REG_TEST(0,3), 0x00000000 }, 208 { REG_TEST(1,3), 0x00000000 }, 209 /* Port config */ 210 { REG_MODE_CFG(3), 0x0000054c }, 211 { REG_MAX_LEN(3), 0x000005ee }, 212 { REG_DEV_SETUP(3), 0x00000001 }, 213 { REG_TBI_CONFIG(3), 0x00000000 }, 214 { REG_DEV_SETUP(3), 0x00000046 }, 215 { REG_PAUSE_CFG(3), 0x00000000 }, 216 { REG_NORMALIZER(3), 0x00000064 }, 217 { REG_DENORM(3), 0x00000010 }, 218 }, 219 }; 220 221 static void run_table(adapter_t *adapter, struct init_table *ib, int len) 222 { 223 int i; 224 225 for (i = 0; i < len; i++) { 226 if (ib[i].addr == INITBLOCK_SLEEP) { 227 DELAY_US( ib[i].data ); 228 } else { 229 vsc_write( adapter, ib[i].addr, ib[i].data ); 230 } 231 } 232 } 233 234 /* ARGSUSED */ 235 static int vsc7321_mac_reset(adapter_t *adapter) 236 { 237 return 0; 238 } 239 240 static struct cmac *vsc7321_mac_create(adapter_t *adapter, int index) 241 { 242 struct cmac *mac; 243 u32 val; 244 int i; 245 246 mac = t1_os_malloc_wait_zero(sizeof(*mac) + sizeof(cmac_instance)); 247 if (!mac) return NULL; 248 249 mac->ops = &vsc7321_ops; 250 mac->instance = (cmac_instance *)(mac + 1); 251 252 mac->adapter = adapter; 253 mac->instance->index = index; 254 255 256 vsc7321_full_reset(adapter); 257 258 i = 0; 259 do { 260 u32 vhi, vlo; 261 262 vhi = vlo = 0; 263 (void) t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); 264 DELAY_US(1); 265 (void) t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); 266 DELAY_US(5); 267 val = (vhi << 16) | vlo; 268 } while ((++i < 10000) && (val == 0xffffffff)); 269 270 271 vsc_read(adapter, REG_CHIP_ID, &val); 272 273 if ((val & 0xfff0ffff) != 0x0F407321) { 274 CH_ERR("%s: Didn't find a VSC 7321.\n", adapter_name(adapter)); 275 t1_os_free((void *)mac, sizeof(*mac) + sizeof(cmac_instance)); 276 return NULL; 277 } 278 279 mac->instance->version = (val >> 16) & 0xf; 280 281 run_table(adapter, vsc7321_reset, DIMOF(vsc7321_reset)); 282 return mac; 283 } 284 285 /* ARGSUSED */ 286 static int mac_intr_handler(struct cmac *mac) 287 { 288 return 0; 289 } 290 291 /* ARGSUSED */ 292 static int mac_intr_enable(struct cmac *mac) 293 { 294 return 0; 295 } 296 297 /* ARGSUSED */ 298 static int mac_intr_disable(struct cmac *mac) 299 { 300 return 0; 301 } 302 303 /* ARGSUSED */ 304 static int mac_intr_clear(struct cmac *mac) 305 { 306 /* Nothing extra needed */ 307 return 0; 308 } 309 310 /* Expect MAC address to be in network byte order. */ 311 static int mac_set_address(struct cmac* mac, u8 addr[6]) 312 { 313 u32 addr_lo, addr_hi; 314 int port = mac->instance->index; 315 316 addr_lo = addr[3]; 317 addr_lo = (addr_lo << 8) | addr[4]; 318 addr_lo = (addr_lo << 8) | addr[5]; 319 320 addr_hi = addr[0]; 321 addr_hi = (addr_hi << 8) | addr[1]; 322 addr_hi = (addr_hi << 8) | addr[2]; 323 324 vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port), addr_lo); 325 vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port), addr_hi); 326 return 0; 327 } 328 329 static int mac_get_address(struct cmac *mac, u8 addr[6]) 330 { 331 u32 addr_lo, addr_hi; 332 int port = mac->instance->index; 333 334 vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo); 335 vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi); 336 337 addr[0] = (u8) (addr_hi >> 16); 338 addr[1] = (u8) (addr_hi >> 8); 339 addr[2] = (u8) addr_hi; 340 addr[3] = (u8) (addr_lo >> 16); 341 addr[4] = (u8) (addr_lo >> 8); 342 addr[5] = (u8) addr_lo; 343 return 0; 344 } 345 346 /* This is intended to reset a port, not the whole MAC */ 347 static int mac_reset(struct cmac *mac) 348 { 349 int index = mac->instance->index; 350 351 run_table(mac->adapter, vsc7321_portinit[index], 352 DIMOF(vsc7321_portinit[index])); 353 return 0; 354 } 355 356 /* ARGSUSED */ 357 static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) 358 { 359 /* Meigs II is always promiscuous. */ 360 return 0; 361 } 362 363 /* ARGSUSED */ 364 static int mac_set_mtu(struct cmac *mac, int mtu) 365 { 366 return 0; 367 } 368 369 /* ARGSUSED */ 370 static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, 371 int fc) 372 { 373 /* XXX Fixme */ 374 return 0; 375 } 376 377 static int mac_enable(struct cmac *mac, int which) 378 { 379 u32 val; 380 int port = mac->instance->index; 381 382 vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 383 if (which & MAC_DIRECTION_RX) 384 val |= 0x2; 385 if (which & MAC_DIRECTION_TX) 386 val |= 1; 387 vsc_write(mac->adapter, REG_MODE_CFG(port), val); 388 return 0; 389 } 390 391 static int mac_disable(struct cmac *mac, int which) 392 { 393 u32 val; 394 int port = mac->instance->index; 395 396 vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 397 if (which & MAC_DIRECTION_RX) 398 val &= ~0x2; 399 if (which & MAC_DIRECTION_TX) 400 val &= ~0x1; 401 vsc_write(mac->adapter, REG_MODE_CFG(port), val); 402 return 0; 403 } 404 405 #if 0 406 /* TBD XXX cmac interface stats will need to assigned to Chelsio's 407 * mac stats. cmac stats is now just usings Chelsio's 408 * so we don't need the conversion. 409 */ 410 int mac_get_statistics(struct cmac* mac, struct cmac_statistics* ps) 411 { 412 port_stats_update(mac); 413 return 0; 414 } 415 #endif 416 417 /* ARGSUSED */ 418 static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 419 int flag) 420 { 421 return &mac->stats; 422 } 423 424 static void mac_destroy(struct cmac *mac) 425 { 426 t1_os_free((void *)mac, sizeof(*mac) + sizeof(cmac_instance)); 427 } 428 429 #ifdef C99_NOT_SUPPORTED 430 static struct cmac_ops vsc7321_ops = { 431 mac_destroy, 432 mac_reset, 433 mac_intr_enable, 434 mac_intr_disable, 435 mac_intr_clear, 436 mac_intr_handler, 437 mac_enable, 438 mac_disable, 439 NULL, 440 NULL, 441 mac_set_mtu, 442 mac_set_rx_mode, 443 mac_set_speed_duplex_fc, 444 NULL, 445 mac_update_statistics, 446 mac_get_address, 447 mac_set_address 448 }; 449 #else 450 static struct cmac_ops vsc7321_ops = { 451 .destroy = mac_destroy, 452 .reset = mac_reset, 453 .interrupt_handler = mac_intr_handler, 454 .interrupt_enable = mac_intr_enable, 455 .interrupt_disable = mac_intr_disable, 456 .interrupt_clear = mac_intr_clear, 457 .enable = mac_enable, 458 .disable = mac_disable, 459 .set_mtu = mac_set_mtu, 460 .set_rx_mode = mac_set_rx_mode, 461 .set_speed_duplex_fc = mac_set_speed_duplex_fc, 462 .statistics_update = mac_update_statistics, 463 .macaddress_get = mac_get_address, 464 .macaddress_set = mac_set_address, 465 }; 466 #endif 467 468 struct gmac t1_vsc7321_ops = { 469 0, 470 vsc7321_mac_create, 471 vsc7321_mac_reset 472 }; 473