diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-07-18 06:20:23 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-07-18 06:20:23 -0400 |
| commit | cd569ef5d6ff9f43e9504f1ffc7fdbe356518149 (patch) | |
| tree | 9a4ab5e600fd09e991aa1fbb69adb1c7950898a4 /drivers/acpi/system.c | |
| parent | 6879827f4e08da219c99b91e4e1d793a924103e3 (diff) | |
| parent | 5b664cb235e97afbf34db9c4d77f08ebd725335e (diff) | |
Merge branch 'linus' into x86/urgent
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 | ||
