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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <npi_espc.h> 29 #include <nxge_espc.h> 30 31 static int npi_vpd_read_prop(npi_handle_t handle, uint32_t ep, 32 const char *prop, int len, char *val); 33 34 npi_status_t 35 npi_espc_pio_enable(npi_handle_t handle) 36 { 37 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_EN_REG), 0x1); 38 return (NPI_SUCCESS); 39 } 40 41 npi_status_t 42 npi_espc_pio_disable(npi_handle_t handle) 43 { 44 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_EN_REG), 0); 45 return (NPI_SUCCESS); 46 } 47 48 npi_status_t 49 npi_espc_eeprom_entry(npi_handle_t handle, io_op_t op, uint32_t addr, 50 uint8_t *data) 51 { 52 uint64_t val = 0; 53 54 if ((addr & ~EPC_EEPROM_ADDR_BITS) != 0) { 55 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 56 " npi_espc_eerprom_entry" 57 " Invalid input addr <0x%x>\n", 58 addr)); 59 return (NPI_FAILURE | NPI_ESPC_EEPROM_ADDR_INVALID); 60 } 61 62 switch (op) { 63 case OP_SET: 64 val = EPC_WRITE_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT) | 65 *data; 66 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val); 67 EPC_WAIT_RW_COMP(handle, &val, EPC_WRITE_COMPLETE); 68 if ((val & EPC_WRITE_COMPLETE) == 0) { 69 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 70 " npi_espc_eeprom_entry" 71 " HW Error: EEPROM_WR <0x%x>\n", 72 val)); 73 return (NPI_FAILURE | NPI_ESPC_EEPROM_WRITE_FAILED); 74 } 75 break; 76 case OP_GET: 77 val = EPC_READ_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT); 78 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val); 79 EPC_WAIT_RW_COMP(handle, &val, EPC_READ_COMPLETE); 80 if ((val & EPC_READ_COMPLETE) == 0) { 81 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 82 " npi_espc_eeprom_entry" 83 " HW Error: EEPROM_RD <0x%x>", 84 val)); 85 return (NPI_FAILURE | NPI_ESPC_EEPROM_READ_FAILED); 86 } 87 NXGE_REG_RD64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), &val); 88 /* 89 * Workaround for synchronization issues - do a second PIO 90 */ 91 val = EPC_READ_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT); 92 NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val); 93 EPC_WAIT_RW_COMP(handle, &val, EPC_READ_COMPLETE); 94 if ((val & EPC_READ_COMPLETE) == 0) { 95 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 96 " npi_espc_eeprom_entry HW Error: " 97 "EEPROM_RD <0x%x>", val)); 98 return (NPI_FAILURE | NPI_ESPC_EEPROM_READ_FAILED); 99 } 100 NXGE_REG_RD64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), &val); 101 *data = val & EPC_EEPROM_DATA_MASK; 102 break; 103 default: 104 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 105 " npi_espc_eeprom_entry" 106 " Invalid Input addr <0x%x>\n", addr)); 107 return (NPI_FAILURE | NPI_ESPC_OPCODE_INVALID); 108 } 109 110 return (NPI_SUCCESS); 111 } 112 113 npi_status_t 114 npi_espc_mac_addr_get(npi_handle_t handle, uint8_t *data) 115 { 116 mac_addr_0_t mac0; 117 mac_addr_1_t mac1; 118 119 NXGE_REG_RD64(handle, ESPC_MAC_ADDR_0, &mac0.value); 120 data[0] = mac0.bits.w0.byte0; 121 data[1] = mac0.bits.w0.byte1; 122 data[2] = mac0.bits.w0.byte2; 123 data[3] = mac0.bits.w0.byte3; 124 125 NXGE_REG_RD64(handle, ESPC_MAC_ADDR_1, &mac1.value); 126 data[4] = mac1.bits.w0.byte4; 127 data[5] = mac1.bits.w0.byte5; 128 129 return (NPI_SUCCESS); 130 } 131 132 npi_status_t 133 npi_espc_num_ports_get(npi_handle_t handle, uint8_t *data) 134 { 135 uint64_t val = 0; 136 137 NXGE_REG_RD64(handle, ESPC_NUM_PORTS_MACS, &val); 138 val &= NUM_PORTS_MASK; 139 *data = (uint8_t)val; 140 141 return (NPI_SUCCESS); 142 } 143 144 npi_status_t 145 npi_espc_num_macs_get(npi_handle_t handle, uint8_t *data) 146 { 147 uint64_t val = 0; 148 149 NXGE_REG_RD64(handle, ESPC_NUM_PORTS_MACS, &val); 150 val &= NUM_MAC_ADDRS_MASK; 151 val = (val >> NUM_MAC_ADDRS_SHIFT); 152 *data = (uint8_t)val; 153 154 return (NPI_SUCCESS); 155 } 156 157 npi_status_t 158 npi_espc_model_str_get(npi_handle_t handle, char *data) 159 { 160 uint64_t val = 0; 161 uint16_t str_len; 162 int i, j; 163 164 NXGE_REG_RD64(handle, ESPC_MOD_STR_LEN, &val); 165 val &= MOD_STR_LEN_MASK; 166 str_len = (uint8_t)val; 167 168 if (str_len > MAX_MOD_STR_LEN) { 169 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 170 " npi_espc_model_str_get" 171 " Model string length %d exceeds max %d\n", 172 str_len, MAX_MOD_STR_LEN)); 173 return (NPI_FAILURE | NPI_ESPC_STR_LEN_INVALID); 174 } 175 176 /* 177 * Might have to reverse the order depending on how the string 178 * is written. 179 */ 180 for (i = 0, j = 0; i < str_len; j++) { 181 NXGE_REG_RD64(handle, ESPC_MOD_STR(j), &val); 182 data[i++] = ((char *)&val)[3]; 183 data[i++] = ((char *)&val)[2]; 184 data[i++] = ((char *)&val)[1]; 185 data[i++] = ((char *)&val)[0]; 186 } 187 188 data[str_len] = '\0'; 189 190 return (NPI_SUCCESS); 191 } 192 193 npi_status_t 194 npi_espc_bd_model_str_get(npi_handle_t handle, char *data) 195 { 196 uint64_t val = 0; 197 uint16_t str_len; 198 int i, j; 199 200 NXGE_REG_RD64(handle, ESPC_BD_MOD_STR_LEN, &val); 201 val &= BD_MOD_STR_LEN_MASK; 202 str_len = (uint8_t)val; 203 204 if (str_len > MAX_BD_MOD_STR_LEN) { 205 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 206 " npi_espc_model_str_get" 207 " Board Model string length %d " 208 "exceeds max %d\n", 209 str_len, MAX_BD_MOD_STR_LEN)); 210 return (NPI_FAILURE | NPI_ESPC_STR_LEN_INVALID); 211 } 212 213 /* 214 * Might have to reverse the order depending on how the string 215 * is written. 216 */ 217 for (i = 0, j = 0; i < str_len; j++) { 218 NXGE_REG_RD64(handle, ESPC_BD_MOD_STR(j), &val); 219 data[i++] = ((char *)&val)[3]; 220 data[i++] = ((char *)&val)[2]; 221 data[i++] = ((char *)&val)[1]; 222 data[i++] = ((char *)&val)[0]; 223 } 224 225 data[str_len] = '\0'; 226 227 return (NPI_SUCCESS); 228 } 229 230 npi_status_t 231 npi_espc_phy_type_get(npi_handle_t handle, uint8_t *data) 232 { 233 phy_type_t phy; 234 235 NXGE_REG_RD64(handle, ESPC_PHY_TYPE, &phy.value); 236 data[0] = phy.bits.w0.pt0_phy_type; 237 data[1] = phy.bits.w0.pt1_phy_type; 238 data[2] = phy.bits.w0.pt2_phy_type; 239 data[3] = phy.bits.w0.pt3_phy_type; 240 241 return (NPI_SUCCESS); 242 } 243 244 npi_status_t 245 npi_espc_port_phy_type_get(npi_handle_t handle, uint8_t *data, uint8_t portn) 246 { 247 phy_type_t phy; 248 249 ASSERT(IS_PORT_NUM_VALID(portn)); 250 251 NXGE_REG_RD64(handle, ESPC_PHY_TYPE, &phy.value); 252 switch (portn) { 253 case 0: 254 *data = phy.bits.w0.pt0_phy_type; 255 break; 256 case 1: 257 *data = phy.bits.w0.pt1_phy_type; 258 break; 259 case 2: 260 *data = phy.bits.w0.pt2_phy_type; 261 break; 262 case 3: 263 *data = phy.bits.w0.pt3_phy_type; 264 break; 265 default: 266 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 267 " npi_espc_port_phy_type_get" 268 " Invalid Input: portn <%d>", 269 portn)); 270 return (NPI_FAILURE | NPI_ESPC_PORT_INVALID); 271 } 272 273 return (NPI_SUCCESS); 274 } 275 276 npi_status_t 277 npi_espc_max_frame_get(npi_handle_t handle, uint16_t *data) 278 { 279 uint64_t val = 0; 280 281 NXGE_REG_RD64(handle, ESPC_MAX_FM_SZ, &val); 282 val &= MAX_FM_SZ_MASK; 283 *data = (uint8_t)val; 284 285 return (NPI_SUCCESS); 286 } 287 288 npi_status_t 289 npi_espc_version_get(npi_handle_t handle, uint16_t *data) 290 { 291 uint64_t val = 0; 292 293 NXGE_REG_RD64(handle, ESPC_VER_IMGSZ, &val); 294 val &= VER_NUM_MASK; 295 *data = (uint8_t)val; 296 297 return (NPI_SUCCESS); 298 } 299 300 npi_status_t 301 npi_espc_img_sz_get(npi_handle_t handle, uint16_t *data) 302 { 303 uint64_t val = 0; 304 305 NXGE_REG_RD64(handle, ESPC_VER_IMGSZ, &val); 306 val &= IMG_SZ_MASK; 307 val = val >> IMG_SZ_SHIFT; 308 *data = (uint8_t)val; 309 310 return (NPI_SUCCESS); 311 } 312 313 npi_status_t 314 npi_espc_chksum_get(npi_handle_t handle, uint8_t *data) 315 { 316 uint64_t val = 0; 317 318 NXGE_REG_RD64(handle, ESPC_CHKSUM, &val); 319 val &= CHKSUM_MASK; 320 *data = (uint8_t)val; 321 322 return (NPI_SUCCESS); 323 } 324 325 npi_status_t 326 npi_espc_intr_num_get(npi_handle_t handle, uint8_t *data) 327 { 328 intr_num_t intr; 329 330 NXGE_REG_RD64(handle, ESPC_INTR_NUM, &intr.value); 331 data[0] = intr.bits.w0.pt0_intr_num; 332 data[1] = intr.bits.w0.pt1_intr_num; 333 data[2] = intr.bits.w0.pt2_intr_num; 334 data[3] = intr.bits.w0.pt3_intr_num; 335 336 return (NPI_SUCCESS); 337 } 338 339 void 340 npi_espc_dump(npi_handle_t handle) 341 { 342 int i; 343 uint64_t val = 0; 344 345 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, 346 "Dumping SEEPROM registers directly:\n\n")); 347 348 for (i = 0; i < 23; i++) { 349 NXGE_REG_RD64(handle, ESPC_NCR_REGN(i), &val); 350 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, 351 "reg[%d] 0x%llx\n", 352 i, val & 0xffffffff)); 353 } 354 355 NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\n\n")); 356 } 357 358 uint32_t 359 npi_espc_reg_get(npi_handle_t handle, int reg_idx) 360 { 361 uint64_t val = 0; 362 uint32_t reg_val = 0; 363 364 NXGE_REG_RD64(handle, ESPC_NCR_REGN(reg_idx), &val); 365 reg_val = val & 0xffffffff; 366 367 return (reg_val); 368 } 369 370 static inline uint8_t vpd_rd(npi_handle_t handle, uint32_t addr) 371 { 372 uint8_t data = 0; 373 374 if (npi_espc_eeprom_entry(handle, OP_GET, addr, &data) != NPI_SUCCESS) 375 data = 0; 376 return (data); 377 } 378 379 npi_status_t 380 npi_espc_vpd_info_get(npi_handle_t handle, p_npi_vpd_info_t vpdp, 381 uint32_t rom_len) 382 { 383 int i, len; 384 uint32_t base = 0, kstart = 0, ep, end; 385 uint8_t fd_flags = 0; 386 387 /* Fill the vpd_info struct with invalid vals */ 388 (void) strcpy(vpdp->model, "\0"); 389 (void) strcpy(vpdp->bd_model, "\0"); 390 (void) strcpy(vpdp->phy_type, "\0"); 391 (void) strcpy(vpdp->ver, "\0"); 392 vpdp->num_macs = 0; 393 for (i = 0; i < ETHERADDRL; i++) { 394 vpdp->mac_addr[i] = 0; 395 } 396 397 ep = 0; 398 end = ep + rom_len; 399 400 /* go through the images till OBP image type is found */ 401 while (ep < end) { 402 base = ep; 403 /* check for expansion rom header signature */ 404 if (vpd_rd(handle, ep) != 0x55 || 405 vpd_rd(handle, ep + 1) != 0xaa) { 406 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 407 "npi_espc_vpd_info_get: expansion rom image " 408 "not found, 0x%x [0x%x 0x%x]", ep, 409 vpd_rd(handle, ep), vpd_rd(handle, ep + 1))); 410 goto vpd_info_err; 411 } 412 /* go to the beginning of the PCI data struct of this image */ 413 ep = ep + 23; 414 ep = base + ((vpd_rd(handle, ep) << 8) | 415 (vpd_rd(handle, ep + 1))); 416 /* check for PCI data struct signature "PCIR" */ 417 if ((vpd_rd(handle, ep) != 0x50) || 418 (vpd_rd(handle, ep + 1) != 0x43) || 419 (vpd_rd(handle, ep + 2) != 0x49) || 420 (vpd_rd(handle, ep + 3) != 0x52)) { 421 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 422 "npi_espc_vpd_info_get: PCIR sig not found")); 423 goto vpd_info_err; 424 } 425 /* check for image type OBP */ 426 if (vpd_rd(handle, ep + 20) != 0x01) { 427 /* go to the next image */ 428 ep = base + ((vpd_rd(handle, base + 2)) * 512); 429 continue; 430 } 431 /* find the beginning of the VPD data */ 432 base = base + (vpd_rd(handle, ep + 8) | 433 (vpd_rd(handle, ep + 9) << 8)); 434 break; 435 } 436 437 /* check first byte of identifier string tag */ 438 if (!base || (vpd_rd(handle, base + 0) != 0x82)) { 439 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 440 "npi_espc_vpd_info_get: Could not find VPD!!")); 441 goto vpd_info_err; 442 } 443 444 /* 445 * skip over the ID string descriptor to go to the read-only VPD 446 * keywords list. 447 */ 448 i = (vpd_rd(handle, base + 1) | 449 (vpd_rd(handle, base + 2) << 8)) + 3; 450 451 while (i < EXPANSION_ROM_SIZE) { 452 if (vpd_rd(handle, base + i) != 0x90) { /* no vpd found */ 453 NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, 454 "nxge_get_vpd_info: Could not find " 455 "VPD ReadOnly list!! [0x%x] %d", 456 vpd_rd(handle, base + i), i)); 457 goto vpd_info_err; 458 } 459 460 /* found a vpd read-only list, get its length */ 461 len = vpd_rd(handle, base + i + 1) | 462 (vpd_rd(handle, base + i + 2) << 8); 463 464 /* extract keywords */ 465 kstart = base + i + 3; 466 ep = kstart; 467 /* 468 * Each keyword field is as follows: 469 * 2 bytes keyword in the form of "Zx" where x = 0,1,2.... 470 * 1 byte keyword data field length - klen 471 * Now the actual keyword data field: 472 * 1 byte VPD property instance, 'M' / 'I' 473 * 2 bytes 474 * 1 byte VPD property data type, 'B' / 'S' 475 * 1 byte VPD property value length - n 476 * Actual property string, length (klen - n - 5) bytes 477 * Actual property value, length n bytes 478 */ 479 while ((ep - kstart) < len) { 480 int klen = vpd_rd(handle, ep + 2); 481 int dlen; 482 char type; 483 484 ep += 3; 485 486 /* 487 * Look for the following properties: 488 * 489 * local-mac-address: 490 * -- VPD Instance 'I' 491 * -- VPD Type String 'B' 492 * -- property string == local-mac-address 493 * 494 * model: 495 * -- VPD Instance 'M' 496 * -- VPD Type String 'S' 497 * -- property string == model 498 * 499 * board-model: 500 * -- VPD Instance 'M' 501 * -- VPD Type String 'S' 502 * -- property string == board-model 503 * 504 * num-mac-addresses: 505 * -- VPD Instance 'I' 506 * -- VPD Type String 'B' 507 * -- property string == num-mac-addresses 508 * 509 * phy-type: 510 * -- VPD Instance 'I' 511 * -- VPD Type String 'S' 512 * -- property string == phy-type 513 * 514 * version: 515 * -- VPD Instance 'M' 516 * -- VPD Type String 'S' 517 * -- property string == version 518 */ 519 if (vpd_rd(handle, ep) == 'M') { 520 type = vpd_rd(handle, ep + 3); 521 if (type == 'S') { 522 dlen = vpd_rd(handle, ep + 4); 523 if (npi_vpd_read_prop(handle, ep + 5, 524 "model", dlen, vpdp->model)) { 525 fd_flags |= FD_MODEL; 526 goto next; 527 } 528 if (npi_vpd_read_prop(handle, ep + 5, 529 "board-model", dlen, 530 vpdp->bd_model)) { 531 fd_flags |= FD_BD_MODEL; 532 goto next; 533 } 534 if (npi_vpd_read_prop(handle, ep + 5, 535 "version", dlen, vpdp->ver)) { 536 fd_flags |= FD_FW_VERSION; 537 goto next; 538 } 539 } 540 goto next; 541 } else if (vpd_rd(handle, ep) == 'I') { 542 type = vpd_rd(handle, ep + 3); 543 if (type == 'B') { 544 dlen = vpd_rd(handle, ep + 4); 545 if (npi_vpd_read_prop(handle, ep + 5, 546 "local-mac-address", dlen, 547 (char *)(vpdp->mac_addr))) { 548 fd_flags |= FD_MAC_ADDR; 549 goto next; 550 } 551 if (npi_vpd_read_prop(handle, ep + 5, 552 "num-mac-addresses", dlen, 553 (char *)&(vpdp->num_macs))) { 554 fd_flags |= FD_NUM_MACS; 555 } 556 } else if (type == 'S') { 557 dlen = vpd_rd(handle, ep + 4); 558 if (npi_vpd_read_prop(handle, ep + 5, 559 "phy-type", dlen, 560 vpdp->phy_type)) { 561 fd_flags |= FD_PHY_TYPE; 562 } 563 } 564 goto next; 565 } else { 566 goto vpd_info_err; 567 } 568 569 next: 570 if ((fd_flags & FD_ALL) == FD_ALL) 571 goto vpd_success; 572 ep += klen; 573 } 574 i += len + 3; 575 } 576 577 vpd_success: 578 return (NPI_SUCCESS); 579 580 vpd_info_err: 581 return (NPI_FAILURE); 582 } 583 584 static int 585 npi_vpd_read_prop(npi_handle_t handle, uint32_t ep, const char *prop, int len, 586 char *val) 587 { 588 int prop_len = strlen(prop) + 1; 589 int i; 590 591 for (i = 0; i < prop_len; i++) { 592 if (vpd_rd(handle, ep + i) != prop[i]) 593 return (0); 594 } 595 596 ep += prop_len; 597 598 for (i = 0; i < len; i++) 599 val[i] = vpd_rd(handle, ep + i); 600 return (1); 601 } 602