diff options
author | Shaohua Li <shaohua.li@intel.com> | 2008-05-11 22:48:10 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2008-05-13 12:51:53 -0400 |
commit | a5d1c8798309a384c2776e5ff472f8ceb6d9065d (patch) | |
tree | 1688166ecd3a3443fe67c7ef1c950f0ac1c48cea | |
parent | 4a367f3a9dbf2e7ffcee4702203479809236ee6e (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.c | 95 |
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 | ||
22 | static u32 ctrlset_buf[3] = {0, 0, 0}; | 22 | struct acpi_osc_data { |
23 | static u32 global_ctrlsets = 0; | 23 | acpi_handle handle; |
24 | u32 ctrlset_buf[3]; | ||
25 | u32 global_ctrlsets; | ||
26 | struct list_head sibiling; | ||
27 | }; | ||
28 | static LIST_HEAD(acpi_osc_data_list); | ||
29 | |||
30 | static 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 | |||
24 | static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | 47 | static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; |
25 | 48 | ||
26 | static acpi_status | 49 | static 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 | ||
91 | query_osc_out: | 126 | query_osc_out: |
92 | kfree(output.pointer); | 127 | kfree(output.pointer); |
128 | out_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 | **/ |
166 | acpi_status __pci_osc_support_set(u32 flags, const char *hid) | 210 | acpi_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; |