aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/system.c
diff options
context:
space:
mode:
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