aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/system.c
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2008-06-19 21:42:47 -0400
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 17:27:04 -0400
commit71b58cbb0c30d1f78636a48c4721529449d6ea37 (patch)
treeb2271201121c7ecd4d275b19772dcc1e64575712 /drivers/acpi/system.c
parent9c9f6d052dc6f469431461a97d49cf9c5558b8ad (diff)
ACPI: Enhance /sys/firmware/interrupts to allow enable/disable/clear from user-space
Allow users to enable/disable/clear a specific & valid GPE/Fixed Event in user space. This is useful for debugging, especially for some interrupt storm issues. All wakeup GPEs are disabled and they can not be enabled at runtime, and we mark them as invalid. All GPEs that don't have a _Lxx/_Exx method are marked as invalid. All Fixed Events that don't have an event handler are marked as invalid and they can't be enabled until an event handler is registered. Signed-off-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Ling Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com>
Diffstat (limited to 'drivers/acpi/system.c')
-rw-r--r--drivers/acpi/system.c169
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
170static u32 *all_counters; 170#define ACPI_EVENT_VALID 0x01
171struct event_counter {
172 u32 count;
173 u32 flags;
174};
175
176static struct event_counter *all_counters;
171static u32 num_gpes; 177static u32 num_gpes;
172static u32 num_counters; 178static u32 num_counters;
173static struct attribute **all_attrs; 179static struct attribute **all_attrs;
@@ -202,9 +208,44 @@ static int count_num_gpes(void)
202 return count; 208 return count;
203} 209}
204 210
211static 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
205static void delete_gpe_attr_array(void) 246static 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
296static 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;
321end:
322 return result;
323}
324
253static ssize_t counter_show(struct kobject *kobj, 325static 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
356end:
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 */
268static ssize_t counter_set(struct kobject *kobj, 366static 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;
424end:
425 return result ? result : size;
284} 426}
285 427
286void acpi_irq_stats_init(void) 428void 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