diff options
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r-- | drivers/pci/pci-acpi.c | 82 |
1 files changed, 38 insertions, 44 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index ae5ec76dca77..3582512e7226 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -24,13 +24,14 @@ struct acpi_osc_data { | |||
24 | acpi_handle handle; | 24 | acpi_handle handle; |
25 | u32 support_set; | 25 | u32 support_set; |
26 | u32 control_set; | 26 | u32 control_set; |
27 | u32 control_query; | ||
28 | int is_queried; | ||
27 | struct list_head sibiling; | 29 | struct list_head sibiling; |
28 | }; | 30 | }; |
29 | static LIST_HEAD(acpi_osc_data_list); | 31 | static LIST_HEAD(acpi_osc_data_list); |
30 | 32 | ||
31 | struct acpi_osc_args { | 33 | struct acpi_osc_args { |
32 | u32 capbuf[3]; | 34 | u32 capbuf[3]; |
33 | u32 ctrl_result; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | static DEFINE_MUTEX(pci_acpi_lock); | 37 | static DEFINE_MUTEX(pci_acpi_lock); |
@@ -56,7 +57,7 @@ static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, | |||
56 | 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | 57 | 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; |
57 | 58 | ||
58 | static acpi_status acpi_run_osc(acpi_handle handle, | 59 | static acpi_status acpi_run_osc(acpi_handle handle, |
59 | struct acpi_osc_args *osc_args) | 60 | struct acpi_osc_args *osc_args, u32 *retval) |
60 | { | 61 | { |
61 | acpi_status status; | 62 | acpi_status status; |
62 | struct acpi_object_list input; | 63 | struct acpi_object_list input; |
@@ -112,8 +113,7 @@ static acpi_status acpi_run_osc(acpi_handle handle, | |||
112 | goto out_kfree; | 113 | goto out_kfree; |
113 | } | 114 | } |
114 | out_success: | 115 | out_success: |
115 | osc_args->ctrl_result = | 116 | *retval = *((u32 *)(out_obj->buffer.pointer + 8)); |
116 | *((u32 *)(out_obj->buffer.pointer + 8)); | ||
117 | status = AE_OK; | 117 | status = AE_OK; |
118 | 118 | ||
119 | out_kfree: | 119 | out_kfree: |
@@ -121,11 +121,10 @@ out_kfree: | |||
121 | return status; | 121 | return status; |
122 | } | 122 | } |
123 | 123 | ||
124 | static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data, | 124 | static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data) |
125 | u32 *result) | ||
126 | { | 125 | { |
127 | acpi_status status; | 126 | acpi_status status; |
128 | u32 support_set; | 127 | u32 support_set, result; |
129 | struct acpi_osc_args osc_args; | 128 | struct acpi_osc_args osc_args; |
130 | 129 | ||
131 | /* do _OSC query for all possible controls */ | 130 | /* do _OSC query for all possible controls */ |
@@ -134,56 +133,45 @@ static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data, | |||
134 | osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; | 133 | osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; |
135 | osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; | 134 | osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; |
136 | 135 | ||
137 | status = acpi_run_osc(osc_data->handle, &osc_args); | 136 | status = acpi_run_osc(osc_data->handle, &osc_args, &result); |
138 | if (ACPI_SUCCESS(status)) { | 137 | if (ACPI_SUCCESS(status)) { |
139 | osc_data->support_set = support_set; | 138 | osc_data->support_set = support_set; |
140 | *result = osc_args.ctrl_result; | 139 | osc_data->control_query = result; |
140 | osc_data->is_queried = 1; | ||
141 | } | 141 | } |
142 | 142 | ||
143 | return status; | 143 | return status; |
144 | } | 144 | } |
145 | 145 | ||
146 | static acpi_status acpi_query_osc(acpi_handle handle, | 146 | /* |
147 | u32 level, void *context, void **retval) | 147 | * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature |
148 | * @flags: Bitmask of flags to support | ||
149 | * | ||
150 | * See the ACPI spec for the definition of the flags | ||
151 | */ | ||
152 | int pci_acpi_osc_support(acpi_handle handle, u32 flags) | ||
148 | { | 153 | { |
149 | acpi_status status; | 154 | acpi_status status; |
150 | struct acpi_osc_data *osc_data; | ||
151 | u32 flags = (unsigned long)context, dummy; | ||
152 | acpi_handle tmp; | 155 | acpi_handle tmp; |
156 | struct acpi_osc_data *osc_data; | ||
157 | int rc = 0; | ||
153 | 158 | ||
154 | status = acpi_get_handle(handle, "_OSC", &tmp); | 159 | status = acpi_get_handle(handle, "_OSC", &tmp); |
155 | if (ACPI_FAILURE(status)) | 160 | if (ACPI_FAILURE(status)) |
156 | return AE_OK; | 161 | return -ENOTTY; |
157 | 162 | ||
158 | mutex_lock(&pci_acpi_lock); | 163 | mutex_lock(&pci_acpi_lock); |
159 | osc_data = acpi_get_osc_data(handle); | 164 | osc_data = acpi_get_osc_data(handle); |
160 | if (!osc_data) { | 165 | if (!osc_data) { |
161 | printk(KERN_ERR "acpi osc data array is full\n"); | 166 | printk(KERN_ERR "acpi osc data array is full\n"); |
167 | rc = -ENOMEM; | ||
162 | goto out; | 168 | goto out; |
163 | } | 169 | } |
164 | 170 | ||
165 | __acpi_query_osc(flags, osc_data, &dummy); | 171 | __acpi_query_osc(flags, osc_data); |
166 | out: | 172 | out: |
167 | mutex_unlock(&pci_acpi_lock); | 173 | mutex_unlock(&pci_acpi_lock); |
168 | return AE_OK; | 174 | return rc; |
169 | } | ||
170 | |||
171 | /** | ||
172 | * __pci_osc_support_set - register OS support to Firmware | ||
173 | * @flags: OS support bits | ||
174 | * @hid: hardware ID | ||
175 | * | ||
176 | * Update OS support fields and doing a _OSC Query to obtain an update | ||
177 | * from Firmware on supported control bits. | ||
178 | **/ | ||
179 | acpi_status __pci_osc_support_set(u32 flags, const char *hid) | ||
180 | { | ||
181 | if (!(flags & OSC_SUPPORT_MASKS)) | ||
182 | return AE_TYPE; | ||
183 | |||
184 | acpi_get_devices(hid, acpi_query_osc, | ||
185 | (void *)(unsigned long)flags, NULL); | ||
186 | return AE_OK; | ||
187 | } | 175 | } |
188 | 176 | ||
189 | /** | 177 | /** |
@@ -196,7 +184,7 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid) | |||
196 | acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | 184 | acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) |
197 | { | 185 | { |
198 | acpi_status status; | 186 | acpi_status status; |
199 | u32 ctrlset, control_set, result; | 187 | u32 control_req, control_set, result; |
200 | acpi_handle tmp; | 188 | acpi_handle tmp; |
201 | struct acpi_osc_data *osc_data; | 189 | struct acpi_osc_data *osc_data; |
202 | struct acpi_osc_args osc_args; | 190 | struct acpi_osc_args osc_args; |
@@ -213,28 +201,34 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | |||
213 | goto out; | 201 | goto out; |
214 | } | 202 | } |
215 | 203 | ||
216 | ctrlset = (flags & OSC_CONTROL_MASKS); | 204 | control_req = (flags & OSC_CONTROL_MASKS); |
217 | if (!ctrlset) { | 205 | if (!control_req) { |
218 | status = AE_TYPE; | 206 | status = AE_TYPE; |
219 | goto out; | 207 | goto out; |
220 | } | 208 | } |
221 | 209 | ||
222 | status = __acpi_query_osc(osc_data->support_set, osc_data, &result); | 210 | /* No need to evaluate _OSC if the control was already granted. */ |
223 | if (ACPI_FAILURE(status)) | 211 | if ((osc_data->control_set & control_req) == control_req) |
224 | goto out; | 212 | goto out; |
225 | 213 | ||
226 | if ((result & ctrlset) != ctrlset) { | 214 | if (!osc_data->is_queried) { |
215 | status = __acpi_query_osc(osc_data->support_set, osc_data); | ||
216 | if (ACPI_FAILURE(status)) | ||
217 | goto out; | ||
218 | } | ||
219 | |||
220 | if ((osc_data->control_query & control_req) != control_req) { | ||
227 | status = AE_SUPPORT; | 221 | status = AE_SUPPORT; |
228 | goto out; | 222 | goto out; |
229 | } | 223 | } |
230 | 224 | ||
231 | control_set = osc_data->control_set | ctrlset; | 225 | control_set = osc_data->control_set | control_req; |
232 | osc_args.capbuf[OSC_QUERY_TYPE] = 0; | 226 | osc_args.capbuf[OSC_QUERY_TYPE] = 0; |
233 | osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set; | 227 | osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set; |
234 | osc_args.capbuf[OSC_CONTROL_TYPE] = control_set; | 228 | osc_args.capbuf[OSC_CONTROL_TYPE] = control_set; |
235 | status = acpi_run_osc(handle, &osc_args); | 229 | status = acpi_run_osc(handle, &osc_args, &result); |
236 | if (ACPI_SUCCESS(status)) | 230 | if (ACPI_SUCCESS(status)) |
237 | osc_data->control_set = control_set; | 231 | osc_data->control_set = result; |
238 | out: | 232 | out: |
239 | mutex_unlock(&pci_acpi_lock); | 233 | mutex_unlock(&pci_acpi_lock); |
240 | return status; | 234 | return status; |
@@ -375,7 +369,7 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) | |||
375 | * The string should be the same as root bridge's name | 369 | * The string should be the same as root bridge's name |
376 | * Please look at 'pci_scan_bus_parented' | 370 | * Please look at 'pci_scan_bus_parented' |
377 | */ | 371 | */ |
378 | num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); | 372 | num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus); |
379 | if (num != 2) | 373 | if (num != 2) |
380 | return -ENODEV; | 374 | return -ENODEV; |
381 | *handle = acpi_get_pci_rootbridge_handle(seg, bus); | 375 | *handle = acpi_get_pci_rootbridge_handle(seg, bus); |