diff options
Diffstat (limited to 'drivers/acpi/system.c')
-rw-r--r-- | drivers/acpi/system.c | 169 |
1 files changed, 156 insertions, 13 deletions
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 5bd2dec9a7ac..d8e3f153b295 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c | |||
@@ -167,7 +167,13 @@ static int acpi_system_sysfs_init(void) | |||
167 | #define COUNT_ERROR 2 /* other */ | 167 | #define COUNT_ERROR 2 /* other */ |
168 | #define NUM_COUNTERS_EXTRA 3 | 168 | #define NUM_COUNTERS_EXTRA 3 |
169 | 169 | ||
170 | static u32 *all_counters; | 170 | #define ACPI_EVENT_VALID 0x01 |
171 | struct event_counter { | ||
172 | u32 count; | ||
173 | u32 flags; | ||
174 | }; | ||
175 | |||
176 | static struct event_counter *all_counters; | ||
171 | static u32 num_gpes; | 177 | static u32 num_gpes; |
172 | static u32 num_counters; | 178 | static u32 num_counters; |
173 | static struct attribute **all_attrs; | 179 | static struct attribute **all_attrs; |
@@ -202,9 +208,44 @@ static int count_num_gpes(void) | |||
202 | return count; | 208 | return count; |
203 | } | 209 | } |
204 | 210 | ||
211 | static int get_gpe_device(int index, acpi_handle *handle) | ||
212 | { | ||
213 | struct acpi_gpe_xrupt_info *gpe_xrupt_info; | ||
214 | struct acpi_gpe_block_info *gpe_block; | ||
215 | acpi_cpu_flags flags; | ||
216 | struct acpi_namespace_node *node; | ||
217 | |||
218 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | ||
219 | |||
220 | gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; | ||
221 | while (gpe_xrupt_info) { | ||
222 | gpe_block = gpe_xrupt_info->gpe_block_list_head; | ||
223 | node = gpe_block->node; | ||
224 | while (gpe_block) { | ||
225 | index -= gpe_block->register_count * | ||
226 | ACPI_GPE_REGISTER_WIDTH; | ||
227 | if (index < 0) { | ||
228 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | ||
229 | /* return NULL if it's FADT GPE */ | ||
230 | if (node->type != ACPI_TYPE_DEVICE) | ||
231 | *handle = NULL; | ||
232 | else | ||
233 | *handle = node; | ||
234 | return 0; | ||
235 | } | ||
236 | node = gpe_block->node; | ||
237 | gpe_block = gpe_block->next; | ||
238 | } | ||
239 | gpe_xrupt_info = gpe_xrupt_info->next; | ||
240 | } | ||
241 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | ||
242 | |||
243 | return -ENODEV; | ||
244 | } | ||
245 | |||
205 | static void delete_gpe_attr_array(void) | 246 | static void delete_gpe_attr_array(void) |
206 | { | 247 | { |
207 | u32 *tmp = all_counters; | 248 | struct event_counter *tmp = all_counters; |
208 | 249 | ||
209 | all_counters = NULL; | 250 | all_counters = NULL; |
210 | kfree(tmp); | 251 | kfree(tmp); |
@@ -230,9 +271,10 @@ void acpi_os_gpe_count(u32 gpe_number) | |||
230 | return; | 271 | return; |
231 | 272 | ||
232 | if (gpe_number < num_gpes) | 273 | if (gpe_number < num_gpes) |
233 | all_counters[gpe_number]++; | 274 | all_counters[gpe_number].count++; |
234 | else | 275 | else |
235 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++; | 276 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]. |
277 | count++; | ||
236 | 278 | ||
237 | return; | 279 | return; |
238 | } | 280 | } |
@@ -243,44 +285,144 @@ void acpi_os_fixed_event_count(u32 event_number) | |||
243 | return; | 285 | return; |
244 | 286 | ||
245 | if (event_number < ACPI_NUM_FIXED_EVENTS) | 287 | if (event_number < ACPI_NUM_FIXED_EVENTS) |
246 | all_counters[num_gpes + event_number]++; | 288 | all_counters[num_gpes + event_number].count++; |
247 | else | 289 | else |
248 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++; | 290 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]. |
291 | count++; | ||
249 | 292 | ||
250 | return; | 293 | return; |
251 | } | 294 | } |
252 | 295 | ||
296 | static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle) | ||
297 | { | ||
298 | int result = 0; | ||
299 | |||
300 | if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) | ||
301 | goto end; | ||
302 | |||
303 | if (index < num_gpes) { | ||
304 | result = get_gpe_device(index, handle); | ||
305 | if (result) { | ||
306 | ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, | ||
307 | "Invalid GPE 0x%x\n", index)); | ||
308 | goto end; | ||
309 | } | ||
310 | result = acpi_get_gpe_status(*handle, index, | ||
311 | ACPI_NOT_ISR, status); | ||
312 | } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) | ||
313 | result = acpi_get_event_status(index - num_gpes, status); | ||
314 | |||
315 | /* | ||
316 | * sleep/power button GPE/Fixed Event is enabled after acpi_system_init, | ||
317 | * check the status at runtime and mark it as valid once it's enabled | ||
318 | */ | ||
319 | if (!result && (*status & ACPI_EVENT_FLAG_ENABLED)) | ||
320 | all_counters[index].flags |= ACPI_EVENT_VALID; | ||
321 | end: | ||
322 | return result; | ||
323 | } | ||
324 | |||
253 | static ssize_t counter_show(struct kobject *kobj, | 325 | static ssize_t counter_show(struct kobject *kobj, |
254 | struct kobj_attribute *attr, char *buf) | 326 | struct kobj_attribute *attr, char *buf) |
255 | { | 327 | { |
256 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] = | 328 | int index = attr - counter_attrs; |
329 | int size; | ||
330 | acpi_handle handle; | ||
331 | acpi_event_status status; | ||
332 | int result = 0; | ||
333 | |||
334 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count = | ||
257 | acpi_irq_handled; | 335 | acpi_irq_handled; |
258 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] = | 336 | all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count = |
259 | acpi_gpe_count; | 337 | acpi_gpe_count; |
260 | 338 | ||
261 | return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]); | 339 | size = sprintf(buf, "%8d", all_counters[index].count); |
340 | |||
341 | /* "gpe_all" or "sci" */ | ||
342 | if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) | ||
343 | goto end; | ||
344 | |||
345 | result = get_status(index, &status, &handle); | ||
346 | if (result) | ||
347 | goto end; | ||
348 | |||
349 | if (!(all_counters[index].flags & ACPI_EVENT_VALID)) | ||
350 | size += sprintf(buf + size, " invalid"); | ||
351 | else if (status & ACPI_EVENT_FLAG_ENABLED) | ||
352 | size += sprintf(buf + size, " enable"); | ||
353 | else | ||
354 | size += sprintf(buf + size, " disable"); | ||
355 | |||
356 | end: | ||
357 | size += sprintf(buf + size, "\n"); | ||
358 | return result ? result : size; | ||
262 | } | 359 | } |
263 | 360 | ||
264 | /* | 361 | /* |
265 | * counter_set() sets the specified counter. | 362 | * counter_set() sets the specified counter. |
266 | * setting the total "sci" file to any value clears all counters. | 363 | * setting the total "sci" file to any value clears all counters. |
364 | * enable/disable/clear a gpe/fixed event in user space. | ||
267 | */ | 365 | */ |
268 | static ssize_t counter_set(struct kobject *kobj, | 366 | static ssize_t counter_set(struct kobject *kobj, |
269 | struct kobj_attribute *attr, const char *buf, size_t size) | 367 | struct kobj_attribute *attr, const char *buf, size_t size) |
270 | { | 368 | { |
271 | int index = attr - counter_attrs; | 369 | int index = attr - counter_attrs; |
370 | acpi_event_status status; | ||
371 | acpi_handle handle; | ||
372 | int result = 0; | ||
272 | 373 | ||
273 | if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { | 374 | if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { |
274 | int i; | 375 | int i; |
275 | for (i = 0; i < num_counters; ++i) | 376 | for (i = 0; i < num_counters; ++i) |
276 | all_counters[i] = 0; | 377 | all_counters[i].count = 0; |
277 | acpi_gpe_count = 0; | 378 | acpi_gpe_count = 0; |
278 | acpi_irq_handled = 0; | 379 | acpi_irq_handled = 0; |
380 | goto end; | ||
381 | } | ||
279 | 382 | ||
383 | /* show the event status for both GPEs and Fixed Events */ | ||
384 | result = get_status(index, &status, &handle); | ||
385 | if (result) | ||
386 | goto end; | ||
387 | |||
388 | if (!(all_counters[index].flags & ACPI_EVENT_VALID)) { | ||
389 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, | ||
390 | "Can not change Invalid GPE/Fixed Event status\n")); | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | if (index < num_gpes) { | ||
395 | if (!strcmp(buf, "disable\n") && | ||
396 | (status & ACPI_EVENT_FLAG_ENABLED)) | ||
397 | result = acpi_disable_gpe(handle, index, ACPI_NOT_ISR); | ||
398 | else if (!strcmp(buf, "enable\n") && | ||
399 | !(status & ACPI_EVENT_FLAG_ENABLED)) | ||
400 | result = acpi_enable_gpe(handle, index, ACPI_NOT_ISR); | ||
401 | else if (!strcmp(buf, "clear\n") && | ||
402 | (status & ACPI_EVENT_FLAG_SET)) | ||
403 | result = acpi_clear_gpe(handle, index, ACPI_NOT_ISR); | ||
404 | else | ||
405 | all_counters[index].count = strtoul(buf, NULL, 0); | ||
406 | } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) { | ||
407 | int event = index - num_gpes; | ||
408 | if (!strcmp(buf, "disable\n") && | ||
409 | (status & ACPI_EVENT_FLAG_ENABLED)) | ||
410 | result = acpi_disable_event(event, ACPI_NOT_ISR); | ||
411 | else if (!strcmp(buf, "enable\n") && | ||
412 | !(status & ACPI_EVENT_FLAG_ENABLED)) | ||
413 | result = acpi_enable_event(event, ACPI_NOT_ISR); | ||
414 | else if (!strcmp(buf, "clear\n") && | ||
415 | (status & ACPI_EVENT_FLAG_SET)) | ||
416 | result = acpi_clear_event(event); | ||
417 | else | ||
418 | all_counters[index].count = strtoul(buf, NULL, 0); | ||
280 | } else | 419 | } else |
281 | all_counters[index] = strtoul(buf, NULL, 0); | 420 | all_counters[index].count = strtoul(buf, NULL, 0); |
282 | 421 | ||
283 | return size; | 422 | if (ACPI_FAILURE(result)) |
423 | result = -EINVAL; | ||
424 | end: | ||
425 | return result ? result : size; | ||
284 | } | 426 | } |
285 | 427 | ||
286 | void acpi_irq_stats_init(void) | 428 | void acpi_irq_stats_init(void) |
@@ -298,7 +440,8 @@ void acpi_irq_stats_init(void) | |||
298 | if (all_attrs == NULL) | 440 | if (all_attrs == NULL) |
299 | return; | 441 | return; |
300 | 442 | ||
301 | all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL); | 443 | all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), |
444 | GFP_KERNEL); | ||
302 | if (all_counters == NULL) | 445 | if (all_counters == NULL) |
303 | goto fail; | 446 | goto fail; |
304 | 447 | ||