diff options
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r-- | drivers/pci/pci-acpi.c | 92 |
1 files changed, 60 insertions, 32 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 7764768b6a0..dfe7c8e1b18 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/pci-aspm.h> | ||
14 | #include <acpi/acpi.h> | 15 | #include <acpi/acpi.h> |
15 | #include <acpi/acnamesp.h> | 16 | #include <acpi/acnamesp.h> |
16 | #include <acpi/acresrc.h> | 17 | #include <acpi/acresrc.h> |
@@ -23,17 +24,17 @@ struct acpi_osc_data { | |||
23 | acpi_handle handle; | 24 | acpi_handle handle; |
24 | u32 support_set; | 25 | u32 support_set; |
25 | u32 control_set; | 26 | u32 control_set; |
26 | int is_queried; | ||
27 | u32 query_result; | ||
28 | struct list_head sibiling; | 27 | struct list_head sibiling; |
29 | }; | 28 | }; |
30 | static LIST_HEAD(acpi_osc_data_list); | 29 | static LIST_HEAD(acpi_osc_data_list); |
31 | 30 | ||
32 | struct acpi_osc_args { | 31 | struct acpi_osc_args { |
33 | u32 capbuf[3]; | 32 | u32 capbuf[3]; |
34 | u32 query_result; | 33 | u32 ctrl_result; |
35 | }; | 34 | }; |
36 | 35 | ||
36 | static DEFINE_MUTEX(pci_acpi_lock); | ||
37 | |||
37 | static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) | 38 | static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) |
38 | { | 39 | { |
39 | struct acpi_osc_data *data; | 40 | struct acpi_osc_data *data; |
@@ -107,9 +108,8 @@ static acpi_status acpi_run_osc(acpi_handle handle, | |||
107 | goto out_kfree; | 108 | goto out_kfree; |
108 | } | 109 | } |
109 | out_success: | 110 | out_success: |
110 | if (flags & OSC_QUERY_ENABLE) | 111 | osc_args->ctrl_result = |
111 | osc_args->query_result = | 112 | *((u32 *)(out_obj->buffer.pointer + 8)); |
112 | *((u32 *)(out_obj->buffer.pointer + 8)); | ||
113 | status = AE_OK; | 113 | status = AE_OK; |
114 | 114 | ||
115 | out_kfree: | 115 | out_kfree: |
@@ -117,41 +117,53 @@ out_kfree: | |||
117 | return status; | 117 | return status; |
118 | } | 118 | } |
119 | 119 | ||
120 | static acpi_status acpi_query_osc(acpi_handle handle, | 120 | static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data, |
121 | u32 level, void *context, void **retval) | 121 | u32 *result) |
122 | { | 122 | { |
123 | acpi_status status; | 123 | acpi_status status; |
124 | struct acpi_osc_data *osc_data; | 124 | u32 support_set; |
125 | u32 flags = (unsigned long)context, support_set; | ||
126 | acpi_handle tmp; | ||
127 | struct acpi_osc_args osc_args; | 125 | struct acpi_osc_args osc_args; |
128 | 126 | ||
129 | status = acpi_get_handle(handle, "_OSC", &tmp); | ||
130 | if (ACPI_FAILURE(status)) | ||
131 | return status; | ||
132 | |||
133 | osc_data = acpi_get_osc_data(handle); | ||
134 | if (!osc_data) { | ||
135 | printk(KERN_ERR "acpi osc data array is full\n"); | ||
136 | return AE_ERROR; | ||
137 | } | ||
138 | |||
139 | /* do _OSC query for all possible controls */ | 127 | /* do _OSC query for all possible controls */ |
140 | support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); | 128 | support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); |
141 | osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | 129 | osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; |
142 | osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; | 130 | osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; |
143 | osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; | 131 | osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; |
144 | 132 | ||
145 | status = acpi_run_osc(handle, &osc_args); | 133 | status = acpi_run_osc(osc_data->handle, &osc_args); |
146 | if (ACPI_SUCCESS(status)) { | 134 | if (ACPI_SUCCESS(status)) { |
147 | osc_data->support_set = support_set; | 135 | osc_data->support_set = support_set; |
148 | osc_data->query_result = osc_args.query_result; | 136 | *result = osc_args.ctrl_result; |
149 | osc_data->is_queried = 1; | ||
150 | } | 137 | } |
151 | 138 | ||
152 | return status; | 139 | return status; |
153 | } | 140 | } |
154 | 141 | ||
142 | static acpi_status acpi_query_osc(acpi_handle handle, | ||
143 | u32 level, void *context, void **retval) | ||
144 | { | ||
145 | acpi_status status; | ||
146 | struct acpi_osc_data *osc_data; | ||
147 | u32 flags = (unsigned long)context, dummy; | ||
148 | acpi_handle tmp; | ||
149 | |||
150 | status = acpi_get_handle(handle, "_OSC", &tmp); | ||
151 | if (ACPI_FAILURE(status)) | ||
152 | return AE_OK; | ||
153 | |||
154 | mutex_lock(&pci_acpi_lock); | ||
155 | osc_data = acpi_get_osc_data(handle); | ||
156 | if (!osc_data) { | ||
157 | printk(KERN_ERR "acpi osc data array is full\n"); | ||
158 | goto out; | ||
159 | } | ||
160 | |||
161 | __acpi_query_osc(flags, osc_data, &dummy); | ||
162 | out: | ||
163 | mutex_unlock(&pci_acpi_lock); | ||
164 | return AE_OK; | ||
165 | } | ||
166 | |||
155 | /** | 167 | /** |
156 | * __pci_osc_support_set - register OS support to Firmware | 168 | * __pci_osc_support_set - register OS support to Firmware |
157 | * @flags: OS support bits | 169 | * @flags: OS support bits |
@@ -180,7 +192,7 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid) | |||
180 | acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | 192 | acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) |
181 | { | 193 | { |
182 | acpi_status status; | 194 | acpi_status status; |
183 | u32 ctrlset, control_set; | 195 | u32 ctrlset, control_set, result; |
184 | acpi_handle tmp; | 196 | acpi_handle tmp; |
185 | struct acpi_osc_data *osc_data; | 197 | struct acpi_osc_data *osc_data; |
186 | struct acpi_osc_args osc_args; | 198 | struct acpi_osc_args osc_args; |
@@ -189,19 +201,28 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | |||
189 | if (ACPI_FAILURE(status)) | 201 | if (ACPI_FAILURE(status)) |
190 | return status; | 202 | return status; |
191 | 203 | ||
204 | mutex_lock(&pci_acpi_lock); | ||
192 | osc_data = acpi_get_osc_data(handle); | 205 | osc_data = acpi_get_osc_data(handle); |
193 | if (!osc_data) { | 206 | if (!osc_data) { |
194 | printk(KERN_ERR "acpi osc data array is full\n"); | 207 | printk(KERN_ERR "acpi osc data array is full\n"); |
195 | return AE_ERROR; | 208 | status = AE_ERROR; |
209 | goto out; | ||
196 | } | 210 | } |
197 | 211 | ||
198 | ctrlset = (flags & OSC_CONTROL_MASKS); | 212 | ctrlset = (flags & OSC_CONTROL_MASKS); |
199 | if (!ctrlset) | 213 | if (!ctrlset) { |
200 | return AE_TYPE; | 214 | status = AE_TYPE; |
215 | goto out; | ||
216 | } | ||
201 | 217 | ||
202 | if (osc_data->is_queried && | 218 | status = __acpi_query_osc(osc_data->support_set, osc_data, &result); |
203 | ((osc_data->query_result & ctrlset) != ctrlset)) | 219 | if (ACPI_FAILURE(status)) |
204 | return AE_SUPPORT; | 220 | goto out; |
221 | |||
222 | if ((result & ctrlset) != ctrlset) { | ||
223 | status = AE_SUPPORT; | ||
224 | goto out; | ||
225 | } | ||
205 | 226 | ||
206 | control_set = osc_data->control_set | ctrlset; | 227 | control_set = osc_data->control_set | ctrlset; |
207 | osc_args.capbuf[OSC_QUERY_TYPE] = 0; | 228 | osc_args.capbuf[OSC_QUERY_TYPE] = 0; |
@@ -210,7 +231,8 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | |||
210 | status = acpi_run_osc(handle, &osc_args); | 231 | status = acpi_run_osc(handle, &osc_args); |
211 | if (ACPI_SUCCESS(status)) | 232 | if (ACPI_SUCCESS(status)) |
212 | osc_data->control_set = control_set; | 233 | osc_data->control_set = control_set; |
213 | 234 | out: | |
235 | mutex_unlock(&pci_acpi_lock); | ||
214 | return status; | 236 | return status; |
215 | } | 237 | } |
216 | EXPORT_SYMBOL(pci_osc_control_set); | 238 | EXPORT_SYMBOL(pci_osc_control_set); |
@@ -372,6 +394,12 @@ static int __init acpi_pci_init(void) | |||
372 | printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); | 394 | printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); |
373 | pci_no_msi(); | 395 | pci_no_msi(); |
374 | } | 396 | } |
397 | |||
398 | if (acpi_gbl_FADT.boot_flags & BAF_PCIE_ASPM_CONTROL) { | ||
399 | printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); | ||
400 | pcie_no_aspm(); | ||
401 | } | ||
402 | |||
375 | ret = register_acpi_bus_type(&acpi_pci_bus); | 403 | ret = register_acpi_bus_type(&acpi_pci_bus); |
376 | if (ret) | 404 | if (ret) |
377 | return 0; | 405 | return 0; |