/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include static int npi_vpd_read_prop(npi_handle_t handle, uint32_t ep, const char *prop, int len, char *val); npi_status_t npi_espc_pio_enable(npi_handle_t handle) { NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_EN_REG), 0x1); return (NPI_SUCCESS); } npi_status_t npi_espc_pio_disable(npi_handle_t handle) { NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_EN_REG), 0); return (NPI_SUCCESS); } npi_status_t npi_espc_eeprom_entry(npi_handle_t handle, io_op_t op, uint32_t addr, uint8_t *data) { uint64_t val = 0; if ((addr & ~EPC_EEPROM_ADDR_BITS) != 0) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_eerprom_entry" " Invalid input addr <0x%x>\n", addr)); return (NPI_FAILURE | NPI_ESPC_EEPROM_ADDR_INVALID); } switch (op) { case OP_SET: val = EPC_WRITE_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT) | *data; NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val); EPC_WAIT_RW_COMP(handle, &val, EPC_WRITE_COMPLETE); if ((val & EPC_WRITE_COMPLETE) == 0) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_eeprom_entry" " HW Error: EEPROM_WR <0x%x>\n", val)); return (NPI_FAILURE | NPI_ESPC_EEPROM_WRITE_FAILED); } break; case OP_GET: val = EPC_READ_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT); NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val); EPC_WAIT_RW_COMP(handle, &val, EPC_READ_COMPLETE); if ((val & EPC_READ_COMPLETE) == 0) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_eeprom_entry" " HW Error: EEPROM_RD <0x%x>", val)); return (NPI_FAILURE | NPI_ESPC_EEPROM_READ_FAILED); } NXGE_REG_RD64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), &val); /* * Workaround for synchronization issues - do a second PIO */ val = EPC_READ_INITIATE | (addr << EPC_EEPROM_ADDR_SHIFT); NXGE_REG_WR64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), val); EPC_WAIT_RW_COMP(handle, &val, EPC_READ_COMPLETE); if ((val & EPC_READ_COMPLETE) == 0) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_eeprom_entry HW Error: " "EEPROM_RD <0x%x>", val)); return (NPI_FAILURE | NPI_ESPC_EEPROM_READ_FAILED); } NXGE_REG_RD64(handle, ESPC_REG_ADDR(ESPC_PIO_STATUS_REG), &val); *data = val & EPC_EEPROM_DATA_MASK; break; default: NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_eeprom_entry" " Invalid Input addr <0x%x>\n", addr)); return (NPI_FAILURE | NPI_ESPC_OPCODE_INVALID); } return (NPI_SUCCESS); } npi_status_t npi_espc_mac_addr_get(npi_handle_t handle, uint8_t *data) { mac_addr_0_t mac0; mac_addr_1_t mac1; NXGE_REG_RD64(handle, ESPC_MAC_ADDR_0, &mac0.value); data[0] = mac0.bits.w0.byte0; data[1] = mac0.bits.w0.byte1; data[2] = mac0.bits.w0.byte2; data[3] = mac0.bits.w0.byte3; NXGE_REG_RD64(handle, ESPC_MAC_ADDR_1, &mac1.value); data[4] = mac1.bits.w0.byte4; data[5] = mac1.bits.w0.byte5; return (NPI_SUCCESS); } npi_status_t npi_espc_num_ports_get(npi_handle_t handle, uint8_t *data) { uint64_t val = 0; NXGE_REG_RD64(handle, ESPC_NUM_PORTS_MACS, &val); val &= NUM_PORTS_MASK; *data = (uint8_t)val; return (NPI_SUCCESS); } npi_status_t npi_espc_num_macs_get(npi_handle_t handle, uint8_t *data) { uint64_t val = 0; NXGE_REG_RD64(handle, ESPC_NUM_PORTS_MACS, &val); val &= NUM_MAC_ADDRS_MASK; val = (val >> NUM_MAC_ADDRS_SHIFT); *data = (uint8_t)val; return (NPI_SUCCESS); } npi_status_t npi_espc_model_str_get(npi_handle_t handle, char *data) { uint64_t val = 0; uint16_t str_len; int i, j; NXGE_REG_RD64(handle, ESPC_MOD_STR_LEN, &val); val &= MOD_STR_LEN_MASK; str_len = (uint8_t)val; if (str_len > MAX_MOD_STR_LEN) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_model_str_get" " Model string length %d exceeds max %d\n", str_len, MAX_MOD_STR_LEN)); return (NPI_FAILURE | NPI_ESPC_STR_LEN_INVALID); } /* * Might have to reverse the order depending on how the string * is written. */ for (i = 0, j = 0; i < str_len; j++) { NXGE_REG_RD64(handle, ESPC_MOD_STR(j), &val); data[i++] = ((char *)&val)[3]; data[i++] = ((char *)&val)[2]; data[i++] = ((char *)&val)[1]; data[i++] = ((char *)&val)[0]; } data[str_len] = '\0'; return (NPI_SUCCESS); } npi_status_t npi_espc_bd_model_str_get(npi_handle_t handle, char *data) { uint64_t val = 0; uint16_t str_len; int i, j; NXGE_REG_RD64(handle, ESPC_BD_MOD_STR_LEN, &val); val &= BD_MOD_STR_LEN_MASK; str_len = (uint8_t)val; if (str_len > MAX_BD_MOD_STR_LEN) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_model_str_get" " Board Model string length %d " "exceeds max %d\n", str_len, MAX_BD_MOD_STR_LEN)); return (NPI_FAILURE | NPI_ESPC_STR_LEN_INVALID); } /* * Might have to reverse the order depending on how the string * is written. */ for (i = 0, j = 0; i < str_len; j++) { NXGE_REG_RD64(handle, ESPC_BD_MOD_STR(j), &val); data[i++] = ((char *)&val)[3]; data[i++] = ((char *)&val)[2]; data[i++] = ((char *)&val)[1]; data[i++] = ((char *)&val)[0]; } data[str_len] = '\0'; return (NPI_SUCCESS); } npi_status_t npi_espc_phy_type_get(npi_handle_t handle, uint8_t *data) { phy_type_t phy; NXGE_REG_RD64(handle, ESPC_PHY_TYPE, &phy.value); data[0] = phy.bits.w0.pt0_phy_type; data[1] = phy.bits.w0.pt1_phy_type; data[2] = phy.bits.w0.pt2_phy_type; data[3] = phy.bits.w0.pt3_phy_type; return (NPI_SUCCESS); } npi_status_t npi_espc_port_phy_type_get(npi_handle_t handle, uint8_t *data, uint8_t portn) { phy_type_t phy; ASSERT(IS_PORT_NUM_VALID(portn)); NXGE_REG_RD64(handle, ESPC_PHY_TYPE, &phy.value); switch (portn) { case 0: *data = phy.bits.w0.pt0_phy_type; break; case 1: *data = phy.bits.w0.pt1_phy_type; break; case 2: *data = phy.bits.w0.pt2_phy_type; break; case 3: *data = phy.bits.w0.pt3_phy_type; break; default: NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_espc_port_phy_type_get" " Invalid Input: portn <%d>", portn)); return (NPI_FAILURE | NPI_ESPC_PORT_INVALID); } return (NPI_SUCCESS); } npi_status_t npi_espc_max_frame_get(npi_handle_t handle, uint16_t *data) { uint64_t val = 0; NXGE_REG_RD64(handle, ESPC_MAX_FM_SZ, &val); val &= MAX_FM_SZ_MASK; *data = (uint8_t)val; return (NPI_SUCCESS); } npi_status_t npi_espc_version_get(npi_handle_t handle, uint16_t *data) { uint64_t val = 0; NXGE_REG_RD64(handle, ESPC_VER_IMGSZ, &val); val &= VER_NUM_MASK; *data = (uint8_t)val; return (NPI_SUCCESS); } npi_status_t npi_espc_img_sz_get(npi_handle_t handle, uint16_t *data) { uint64_t val = 0; NXGE_REG_RD64(handle, ESPC_VER_IMGSZ, &val); val &= IMG_SZ_MASK; val = val >> IMG_SZ_SHIFT; *data = (uint8_t)val; return (NPI_SUCCESS); } npi_status_t npi_espc_chksum_get(npi_handle_t handle, uint8_t *data) { uint64_t val = 0; NXGE_REG_RD64(handle, ESPC_CHKSUM, &val); val &= CHKSUM_MASK; *data = (uint8_t)val; return (NPI_SUCCESS); } npi_status_t npi_espc_intr_num_get(npi_handle_t handle, uint8_t *data) { intr_num_t intr; NXGE_REG_RD64(handle, ESPC_INTR_NUM, &intr.value); data[0] = intr.bits.w0.pt0_intr_num; data[1] = intr.bits.w0.pt1_intr_num; data[2] = intr.bits.w0.pt2_intr_num; data[3] = intr.bits.w0.pt3_intr_num; return (NPI_SUCCESS); } void npi_espc_dump(npi_handle_t handle) { int i; uint64_t val = 0; NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "Dumping SEEPROM registers directly:\n\n")); for (i = 0; i < 23; i++) { NXGE_REG_RD64(handle, ESPC_NCR_REGN(i), &val); NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "reg[%d] 0x%llx\n", i, val & 0xffffffff)); } NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\n\n")); } uint32_t npi_espc_reg_get(npi_handle_t handle, int reg_idx) { uint64_t val = 0; uint32_t reg_val = 0; NXGE_REG_RD64(handle, ESPC_NCR_REGN(reg_idx), &val); reg_val = val & 0xffffffff; return (reg_val); } static inline uint8_t vpd_rd(npi_handle_t handle, uint32_t addr) { uint8_t data = 0; if (npi_espc_eeprom_entry(handle, OP_GET, addr, &data) != NPI_SUCCESS) data = 0; return (data); } npi_status_t npi_espc_vpd_info_get(npi_handle_t handle, p_npi_vpd_info_t vpdp, uint32_t rom_len) { int i, len; uint32_t base = 0, kstart = 0, ep, end; uint8_t fd_flags = 0; /* Fill the vpd_info struct with invalid vals */ (void) strcpy(vpdp->model, "\0"); (void) strcpy(vpdp->bd_model, "\0"); (void) strcpy(vpdp->phy_type, "\0"); (void) strcpy(vpdp->ver, "\0"); vpdp->num_macs = 0; for (i = 0; i < ETHERADDRL; i++) { vpdp->mac_addr[i] = 0; } ep = 0; end = ep + rom_len; /* go through the images till OBP image type is found */ while (ep < end) { base = ep; /* check for expansion rom header signature */ if (vpd_rd(handle, ep) != 0x55 || vpd_rd(handle, ep + 1) != 0xaa) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "npi_espc_vpd_info_get: expansion rom image " "not found, 0x%x [0x%x 0x%x]", ep, vpd_rd(handle, ep), vpd_rd(handle, ep + 1))); goto vpd_info_err; } /* go to the beginning of the PCI data struct of this image */ ep = ep + 23; ep = base + ((vpd_rd(handle, ep) << 8) | (vpd_rd(handle, ep + 1))); /* check for PCI data struct signature "PCIR" */ if ((vpd_rd(handle, ep) != 0x50) || (vpd_rd(handle, ep + 1) != 0x43) || (vpd_rd(handle, ep + 2) != 0x49) || (vpd_rd(handle, ep + 3) != 0x52)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "npi_espc_vpd_info_get: PCIR sig not found")); goto vpd_info_err; } /* check for image type OBP */ if (vpd_rd(handle, ep + 20) != 0x01) { /* go to the next image */ ep = base + ((vpd_rd(handle, base + 2)) * 512); continue; } /* find the beginning of the VPD data */ base = base + (vpd_rd(handle, ep + 8) | (vpd_rd(handle, ep + 9) << 8)); break; } /* check first byte of identifier string tag */ if (!base || (vpd_rd(handle, base + 0) != 0x82)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "npi_espc_vpd_info_get: Could not find VPD!!")); goto vpd_info_err; } /* * skip over the ID string descriptor to go to the read-only VPD * keywords list. */ i = (vpd_rd(handle, base + 1) | (vpd_rd(handle, base + 2) << 8)) + 3; while (i < EXPANSION_ROM_SIZE) { if (vpd_rd(handle, base + i) != 0x90) { /* no vpd found */ NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "nxge_get_vpd_info: Could not find " "VPD ReadOnly list!! [0x%x] %d", vpd_rd(handle, base + i), i)); goto vpd_info_err; } /* found a vpd read-only list, get its length */ len = vpd_rd(handle, base + i + 1) | (vpd_rd(handle, base + i + 2) << 8); /* extract keywords */ kstart = base + i + 3; ep = kstart; /* * Each keyword field is as follows: * 2 bytes keyword in the form of "Zx" where x = 0,1,2.... * 1 byte keyword data field length - klen * Now the actual keyword data field: * 1 byte VPD property instance, 'M' / 'I' * 2 bytes * 1 byte VPD property data type, 'B' / 'S' * 1 byte VPD property value length - n * Actual property string, length (klen - n - 5) bytes * Actual property value, length n bytes */ while ((ep - kstart) < len) { int klen = vpd_rd(handle, ep + 2); int dlen; char type; ep += 3; /* * Look for the following properties: * * local-mac-address: * -- VPD Instance 'I' * -- VPD Type String 'B' * -- property string == local-mac-address * * model: * -- VPD Instance 'M' * -- VPD Type String 'S' * -- property string == model * * board-model: * -- VPD Instance 'M' * -- VPD Type String 'S' * -- property string == board-model * * num-mac-addresses: * -- VPD Instance 'I' * -- VPD Type String 'B' * -- property string == num-mac-addresses * * phy-type: * -- VPD Instance 'I' * -- VPD Type String 'S' * -- property string == phy-type * * version: * -- VPD Instance 'M' * -- VPD Type String 'S' * -- property string == version */ if (vpd_rd(handle, ep) == 'M') { type = vpd_rd(handle, ep + 3); if (type == 'S') { dlen = vpd_rd(handle, ep + 4); if (npi_vpd_read_prop(handle, ep + 5, "model", dlen, vpdp->model)) { fd_flags |= FD_MODEL; goto next; } if (npi_vpd_read_prop(handle, ep + 5, "board-model", dlen, vpdp->bd_model)) { fd_flags |= FD_BD_MODEL; goto next; } if (npi_vpd_read_prop(handle, ep + 5, "version", dlen, vpdp->ver)) { fd_flags |= FD_FW_VERSION; goto next; } } goto next; } else if (vpd_rd(handle, ep) == 'I') { type = vpd_rd(handle, ep + 3); if (type == 'B') { dlen = vpd_rd(handle, ep + 4); if (npi_vpd_read_prop(handle, ep + 5, "local-mac-address", dlen, (char *)(vpdp->mac_addr))) { fd_flags |= FD_MAC_ADDR; goto next; } if (npi_vpd_read_prop(handle, ep + 5, "num-mac-addresses", dlen, (char *)&(vpdp->num_macs))) { fd_flags |= FD_NUM_MACS; } } else if (type == 'S') { dlen = vpd_rd(handle, ep + 4); if (npi_vpd_read_prop(handle, ep + 5, "phy-type", dlen, vpdp->phy_type)) { fd_flags |= FD_PHY_TYPE; } } goto next; } else { goto vpd_info_err; } next: if ((fd_flags & FD_ALL) == FD_ALL) goto vpd_success; ep += klen; } i += len + 3; } vpd_success: return (NPI_SUCCESS); vpd_info_err: return (NPI_FAILURE); } static int npi_vpd_read_prop(npi_handle_t handle, uint32_t ep, const char *prop, int len, char *val) { int prop_len = strlen(prop) + 1; int i; for (i = 0; i < prop_len; i++) { if (vpd_rd(handle, ep + i) != prop[i]) return (0); } ep += prop_len; for (i = 0; i < len; i++) val[i] = vpd_rd(handle, ep + i); return (1); }