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.c184
1 files changed, 158 insertions, 26 deletions
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 769f24855eb6..d8e3f153b295 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -77,7 +77,6 @@ static ssize_t acpi_table_show(struct kobject *kobj,
77 container_of(bin_attr, struct acpi_table_attr, attr); 77 container_of(bin_attr, struct acpi_table_attr, attr);
78 struct acpi_table_header *table_header = NULL; 78 struct acpi_table_header *table_header = NULL;
79 acpi_status status; 79 acpi_status status;
80 ssize_t ret_count = count;
81 80
82 status = 81 status =
83 acpi_get_table(table_attr->name, table_attr->instance, 82 acpi_get_table(table_attr->name, table_attr->instance,
@@ -85,18 +84,8 @@ static ssize_t acpi_table_show(struct kobject *kobj,
85 if (ACPI_FAILURE(status)) 84 if (ACPI_FAILURE(status))
86 return -ENODEV; 85 return -ENODEV;
87 86
88 if (offset >= table_header->length) { 87 return memory_read_from_buffer(buf, count, &offset,
89 ret_count = 0; 88 table_header, table_header->length);
90 goto end;
91 }
92
93 if (offset + ret_count > table_header->length)
94 ret_count = table_header->length - offset;
95
96 memcpy(buf, ((char *)table_header) + offset, ret_count);
97
98 end:
99 return ret_count;
100} 89}
101 90
102static void acpi_table_attr_init(struct acpi_table_attr *table_attr, 91static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
@@ -178,7 +167,13 @@ static int acpi_system_sysfs_init(void)
178#define COUNT_ERROR 2 /* other */ 167#define COUNT_ERROR 2 /* other */
179#define NUM_COUNTERS_EXTRA 3 168#define NUM_COUNTERS_EXTRA 3
180 169
181static 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;
182static u32 num_gpes; 177static u32 num_gpes;
183static u32 num_counters; 178static u32 num_counters;
184static struct attribute **all_attrs; 179static struct attribute **all_attrs;
@@ -213,9 +208,44 @@ static int count_num_gpes(void)
213 return count; 208 return count;
214} 209}
215 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
216static void delete_gpe_attr_array(void) 246static void delete_gpe_attr_array(void)
217{ 247{
218 u32 *tmp = all_counters; 248 struct event_counter *tmp = all_counters;
219 249
220 all_counters = NULL; 250 all_counters = NULL;
221 kfree(tmp); 251 kfree(tmp);
@@ -241,9 +271,10 @@ void acpi_os_gpe_count(u32 gpe_number)
241 return; 271 return;
242 272
243 if (gpe_number < num_gpes) 273 if (gpe_number < num_gpes)
244 all_counters[gpe_number]++; 274 all_counters[gpe_number].count++;
245 else 275 else
246 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++; 276 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR].
277 count++;
247 278
248 return; 279 return;
249} 280}
@@ -254,44 +285,144 @@ void acpi_os_fixed_event_count(u32 event_number)
254 return; 285 return;
255 286
256 if (event_number < ACPI_NUM_FIXED_EVENTS) 287 if (event_number < ACPI_NUM_FIXED_EVENTS)
257 all_counters[num_gpes + event_number]++; 288 all_counters[num_gpes + event_number].count++;
258 else 289 else
259 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++; 290 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR].
291 count++;
260 292
261 return; 293 return;
262} 294}
263 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
264static ssize_t counter_show(struct kobject *kobj, 325static ssize_t counter_show(struct kobject *kobj,
265 struct kobj_attribute *attr, char *buf) 326 struct kobj_attribute *attr, char *buf)
266{ 327{
267 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 =
268 acpi_irq_handled; 335 acpi_irq_handled;
269 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] = 336 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count =
270 acpi_gpe_count; 337 acpi_gpe_count;
271 338
272 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;
273} 359}
274 360
275/* 361/*
276 * counter_set() sets the specified counter. 362 * counter_set() sets the specified counter.
277 * 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.
278 */ 365 */
279static ssize_t counter_set(struct kobject *kobj, 366static ssize_t counter_set(struct kobject *kobj,
280 struct kobj_attribute *attr, const char *buf, size_t size) 367 struct kobj_attribute *attr, const char *buf, size_t size)
281{ 368{
282 int index = attr - counter_attrs; 369 int index = attr - counter_attrs;
370 acpi_event_status status;
371 acpi_handle handle;
372 int result = 0;
283 373
284 if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 374 if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
285 int i; 375 int i;
286 for (i = 0; i < num_counters; ++i) 376 for (i = 0; i < num_counters; ++i)
287 all_counters[i] = 0; 377 all_counters[i].count = 0;
288 acpi_gpe_count = 0; 378 acpi_gpe_count = 0;
289 acpi_irq_handled = 0; 379 acpi_irq_handled = 0;
380 goto end;
381 }
290 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);
291 } else 419 } else
292 all_counters[index] = strtoul(buf, NULL, 0); 420 all_counters[index].count = strtoul(buf, NULL, 0);
293 421
294 return size; 422 if (ACPI_FAILURE(result))
423 result = -EINVAL;
424end:
425 return result ? result : size;
295} 426}
296 427
297void acpi_irq_stats_init(void) 428void acpi_irq_stats_init(void)
@@ -309,7 +440,8 @@ void acpi_irq_stats_init(void)
309 if (all_attrs == NULL) 440 if (all_attrs == NULL)
310 return; 441 return;
311 442
312 all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL); 443 all_counters = kzalloc(sizeof(struct event_counter) * (num_counters),
444 GFP_KERNEL);
313 if (all_counters == NULL) 445 if (all_counters == NULL)
314 goto fail; 446 goto fail;
315 447