void vpd_iohub_load(struct dt_node *hub_node) { char record[4] = "LXR0"; const void *valid_lx; uint8_t lx_size; int r; const uint32_t *p; const uint8_t *lx; unsigned int lxrn; p = dt_prop_get_def(hub_node, "ibm,vpd-lx-info", NULL); if (!p) return; lxrn = p[0]; lx = (const char *)&p[1]; /* verify the lid preload has started */ if (!vpd_lid || !vpd_lid_no) { prlog(PR_WARNING, "VPD: WARNING: Unable to load VPD lid"); return; } r = fsp_wait_lid_loaded(vpd_lid_no); if (r) goto fail; /* Validate it */ if (lxrn < 9) record[3] = '0' + lxrn; else memcpy(record, "VINI", 4); valid_lx = vpd_find(vpd_lid, vpd_lid_size, record, "LX", &lx_size); if (!valid_lx || lx_size != 8) { prerror("VPD: Cannot find validation LX record\n"); goto fail; } if (memcmp(valid_lx, lx, 8) != 0) { prerror("VPD: LX record mismatch !\n"); goto fail; } printf("VPD: Loaded %zu bytes\n", vpd_lid_size); dt_add_property(hub_node, "ibm,io-vpd", vpd_lid, vpd_lid_size); free(vpd_lid); return; fail: free(vpd_lid); vpd_lid = NULL; prerror("VPD: Failed to load VPD LID\n"); return; }
char *vpd_gets(const char *key, char *buffer, int size, enum vpd_region region) { const void *string_address; int string_size; string_address = vpd_find(key, &string_size, region); if (!string_address) return NULL; if (size > (string_size + 1)) { memcpy(buffer, string_address, string_size); buffer[string_size] = '\0'; } else { memcpy(buffer, string_address, size - 1); buffer[size - 1] = '\0'; } return buffer; }
static void add_size_to_ram_area(struct dt_node *ram_node, const struct HDIF_common_hdr *hdr, int indx_vpd) { const void *fruvpd; unsigned int fruvpd_sz; const void *kw; char *str; uint8_t kwsz; fruvpd = HDIF_get_idata(hdr, indx_vpd, &fruvpd_sz); if (!CHECK_SPPTR(fruvpd)) return; /* DIMM Size */ kw = vpd_find(fruvpd, fruvpd_sz, "VINI", "SZ", &kwsz); if (!kw) return; str = zalloc(kwsz + 1); memcpy(str, kw, kwsz); dt_add_property_string(ram_node, "size", str); free(str); }
/* Helper to load a VPD LID. Pass a ptr to the corresponding LX keyword */ static void *vpd_lid_load(const uint8_t *lx, uint8_t lxrn, size_t *size) { /* Now this is a guess game as we don't have the info from the * pHyp folks. But basically, it seems to boil down to loading * a LID whose name is 0x80e000yy where yy is the last 2 digits * of the LX record in hex. * * [ Correction: After a chat with some folks, it looks like it's * actually 4 digits, though the lid number is limited to fff * so we weren't far off. ] * * For safety, we look for a matching LX record in an LXRn * (n = lxrn argument) or in VINI if lxrn=0xff */ uint32_t lid_no = 0x80e00000 | ((lx[6] & 0xf) << 8) | lx[7]; /* We don't quite know how to get to the LID directory so * we don't know the size. Let's allocate 16K. All the VPD LIDs * I've seen so far are much smaller. */ #define VPD_LID_MAX_SIZE 0x4000 void *data = malloc(VPD_LID_MAX_SIZE); char record[4] = "LXR0"; const void *valid_lx; uint8_t lx_size; int rc; if (!data) { prerror("VPD: Failed to allocate memory for LID\n"); return NULL; } /* Adjust LID number for flash side */ lid_no = fsp_adjust_lid_side(lid_no); printf("VPD: Trying to load VPD LID 0x%08x...\n", lid_no); *size = VPD_LID_MAX_SIZE; /* Load it from the FSP */ rc = fsp_fetch_data(0, FSP_DATASET_NONSP_LID, lid_no, 0, data, size); if (rc) { prerror("VPD: Error %d loading VPD LID\n", rc); goto fail; } /* Validate it */ if (lxrn < 9) record[3] = '0' + lxrn; else memcpy(record, "VINI", 4); valid_lx = vpd_find(data, *size, record, "LX", &lx_size); if (!valid_lx || lx_size != 8) { prerror("VPD: Cannot find validation LX record\n"); goto fail; } if (memcmp(valid_lx, lx, 8) != 0) { prerror("VPD: LX record mismatch !\n"); goto fail; } printf("VPD: Loaded %zu bytes\n", *size); /* Got it ! */ return realloc(data, *size); fail: free(data); return NULL; }