aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c110
1 files changed, 110 insertions, 0 deletions
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 *