int cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *np) { int i, len, rc; char *p; const __be32 *prop; u16 device_id, vendor_id; u32 val = 0, class_code; /* Properties are read in the same order as listed in PAPR */ if (cxl_verbose) { pr_info("Dump of the 'ibm,coherent-platform-function' node properties:\n"); prop = of_get_property(np, "compatible", &len); i = 0; while (i < len) { p = (char *) prop + i; pr_info("compatible: %s\n", p); i += strlen(p) + 1; } read_prop_string(np, "name"); } rc = read_phys_addr(np, "reg", afu); if (rc) return rc; rc = read_phys_addr(np, "assigned-addresses", afu); if (rc) return rc; if (afu->psn_phys == 0) afu->psa = false; else afu->psa = true; if (cxl_verbose) { read_prop_string(np, "ibm,loc-code"); read_prop_string(np, "device_type"); } read_prop_dword(np, "ibm,#processes", &afu->max_procs_virtualised); if (cxl_verbose) { read_prop_dword(np, "ibm,scratchpad-size", &val); read_prop_dword(np, "ibm,programmable", &val); read_prop_string(np, "ibm,phandle"); read_vpd(NULL, afu); } read_prop_dword(np, "ibm,max-ints-per-process", &afu->guest->max_ints); afu->irqs_max = afu->guest->max_ints; prop = read_prop_dword(np, "ibm,min-ints-per-process", &afu->pp_irqs); if (prop) { /* One extra interrupt for the PSL interrupt is already * included. Remove it now to keep only AFU interrupts and * match the native case. */ afu->pp_irqs--; } if (cxl_verbose) { read_prop_dword(np, "ibm,max-ints", &val); read_prop_dword(np, "ibm,vpd-size", &val); } read_prop64_dword(np, "ibm,error-buffer-size", &afu->eb_len); afu->eb_offset = 0; if (cxl_verbose) read_prop_dword(np, "ibm,config-record-type", &val); read_prop64_dword(np, "ibm,config-record-size", &afu->crs_len); afu->crs_offset = 0; read_prop_dword(np, "ibm,#config-records", &afu->crs_num); if (cxl_verbose) { for (i = 0; i < afu->crs_num; i++) { rc = cxl_ops->afu_cr_read16(afu, i, PCI_DEVICE_ID, &device_id); if (!rc) pr_info("record %d - device-id: %#x\n", i, device_id); rc = cxl_ops->afu_cr_read16(afu, i, PCI_VENDOR_ID, &vendor_id); if (!rc) pr_info("record %d - vendor-id: %#x\n", i, vendor_id); rc = cxl_ops->afu_cr_read32(afu, i, PCI_CLASS_REVISION, &class_code); if (!rc) { class_code >>= 8; pr_info("record %d - class-code: %#x\n", i, class_code); } } read_prop_dword(np, "ibm,function-number", &val); read_prop_dword(np, "ibm,privileged-function", &val); read_prop_dword(np, "vendor-id", &val); read_prop_dword(np, "device-id", &val); read_prop_dword(np, "revision-id", &val); read_prop_dword(np, "class-code", &val); read_prop_dword(np, "subsystem-vendor-id", &val); read_prop_dword(np, "subsystem-id", &val); }
void cap_vpd(struct device *d) { word res_addr = 0, res_len, part_pos, part_len; byte buf[256]; byte tag; byte csum = 0; printf("Vital Product Data\n"); if (verbose < 2) return; while (res_addr <= PCI_VPD_ADDR_MASK) { if (!read_vpd(d, res_addr, &tag, 1, &csum)) break; if (tag & 0x80) { if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3) break; if (!read_vpd(d, res_addr + 1, buf, 2, &csum)) break; res_len = buf[0] + (buf[1] << 8); res_addr += 3; } else { res_len = tag & 7; tag >>= 3; res_addr += 1; } if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr) break; part_pos = 0; switch (tag) { case 0x0f: printf("\t\tEnd\n"); return; case 0x82: printf("\t\tProduct Name: "); while (part_pos < res_len) { part_len = res_len - part_pos; if (part_len > sizeof(buf)) part_len = sizeof(buf); if (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum)) break; print_vpd_string(buf, part_len); part_pos += part_len; } printf("\n"); break; case 0x90: case 0x91: printf("\t\t%s fields:\n", (tag == 0x90) ? "Read-only" : "Read/write"); while (part_pos + 3 <= res_len) { word read_len; const struct vpd_item *item; byte id1, id2; if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum)) break; part_pos += 3; id1 = buf[0]; id2 = buf[1]; part_len = buf[2]; if (part_len > res_len - part_pos) break; /* Is this item known? */ for (item=vpd_items; item->id1 && item->id1 != id1 || item->id2 && item->id2 != id2; item++) ; /* Only read the first byte of the RV field because the * remaining bytes are not included in the checksum. */ read_len = (item->format == F_RESVD) ? 1 : part_len; if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum)) break; printf("\t\t\t[%c%c] %s: ", id1, id2, item->name); switch (item->format) { case F_TEXT: print_vpd_string(buf, part_len); printf("\n"); break; case F_BINARY: print_vpd_binary(buf, part_len); printf("\n"); break; case F_RESVD: printf("checksum %s, %d byte(s) reserved\n", csum ? "bad" : "good", part_len - 1); break; case F_RDWR: printf("%d byte(s) free\n", part_len); break; } part_pos += part_len; } break; default: printf("\t\tUnknown %s resource type %02x, will not decode more.\n", (tag & 0x80) ? "large" : "small", tag & ~0x80); return; } res_addr += res_len; } if (res_addr == 0) printf("\t\tNot readable\n"); else printf("\t\tNo end tag found\n"); }