ia64/xen-unstable

changeset 14637:78af882eb6fc

pciback: Devices can lose config space info on D3->D0 transition, yet
they may not (and even if they try, can not) restore the BARs. Since
Linux does not do this for us, pciback must do it for itself manually.

Possible todo: Restore all first 64 bytes of the config space?

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Wed Mar 28 20:19:11 2007 +0100 (2007-03-28)
parents eddce921d414
children ea55ead0fd47
files linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_pm.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_pm.c	Wed Mar 28 18:48:54 2007 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_pm.c	Wed Mar 28 20:19:11 2007 +0100
     1.3 @@ -32,19 +32,19 @@ static int pm_ctrl_write(struct pci_dev 
     1.4  			 void *data)
     1.5  {
     1.6  	int err;
     1.7 -	u16 cur_value;
     1.8 -	pci_power_t new_state;
     1.9 +	u16 old_value;
    1.10 +	pci_power_t new_state, old_state;
    1.11  
    1.12 -	/* Handle setting power state separately */
    1.13 -	new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
    1.14 -
    1.15 -	err = pci_read_config_word(dev, offset, &cur_value);
    1.16 +	err = pci_read_config_word(dev, offset, &old_value);
    1.17  	if (err)
    1.18  		goto out;
    1.19  
    1.20 +	old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
    1.21 +	new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
    1.22 +
    1.23  	new_value &= PM_OK_BITS;
    1.24 -	if ((cur_value & PM_OK_BITS) != new_value) {
    1.25 -		new_value = (cur_value & ~PM_OK_BITS) | new_value;
    1.26 +	if ((old_value & PM_OK_BITS) != new_value) {
    1.27 +		new_value = (old_value & ~PM_OK_BITS) | new_value;
    1.28  		err = pci_write_config_word(dev, offset, new_value);
    1.29  		if (err)
    1.30  			goto out;
    1.31 @@ -53,10 +53,25 @@ static int pm_ctrl_write(struct pci_dev 
    1.32  	/* Let pci core handle the power management change */
    1.33  	dev_dbg(&dev->dev, "set power state to %x\n", new_state);
    1.34  	err = pci_set_power_state(dev, new_state);
    1.35 -	if (err)
    1.36 +	if (err) {
    1.37  		err = PCIBIOS_SET_FAILED;
    1.38 +		goto out;
    1.39 +	}
    1.40  
    1.41 -      out:
    1.42 +	/*
    1.43 +	 * Device may lose PCI config info on D3->D0 transition. This
    1.44 +	 * is a problem for some guests which will not reset BARs. Even
    1.45 +	 * those that have a go will be foiled by our BAR-write handler
    1.46 +	 * which will discard the write! Since Linux won't re-init
    1.47 +	 * the config space automatically in all cases, we do it here.
    1.48 +	 * Future: Should we re-initialise all first 64 bytes of config space?
    1.49 +	 */
    1.50 +	if (new_state == PCI_D0 &&
    1.51 +	    (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
    1.52 +	    !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
    1.53 +		pci_restore_bars(dev);
    1.54 +
    1.55 + out:
    1.56  	return err;
    1.57  }
    1.58