diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 108 |
1 files changed, 89 insertions, 19 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 71d561fda0a2..ae3df46eaabf 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -314,6 +314,24 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) } EXPORT_SYMBOL_GPL(pci_find_ht_capability); +void pcie_wait_pending_transaction(struct pci_dev *dev) +{ + int pos; + u16 reg16; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return; + while (1) { + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); + if (!(reg16 & PCI_EXP_DEVSTA_TRPND)) + break; + cpu_relax(); + } + +} +EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction); + /** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched @@ -353,7 +371,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * Restore the BAR values for a given device, so as to make it * accessible by its driver. */ -void +static void pci_restore_bars(struct pci_dev *dev) { int i, numres; @@ -551,6 +569,7 @@ static int pci_save_pcie_state(struct pci_dev *dev) int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; + int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (pos <= 0) @@ -559,6 +578,8 @@ static int pci_save_pcie_state(struct pci_dev *dev) save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); if (!save_state) save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); + else + found = 1; if (!save_state) { dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); return -ENOMEM; @@ -569,7 +590,9 @@ static int pci_save_pcie_state(struct pci_dev *dev) pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); - pci_add_saved_cap(dev, save_state); + save_state->cap_nr = PCI_CAP_ID_EXP; + if (!found) + pci_add_saved_cap(dev, save_state); return 0; } @@ -597,14 +620,17 @@ static int pci_save_pcix_state(struct pci_dev *dev) int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; + int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (pos <= 0) return 0; - save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); if (!save_state) save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL); + else + found = 1; if (!save_state) { dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); return -ENOMEM; @@ -612,7 +638,9 @@ static int pci_save_pcix_state(struct pci_dev *dev) cap = (u16 *)&save_state->data[0]; pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]); - pci_add_saved_cap(dev, save_state); + save_state->cap_nr = PCI_CAP_ID_PCIX; + if (!found) + pci_add_saved_cap(dev, save_state); return 0; } @@ -713,23 +741,19 @@ int pci_reenable_device(struct pci_dev *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 __pci_enable_device_flags(struct pci_dev *dev, + resource_size_t flags) { int err; + int i, bars = 0; if (atomic_add_return(1, &dev->enable_cnt) > 1) 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) atomic_dec(&dev->enable_cnt); @@ -737,6 +761,32 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) } /** + * 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 * @@ -749,7 +799,7 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) */ int pci_enable_device(struct pci_dev *dev) { - return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); + return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); } /* @@ -823,7 +873,8 @@ int pcim_enable_device(struct pci_dev *pdev) dr = get_pci_dr(pdev); if (unlikely(!dr)) return -ENOMEM; - WARN_ON(!!dr->enabled); + if (dr->enabled) + return 0; rc = pci_enable_device(pdev); if (!rc) { @@ -884,6 +935,9 @@ pci_disable_device(struct pci_dev *dev) if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; + /* Wait for all transactions are finished before disabling the device */ + pcie_wait_pending_transaction(dev); + pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; @@ -1397,6 +1451,22 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) } #endif +#ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE +int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size) +{ + return dma_set_max_seg_size(&dev->dev, size); +} +EXPORT_SYMBOL(pci_set_dma_max_seg_size); +#endif + +#ifndef HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY +int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask) +{ + return dma_set_seg_boundary(&dev->dev, mask); +} +EXPORT_SYMBOL(pci_set_dma_seg_boundary); +#endif + /** * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count * @dev: PCI device to query @@ -1618,9 +1688,9 @@ early_param("pci", pci_setup); device_initcall(pci_init); -EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_reenable_device); -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); |