aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/access.c2
-rw-r--r--drivers/pci/pci.c110
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--include/linux/pci.h3
4 files changed, 116 insertions, 1 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 0c4c71712dfc..2a581642c237 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -13,7 +13,7 @@
13 * configuration space. 13 * configuration space.
14 */ 14 */
15 15
16static DEFINE_RAW_SPINLOCK(pci_lock); 16DEFINE_RAW_SPINLOCK(pci_lock);
17 17
18/* 18/*
19 * Wrappers for all PCI configuration access functions. They just check 19 * Wrappers for all PCI configuration access functions. They just check
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c3cca7cdc6e5..924193ef4fe1 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2768,6 +2768,116 @@ pci_intx(struct pci_dev *pdev, int enable)
2768} 2768}
2769 2769
2770/** 2770/**
2771 * pci_intx_mask_supported - probe for INTx masking support
2772 * @pdev: the PCI device to operate on
2773 *
2774 * Check if the device dev support INTx masking via the config space
2775 * command word.
2776 */
2777bool pci_intx_mask_supported(struct pci_dev *dev)
2778{
2779 bool mask_supported = false;
2780 u16 orig, new;
2781
2782 pci_cfg_access_lock(dev);
2783
2784 pci_read_config_word(dev, PCI_COMMAND, &orig);
2785 pci_write_config_word(dev, PCI_COMMAND,
2786 orig ^ PCI_COMMAND_INTX_DISABLE);
2787 pci_read_config_word(dev, PCI_COMMAND, &new);
2788
2789 /*
2790 * There's no way to protect against hardware bugs or detect them
2791 * reliably, but as long as we know what the value should be, let's
2792 * go ahead and check it.
2793 */
2794 if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) {
2795 dev_err(&dev->dev, "Command register changed from "
2796 "0x%x to 0x%x: driver or hardware bug?\n", orig, new);
2797 } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) {
2798 mask_supported = true;
2799 pci_write_config_word(dev, PCI_COMMAND, orig);
2800 }
2801
2802 pci_cfg_access_unlock(dev);
2803 return mask_supported;
2804}
2805EXPORT_SYMBOL_GPL(pci_intx_mask_supported);
2806
2807static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
2808{
2809 struct pci_bus *bus = dev->bus;
2810 bool mask_updated = true;
2811 u32 cmd_status_dword;
2812 u16 origcmd, newcmd;
2813 unsigned long flags;
2814 bool irq_pending;
2815
2816 /*
2817 * We do a single dword read to retrieve both command and status.
2818 * Document assumptions that make this possible.
2819 */
2820 BUILD_BUG_ON(PCI_COMMAND % 4);
2821 BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
2822
2823 raw_spin_lock_irqsave(&pci_lock, flags);
2824
2825 bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
2826
2827 irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
2828
2829 /*
2830 * Check interrupt status register to see whether our device
2831 * triggered the interrupt (when masking) or the next IRQ is
2832 * already pending (when unmasking).
2833 */
2834 if (mask != irq_pending) {
2835 mask_updated = false;
2836 goto done;
2837 }
2838
2839 origcmd = cmd_status_dword;
2840 newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
2841 if (mask)
2842 newcmd |= PCI_COMMAND_INTX_DISABLE;
2843 if (newcmd != origcmd)
2844 bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
2845
2846done:
2847 raw_spin_unlock_irqrestore(&pci_lock, flags);
2848
2849 return mask_updated;
2850}
2851
2852/**
2853 * pci_check_and_mask_intx - mask INTx on pending interrupt
2854 * @pdev: the PCI device to operate on
2855 *
2856 * Check if the device dev has its INTx line asserted, mask it and
2857 * return true in that case. False is returned if not interrupt was
2858 * pending.
2859 */
2860bool pci_check_and_mask_intx(struct pci_dev *dev)
2861{
2862 return pci_check_and_set_intx_mask(dev, true);
2863}
2864EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
2865
2866/**
2867 * pci_check_and_mask_intx - unmask INTx of no interrupt is pending
2868 * @pdev: the PCI device to operate on
2869 *
2870 * Check if the device dev has its INTx line asserted, unmask it if not
2871 * and return true. False is returned and the mask remains active if
2872 * there was still an interrupt pending.
2873 */
2874bool pci_check_and_unmask_intx(struct pci_dev *dev)
2875{
2876 return pci_check_and_set_intx_mask(dev, false);
2877}
2878EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
2879
2880/**
2771 * pci_msi_off - disables any msi or msix capabilities 2881 * pci_msi_off - disables any msi or msix capabilities
2772 * @dev: the PCI device to operate on 2882 * @dev: the PCI device to operate on
2773 * 2883 *
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index b74084e9ca12..3b6e4ed306b6 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -136,6 +136,8 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
136/* Lock for read/write access to pci device and bus lists */ 136/* Lock for read/write access to pci device and bus lists */
137extern struct rw_semaphore pci_bus_sem; 137extern struct rw_semaphore pci_bus_sem;
138 138
139extern raw_spinlock_t pci_lock;
140
139extern unsigned int pci_pm_d3_delay; 141extern unsigned int pci_pm_d3_delay;
140 142
141#ifdef CONFIG_PCI_MSI 143#ifdef CONFIG_PCI_MSI
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 72401596b2a8..4286b853956e 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -804,6 +804,9 @@ int __must_check pci_set_mwi(struct pci_dev *dev);
804int pci_try_set_mwi(struct pci_dev *dev); 804int pci_try_set_mwi(struct pci_dev *dev);
805void pci_clear_mwi(struct pci_dev *dev); 805void pci_clear_mwi(struct pci_dev *dev);
806void pci_intx(struct pci_dev *dev, int enable); 806void pci_intx(struct pci_dev *dev, int enable);
807bool pci_intx_mask_supported(struct pci_dev *dev);
808bool pci_check_and_mask_intx(struct pci_dev *dev);
809bool pci_check_and_unmask_intx(struct pci_dev *dev);
807void pci_msi_off(struct pci_dev *dev); 810void pci_msi_off(struct pci_dev *dev);
808int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size); 811int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
809int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask); 812int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);