From: Prarit Bhargava <prarit@redhat.com> Date: Mon, 30 Mar 2009 08:09:55 -0400 Subject: [pci] add pci*_selected_region/pci_enable_device_io|mem Message-id: 20090330120953.29177.26767.sendpatchset@prarit.bos.redhat.com O-Subject: [RHEL5 PATCH 1/5]: pci - add pci*_selected_region() and pci_enable_device_{io|mem} functions Bugzilla: 442007 RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> RH-Acked-by: Andy Gospodarek <gospo@redhat.com> RH-Acked-by: David Miller <davem@redhat.com> RH-Acked-by: Tomas Henzl <thenzl@redhat.com> Backport of c87deff776feacd05a7411097e8c8c57e549e638 and b718989da7cf1f77ed5665dba0d2c73bd9dfe2d7, which add pci*_selected_region and pci_enable_device_{io|mem} functions to RHEL5. Resolves BZ 442007. diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index efcdb65..cd382e3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -632,6 +632,62 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) return 0; } +static int do_pci_enable_device(struct pci_dev *dev, int bars) +{ + int err; + err = pci_enable_device_bars(dev, bars); + if (err) + return err; + pci_fixup_device(pci_fixup_enable, dev); + + return 0; +} + +static int __pci_enable_device_flags(struct pci_dev *dev, + resource_size_t flags) +{ + int err; + int i, bars = 0; + + if (dev->is_enabled) + return 0; /* already enabled */ + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + + err = do_pci_enable_device(dev, bars); + if (err < 0) + dev->is_enabled = 0; + return err; +} + +/** + * pci_enable_device_io - Initialize a device for use with IO space + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O resources. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int pci_enable_device_io(struct pci_dev *dev) +{ + return __pci_enable_device_flags(dev, IORESOURCE_IO); +} + +/** + * pci_enable_device_mem - Initialize a device for use with Memory space + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable Memory resources. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int pci_enable_device_mem(struct pci_dev *dev) +{ + return __pci_enable_device_flags(dev, IORESOURCE_MEM); +} + /** * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized @@ -639,21 +695,14 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) * Initialize device before it's used by a driver. Ask low-level code * to enable I/O and memory. Wake up the device if it was suspended. * Beware, this function can fail. + * + * Note we don't actually enable the device many times if we call + * this function repeatedly. */ int pci_enable_device(struct pci_dev *dev) { - int err; - - if (dev->is_enabled) - return 0; - - err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); - if (err) - return err; - pci_fixup_device(pci_fixup_enable, dev); - dev->is_enabled = 1; - return 0; + return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); } /* @@ -972,6 +1021,47 @@ err_out: return -EBUSY; } +/** + * pci_release_selected_regions - Release selected PCI I/O and memory resources + * @pdev: PCI device whose resources were previously reserved + * @bars: Bitmask of BARs to be released + * + * Release selected PCI I/O and memory resources previously reserved. + * Call this function only after all use of the PCI regions has ceased. + */ +void pci_release_selected_regions(struct pci_dev *pdev, int bars) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + pci_release_region(pdev, i); +} + +/** + * pci_request_selected_regions - Reserve selected PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @bars: Bitmask of BARs to be requested + * @res_name: Name to be associated with resource + */ +int pci_request_selected_regions(struct pci_dev *pdev, int bars, + const char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + if(pci_request_region(pdev, i, res_name)) + goto err_out; + return 0; + +err_out: + while(--i >= 0) + if (bars & (1 << i)) + pci_release_region(pdev, i); + + return -EBUSY; +} /** * pci_release_regions - Release reserved PCI I/O and memory resources @@ -984,10 +1074,7 @@ err_out: void pci_release_regions(struct pci_dev *pdev) { - int i; - - for (i = 0; i < 6; i++) - pci_release_region(pdev, i); + pci_release_selected_regions(pdev, (1 << 6) - 1); } /** @@ -1005,18 +1092,7 @@ void pci_release_regions(struct pci_dev *pdev) */ int pci_request_regions(struct pci_dev *pdev, const char *res_name) { - int i; - - for (i = 0; i < 6; i++) - if(pci_request_region(pdev, i, res_name)) - goto err_out; - return 0; - -err_out: - while(--i >= 0) - pci_release_region(pdev, i); - - return -EBUSY; + return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name); } /** @@ -1376,6 +1452,22 @@ out: } EXPORT_SYMBOL(pcie_set_readrq); +/** + * pci_select_bars - Make BAR mask from the type of resource + * @pdev: the PCI device for which BAR mask is made + * @flags: resource type mask to be selected + * + * This helper routine makes bar mask from the type of resource. + */ +int pci_select_bars(struct pci_dev *dev, unsigned long flags) +{ + int i, bars = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (pci_resource_flags(dev, i) & flags) + bars |= (1 << i); + return bars; +} + static int __devinit pci_init(void) { struct pci_dev *dev = NULL; @@ -1417,6 +1509,8 @@ EXPORT_SYMBOL(isa_bridge); EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_enable_device_bars); +EXPORT_SYMBOL(pci_enable_device_io); +EXPORT_SYMBOL(pci_enable_device_mem); EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pcim_enable_device); EXPORT_SYMBOL(pcim_pin_device); @@ -1427,6 +1521,8 @@ EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_release_region); EXPORT_SYMBOL(pci_request_region); +EXPORT_SYMBOL(pci_release_selected_regions); +EXPORT_SYMBOL(pci_request_selected_regions); EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_try_set_mwi); @@ -1436,6 +1532,7 @@ EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_set_consistent_dma_mask); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_find_parent_resource); +EXPORT_SYMBOL(pci_select_bars); EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_save_state); diff --git a/include/linux/pci.h b/include/linux/pci.h index 42d636a..736aa36 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -545,6 +545,8 @@ static inline int pci_is_managed(struct pci_dev *pdev) int pci_enable_device(struct pci_dev *dev); int pci_enable_device_bars(struct pci_dev *dev, int mask); +int pci_enable_device_io(struct pci_dev *dev); +int pci_enable_device_mem(struct pci_dev *dev); void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); @@ -563,6 +565,7 @@ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int pci_assign_resource(struct pci_dev *dev, int i); int pci_assign_resource_fixed(struct pci_dev *dev, int i); void pci_restore_bars(struct pci_dev *dev); +int pci_select_bars(struct pci_dev *dev, unsigned long flags); /* ROM control related routines */ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); @@ -591,6 +594,8 @@ int pci_request_regions(struct pci_dev *, const char *); void pci_release_regions(struct pci_dev *); int pci_request_region(struct pci_dev *, int, const char *); void pci_release_region(struct pci_dev *, int); +int pci_request_selected_regions(struct pci_dev *, int, const char *); +void pci_release_selected_regions(struct pci_dev *, int); /* drivers/pci/bus.c */ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,