aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2012-09-17 22:20:28 -0700
committerYinghai Lu <yinghai@kernel.org>2012-09-17 22:20:28 -0700
commit1ccdaf884736ea976fce580b786c9e7e95d45176 (patch)
tree9347abef0838f7e57317f6f50f1837380c4c91ef
parent90d5807db727abf357342105208f6a030de22621 (diff)
downloadlinux-yinghai-1ccdaf884736ea976fce580b786c9e7e95d45176.tar.gz
pci: pci resource iterator
Currently pci_dev structure holds an array of 17 PCI resources; six base BARs, one ROM BAR, four BRIDGE BARs, six sriov BARs. This is wasteful. A bridge device just needs the 4 bridge resources. A non-bridge device just needs the six base resources and one ROM resource. The sriov resources are needed only if the device has SRIOV capability. The pci_dev structure needs to be re-organized to avoid unnecessary bloating. However too much code outside the pci-bus driver, assumes the internal details of the pci_dev structure, thus making it hard to re-organize the datastructure. As a first step this patch provides generic methods to access the resource structure of the pci_dev. Finally we can re-organize the resource structure in the pci_dev structure and correspondingly update the methods. -v2: Consolidated iterator interface as per Bjorn's suggestion. -v3: Add the idx back - Yinghai Lu -v7: Change to use bitmap for searching - Yinghai Lu Signed-off-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r--drivers/pci/probe.c47
-rw-r--r--include/linux/pci.h24
2 files changed, 71 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bfdd3b2489f771..29f2c6f5622cec 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -123,6 +123,53 @@ int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res)
return -1;
}
+static void __init_res_idx_mask(unsigned long *mask, int flag)
+{
+ bitmap_zero(mask, PCI_NUM_RESOURCES);
+ if (flag & PCI_STD_RES)
+ bitmap_set(mask, PCI_STD_RESOURCES,
+ PCI_STD_RESOURCE_END - PCI_STD_RESOURCES + 1);
+ if (flag & PCI_ROM_RES)
+ bitmap_set(mask, PCI_ROM_RESOURCE, 1);
+#ifdef CONFIG_PCI_IOV
+ if (flag & PCI_IOV_RES)
+ bitmap_set(mask, PCI_IOV_RESOURCES,
+ PCI_IOV_RESOURCE_END - PCI_IOV_RESOURCES + 1);
+#endif
+ if (flag & PCI_BRIDGE_RES)
+ bitmap_set(mask, PCI_BRIDGE_RESOURCES,
+ PCI_BRIDGE_RESOURCE_END - PCI_BRIDGE_RESOURCES + 1);
+}
+
+static DECLARE_BITMAP(res_idx_mask[1 << PCI_RES_BLOCK_NUM], PCI_NUM_RESOURCES);
+static int __init pci_res_idx_mask_init(void)
+{
+ int i;
+
+ for (i = 0; i < (1 << PCI_RES_BLOCK_NUM); i++)
+ __init_res_idx_mask(res_idx_mask[i], i);
+
+ return 0;
+}
+postcore_initcall(pci_res_idx_mask_init);
+
+static inline unsigned long *get_res_idx_mask(int flag)
+{
+ return res_idx_mask[flag & ((1 << PCI_RES_BLOCK_NUM) - 1)];
+}
+
+int pci_next_resource_idx(int i, int flag)
+{
+ i++;
+ if (i < PCI_NUM_RESOURCES)
+ i = find_next_bit(get_res_idx_mask(flag), PCI_NUM_RESOURCES, i);
+
+ if (i < PCI_NUM_RESOURCES)
+ return i;
+
+ return -1;
+}
+
static u64 pci_size(u64 base, u64 maxbase, u64 mask)
{
u64 size = mask & maxbase; /* Find the significant bits */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 87afd5d7233733..ef142f4f524701 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -360,6 +360,30 @@ struct pci_dev {
struct resource *pci_dev_resource_n(struct pci_dev *dev, int n);
int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);
+#define PCI_STD_RES (1<<0)
+#define PCI_ROM_RES (1<<1)
+#define PCI_IOV_RES (1<<2)
+#define PCI_BRIDGE_RES (1<<3)
+#define PCI_RES_BLOCK_NUM 4
+
+#define PCI_ALL_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES)
+#define PCI_NOSTD_RES (PCI_ALL_RES & ~PCI_STD_RES)
+#define PCI_NOIOV_RES (PCI_ALL_RES & ~PCI_IOV_RES)
+#define PCI_NOROM_RES (PCI_ALL_RES & ~PCI_ROM_RES)
+#define PCI_NOBRIDGE_RES (PCI_ALL_RES & ~PCI_BRIDGE_RES)
+#define PCI_STD_ROM_RES (PCI_STD_RES | PCI_ROM_RES)
+#define PCI_STD_IOV_RES (PCI_STD_RES | PCI_IOV_RES)
+#define PCI_STD_ROM_IOV_RES (PCI_STD_RES | PCI_ROM_RES | PCI_IOV_RES)
+
+int pci_next_resource_idx(int i, int flag);
+
+#define for_each_pci_resource(dev, res, i, flag) \
+ for (i = pci_next_resource_idx(-1, flag), \
+ res = pci_dev_resource_n(dev, i); \
+ res; \
+ i = pci_next_resource_idx(i, flag), \
+ res = pci_dev_resource_n(dev, i))
+
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_IOV