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