aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-acpi.c
diff options
context:
space:
mode:
authorTaku Izumi <izumi.taku@jp.fujitsu.com>2008-10-17 00:48:36 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-10-22 19:42:33 -0400
commit9778c14b4ca2c81e437fc2fd2b1f3d676937db27 (patch)
treeecd32dcf1fae311e7caaa400f492051aeb2c66a1 /drivers/pci/pci-acpi.c
parent2515ddc6db8eb49a79f0fe5e67ff09ac7c81eab4 (diff)
ACPI/PCI: Fix possible race condition on _OSC evaluation
Fix possible race condition on _OSC evaluation. Current _OSC evaluation code has possible race condition because it maniputes osc_data linked list or its contents without any lock mechanism. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r--drivers/pci/pci-acpi.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 89a2f0fa10f9..14848bf95e82 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -35,6 +35,8 @@ struct acpi_osc_args {
35 u32 query_result; 35 u32 query_result;
36}; 36};
37 37
38static DEFINE_MUTEX(pci_acpi_lock);
39
38static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) 40static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
39{ 41{
40 struct acpi_osc_data *data; 42 struct acpi_osc_data *data;
@@ -131,10 +133,12 @@ static acpi_status acpi_query_osc(acpi_handle handle,
131 if (ACPI_FAILURE(status)) 133 if (ACPI_FAILURE(status))
132 return status; 134 return status;
133 135
136 mutex_lock(&pci_acpi_lock);
134 osc_data = acpi_get_osc_data(handle); 137 osc_data = acpi_get_osc_data(handle);
135 if (!osc_data) { 138 if (!osc_data) {
136 printk(KERN_ERR "acpi osc data array is full\n"); 139 printk(KERN_ERR "acpi osc data array is full\n");
137 return AE_ERROR; 140 status = AE_ERROR;
141 goto out;
138 } 142 }
139 143
140 /* do _OSC query for all possible controls */ 144 /* do _OSC query for all possible controls */
@@ -149,7 +153,8 @@ static acpi_status acpi_query_osc(acpi_handle handle,
149 osc_data->query_result = osc_args.query_result; 153 osc_data->query_result = osc_args.query_result;
150 osc_data->is_queried = 1; 154 osc_data->is_queried = 1;
151 } 155 }
152 156out:
157 mutex_unlock(&pci_acpi_lock);
153 return status; 158 return status;
154} 159}
155 160
@@ -190,19 +195,25 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
190 if (ACPI_FAILURE(status)) 195 if (ACPI_FAILURE(status))
191 return status; 196 return status;
192 197
198 mutex_lock(&pci_acpi_lock);
193 osc_data = acpi_get_osc_data(handle); 199 osc_data = acpi_get_osc_data(handle);
194 if (!osc_data) { 200 if (!osc_data) {
195 printk(KERN_ERR "acpi osc data array is full\n"); 201 printk(KERN_ERR "acpi osc data array is full\n");
196 return AE_ERROR; 202 status = AE_ERROR;
203 goto out;
197 } 204 }
198 205
199 ctrlset = (flags & OSC_CONTROL_MASKS); 206 ctrlset = (flags & OSC_CONTROL_MASKS);
200 if (!ctrlset) 207 if (!ctrlset) {
201 return AE_TYPE; 208 status = AE_TYPE;
209 goto out;
210 }
202 211
203 if (osc_data->is_queried && 212 if (osc_data->is_queried &&
204 ((osc_data->query_result & ctrlset) != ctrlset)) 213 ((osc_data->query_result & ctrlset) != ctrlset)) {
205 return AE_SUPPORT; 214 status = AE_SUPPORT;
215 goto out;
216 }
206 217
207 control_set = osc_data->control_set | ctrlset; 218 control_set = osc_data->control_set | ctrlset;
208 osc_args.capbuf[OSC_QUERY_TYPE] = 0; 219 osc_args.capbuf[OSC_QUERY_TYPE] = 0;
@@ -211,7 +222,8 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
211 status = acpi_run_osc(handle, &osc_args); 222 status = acpi_run_osc(handle, &osc_args);
212 if (ACPI_SUCCESS(status)) 223 if (ACPI_SUCCESS(status))
213 osc_data->control_set = control_set; 224 osc_data->control_set = control_set;
214 225out:
226 mutex_unlock(&pci_acpi_lock);
215 return status; 227 return status;
216} 228}
217EXPORT_SYMBOL(pci_osc_control_set); 229EXPORT_SYMBOL(pci_osc_control_set);