aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2013-08-28 20:55:41 -0600
committerBjorn Helgaas <bhelgaas@google.com>2013-08-28 20:55:41 -0600
commit2e8b5f621dbe29425906852c6079afb6b28720cb (patch)
tree178a58a6dee0599d8b119d6c72969f9b6f4e37ac /drivers/pci
parent07f2daad094bc9e9770143cd2d619de24d84bb3e (diff)
parentfed2451512495f0f0820ac9e53936bd208569bc8 (diff)
Merge branch 'pci/misc' into next
* pci/misc: PCI: Remove pcie_cap_has_devctl() PCI: Support PCIe Capability Slot registers only for ports with slots PCI: Remove PCIe Capability version checks PCI: Allow PCIe Capability link-related register access for switches PCI: Add offsets of PCIe capability registers PCI: Tidy bitmasks and spacing of PCIe capability definitions PCI: Remove obsolete comment reference to pci_pcie_cap2() PCI: Clarify PCI_EXP_TYPE_PCI_BRIDGE comment PCI: Rename PCIe capability definitions to follow convention PCI: Disable decoding for BAR sizing only when it was actually enabled PCI: Add comment about needing pci_msi_off() even when CONFIG_PCI_MSI=n PCI: Add pcibios_pm_ops for optional arch-specific hibernate functionality
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/access.c26
-rw-r--r--drivers/pci/pci-driver.c43
-rw-r--r--drivers/pci/pci.c44
-rw-r--r--drivers/pci/probe.c11
4 files changed, 88 insertions, 36 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 1cc23661f79..0857ca981fa 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -475,37 +475,33 @@ static inline int pcie_cap_version(const struct pci_dev *dev)
return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
}
-static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
-{
- return true;
-}
-
static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
{
int type = pci_pcie_type(dev);
- return pcie_cap_version(dev) > 1 ||
+ return type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_LEG_END ||
type == PCI_EXP_TYPE_ROOT_PORT ||
- type == PCI_EXP_TYPE_ENDPOINT ||
- type == PCI_EXP_TYPE_LEG_END;
+ type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM ||
+ type == PCI_EXP_TYPE_PCI_BRIDGE ||
+ type == PCI_EXP_TYPE_PCIE_BRIDGE;
}
static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
{
int type = pci_pcie_type(dev);
- return pcie_cap_version(dev) > 1 ||
- type == PCI_EXP_TYPE_ROOT_PORT ||
- (type == PCI_EXP_TYPE_DOWNSTREAM &&
- pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT);
+ return (type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_DOWNSTREAM) &&
+ pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
}
static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
{
int type = pci_pcie_type(dev);
- return pcie_cap_version(dev) > 1 ||
- type == PCI_EXP_TYPE_ROOT_PORT ||
+ return type == PCI_EXP_TYPE_ROOT_PORT ||
type == PCI_EXP_TYPE_RC_EC;
}
@@ -520,7 +516,7 @@ static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
case PCI_EXP_DEVCAP:
case PCI_EXP_DEVCTL:
case PCI_EXP_DEVSTA:
- return pcie_cap_has_devctl(dev);
+ return true;
case PCI_EXP_LNKCAP:
case PCI_EXP_LNKCTL:
case PCI_EXP_LNKSTA:
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e6515e21afa..98f7b9b8950 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -763,6 +763,13 @@ static int pci_pm_resume(struct device *dev)
#ifdef CONFIG_HIBERNATE_CALLBACKS
+
+/*
+ * pcibios_pm_ops - provide arch-specific hooks when a PCI device is doing
+ * a hibernate transition
+ */
+struct dev_pm_ops __weak pcibios_pm_ops;
+
static int pci_pm_freeze(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -786,6 +793,9 @@ static int pci_pm_freeze(struct device *dev)
return error;
}
+ if (pcibios_pm_ops.freeze)
+ return pcibios_pm_ops.freeze(dev);
+
return 0;
}
@@ -811,6 +821,9 @@ static int pci_pm_freeze_noirq(struct device *dev)
pci_pm_set_unknown_state(pci_dev);
+ if (pcibios_pm_ops.freeze_noirq)
+ return pcibios_pm_ops.freeze_noirq(dev);
+
return 0;
}
@@ -820,6 +833,12 @@ static int pci_pm_thaw_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
+ if (pcibios_pm_ops.thaw_noirq) {
+ error = pcibios_pm_ops.thaw_noirq(dev);
+ if (error)
+ return error;
+ }
+
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -837,6 +856,12 @@ static int pci_pm_thaw(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
+ if (pcibios_pm_ops.thaw) {
+ error = pcibios_pm_ops.thaw(dev);
+ if (error)
+ return error;
+ }
+
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume(dev);
@@ -878,6 +903,9 @@ static int pci_pm_poweroff(struct device *dev)
Fixup:
pci_fixup_device(pci_fixup_suspend, pci_dev);
+ if (pcibios_pm_ops.poweroff)
+ return pcibios_pm_ops.poweroff(dev);
+
return 0;
}
@@ -911,6 +939,9 @@ static int pci_pm_poweroff_noirq(struct device *dev)
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
+ if (pcibios_pm_ops.poweroff_noirq)
+ return pcibios_pm_ops.poweroff_noirq(dev);
+
return 0;
}
@@ -920,6 +951,12 @@ static int pci_pm_restore_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
+ if (pcibios_pm_ops.restore_noirq) {
+ error = pcibios_pm_ops.restore_noirq(dev);
+ if (error)
+ return error;
+ }
+
pci_pm_default_resume_early(pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
@@ -937,6 +974,12 @@ static int pci_pm_restore(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
+ if (pcibios_pm_ops.restore) {
+ error = pcibios_pm_ops.restore(dev);
+ if (error)
+ return error;
+ }
+
/*
* This is necessary for the hibernation error path in which restore is
* called without restoring the standard config registers of the device.
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4e15bc9712f..b821a62958f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2116,9 +2116,9 @@ void pci_enable_ido(struct pci_dev *dev, unsigned long type)
u16 ctrl = 0;
if (type & PCI_EXP_IDO_REQUEST)
- ctrl |= PCI_EXP_IDO_REQ_EN;
+ ctrl |= PCI_EXP_DEVCTL2_IDO_REQ_EN;
if (type & PCI_EXP_IDO_COMPLETION)
- ctrl |= PCI_EXP_IDO_CMP_EN;
+ ctrl |= PCI_EXP_DEVCTL2_IDO_CMP_EN;
if (ctrl)
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, ctrl);
}
@@ -2134,9 +2134,9 @@ void pci_disable_ido(struct pci_dev *dev, unsigned long type)
u16 ctrl = 0;
if (type & PCI_EXP_IDO_REQUEST)
- ctrl |= PCI_EXP_IDO_REQ_EN;
+ ctrl |= PCI_EXP_DEVCTL2_IDO_REQ_EN;
if (type & PCI_EXP_IDO_COMPLETION)
- ctrl |= PCI_EXP_IDO_CMP_EN;
+ ctrl |= PCI_EXP_DEVCTL2_IDO_CMP_EN;
if (ctrl)
pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, ctrl);
}
@@ -2168,7 +2168,7 @@ int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
int ret;
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
- if (!(cap & PCI_EXP_OBFF_MASK))
+ if (!(cap & PCI_EXP_DEVCAP2_OBFF_MASK))
return -ENOTSUPP; /* no OBFF support at all */
/* Make sure the topology supports OBFF as well */
@@ -2179,17 +2179,17 @@ int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
}
pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &ctrl);
- if (cap & PCI_EXP_OBFF_WAKE)
- ctrl |= PCI_EXP_OBFF_WAKE_EN;
+ if (cap & PCI_EXP_DEVCAP2_OBFF_WAKE)
+ ctrl |= PCI_EXP_DEVCTL2_OBFF_WAKE_EN;
else {
switch (type) {
case PCI_EXP_OBFF_SIGNAL_L0:
- if (!(ctrl & PCI_EXP_OBFF_WAKE_EN))
- ctrl |= PCI_EXP_OBFF_MSGA_EN;
+ if (!(ctrl & PCI_EXP_DEVCTL2_OBFF_WAKE_EN))
+ ctrl |= PCI_EXP_DEVCTL2_OBFF_MSGA_EN;
break;
case PCI_EXP_OBFF_SIGNAL_ALWAYS:
- ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
- ctrl |= PCI_EXP_OBFF_MSGB_EN;
+ ctrl &= ~PCI_EXP_DEVCTL2_OBFF_WAKE_EN;
+ ctrl |= PCI_EXP_DEVCTL2_OBFF_MSGB_EN;
break;
default:
WARN(1, "bad OBFF signal type\n");
@@ -2210,7 +2210,8 @@ EXPORT_SYMBOL(pci_enable_obff);
*/
void pci_disable_obff(struct pci_dev *dev)
{
- pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_OBFF_WAKE_EN);
+ pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_OBFF_WAKE_EN);
}
EXPORT_SYMBOL(pci_disable_obff);
@@ -2258,7 +2259,8 @@ int pci_enable_ltr(struct pci_dev *dev)
return ret;
}
- return pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_LTR_EN);
+ return pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
}
EXPORT_SYMBOL(pci_enable_ltr);
@@ -2275,7 +2277,8 @@ void pci_disable_ltr(struct pci_dev *dev)
if (!pci_ltr_supported(dev))
return;
- pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_LTR_EN);
+ pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
}
EXPORT_SYMBOL(pci_disable_ltr);
@@ -3141,18 +3144,23 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
/**
- * pci_msi_off - disables any msi or msix capabilities
+ * pci_msi_off - disables any MSI or MSI-X capabilities
* @dev: the PCI device to operate on
*
- * If you want to use msi see pci_enable_msi and friends.
- * This is a lower level primitive that allows us to disable
- * msi operation at the device level.
+ * If you want to use MSI, see pci_enable_msi() and friends.
+ * This is a lower-level primitive that allows us to disable
+ * MSI operation at the device level.
*/
void pci_msi_off(struct pci_dev *dev)
{
int pos;
u16 control;
+ /*
+ * This looks like it could go in msi.c, but we need it even when
+ * CONFIG_PCI_MSI=n. For the same reason, we can't use
+ * dev->msi_cap or dev->msix_cap here.
+ */
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (pos) {
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a57762fbe10..eeb50bd6240 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -156,6 +156,8 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
return flags;
}
+#define PCI_COMMAND_DECODE_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+
/**
* pci_read_base - read a PCI BAR
* @dev: the PCI device
@@ -178,8 +180,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
/* No printks while decoding is disabled! */
if (!dev->mmio_always_on) {
pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
- pci_write_config_word(dev, PCI_COMMAND,
- orig_cmd & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
+ if (orig_cmd & PCI_COMMAND_DECODE_ENABLE) {
+ pci_write_config_word(dev, PCI_COMMAND,
+ orig_cmd & ~PCI_COMMAND_DECODE_ENABLE);
+ }
}
res->name = pci_name(dev);
@@ -293,7 +297,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
fail:
res->flags = 0;
out:
- if (!dev->mmio_always_on)
+ if (!dev->mmio_always_on &&
+ (orig_cmd & PCI_COMMAND_DECODE_ENABLE))
pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
if (bar_too_big)