diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 171 |
1 files changed, 103 insertions, 68 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 206c834d263..84c757ba066 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -392,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (state > PCI_D3hot) state = PCI_D3hot; + /* + * If the device or the parent bridge can't support PCI PM, ignore + * the request if we're doing anything besides putting it into D0 + * (which would only happen on boot). + */ + if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) + return 0; + /* Validate current state: * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state @@ -403,13 +411,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) } else if (dev->current_state == state) return 0; /* we're already there */ - /* - * If the device or the parent bridge can't support PCI PM, ignore - * the request if we're doing anything besides putting it into D0 - * (which would only happen on boot). - */ - if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) - return 0; /* find PCI PM capability in list */ pm = pci_find_capability(dev, PCI_CAP_ID_PM); @@ -633,8 +634,6 @@ pci_save_state(struct pci_dev *dev) pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); if ((i = pci_save_msi_state(dev)) != 0) return i; - if ((i = pci_save_msix_state(dev)) != 0) - return i; if ((i = pci_save_pcie_state(dev)) != 0) return i; if ((i = pci_save_pcix_state(dev)) != 0) @@ -672,22 +671,11 @@ pci_restore_state(struct pci_dev *dev) } pci_restore_pcix_state(dev); pci_restore_msi_state(dev); - pci_restore_msix_state(dev); + return 0; } -/** - * pci_enable_device_bars - Initialize some of a device for use - * @dev: PCI device to be initialized - * @bars: bitmask of BAR's that must be configured - * - * Initialize device before it's used by a driver. Ask low-level code - * to enable selected I/O and memory resources. Wake up the device if it - * was suspended. Beware, this function can fail. - */ - -int -pci_enable_device_bars(struct pci_dev *dev, int bars) +static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; @@ -697,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) err = pcibios_enable_device(dev, bars); if (err < 0) return err; + pci_fixup_device(pci_fixup_enable, dev); + return 0; } /** - * __pci_enable_device - Initialize device before it's used by a driver. + * __pci_reenable_device - Resume abandoned device + * @dev: PCI device to be resumed + * + * Note this function is a backend of pci_default_resume and is not supposed + * to be called by normal code, write proper resume handler and use it instead. + */ +int +__pci_reenable_device(struct pci_dev *dev) +{ + if (atomic_read(&dev->enable_cnt)) + return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); + return 0; +} + +/** + * pci_enable_device_bars - Initialize some of a device for use * @dev: PCI device to be initialized + * @bars: bitmask of BAR's that must be configured * * 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 this function is a backend and is not supposed to be called by - * normal code, use pci_enable_device() instead. + * to enable selected I/O and memory resources. Wake up the device if it + * was suspended. Beware, this function can fail. */ int -__pci_enable_device(struct pci_dev *dev) +pci_enable_device_bars(struct pci_dev *dev, int bars) { int err; - err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); - if (err) - return err; - pci_fixup_device(pci_fixup_enable, dev); - return 0; + if (atomic_add_return(1, &dev->enable_cnt) > 1) + return 0; /* already enabled */ + + err = do_pci_enable_device(dev, bars); + if (err < 0) + atomic_dec(&dev->enable_cnt); + return err; } /** @@ -736,13 +741,7 @@ __pci_enable_device(struct pci_dev *dev) */ int pci_enable_device(struct pci_dev *dev) { - int result; - if (atomic_add_return(1, &dev->enable_cnt) > 1) - return 0; /* already enabled */ - result = __pci_enable_device(dev); - if (result < 0) - atomic_dec(&dev->enable_cnt); - return result; + return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); } /** @@ -921,6 +920,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 @@ -933,10 +973,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); } /** @@ -954,18 +991,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); } /** @@ -1148,7 +1174,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) return 0; } #endif - + +/** + * 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; @@ -1181,12 +1223,6 @@ early_param("pci", pci_setup); device_initcall(pci_init); -#if defined(CONFIG_ISA) || defined(CONFIG_EISA) -/* FIXME: Some boxes have multiple ISA bridges! */ -struct pci_dev *isa_bridge; -EXPORT_SYMBOL(isa_bridge); -#endif - EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_enable_device_bars); EXPORT_SYMBOL(pci_enable_device); @@ -1197,6 +1233,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_clear_mwi); @@ -1205,13 +1243,10 @@ 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); EXPORT_SYMBOL(pci_restore_state); EXPORT_SYMBOL(pci_enable_wake); -/* Quirk info */ - -EXPORT_SYMBOL(isa_dma_bridge_buggy); -EXPORT_SYMBOL(pci_pci_problems); |