aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2017-06-06 08:59:17 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-06-06 20:49:05 +1000
commitacd94a9c7c589e36db013c026b5910d24af26bab (patch)
tree86fcd295abaa087d58746ecb00e79226672a5780
parent25897895a076471dc4566671fda5cf7d2a2c3379 (diff)
downloadskiboot-acd94a9c7c589e36db013c026b5910d24af26bab.zip
skiboot-acd94a9c7c589e36db013c026b5910d24af26bab.tar.gz
skiboot-acd94a9c7c589e36db013c026b5910d24af26bab.tar.bz2
pci: Add bitmap to know if a pci device has cfg reg filters
This avoids doing a search through the list of all devices on every config space access to every device under a PHB. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/pci-iov.c1
-rw-r--r--core/pci.c10
-rw-r--r--hw/phb3.c9
-rw-r--r--include/pci.h4
4 files changed, 17 insertions, 7 deletions
diff --git a/core/pci-iov.c b/core/pci-iov.c
index 14c810b..6abb85a 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 0adc6d2..5671b69 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 b33ed7b..c99f1de 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 dc418a9..1e84b51 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -20,6 +20,7 @@
#include <opal.h>
#include <device.h>
#include <lock.h>
+#include <bitmap.h>
#include <ccan/list/list.h>
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,