diff options
Diffstat (limited to 'drivers/pci/pcie/portdrv_pci.c')
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 79 |
1 files changed, 78 insertions, 1 deletions
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index e9095ee508e3..30bac7ed7c16 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -29,6 +29,78 @@ MODULE_LICENSE("GPL"); | |||
29 | /* global data */ | 29 | /* global data */ |
30 | static const char device_name[] = "pcieport-driver"; | 30 | static const char device_name[] = "pcieport-driver"; |
31 | 31 | ||
32 | static void pci_save_msi_state(struct pci_dev *dev) | ||
33 | { | ||
34 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
35 | int i = 0, pos; | ||
36 | u16 control; | ||
37 | |||
38 | if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) | ||
39 | return; | ||
40 | |||
41 | pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); | ||
42 | control = p_ext->saved_msi_config_space[0] >> 16; | ||
43 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, | ||
44 | &p_ext->saved_msi_config_space[i++]); | ||
45 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
46 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, | ||
47 | &p_ext->saved_msi_config_space[i++]); | ||
48 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, | ||
49 | &p_ext->saved_msi_config_space[i++]); | ||
50 | } else | ||
51 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, | ||
52 | &p_ext->saved_msi_config_space[i++]); | ||
53 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
54 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, | ||
55 | &p_ext->saved_msi_config_space[i++]); | ||
56 | } | ||
57 | |||
58 | static void pci_restore_msi_state(struct pci_dev *dev) | ||
59 | { | ||
60 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
61 | int i = 0, pos; | ||
62 | u16 control; | ||
63 | |||
64 | if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) | ||
65 | return; | ||
66 | |||
67 | control = p_ext->saved_msi_config_space[i++] >> 16; | ||
68 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | ||
69 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, | ||
70 | p_ext->saved_msi_config_space[i++]); | ||
71 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
72 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, | ||
73 | p_ext->saved_msi_config_space[i++]); | ||
74 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, | ||
75 | p_ext->saved_msi_config_space[i++]); | ||
76 | } else | ||
77 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, | ||
78 | p_ext->saved_msi_config_space[i++]); | ||
79 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
80 | pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, | ||
81 | p_ext->saved_msi_config_space[i++]); | ||
82 | } | ||
83 | |||
84 | static void pcie_portdrv_save_config(struct pci_dev *dev) | ||
85 | { | ||
86 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
87 | |||
88 | pci_save_state(dev); | ||
89 | if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) | ||
90 | pci_save_msi_state(dev); | ||
91 | } | ||
92 | |||
93 | static void pcie_portdrv_restore_config(struct pci_dev *dev) | ||
94 | { | ||
95 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
96 | |||
97 | pci_restore_state(dev); | ||
98 | if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) | ||
99 | pci_restore_msi_state(dev); | ||
100 | pci_enable_device(dev); | ||
101 | pci_set_master(dev); | ||
102 | } | ||
103 | |||
32 | /* | 104 | /* |
33 | * pcie_portdrv_probe - Probe PCI-Express port devices | 105 | * pcie_portdrv_probe - Probe PCI-Express port devices |
34 | * @dev: PCI-Express port device being probed | 106 | * @dev: PCI-Express port device being probed |
@@ -64,16 +136,21 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, | |||
64 | static void pcie_portdrv_remove (struct pci_dev *dev) | 136 | static void pcie_portdrv_remove (struct pci_dev *dev) |
65 | { | 137 | { |
66 | pcie_port_device_remove(dev); | 138 | pcie_port_device_remove(dev); |
139 | kfree(pci_get_drvdata(dev)); | ||
67 | } | 140 | } |
68 | 141 | ||
69 | #ifdef CONFIG_PM | 142 | #ifdef CONFIG_PM |
70 | static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) | 143 | static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) |
71 | { | 144 | { |
72 | return pcie_port_device_suspend(dev, state); | 145 | int ret = pcie_port_device_suspend(dev, state); |
146 | |||
147 | pcie_portdrv_save_config(dev); | ||
148 | return ret; | ||
73 | } | 149 | } |
74 | 150 | ||
75 | static int pcie_portdrv_resume (struct pci_dev *dev) | 151 | static int pcie_portdrv_resume (struct pci_dev *dev) |
76 | { | 152 | { |
153 | pcie_portdrv_restore_config(dev); | ||
77 | return pcie_port_device_resume(dev); | 154 | return pcie_port_device_resume(dev); |
78 | } | 155 | } |
79 | #endif | 156 | #endif |