aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-acpi127
-rw-r--r--drivers/acpi/events/evxfevnt.c18
-rw-r--r--drivers/acpi/hardware/hwgpe.c2
-rw-r--r--drivers/acpi/system.c169
-rw-r--r--include/acpi/achware.h2
-rw-r--r--include/acpi/acpixf.h4
6 files changed, 258 insertions, 64 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
index 9470ed9afcc0..f27be7d1a49f 100644
--- a/Documentation/ABI/testing/sysfs-firmware-acpi
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -29,46 +29,46 @@ Description:
29 29
30 $ cd /sys/firmware/acpi/interrupts 30 $ cd /sys/firmware/acpi/interrupts
31 $ grep . * 31 $ grep . *
32 error:0 32 error: 0
33 ff_gbl_lock:0 33 ff_gbl_lock: 0 enable
34 ff_pmtimer:0 34 ff_pmtimer: 0 invalid
35 ff_pwr_btn:0 35 ff_pwr_btn: 0 enable
36 ff_rt_clk:0 36 ff_rt_clk: 2 disable
37 ff_slp_btn:0 37 ff_slp_btn: 0 invalid
38 gpe00:0 38 gpe00: 0 invalid
39 gpe01:0 39 gpe01: 0 enable
40 gpe02:0 40 gpe02: 108 enable
41 gpe03:0 41 gpe03: 0 invalid
42 gpe04:0 42 gpe04: 0 invalid
43 gpe05:0 43 gpe05: 0 invalid
44 gpe06:0 44 gpe06: 0 enable
45 gpe07:0 45 gpe07: 0 enable
46 gpe08:0 46 gpe08: 0 invalid
47 gpe09:174 47 gpe09: 0 invalid
48 gpe0A:0 48 gpe0A: 0 invalid
49 gpe0B:0 49 gpe0B: 0 invalid
50 gpe0C:0 50 gpe0C: 0 invalid
51 gpe0D:0 51 gpe0D: 0 invalid
52 gpe0E:0 52 gpe0E: 0 invalid
53 gpe0F:0 53 gpe0F: 0 invalid
54 gpe10:0 54 gpe10: 0 invalid
55 gpe11:60 55 gpe11: 0 invalid
56 gpe12:0 56 gpe12: 0 invalid
57 gpe13:0 57 gpe13: 0 invalid
58 gpe14:0 58 gpe14: 0 invalid
59 gpe15:0 59 gpe15: 0 invalid
60 gpe16:0 60 gpe16: 0 invalid
61 gpe17:0 61 gpe17: 1084 enable
62 gpe18:0 62 gpe18: 0 enable
63 gpe19:7 63 gpe19: 0 invalid
64 gpe1A:0 64 gpe1A: 0 invalid
65 gpe1B:0 65 gpe1B: 0 invalid
66 gpe1C:0 66 gpe1C: 0 invalid
67 gpe1D:0 67 gpe1D: 0 invalid
68 gpe1E:0 68 gpe1E: 0 invalid
69 gpe1F:0 69 gpe1F: 0 invalid
70 gpe_all:241 70 gpe_all: 1192
71 sci:241 71 sci: 1194
72 72
73 sci - The total number of times the ACPI SCI 73 sci - The total number of times the ACPI SCI
74 has claimed an interrupt. 74 has claimed an interrupt.
@@ -89,6 +89,13 @@ Description:
89 89
90 error - an interrupt that can't be accounted for above. 90 error - an interrupt that can't be accounted for above.
91 91
92 invalid: it's either a wakeup GPE or a GPE/Fixed Event that
93 doesn't have an event handler.
94
95 disable: the GPE/Fixed Event is valid but disabled.
96
97 enable: the GPE/Fixed Event is valid and enabled.
98
92 Root has permission to clear any of these counters. Eg. 99 Root has permission to clear any of these counters. Eg.
93 # echo 0 > gpe11 100 # echo 0 > gpe11
94 101
@@ -97,3 +104,43 @@ Description:
97 104
98 None of these counters has an effect on the function 105 None of these counters has an effect on the function
99 of the system, they are simply statistics. 106 of the system, they are simply statistics.
107
108 Besides this, user can also write specific strings to these files
109 to enable/disable/clear ACPI interrupts in user space, which can be
110 used to debug some ACPI interrupt storm issues.
111
112 Note that only writting to VALID GPE/Fixed Event is allowed,
113 i.e. user can only change the status of runtime GPE and
114 Fixed Event with event handler installed.
115
116 Let's take power button fixed event for example, please kill acpid
117 and other user space applications so that the machine won't shutdown
118 when pressing the power button.
119 # cat ff_pwr_btn
120 0
121 # press the power button for 3 times;
122 # cat ff_pwr_btn
123 3
124 # echo disable > ff_pwr_btn
125 # cat ff_pwr_btn
126 disable
127 # press the power button for 3 times;
128 # cat ff_pwr_btn
129 disable
130 # echo enable > ff_pwr_btn
131 # cat ff_pwr_btn
132 4
133 /*
134 * this is because the status bit is set even if the enable bit is cleared,
135 * and it triggers an ACPI fixed event when the enable bit is set again
136 */
137 # press the power button for 3 times;
138 # cat ff_pwr_btn
139 7
140 # echo disable > ff_pwr_btn
141 # press the power button for 3 times;
142 # echo clear > ff_pwr_btn /* clear the status bit */
143 # echo disable > ff_pwr_btn
144 # cat ff_pwr_btn
145 7
146
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 99a7502e6a87..73bfd6bf962f 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -472,7 +472,6 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
472} 472}
473 473
474ACPI_EXPORT_SYMBOL(acpi_clear_gpe) 474ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
475#ifdef ACPI_FUTURE_USAGE
476/******************************************************************************* 475/*******************************************************************************
477 * 476 *
478 * FUNCTION: acpi_get_event_status 477 * FUNCTION: acpi_get_event_status
@@ -489,6 +488,7 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
489acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) 488acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
490{ 489{
491 acpi_status status = AE_OK; 490 acpi_status status = AE_OK;
491 u32 value;
492 492
493 ACPI_FUNCTION_TRACE(acpi_get_event_status); 493 ACPI_FUNCTION_TRACE(acpi_get_event_status);
494 494
@@ -506,7 +506,20 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
506 506
507 status = 507 status =
508 acpi_get_register(acpi_gbl_fixed_event_info[event]. 508 acpi_get_register(acpi_gbl_fixed_event_info[event].
509 status_register_id, event_status); 509 enable_register_id, &value);
510 if (ACPI_FAILURE(status))
511 return_ACPI_STATUS(status);
512
513 *event_status = value;
514
515 status =
516 acpi_get_register(acpi_gbl_fixed_event_info[event].
517 status_register_id, &value);
518 if (ACPI_FAILURE(status))
519 return_ACPI_STATUS(status);
520
521 if (value)
522 *event_status |= ACPI_EVENT_FLAG_SET;
510 523
511 return_ACPI_STATUS(status); 524 return_ACPI_STATUS(status);
512} 525}
@@ -566,7 +579,6 @@ acpi_get_gpe_status(acpi_handle gpe_device,
566} 579}
567 580
568ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) 581ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
569#endif /* ACPI_FUTURE_USAGE */
570/******************************************************************************* 582/*******************************************************************************
571 * 583 *
572 * FUNCTION: acpi_install_gpe_block 584 * FUNCTION: acpi_install_gpe_block
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 58347d6c43f8..0b80db9d9197 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -186,7 +186,6 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
186 * 186 *
187 ******************************************************************************/ 187 ******************************************************************************/
188 188
189#ifdef ACPI_FUTURE_USAGE
190acpi_status 189acpi_status
191acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, 190acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
192 acpi_event_status * event_status) 191 acpi_event_status * event_status)
@@ -246,7 +245,6 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
246 unlock_and_exit: 245 unlock_and_exit:
247 return (status); 246 return (status);
248} 247}
249#endif /* ACPI_FUTURE_USAGE */
250 248
251/****************************************************************************** 249/******************************************************************************
252 * 250 *
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
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index 45e985961f4c..97a72b193276 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -102,11 +102,9 @@ acpi_status
102acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 102acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
103 struct acpi_gpe_block_info *gpe_block); 103 struct acpi_gpe_block_info *gpe_block);
104 104
105#ifdef ACPI_FUTURE_USAGE
106acpi_status 105acpi_status
107acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, 106acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
108 acpi_event_status * event_status); 107 acpi_event_status * event_status);
109#endif /* ACPI_FUTURE_USAGE */
110 108
111acpi_status acpi_hw_disable_all_gpes(void); 109acpi_status acpi_hw_disable_all_gpes(void);
112 110
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index bd95ecc6e0fa..94d94e126e9f 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -248,9 +248,7 @@ acpi_status acpi_disable_event(u32 event, u32 flags);
248 248
249acpi_status acpi_clear_event(u32 event); 249acpi_status acpi_clear_event(u32 event);
250 250
251#ifdef ACPI_FUTURE_USAGE
252acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status); 251acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status);
253#endif /* ACPI_FUTURE_USAGE */
254 252
255acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type); 253acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type);
256 254
@@ -260,12 +258,10 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags);
260 258
261acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags); 259acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags);
262 260
263#ifdef ACPI_FUTURE_USAGE
264acpi_status 261acpi_status
265acpi_get_gpe_status(acpi_handle gpe_device, 262acpi_get_gpe_status(acpi_handle gpe_device,
266 u32 gpe_number, 263 u32 gpe_number,
267 u32 flags, acpi_event_status * event_status); 264 u32 flags, acpi_event_status * event_status);
268#endif /* ACPI_FUTURE_USAGE */
269 265
270acpi_status 266acpi_status
271acpi_install_gpe_block(acpi_handle gpe_device, 267acpi_install_gpe_block(acpi_handle gpe_device,