PCI Firmware Specification v3.0 defined a new optional device list, allowing a single optionrom to handle several device IDs. Add support for this list when looking for an optionrom for a PCI device.
Signed-off-by: Daniel Verkamp daniel@drv.nu --- src/optionroms.c | 33 ++++++++++++++++++++++++++++----- src/optionroms.h | 2 +- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/src/optionroms.c b/src/optionroms.c index 00697b2..0023d90 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -292,19 +292,42 @@ map_pcirom(struct pci_device *pci) goto fail; }
- if (pd->vendor == pci->vendor && pd->device == pci->device - && pd->type == PCIROM_CODETYPE_X86) - // A match - break; + void *nextrom = (void*)((u32)rom + pd->ilen * 512); + + if (pd->vendor == pci->vendor && pd->type == PCIROM_CODETYPE_X86) + { + if (pd->device == pci->device) + { + dprintf(6, "Matched device in PCI header\n"); + goto found; + } + + // PCI header device ID did not match, but vendor ID did + // search device list if available + if (pd->drevision >= 3 && pd->devicelist) { + u16 *devicelist = (u16*)((u32)pd + pd->devicelist); + dprintf(6, "Searching PCIv3 device ID list at %p\n", devicelist); + while (devicelist < (u16*)nextrom && *devicelist) { + dprintf(6, "Dev list entry: %04x\n", *devicelist); + if (*devicelist == pci->device) { + dprintf(6, "Matched device in PCIv3 device list\n"); + goto found; + } + devicelist++; + } + dprintf(6, "Didn't match device ID list\n"); + } + } dprintf(6, "Didn't match dev/ven (got %04x:%04x) or type (got %d)\n" , pd->vendor, pd->device, pd->type); if (pd->indicator & 0x80) { dprintf(6, "No more images left\n"); goto fail; } - rom = (void*)((u32)rom + pd->ilen * 512); + rom = nextrom; }
+found: rom = copy_rom(rom); pci_config_writel(bdf, PCI_ROM_ADDRESS, orig); return rom; diff --git a/src/optionroms.h b/src/optionroms.h index 94ca4ae..487ea45 100644 --- a/src/optionroms.h +++ b/src/optionroms.h @@ -20,7 +20,7 @@ struct pci_data { u32 signature; u16 vendor; u16 device; - u16 vitaldata; + u16 devicelist; u16 dlen; u8 drevision; u8 class_lo;