aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2008-05-11 22:48:10 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-05-13 12:51:53 -0400
commita5d1c8798309a384c2776e5ff472f8ceb6d9065d (patch)
tree1688166ecd3a3443fe67c7ef1c950f0ac1c48cea
parent4a367f3a9dbf2e7ffcee4702203479809236ee6e (diff)
ACPI/PCI: handle multiple _OSC
There is an IA64 system here which have two pci root bridges with _OSC. One _OSC disables SHPC control bit but the other not. Below patch makes _OSC data per-device instead of one global, otherwise linux takes both root bridges don't support SHPC. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--drivers/pci/pci-acpi.c95
1 files changed, 66 insertions, 29 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index ddfd756fc8ed..468d13e1458e 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -19,8 +19,31 @@
19#include <linux/pci-acpi.h> 19#include <linux/pci-acpi.h>
20#include "pci.h" 20#include "pci.h"
21 21
22static u32 ctrlset_buf[3] = {0, 0, 0}; 22struct acpi_osc_data {
23static u32 global_ctrlsets = 0; 23 acpi_handle handle;
24 u32 ctrlset_buf[3];
25 u32 global_ctrlsets;
26 struct list_head sibiling;
27};
28static LIST_HEAD(acpi_osc_data_list);
29
30static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
31{
32 struct acpi_osc_data *data;
33
34 list_for_each_entry(data, &acpi_osc_data_list, sibiling) {
35 if (data->handle == handle)
36 return data;
37 }
38 data = kzalloc(sizeof(*data), GFP_KERNEL);
39 if (!data)
40 return NULL;
41 INIT_LIST_HEAD(&data->sibiling);
42 data->handle = handle;
43 list_add_tail(&data->sibiling, &acpi_osc_data_list);
44 return data;
45}
46
24static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; 47static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
25 48
26static acpi_status 49static acpi_status
@@ -37,8 +60,21 @@ acpi_query_osc (
37 union acpi_object *out_obj; 60 union acpi_object *out_obj;
38 u32 osc_dw0; 61 u32 osc_dw0;
39 acpi_status *ret_status = (acpi_status *)retval; 62 acpi_status *ret_status = (acpi_status *)retval;
63 struct acpi_osc_data *osc_data = acpi_get_osc_data(handle);
64 u32 flags = (unsigned long)context, temp;
65
66 if (!osc_data) {
67 printk(KERN_ERR "acpi osc data array is full\n");
68 return AE_ERROR;
69 }
70
71 osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
72
73 /* do _OSC query for all possible controls */
74 temp = osc_data->ctrlset_buf[OSC_CONTROL_TYPE];
75 osc_data->ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
76 osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
40 77
41
42 /* Setting up input parameters */ 78 /* Setting up input parameters */
43 input.count = 4; 79 input.count = 4;
44 input.pointer = in_params; 80 input.pointer = in_params;
@@ -51,13 +87,11 @@ acpi_query_osc (
51 in_params[2].integer.value = 3; 87 in_params[2].integer.value = 3;
52 in_params[3].type = ACPI_TYPE_BUFFER; 88 in_params[3].type = ACPI_TYPE_BUFFER;
53 in_params[3].buffer.length = 12; 89 in_params[3].buffer.length = 12;
54 in_params[3].buffer.pointer = (u8 *)context; 90 in_params[3].buffer.pointer = (u8 *)osc_data->ctrlset_buf;
55 91
56 status = acpi_evaluate_object(handle, "_OSC", &input, &output); 92 status = acpi_evaluate_object(handle, "_OSC", &input, &output);
57 if (ACPI_FAILURE (status)) { 93 if (ACPI_FAILURE(status))
58 *ret_status = status; 94 goto out_nofree;
59 return status;
60 }
61 out_obj = output.pointer; 95 out_obj = output.pointer;
62 96
63 if (out_obj->type != ACPI_TYPE_BUFFER) { 97 if (out_obj->type != ACPI_TYPE_BUFFER) {
@@ -76,7 +110,8 @@ acpi_query_osc (
76 printk(KERN_DEBUG "_OSC invalid revision\n"); 110 printk(KERN_DEBUG "_OSC invalid revision\n");
77 if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { 111 if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
78 /* Update Global Control Set */ 112 /* Update Global Control Set */
79 global_ctrlsets = *((u32 *)(out_obj->buffer.pointer+8)); 113 osc_data->global_ctrlsets =
114 *((u32 *)(out_obj->buffer.pointer + 8));
80 status = AE_OK; 115 status = AE_OK;
81 goto query_osc_out; 116 goto query_osc_out;
82 } 117 }
@@ -85,12 +120,21 @@ acpi_query_osc (
85 } 120 }
86 121
87 /* Update Global Control Set */ 122 /* Update Global Control Set */
88 global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8)); 123 osc_data->global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
89 status = AE_OK; 124 status = AE_OK;
90 125
91query_osc_out: 126query_osc_out:
92 kfree(output.pointer); 127 kfree(output.pointer);
128out_nofree:
93 *ret_status = status; 129 *ret_status = status;
130
131 osc_data->ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
132 osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = temp;
133 if (ACPI_FAILURE(status)) {
134 /* no osc support at all */
135 osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] = 0;
136 }
137
94 return status; 138 return status;
95} 139}
96 140
@@ -165,28 +209,15 @@ run_osc_out:
165 **/ 209 **/
166acpi_status __pci_osc_support_set(u32 flags, const char *hid) 210acpi_status __pci_osc_support_set(u32 flags, const char *hid)
167{ 211{
168 u32 temp;
169 acpi_status retval = AE_NOT_FOUND; 212 acpi_status retval = AE_NOT_FOUND;
170 213
171 if (!(flags & OSC_SUPPORT_MASKS)) { 214 if (!(flags & OSC_SUPPORT_MASKS)) {
172 return AE_TYPE; 215 return AE_TYPE;
173 } 216 }
174 ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
175
176 /* do _OSC query for all possible controls */
177 temp = ctrlset_buf[OSC_CONTROL_TYPE];
178 ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
179 ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
180 acpi_get_devices(hid, 217 acpi_get_devices(hid,
181 acpi_query_osc, 218 acpi_query_osc,
182 ctrlset_buf, 219 (void *)(unsigned long)flags,
183 (void **) &retval ); 220 (void **) &retval );
184 ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
185 ctrlset_buf[OSC_CONTROL_TYPE] = temp;
186 if (ACPI_FAILURE(retval)) {
187 /* no osc support at all */
188 ctrlset_buf[OSC_SUPPORT_TYPE] = 0;
189 }
190 return AE_OK; 221 return AE_OK;
191} 222}
192 223
@@ -201,19 +232,25 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
201{ 232{
202 acpi_status status; 233 acpi_status status;
203 u32 ctrlset; 234 u32 ctrlset;
235 struct acpi_osc_data *osc_data = acpi_get_osc_data(handle);
236
237 if (!osc_data) {
238 printk(KERN_ERR "acpi osc data array is full\n");
239 return AE_ERROR;
240 }
204 241
205 ctrlset = (flags & OSC_CONTROL_MASKS); 242 ctrlset = (flags & OSC_CONTROL_MASKS);
206 if (!ctrlset) { 243 if (!ctrlset) {
207 return AE_TYPE; 244 return AE_TYPE;
208 } 245 }
209 if (ctrlset_buf[OSC_SUPPORT_TYPE] && 246 if (osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] &&
210 ((global_ctrlsets & ctrlset) != ctrlset)) { 247 ((osc_data->global_ctrlsets & ctrlset) != ctrlset)) {
211 return AE_SUPPORT; 248 return AE_SUPPORT;
212 } 249 }
213 ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset; 250 osc_data->ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
214 status = acpi_run_osc(handle, ctrlset_buf); 251 status = acpi_run_osc(handle, osc_data->ctrlset_buf);
215 if (ACPI_FAILURE (status)) { 252 if (ACPI_FAILURE (status)) {
216 ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset; 253 osc_data->ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
217 } 254 }
218 255
219 return status; 256 return status;