diff options
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r-- | drivers/pci/pci-acpi.c | 277 |
1 files changed, 126 insertions, 151 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 9d6fc8e6285d..7764768b6a0e 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -21,12 +21,19 @@ | |||
21 | 21 | ||
22 | struct acpi_osc_data { | 22 | struct acpi_osc_data { |
23 | acpi_handle handle; | 23 | acpi_handle handle; |
24 | u32 ctrlset_buf[3]; | 24 | u32 support_set; |
25 | u32 global_ctrlsets; | 25 | u32 control_set; |
26 | int is_queried; | ||
27 | u32 query_result; | ||
26 | struct list_head sibiling; | 28 | struct list_head sibiling; |
27 | }; | 29 | }; |
28 | static LIST_HEAD(acpi_osc_data_list); | 30 | static LIST_HEAD(acpi_osc_data_list); |
29 | 31 | ||
32 | struct acpi_osc_args { | ||
33 | u32 capbuf[3]; | ||
34 | u32 query_result; | ||
35 | }; | ||
36 | |||
30 | static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) | 37 | static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) |
31 | { | 38 | { |
32 | struct acpi_osc_data *data; | 39 | struct acpi_osc_data *data; |
@@ -44,42 +51,18 @@ static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) | |||
44 | return data; | 51 | return data; |
45 | } | 52 | } |
46 | 53 | ||
47 | static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | 54 | static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, |
55 | 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | ||
48 | 56 | ||
49 | static acpi_status | 57 | static acpi_status acpi_run_osc(acpi_handle handle, |
50 | acpi_query_osc ( | 58 | struct acpi_osc_args *osc_args) |
51 | acpi_handle handle, | ||
52 | u32 level, | ||
53 | void *context, | ||
54 | void **retval ) | ||
55 | { | 59 | { |
56 | acpi_status status; | 60 | acpi_status status; |
57 | struct acpi_object_list input; | 61 | struct acpi_object_list input; |
58 | union acpi_object in_params[4]; | 62 | union acpi_object in_params[4]; |
59 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | 63 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; |
60 | union acpi_object *out_obj; | 64 | union acpi_object *out_obj; |
61 | u32 osc_dw0; | 65 | u32 osc_dw0, flags = osc_args->capbuf[OSC_QUERY_TYPE]; |
62 | acpi_status *ret_status = (acpi_status *)retval; | ||
63 | struct acpi_osc_data *osc_data; | ||
64 | u32 flags = (unsigned long)context, temp; | ||
65 | acpi_handle tmp; | ||
66 | |||
67 | status = acpi_get_handle(handle, "_OSC", &tmp); | ||
68 | if (ACPI_FAILURE(status)) | ||
69 | return status; | ||
70 | |||
71 | osc_data = acpi_get_osc_data(handle); | ||
72 | if (!osc_data) { | ||
73 | printk(KERN_ERR "acpi osc data array is full\n"); | ||
74 | return AE_ERROR; | ||
75 | } | ||
76 | |||
77 | osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS); | ||
78 | |||
79 | /* do _OSC query for all possible controls */ | ||
80 | temp = osc_data->ctrlset_buf[OSC_CONTROL_TYPE]; | ||
81 | osc_data->ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | ||
82 | osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; | ||
83 | 66 | ||
84 | /* Setting up input parameters */ | 67 | /* Setting up input parameters */ |
85 | input.count = 4; | 68 | input.count = 4; |
@@ -93,20 +76,19 @@ acpi_query_osc ( | |||
93 | in_params[2].integer.value = 3; | 76 | in_params[2].integer.value = 3; |
94 | in_params[3].type = ACPI_TYPE_BUFFER; | 77 | in_params[3].type = ACPI_TYPE_BUFFER; |
95 | in_params[3].buffer.length = 12; | 78 | in_params[3].buffer.length = 12; |
96 | in_params[3].buffer.pointer = (u8 *)osc_data->ctrlset_buf; | 79 | in_params[3].buffer.pointer = (u8 *)osc_args->capbuf; |
97 | 80 | ||
98 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); | 81 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); |
99 | if (ACPI_FAILURE(status)) | 82 | if (ACPI_FAILURE(status)) |
100 | goto out_nofree; | 83 | return status; |
101 | out_obj = output.pointer; | ||
102 | 84 | ||
85 | out_obj = output.pointer; | ||
103 | if (out_obj->type != ACPI_TYPE_BUFFER) { | 86 | if (out_obj->type != ACPI_TYPE_BUFFER) { |
104 | printk(KERN_DEBUG | 87 | printk(KERN_DEBUG "Evaluate _OSC returns wrong type\n"); |
105 | "Evaluate _OSC returns wrong type\n"); | ||
106 | status = AE_TYPE; | 88 | status = AE_TYPE; |
107 | goto query_osc_out; | 89 | goto out_kfree; |
108 | } | 90 | } |
109 | osc_dw0 = *((u32 *) out_obj->buffer.pointer); | 91 | osc_dw0 = *((u32 *)out_obj->buffer.pointer); |
110 | if (osc_dw0) { | 92 | if (osc_dw0) { |
111 | if (osc_dw0 & OSC_REQUEST_ERROR) | 93 | if (osc_dw0 & OSC_REQUEST_ERROR) |
112 | printk(KERN_DEBUG "_OSC request fails\n"); | 94 | printk(KERN_DEBUG "_OSC request fails\n"); |
@@ -115,93 +97,58 @@ acpi_query_osc ( | |||
115 | if (osc_dw0 & OSC_INVALID_REVISION_ERROR) | 97 | if (osc_dw0 & OSC_INVALID_REVISION_ERROR) |
116 | printk(KERN_DEBUG "_OSC invalid revision\n"); | 98 | printk(KERN_DEBUG "_OSC invalid revision\n"); |
117 | if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { | 99 | if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { |
118 | /* Update Global Control Set */ | 100 | if (flags & OSC_QUERY_ENABLE) |
119 | osc_data->global_ctrlsets = | 101 | goto out_success; |
120 | *((u32 *)(out_obj->buffer.pointer + 8)); | 102 | printk(KERN_DEBUG "_OSC FW not grant req. control\n"); |
121 | status = AE_OK; | 103 | status = AE_SUPPORT; |
122 | goto query_osc_out; | 104 | goto out_kfree; |
123 | } | 105 | } |
124 | status = AE_ERROR; | 106 | status = AE_ERROR; |
125 | goto query_osc_out; | 107 | goto out_kfree; |
126 | } | 108 | } |
127 | 109 | out_success: | |
128 | /* Update Global Control Set */ | 110 | if (flags & OSC_QUERY_ENABLE) |
129 | osc_data->global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8)); | 111 | osc_args->query_result = |
112 | *((u32 *)(out_obj->buffer.pointer + 8)); | ||
130 | status = AE_OK; | 113 | status = AE_OK; |
131 | 114 | ||
132 | query_osc_out: | 115 | out_kfree: |
133 | kfree(output.pointer); | 116 | kfree(output.pointer); |
134 | out_nofree: | ||
135 | *ret_status = status; | ||
136 | |||
137 | osc_data->ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE; | ||
138 | osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = temp; | ||
139 | if (ACPI_FAILURE(status)) { | ||
140 | /* no osc support at all */ | ||
141 | osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] = 0; | ||
142 | } | ||
143 | |||
144 | return status; | 117 | return status; |
145 | } | 118 | } |
146 | 119 | ||
147 | 120 | static acpi_status acpi_query_osc(acpi_handle handle, | |
148 | static acpi_status | 121 | u32 level, void *context, void **retval) |
149 | acpi_run_osc ( | ||
150 | acpi_handle handle, | ||
151 | void *context) | ||
152 | { | 122 | { |
153 | acpi_status status; | 123 | acpi_status status; |
154 | struct acpi_object_list input; | 124 | struct acpi_osc_data *osc_data; |
155 | union acpi_object in_params[4]; | 125 | u32 flags = (unsigned long)context, support_set; |
156 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | 126 | acpi_handle tmp; |
157 | union acpi_object *out_obj; | 127 | struct acpi_osc_args osc_args; |
158 | u32 osc_dw0; | ||
159 | |||
160 | /* Setting up input parameters */ | ||
161 | input.count = 4; | ||
162 | input.pointer = in_params; | ||
163 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
164 | in_params[0].buffer.length = 16; | ||
165 | in_params[0].buffer.pointer = OSC_UUID; | ||
166 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
167 | in_params[1].integer.value = 1; | ||
168 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
169 | in_params[2].integer.value = 3; | ||
170 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
171 | in_params[3].buffer.length = 12; | ||
172 | in_params[3].buffer.pointer = (u8 *)context; | ||
173 | 128 | ||
174 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); | 129 | status = acpi_get_handle(handle, "_OSC", &tmp); |
175 | if (ACPI_FAILURE (status)) | 130 | if (ACPI_FAILURE(status)) |
176 | return status; | 131 | return status; |
177 | 132 | ||
178 | out_obj = output.pointer; | 133 | osc_data = acpi_get_osc_data(handle); |
179 | if (out_obj->type != ACPI_TYPE_BUFFER) { | 134 | if (!osc_data) { |
180 | printk(KERN_DEBUG | 135 | printk(KERN_ERR "acpi osc data array is full\n"); |
181 | "Evaluate _OSC returns wrong type\n"); | 136 | return AE_ERROR; |
182 | status = AE_TYPE; | ||
183 | goto run_osc_out; | ||
184 | } | 137 | } |
185 | osc_dw0 = *((u32 *) out_obj->buffer.pointer); | 138 | |
186 | if (osc_dw0) { | 139 | /* do _OSC query for all possible controls */ |
187 | if (osc_dw0 & OSC_REQUEST_ERROR) | 140 | support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); |
188 | printk(KERN_DEBUG "_OSC request fails\n"); | 141 | osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; |
189 | if (osc_dw0 & OSC_INVALID_UUID_ERROR) | 142 | osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; |
190 | printk(KERN_DEBUG "_OSC invalid UUID\n"); | 143 | osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; |
191 | if (osc_dw0 & OSC_INVALID_REVISION_ERROR) | 144 | |
192 | printk(KERN_DEBUG "_OSC invalid revision\n"); | 145 | status = acpi_run_osc(handle, &osc_args); |
193 | if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { | 146 | if (ACPI_SUCCESS(status)) { |
194 | printk(KERN_DEBUG "_OSC FW not grant req. control\n"); | 147 | osc_data->support_set = support_set; |
195 | status = AE_SUPPORT; | 148 | osc_data->query_result = osc_args.query_result; |
196 | goto run_osc_out; | 149 | osc_data->is_queried = 1; |
197 | } | ||
198 | status = AE_ERROR; | ||
199 | goto run_osc_out; | ||
200 | } | 150 | } |
201 | status = AE_OK; | ||
202 | 151 | ||
203 | run_osc_out: | ||
204 | kfree(output.pointer); | ||
205 | return status; | 152 | return status; |
206 | } | 153 | } |
207 | 154 | ||
@@ -215,15 +162,11 @@ run_osc_out: | |||
215 | **/ | 162 | **/ |
216 | acpi_status __pci_osc_support_set(u32 flags, const char *hid) | 163 | acpi_status __pci_osc_support_set(u32 flags, const char *hid) |
217 | { | 164 | { |
218 | acpi_status retval = AE_NOT_FOUND; | 165 | if (!(flags & OSC_SUPPORT_MASKS)) |
219 | |||
220 | if (!(flags & OSC_SUPPORT_MASKS)) { | ||
221 | return AE_TYPE; | 166 | return AE_TYPE; |
222 | } | 167 | |
223 | acpi_get_devices(hid, | 168 | acpi_get_devices(hid, acpi_query_osc, |
224 | acpi_query_osc, | 169 | (void *)(unsigned long)flags, NULL); |
225 | (void *)(unsigned long)flags, | ||
226 | (void **) &retval ); | ||
227 | return AE_OK; | 170 | return AE_OK; |
228 | } | 171 | } |
229 | 172 | ||
@@ -236,10 +179,11 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid) | |||
236 | **/ | 179 | **/ |
237 | acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | 180 | acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) |
238 | { | 181 | { |
239 | acpi_status status; | 182 | acpi_status status; |
240 | u32 ctrlset; | 183 | u32 ctrlset, control_set; |
241 | acpi_handle tmp; | 184 | acpi_handle tmp; |
242 | struct acpi_osc_data *osc_data; | 185 | struct acpi_osc_data *osc_data; |
186 | struct acpi_osc_args osc_args; | ||
243 | 187 | ||
244 | status = acpi_get_handle(handle, "_OSC", &tmp); | 188 | status = acpi_get_handle(handle, "_OSC", &tmp); |
245 | if (ACPI_FAILURE(status)) | 189 | if (ACPI_FAILURE(status)) |
@@ -252,24 +196,25 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | |||
252 | } | 196 | } |
253 | 197 | ||
254 | ctrlset = (flags & OSC_CONTROL_MASKS); | 198 | ctrlset = (flags & OSC_CONTROL_MASKS); |
255 | if (!ctrlset) { | 199 | if (!ctrlset) |
256 | return AE_TYPE; | 200 | return AE_TYPE; |
257 | } | 201 | |
258 | if (osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] && | 202 | if (osc_data->is_queried && |
259 | ((osc_data->global_ctrlsets & ctrlset) != ctrlset)) { | 203 | ((osc_data->query_result & ctrlset) != ctrlset)) |
260 | return AE_SUPPORT; | 204 | return AE_SUPPORT; |
261 | } | 205 | |
262 | osc_data->ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset; | 206 | control_set = osc_data->control_set | ctrlset; |
263 | status = acpi_run_osc(handle, osc_data->ctrlset_buf); | 207 | osc_args.capbuf[OSC_QUERY_TYPE] = 0; |
264 | if (ACPI_FAILURE (status)) { | 208 | osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set; |
265 | osc_data->ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset; | 209 | osc_args.capbuf[OSC_CONTROL_TYPE] = control_set; |
266 | } | 210 | status = acpi_run_osc(handle, &osc_args); |
267 | 211 | if (ACPI_SUCCESS(status)) | |
212 | osc_data->control_set = control_set; | ||
213 | |||
268 | return status; | 214 | return status; |
269 | } | 215 | } |
270 | EXPORT_SYMBOL(pci_osc_control_set); | 216 | EXPORT_SYMBOL(pci_osc_control_set); |
271 | 217 | ||
272 | #ifdef CONFIG_ACPI_SLEEP | ||
273 | /* | 218 | /* |
274 | * _SxD returns the D-state with the highest power | 219 | * _SxD returns the D-state with the highest power |
275 | * (lowest D-state number) supported in the S-state "x". | 220 | * (lowest D-state number) supported in the S-state "x". |
@@ -293,13 +238,11 @@ EXPORT_SYMBOL(pci_osc_control_set); | |||
293 | * choose highest power _SxD or any lower power | 238 | * choose highest power _SxD or any lower power |
294 | */ | 239 | */ |
295 | 240 | ||
296 | static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev, | 241 | static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev) |
297 | pm_message_t state) | ||
298 | { | 242 | { |
299 | int acpi_state; | 243 | int acpi_state; |
300 | 244 | ||
301 | acpi_state = acpi_pm_device_sleep_state(&pdev->dev, | 245 | acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL); |
302 | device_may_wakeup(&pdev->dev), NULL); | ||
303 | if (acpi_state < 0) | 246 | if (acpi_state < 0) |
304 | return PCI_POWER_ERROR; | 247 | return PCI_POWER_ERROR; |
305 | 248 | ||
@@ -315,7 +258,13 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev, | |||
315 | } | 258 | } |
316 | return PCI_POWER_ERROR; | 259 | return PCI_POWER_ERROR; |
317 | } | 260 | } |
318 | #endif | 261 | |
262 | static bool acpi_pci_power_manageable(struct pci_dev *dev) | ||
263 | { | ||
264 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
265 | |||
266 | return handle ? acpi_bus_power_manageable(handle) : false; | ||
267 | } | ||
319 | 268 | ||
320 | static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | 269 | static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) |
321 | { | 270 | { |
@@ -328,12 +277,11 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
328 | [PCI_D3hot] = ACPI_STATE_D3, | 277 | [PCI_D3hot] = ACPI_STATE_D3, |
329 | [PCI_D3cold] = ACPI_STATE_D3 | 278 | [PCI_D3cold] = ACPI_STATE_D3 |
330 | }; | 279 | }; |
280 | int error = -EINVAL; | ||
331 | 281 | ||
332 | if (!handle) | ||
333 | return -ENODEV; | ||
334 | /* If the ACPI device has _EJ0, ignore the device */ | 282 | /* If the ACPI device has _EJ0, ignore the device */ |
335 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) | 283 | if (!handle || ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) |
336 | return 0; | 284 | return -ENODEV; |
337 | 285 | ||
338 | switch (state) { | 286 | switch (state) { |
339 | case PCI_D0: | 287 | case PCI_D0: |
@@ -341,11 +289,41 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
341 | case PCI_D2: | 289 | case PCI_D2: |
342 | case PCI_D3hot: | 290 | case PCI_D3hot: |
343 | case PCI_D3cold: | 291 | case PCI_D3cold: |
344 | return acpi_bus_set_power(handle, state_conv[state]); | 292 | error = acpi_bus_set_power(handle, state_conv[state]); |
345 | } | 293 | } |
346 | return -EINVAL; | 294 | |
295 | if (!error) | ||
296 | dev_printk(KERN_INFO, &dev->dev, | ||
297 | "power state changed by ACPI to D%d\n", state); | ||
298 | |||
299 | return error; | ||
300 | } | ||
301 | |||
302 | static bool acpi_pci_can_wakeup(struct pci_dev *dev) | ||
303 | { | ||
304 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
305 | |||
306 | return handle ? acpi_bus_can_wakeup(handle) : false; | ||
307 | } | ||
308 | |||
309 | static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) | ||
310 | { | ||
311 | int error = acpi_pm_device_sleep_wake(&dev->dev, enable); | ||
312 | |||
313 | if (!error) | ||
314 | dev_printk(KERN_INFO, &dev->dev, | ||
315 | "wake-up capability %s by ACPI\n", | ||
316 | enable ? "enabled" : "disabled"); | ||
317 | return error; | ||
347 | } | 318 | } |
348 | 319 | ||
320 | static struct pci_platform_pm_ops acpi_pci_platform_pm = { | ||
321 | .is_manageable = acpi_pci_power_manageable, | ||
322 | .set_state = acpi_pci_set_power_state, | ||
323 | .choose_state = acpi_pci_choose_state, | ||
324 | .can_wakeup = acpi_pci_can_wakeup, | ||
325 | .sleep_wake = acpi_pci_sleep_wake, | ||
326 | }; | ||
349 | 327 | ||
350 | /* ACPI bus type */ | 328 | /* ACPI bus type */ |
351 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) | 329 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) |
@@ -397,10 +375,7 @@ static int __init acpi_pci_init(void) | |||
397 | ret = register_acpi_bus_type(&acpi_pci_bus); | 375 | ret = register_acpi_bus_type(&acpi_pci_bus); |
398 | if (ret) | 376 | if (ret) |
399 | return 0; | 377 | return 0; |
400 | #ifdef CONFIG_ACPI_SLEEP | 378 | pci_set_platform_pm(&acpi_pci_platform_pm); |
401 | platform_pci_choose_state = acpi_pci_choose_state; | ||
402 | #endif | ||
403 | platform_pci_set_power_state = acpi_pci_set_power_state; | ||
404 | return 0; | 379 | return 0; |
405 | } | 380 | } |
406 | arch_initcall(acpi_pci_init); | 381 | arch_initcall(acpi_pci_init); |