aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-11-05 15:16:36 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-11-11 12:38:14 -0500
commit97c145f7c87453cec90e91238fba5fe2c1561b32 (patch)
treee69b486547e713b6a9358ad780dcdf7b697a7912 /drivers/pci
parent3b519e4ea618b6943a82931630872907f9ac2c2b (diff)
PCI: read current power state at enable time
When we enable a PCI device, we avoid doing a lot of the initial setup work if the device's enable count is non-zero. If we don't fetch the power state though, we may later fail to set up MSI due to the unknown status. So pick it up before we short circuit the rest due to a pre-existing enable or mismatched enable/disable pair (as happens with VGA devices, which are special in a special way). Tested-by: Jesse Brandeburg <jesse.brandeburg@gmail.com> Reported-by: Dave Airlie <airlied@linux.ie> Tested-by: Dave Airlie <airlied@linux.ie> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e98c8104297b..710c8a29be0d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1007,6 +1007,18 @@ static int __pci_enable_device_flags(struct pci_dev *dev,
1007 int err; 1007 int err;
1008 int i, bars = 0; 1008 int i, bars = 0;
1009 1009
1010 /*
1011 * Power state could be unknown at this point, either due to a fresh
1012 * boot or a device removal call. So get the current power state
1013 * so that things like MSI message writing will behave as expected
1014 * (e.g. if the device really is in D0 at enable time).
1015 */
1016 if (dev->pm_cap) {
1017 u16 pmcsr;
1018 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
1019 dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
1020 }
1021
1010 if (atomic_add_return(1, &dev->enable_cnt) > 1) 1022 if (atomic_add_return(1, &dev->enable_cnt) > 1)
1011 return 0; /* already enabled */ 1023 return 0; /* already enabled */
1012 1024