diff --git a/core/pci-iov.c b/core/pci-iov.c index 14c810b960fb..6abb85addd7b 100644 --- a/core/pci-iov.c +++ b/core/pci-iov.c @@ -184,6 +184,7 @@ static void pci_iov_init_VF(struct pci_device *pd, struct pci_device *vf) vf->dn = NULL; vf->slot = NULL; vf->parent = pd; + vf->phb = pd->phb; list_head_init(&vf->pcrf); list_head_init(&vf->children); } diff --git a/core/pci.c b/core/pci.c index 0adc6d2cd768..5671b690d058 100644 --- a/core/pci.c +++ b/core/pci.c @@ -247,6 +247,7 @@ static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *paren PCIERR(phb, bdfn,"Failed to allocate structure pci_device !\n"); goto fail; } + pd->phb = phb; pd->bdfn = bdfn; pd->vdid = vdid; pci_cfg_read32(phb, bdfn, PCI_CFG_SUBSYS_VENDOR_ID, &pd->sub_vdid); @@ -951,6 +952,9 @@ int64_t pci_register_phb(struct phb *phb, int opal_id) init_lock(&phb->lock); list_head_init(&phb->devices); + phb->filter_map = zalloc(BITMAP_BYTES(0x10000)); + assert(phb->filter_map); + return OPAL_SUCCESS; } @@ -1764,6 +1768,11 @@ struct pci_cfg_reg_filter *pci_find_cfg_reg_filter(struct pci_device *pd, return NULL; } +bool pci_device_has_cfg_reg_filters(struct phb *phb, uint16_t bdfn) +{ + return bitmap_tst_bit(*phb->filter_map, bdfn); +} + struct pci_cfg_reg_filter *pci_add_cfg_reg_filter(struct pci_device *pd, uint32_t start, uint32_t len, uint32_t flags, @@ -1793,6 +1802,7 @@ struct pci_cfg_reg_filter *pci_add_cfg_reg_filter(struct pci_device *pd, if (pd->pcrf_end < (start + len)) pd->pcrf_end = start + len; list_add_tail(&pd->pcrf, &pcrf->link); + bitmap_set_bit(*pd->phb->filter_map, pd->bdfn); return pcrf; } diff --git a/hw/phb3.c b/hw/phb3.c index b33ed7ba5311..c99f1deed620 100644 --- a/hw/phb3.c +++ b/hw/phb3.c @@ -236,13 +236,8 @@ static void phb3_pcicfg_filter(struct phb *phb, uint32_t bdfn, return; } - /* FIXME: It harms the performance to search the PCI - * device which doesn't have any filters at all. So - * it's worthy to maintain a table in PHB to indicate - * the PCI devices who have filters. However, bitmap - * seems not supported by skiboot yet. To implement - * it after bitmap is supported. - */ + if (!pci_device_has_cfg_reg_filters(phb, bdfn)) + return; pd = pci_find_dev(phb, bdfn); pcrf = pd ? pci_find_cfg_reg_filter(pd, offset, len) : NULL; if (!pcrf || !pcrf->func) diff --git a/include/pci.h b/include/pci.h index dc418a906acb..1e84b512ccf7 100644 --- a/include/pci.h +++ b/include/pci.h @@ -20,6 +20,7 @@ #include #include #include +#include #include struct pci_device; @@ -87,6 +88,7 @@ struct pci_device { struct dt_node *dn; struct pci_slot *slot; struct pci_device *parent; + struct phb *phb; struct list_head children; struct list_node link; }; @@ -343,6 +345,7 @@ struct phb { const struct phb_ops *ops; struct pci_lsi_state lstate; uint32_t mps; + bitmap_t *filter_map; /* PCI-X only slot info, for PCI-E this is in the RC bridge */ struct pci_slot *slot; @@ -424,6 +427,7 @@ extern struct pci_device *pci_walk_dev(struct phb *phb, void *userdata); extern struct pci_device *pci_find_dev(struct phb *phb, uint16_t bdfn); extern void pci_restore_bridge_buses(struct phb *phb, struct pci_device *pd); +extern bool pci_device_has_cfg_reg_filters(struct phb *phb, uint16_t bdfn); extern struct pci_cfg_reg_filter *pci_find_cfg_reg_filter(struct pci_device *pd, uint32_t start, uint32_t len); extern struct pci_cfg_reg_filter *pci_add_cfg_reg_filter(struct pci_device *pd,