On Thu, Apr 4, 2013 at 3:18 PM, Bjorn Helgaas <bhelg...@google.com> wrote: > On Wed, Mar 13, 2013 at 5:27 PM, Yinghai Lu <ying...@kernel.org> wrote: >> From: Ram Pai <linux...@us.ibm.com> >> >> 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 >> -v8: Fix acpiphp module compiling error that is found by >> Steven Newbury <st...@snewbury.org.uk> - Yinghai Lu >> >> Signed-off-by: Ram Pai <linux...@us.ibm.com> >> Signed-off-by: Yinghai Lu <ying...@kernel.org> >> --- >> drivers/pci/probe.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ >> include/linux/pci.h | 24 ++++++++++++++++++++++++ >> 2 files changed, 72 insertions(+) >> >> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c >> index 1df75f7..ac751a6 100644 >> --- a/drivers/pci/probe.c >> +++ b/drivers/pci/probe.c >> @@ -123,6 +123,54 @@ 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; >> +} >> +EXPORT_SYMBOL(pci_next_resource_idx); >> + >> 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 aefff8b..127a856 100644 >> --- a/include/linux/pci.h >> +++ b/include/linux/pci.h >> @@ -341,6 +341,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 > > I think this turned out to be a disaster, with all the bitmaps and > helper functions. Filtering in the bodies of the > for_each_pci_resource() users has *got* to be better. That probably > requires a wrapper struct around the struct resource. Or possibly > having a wrapper struct with a "type" or "flags" field would make > filtering in for_each_pci_resources() itself cleaner to implement.
Do you mean have extra struct that will wrapper resource ? and the struct will have type that will tell that resource is PCI bridge resource or other std/sriov resource? then that struct need to have BAR in it. that looks like addon_res that is added in this patchset. but for the std/bridge/sriov, idx is used all the way and in all over the drivers. > > I think it would also help if we got rid of all the "PCI_NO*_RES" > definitions and just had the users explicitly specify what they *do* > want. yes, remove PCI_NO*_RES should be more clean Thanks Yinghai -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/