source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_pm.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 3.0 KB
Line 
1/*
2 * PCI Backend - Configuration space overlay for power management
3 *
4 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
5 */
6
7#include <linux/pci.h>
8#include "conf_space.h"
9#include "conf_space_capability.h"
10
11static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
12                        void *data)
13{
14        int err;
15        u16 real_value;
16
17        err = pci_read_config_word(dev, offset, &real_value);
18        if (err)
19                goto out;
20
21        *value = real_value & ~PCI_PM_CAP_PME_MASK;
22
23      out:
24        return err;
25}
26
27/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
28 * Can't allow driver domain to enable PMEs - they're shared */
29#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
30
31static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
32                         void *data)
33{
34        int err;
35        u16 old_value;
36        pci_power_t new_state, old_state;
37
38        err = pci_read_config_word(dev, offset, &old_value);
39        if (err)
40                goto out;
41
42        old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
43        new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
44
45        new_value &= PM_OK_BITS;
46        if ((old_value & PM_OK_BITS) != new_value) {
47                new_value = (old_value & ~PM_OK_BITS) | new_value;
48                err = pci_write_config_word(dev, offset, new_value);
49                if (err)
50                        goto out;
51        }
52
53        /* Let pci core handle the power management change */
54        dev_dbg(&dev->dev, "set power state to %x\n", new_state);
55        err = pci_set_power_state(dev, new_state);
56        if (err) {
57                err = PCIBIOS_SET_FAILED;
58                goto out;
59        }
60
61        /*
62         * Device may lose PCI config info on D3->D0 transition. This
63         * is a problem for some guests which will not reset BARs. Even
64         * those that have a go will be foiled by our BAR-write handler
65         * which will discard the write! Since Linux won't re-init
66         * the config space automatically in all cases, we do it here.
67         * Future: Should we re-initialise all first 64 bytes of config space?
68         */
69        if (new_state == PCI_D0 &&
70            (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
71            !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
72                pci_restore_bars(dev);
73
74 out:
75        return err;
76}
77
78/* Ensure PMEs are disabled */
79static void *pm_ctrl_init(struct pci_dev *dev, int offset)
80{
81        int err;
82        u16 value;
83
84        err = pci_read_config_word(dev, offset, &value);
85        if (err)
86                goto out;
87
88        if (value & PCI_PM_CTRL_PME_ENABLE) {
89                value &= ~PCI_PM_CTRL_PME_ENABLE;
90                err = pci_write_config_word(dev, offset, value);
91        }
92
93      out:
94        return ERR_PTR(err);
95}
96
97static struct config_field caplist_pm[] = {
98        {
99                .offset     = PCI_PM_PMC,
100                .size       = 2,
101                .u.w.read   = pm_caps_read,
102        },
103        {
104                .offset     = PCI_PM_CTRL,
105                .size       = 2,
106                .init       = pm_ctrl_init,
107                .u.w.read   = pciback_read_config_word,
108                .u.w.write  = pm_ctrl_write,
109        },
110        {
111                .offset     = PCI_PM_PPB_EXTENSIONS,
112                .size       = 1,
113                .u.b.read   = pciback_read_config_byte,
114        },
115        {
116                .offset     = PCI_PM_DATA_REGISTER,
117                .size       = 1,
118                .u.b.read   = pciback_read_config_byte,
119        },
120        {
121                .size = 0,
122        },
123};
124
125struct pciback_config_capability pciback_config_capability_pm = {
126        .capability = PCI_CAP_ID_PM,
127        .fields = caplist_pm,
128};
Note: See TracBrowser for help on using the repository browser.