This updat is a reminiscence of x86 implementation - to provision a possible future common PCI interface. Make pcidevaddr_t as int, not u16. There is no good reason to limit it to u16 while omitting properly adjusted bit fields. Cc: Andrew Jones <drjones@xxxxxxxxxx> Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx> --- lib/pci-host-generic.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pci.h | 18 +++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c index f3161f8..3d9c271 100644 --- a/lib/pci-host-generic.c +++ b/lib/pci-host-generic.c @@ -29,6 +29,11 @@ static u8 pci_config_readb(const void *conf, int off) return readb(conf + off); } +static u16 pci_config_readw(const void *conf, int off) +{ + return readw(conf + off); +} + static u32 pci_config_readl(const void *conf, int off) { return readl(conf + off); @@ -351,6 +356,55 @@ int pci_bus_scan(struct pci *pci) return nr_dev; } +static pcidevaddr_t encode_addr(int bus, int dev, int fn) +{ + assert(bus < 256 && dev < 32 && fn < 8); + return bus << 16 | dev << 11 | fn; +} + +static void decode_addr(pcidevaddr_t bdf, int *bus, int *dev, int *fn) +{ + *bus = (bdf >> 16) & 0xff; + *dev = (bdf >> 11) & 0x1f; + *fn = (bdf >> 8) & 0x03; +} + +pcidevaddr_t pci_find_dev(struct pci *pci, u16 vendor_id, u16 device_id) +{ + void *conf; + int dev; + + for_each_pci_dev(pci, dev, conf) { + if (vendor_id == pci_config_readw(conf, PCI_VENDOR_ID) && + device_id == pci_config_readw(conf, PCI_DEVICE_ID)) + return encode_addr(0, dev, 0); + } + + return PCIDEVADDR_INVALID; +} + +phys_addr_t pci_bar_addr(struct pci *pci, pcidevaddr_t bdf, int bar) +{ + void *conf; + struct pci_addr_space *res; + pci_res_type_t type; + phys_addr_t addr; + bool is64; + int bus, dev, fn; + + decode_addr(bdf, &bus, &dev, &fn); + assert(!bus && !fn); /* We support bus 0 and function 0 only */ + + conf = dev_conf(pci, dev); + assert(pci_config_readb(conf, PCI_HEADER_TYPE) == + PCI_HEADER_TYPE_NORMAL); + + assert(pci_get_bar(conf, bar, &type, &addr, NULL, &is64)); + assert(res = pci_find_res(pci->sysdata, type)); + + return res->cpu_range.start + (addr - res->pci_range.start); +} + struct pci *pci_dt_probe(void) { struct pci_host_bridge *host; diff --git a/lib/pci.h b/lib/pci.h index bc4f2d2..7d9baad 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -7,8 +7,26 @@ struct pci { void *sysdata; }; +/* + * Make it a reminiscence of x86 implementation - to provision a possible + * future merge. + * + * Unlike x86, PCIDEVADDR_INVALID is -1, not 0. PCI bus-device-function + * of 00.00:0 is a legitimate PCI address, so x86 needs a fix. + * + * Also, make pcidevaddr_t int, not u16. There is no good reason to limit + * it to u16 while omitting properly adjusted bit fields. + * + */ +typedef enum { + PCIDEVADDR_INVALID = -1 +} pcidevaddr_t; + extern struct pci *pci_dt_probe(void); extern int pci_bus_scan(struct pci *pci); extern void pci_shutdown(struct pci *pci); +extern pcidevaddr_t pci_find_dev(struct pci *pci, u16 vendor_id, u16 device_id); +extern phys_addr_t pci_bar_addr(struct pci *pci, pcidevaddr_t bdf, int bar_nr); + #endif -- 1.8.3.1 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm