static struct pci_dev * create_pci_dev(struct pci_access * pci, char * slot) { struct pci_filter filter; pci_filter_init(pci, &filter); if (pci_filter_parse_slot(&filter, slot)) { fprintf(stderr, "Failed to parse device id %s\n", slot); goto pci_filter_parse_failed; } pci_init(pci); struct pci_dev * dev = pci_get_dev(pci, filter.domain, filter.bus, filter.slot, filter.func); if (! dev) { fprintf(stderr, "Failed to allocate dev\n"); goto pci_get_dev_failed; } pci_fill_info(dev, PCI_FILL_IDENT); return dev; pci_get_dev_failed: pci_filter_parse_failed: return NULL; }
int print_ambs(struct pci_dev *dev, struct pci_access *pacc) { struct pci_dev *dev16; int branch, channel, amb; int max_branch, max_channel, max_amb; volatile void *ambconfig; uint64_t ambconfig_phys; printf("\n============= AMBs ============\n\n"); switch (dev->device_id) { case PCI_DEVICE_ID_INTEL_I5000P: case PCI_DEVICE_ID_INTEL_I5000X: case PCI_DEVICE_ID_INTEL_I5000Z: max_branch = 2; if (!(dev16 = pci_get_dev(pacc, 0, 0, 0x10, 0))) { perror("Error: no device 0:16.0\n"); return 1; } ambconfig_phys = ((uint64_t)pci_read_long(dev16, 0x4c) << 32) | pci_read_long(dev16, 0x48); max_channel = pci_read_byte(dev16, 0x56)/max_branch; max_amb = pci_read_byte(dev16, 0x57); pci_free_dev(dev16); break; default: fprintf(stderr, "Error: Dumping AMBs on this MCH is not (yet) supported.\n"); return 1; } if (!(ambconfig = map_physical(ambconfig_phys, AMB_CONFIG_SPACE_SIZE))) { fprintf(stderr, "Error mapping AMB config space\n"); return 1; } for(branch = 0; branch < max_branch; branch++) { for(channel = 0; channel < max_channel; channel++) { for(amb = 0; amb < max_amb; amb++) { dump_amb(ambconfig, branch, channel, amb); } } } unmap_physical((void *)ambconfig, AMB_CONFIG_SPACE_SIZE); return 0; }
int get_pch_sbreg_addr(struct pci_access *pci, pciaddr_t *sbreg_addr) { MSG("Checking for a Series 10 PCH system"); struct pci_dev *d31f1 = pci_get_dev(pci, 0, 0, 31, 1); pci_fill_info(d31f1, PCI_FILL_IDENT); if(d31f1->vendor_id == 0xffff) { MSG("Cannot find D31:F1, assuming it is hidden by firmware"); uint32_t p2sb_ctrl = pci_read_long(d31f1, REG_P2SB_CTRL); MSG("P2SB_CTRL=%02x", p2sb_ctrl); if(!(p2sb_ctrl & REG_P2SB_CTRL_HIDE)) { ERR("D31:F1 is hidden but P2SB_E1 is not 0xff, bailing out"); } MSG("Unhiding P2SB"); pci_write_long(d31f1, REG_P2SB_CTRL, p2sb_ctrl & ~REG_P2SB_CTRL_HIDE); p2sb_ctrl = pci_read_long(d31f1, REG_P2SB_CTRL); MSG("P2SB_CTRL=%02x", p2sb_ctrl); if(p2sb_ctrl & REG_P2SB_CTRL_HIDE) { ERR("Cannot unhide PS2B"); } pci_fill_info(d31f1, PCI_FILL_RESCAN | PCI_FILL_IDENT); if(d31f1->vendor_id == 0xffff) { ERR("P2SB unhidden but does not enumerate, bailing out"); } } pci_fill_info(d31f1, PCI_FILL_RESCAN | PCI_FILL_IDENT | PCI_FILL_BASES); if(d31f1->vendor_id != 0x8086) { ERR("Vendor of D31:F1 is not Intel"); } else if((uint32_t)d31f1->base_addr[0] == 0xffffffff) { ERR("SBREG_BAR is not implemented in D31:F1"); } *sbreg_addr = d31f1->base_addr[0] &~ 0xf; MSG("SBREG_ADDR=%08lx", *sbreg_addr); MSG("Hiding P2SB again"); uint32_t p2sb_ctrl = pci_read_long(d31f1, REG_P2SB_CTRL); pci_write_long(d31f1, REG_P2SB_CTRL, p2sb_ctrl | REG_P2SB_CTRL_HIDE); pci_fill_info(d31f1, PCI_FILL_RESCAN | PCI_FILL_IDENT); if(d31f1->vendor_id != 0xffff) { ERR("Cannot hide P2SB"); } return 0; }
static void dump_init(struct pci_access *a) { char *name = a->method_params[PCI_ACCESS_DUMP]; FILE *f; char buf[256]; struct pci_dev *dev = NULL; int len, bn, dn, fn, i, j; if (!a) a->error("dump: File name not given."); if (!(f = fopen(name, "r"))) a->error("dump: Cannot open %s: %s", name, strerror(errno)); while (fgets(buf, sizeof(buf)-1, f)) { char *z = strchr(buf, '\n'); if (!z) a->error("dump: line too long or unterminated"); *z-- = 0; if (z >= buf && *z == '\r') *z-- = 0; len = z - buf + 1; if (len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' && sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3) { dev = pci_get_dev(a, bn, dn, fn); dev->aux = pci_malloc(a, 256); memset(dev->aux, 0xff, 256); pci_link_dev(a, dev); } else if (!len) dev = NULL; else if (dev && len >= 51 && buf[2] == ':' && buf[3] == ' ' && sscanf(buf, "%x: ", &i) == 1) { z = buf+3; while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2])) { z++; if (sscanf(z, "%x", &j) != 1 || i >= 256) a->error("dump: Malformed line"); ((byte *) dev->aux)[i++] = j; z += 2; } } } }
static int shell_pci_getdev( int argc, char *argv[], struct shell_pci_modifier *mod) { unsigned long pciid; struct pci_dev *dev; if (argc != 3) return -1; pciid = get_pciid_from_string(argv[2]); if ((pciid & 0xffff0000) != 0) return -1; if (pci_get_dev(pciid, &dev)) { printf(" GETDEV: no device on [%lx:%lx:%lx]\n", PCI_DEV_EXPAND(pciid)); return 0; } printf(" PCI RAM DEVICE: %p\n", dev); return 0; }
static void dump_init(struct pci_access *a) { char *name = a->method_params[PCI_ACCESS_DUMP]; FILE *f; char buf[256]; struct pci_dev *dev = NULL; int len, mn, bn, dn, fn, i, j; if (!a) a->error("dump: File name not given."); if (!(f = fopen(name, "r"))) a->error("dump: Cannot open %s: %s", name, strerror(errno)); while (fgets(buf, sizeof(buf)-1, f)) { char *z = strchr(buf, '\n'); if (!z) a->error("dump: line too long or unterminated"); *z-- = 0; if (z >= buf && *z == '\r') *z-- = 0; len = z - buf + 1; mn = 0; if ((len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' && sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3) || (len >= 13 && buf[4] == ':' && buf[7] == ':' && buf[10] == '.' && buf[12] == ' ' && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)) { dev = pci_get_dev(a, mn, bn, dn, fn); dump_alloc_data(dev, 256); pci_link_dev(a, dev); } else if (!len) dev = NULL; else if (dev && (len >= 51 && buf[2] == ':' && buf[3] == ' ' || len >= 52 && buf[3] == ':' && buf[4] == ' ') && sscanf(buf, "%x: ", &i) == 1) { struct dump_data *dd = dev->aux; z = strchr(buf, ' '); while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2])) { z++; if (sscanf(z, "%x", &j) != 1 || i >= 256) a->error("dump: Malformed line"); if (i >= 4096) break; if (i > dd->allocated) /* Need to re-allocate the buffer */ { dump_alloc_data(dev, 4096); memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256); pci_mfree(dd); dd = dev->aux; } dd->data[i++] = j; if (i > dd->len) dd->len = i; z += 2; } } } }
int print_pmbase(struct pci_dev *sb, struct pci_access *pacc) { int i, size; uint16_t pmbase; const io_register_t *pm_registers; struct pci_dev *acpi; printf("\n============= PMBASE ============\n\n"); switch (sb->device_id) { case PCI_DEVICE_ID_INTEL_3400: case PCI_DEVICE_ID_INTEL_3420: case PCI_DEVICE_ID_INTEL_3450: case PCI_DEVICE_ID_INTEL_3400_DESKTOP: case PCI_DEVICE_ID_INTEL_3400_MOBILE: case PCI_DEVICE_ID_INTEL_3400_MOBILE_SFF: case PCI_DEVICE_ID_INTEL_B55_A: case PCI_DEVICE_ID_INTEL_B55_B: case PCI_DEVICE_ID_INTEL_H55: case PCI_DEVICE_ID_INTEL_H57: case PCI_DEVICE_ID_INTEL_HM55: case PCI_DEVICE_ID_INTEL_HM57: case PCI_DEVICE_ID_INTEL_P55: case PCI_DEVICE_ID_INTEL_PM55: case PCI_DEVICE_ID_INTEL_Q57: case PCI_DEVICE_ID_INTEL_QM57: case PCI_DEVICE_ID_INTEL_QS57: case PCI_DEVICE_ID_INTEL_Z68: case PCI_DEVICE_ID_INTEL_P67: case PCI_DEVICE_ID_INTEL_UM67: case PCI_DEVICE_ID_INTEL_HM65: case PCI_DEVICE_ID_INTEL_H67: case PCI_DEVICE_ID_INTEL_HM67: case PCI_DEVICE_ID_INTEL_Q65: case PCI_DEVICE_ID_INTEL_QS67: case PCI_DEVICE_ID_INTEL_Q67: case PCI_DEVICE_ID_INTEL_QM67: case PCI_DEVICE_ID_INTEL_B65: case PCI_DEVICE_ID_INTEL_C202: case PCI_DEVICE_ID_INTEL_C204: case PCI_DEVICE_ID_INTEL_C206: case PCI_DEVICE_ID_INTEL_H61: case PCI_DEVICE_ID_INTEL_Z77: case PCI_DEVICE_ID_INTEL_Z75: case PCI_DEVICE_ID_INTEL_Q77: case PCI_DEVICE_ID_INTEL_Q75: case PCI_DEVICE_ID_INTEL_B75: case PCI_DEVICE_ID_INTEL_H77: case PCI_DEVICE_ID_INTEL_C216: case PCI_DEVICE_ID_INTEL_QM77: case PCI_DEVICE_ID_INTEL_QS77: case PCI_DEVICE_ID_INTEL_HM77: case PCI_DEVICE_ID_INTEL_UM77: case PCI_DEVICE_ID_INTEL_HM76: case PCI_DEVICE_ID_INTEL_HM75: case PCI_DEVICE_ID_INTEL_HM70: case PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_FULL: case PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_PREM: case PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_BASE: case PCI_DEVICE_ID_INTEL_BAYTRAIL_LPC: pmbase = pci_read_word(sb, 0x40) & 0xff80; pm_registers = pch_pm_registers; size = ARRAY_SIZE(pch_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH10R: pmbase = pci_read_word(sb, 0x40) & 0xff80; pm_registers = ich10_pm_registers; size = ARRAY_SIZE(ich10_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH7: case PCI_DEVICE_ID_INTEL_ICH7M: case PCI_DEVICE_ID_INTEL_ICH7DH: case PCI_DEVICE_ID_INTEL_ICH7MDH: case PCI_DEVICE_ID_INTEL_NM10: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich7_pm_registers; size = ARRAY_SIZE(ich7_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH9DH: case PCI_DEVICE_ID_INTEL_ICH9DO: case PCI_DEVICE_ID_INTEL_ICH9R: case PCI_DEVICE_ID_INTEL_ICH9: case PCI_DEVICE_ID_INTEL_ICH9M: case PCI_DEVICE_ID_INTEL_ICH9ME: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich9_pm_registers; size = ARRAY_SIZE(ich9_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH8: case PCI_DEVICE_ID_INTEL_ICH8M: case PCI_DEVICE_ID_INTEL_ICH8ME: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich8_pm_registers; size = ARRAY_SIZE(ich8_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH6: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich6_pm_registers; size = ARRAY_SIZE(ich6_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH5: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich5_pm_registers; size = ARRAY_SIZE(ich5_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH4: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich4_pm_registers; size = ARRAY_SIZE(ich4_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH2: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich2_pm_registers; size = ARRAY_SIZE(ich2_pm_registers); break; case PCI_DEVICE_ID_INTEL_ICH0: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = ich0_pm_registers; size = ARRAY_SIZE(ich0_pm_registers); break; case PCI_DEVICE_ID_INTEL_82371XX: acpi = pci_get_dev(pacc, sb->domain, sb->bus, sb->dev, 3); if (!acpi) { printf("Southbridge function 3 not found.\n"); return 1; } pmbase = pci_read_word(acpi, 0x40) & 0xfffc; pm_registers = i82371xx_pm_registers; size = ARRAY_SIZE(i82371xx_pm_registers); break; case PCI_DEVICE_ID_INTEL_I63XX: pmbase = pci_read_word(sb, 0x40) & 0xfffc; pm_registers = i63xx_pm_registers; size = ARRAY_SIZE(i63xx_pm_registers); break; case 0x1234: // Dummy for non-existent functionality printf("This southbridge does not have PMBASE.\n"); return 1; default: printf("Error: Dumping PMBASE on this southbridge is not (yet) supported.\n"); return 1; } printf("PMBASE = 0x%04x (IO)\n\n", pmbase); for (i = 0; i < size; i++) { switch (pm_registers[i].size) { case 8: printf("pmbase+0x%04x: 0x%08x (%s)\n" " 0x%08x\n", pm_registers[i].addr, inl(pmbase+pm_registers[i].addr), pm_registers[i].name, inl(pmbase+pm_registers[i].addr+4)); break; case 4: printf("pmbase+0x%04x: 0x%08x (%s)\n", pm_registers[i].addr, inl(pmbase+pm_registers[i].addr), pm_registers[i].name); break; case 2: printf("pmbase+0x%04x: 0x%04x (%s)\n", pm_registers[i].addr, inw(pmbase+pm_registers[i].addr), pm_registers[i].name); break; case 1: printf("pmbase+0x%04x: 0x%02x (%s)\n", pm_registers[i].addr, inb(pmbase+pm_registers[i].addr), pm_registers[i].name); break; } } return 0; }
sbone_err_t sbone_dev_open_pcie (sbone_dev_t* dev, int dom, int bus, int _dev, int fun) { static const size_t nbar = sizeof(dev->bar_addrs) / sizeof(dev->bar_addrs[0]); int mem_fd; size_t i; struct pci_access* pci_access; struct pci_dev* pci_dev; int err = -1; /* zero device */ for (i = 0; i < nbar; ++i) dev->bar_sizes[i] = 0; dev->nid = -1; /* find the pci device */ pci_access = pci_alloc(); if (pci_access == NULL) { PERROR(); goto on_error_0; } pci_init(pci_access); pci_scan_bus(pci_access); pci_dev = pci_get_dev(pci_access, dom, bus, _dev, fun); if (pci_dev == NULL) { PERROR(); goto on_error_1; } pci_fill_info(pci_dev, PCI_FILL_IDENT | PCI_FILL_BASES); /* map bars */ mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (mem_fd == -1) { PERROR(); goto on_error_2; } for (i = 0; i < nbar; ++i) { #if 1 /* FIXME: pci_dev->size[i] not detected by pci_fill_info ... */ if (pci_dev->base_addr[i] != 0) pci_dev->size[i] = get_bar_size(pci_access, pci_dev, i); #endif /* FIXME */ dev->bar_sizes[i] = pci_dev->size[i]; if (dev->bar_sizes[i] == 0) continue ; dev->bar_addrs[i] = (uintptr_t)mmap ( NULL, pci_dev->size[i], PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, mem_fd, pci_dev->base_addr[i] ); if (dev->bar_addrs[i] == (uintptr_t)MAP_FAILED) { size_t j; for (j = 0; j < i; ++j) munmap((void*)dev->bar_addrs[i], dev->bar_sizes[i]); PERROR(); goto on_error_3; } } if ((dev->fd = open("/dev/sbone", O_RDWR)) == -1) { PERROR(); goto on_error_3; } /* success */ err = 0; on_error_3: close(mem_fd); on_error_2: pci_free_dev(pci_dev); on_error_1: pci_cleanup(pci_access); on_error_0: return err; }
static void dump_init(struct pci_access *a) { char *name = pci_get_param(a, "dump.name"); FILE *f; char buf[256]; struct pci_dev *dev = NULL; int len, mn, bn, dn, fn, i, j; if (!name) a->error("dump: File name not given."); if (!(f = fopen(name, "r"))) a->error("dump: Cannot open %s: %s", name, strerror(errno)); while (fgets(buf, sizeof(buf)-1, f)) { char *z = strchr(buf, '\n'); if (!z) { fclose(f); a->error("dump: line too long or unterminated"); } *z-- = 0; if (z >= buf && *z == '\r') *z-- = 0; len = z - buf + 1; mn = 0; if ((dump_validate(buf, "##:##.# ") && sscanf(buf, "%x:%x.%d", &bn, &dn, &fn) == 3) || (dump_validate(buf, "####:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)) { dev = pci_get_dev(a, mn, bn, dn, fn); dump_alloc_data(dev, 256); pci_link_dev(a, dev); } else if (!len) dev = NULL; else if (dev && (dump_validate(buf, "##: ") || dump_validate(buf, "###: ")) && sscanf(buf, "%x: ", &i) == 1) { struct dump_data *dd = dev->aux; z = strchr(buf, ' ') + 1; while (isxdigit(z[0]) && isxdigit(z[1]) && (!z[2] || z[2] == ' ') && sscanf(z, "%x", &j) == 1 && j < 256) { if (i >= 4096) { fclose(f); a->error("dump: At most 4096 bytes of config space are supported"); } if (i >= dd->allocated) /* Need to re-allocate the buffer */ { dump_alloc_data(dev, 4096); memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256); pci_mfree(dd); dd = dev->aux; } dd->data[i++] = j; if (i > dd->len) dd->len = i; z += 2; if (*z) z++; } if (*z) { fclose(f); a->error("dump: Malformed line"); } } } fclose(f); }