Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branches 'release' and 'stats' into release

Len Brown e5e54bc8 70ec75c5

+325 -9
+99
Documentation/ABI/testing/sysfs-firmware-acpi
··· 1 + What: /sys/firmware/acpi/interrupts/ 2 + Date: February 2008 3 + Contact: Len Brown <lenb@kernel.org> 4 + Description: 5 + All ACPI interrupts are handled via a single IRQ, 6 + the System Control Interrupt (SCI), which appears 7 + as "acpi" in /proc/interrupts. 8 + 9 + However, one of the main functions of ACPI is to make 10 + the platform understand random hardware without 11 + special driver support. So while the SCI handles a few 12 + well known (fixed feature) interrupts sources, such 13 + as the power button, it can also handle a variable 14 + number of a "General Purpose Events" (GPE). 15 + 16 + A GPE vectors to a specified handler in AML, which 17 + can do a anything the BIOS writer wants from 18 + OS context. GPE 0x12, for example, would vector 19 + to a level or edge handler called _L12 or _E12. 20 + The handler may do its business and return. 21 + Or the handler may send send a Notify event 22 + to a Linux device driver registered on an ACPI device, 23 + such as a battery, or a processor. 24 + 25 + To figure out where all the SCI's are coming from, 26 + /sys/firmware/acpi/interrupts contains a file listing 27 + every possible source, and the count of how many 28 + times it has triggered. 29 + 30 + $ cd /sys/firmware/acpi/interrupts 31 + $ grep . * 32 + error:0 33 + ff_gbl_lock:0 34 + ff_pmtimer:0 35 + ff_pwr_btn:0 36 + ff_rt_clk:0 37 + ff_slp_btn:0 38 + gpe00:0 39 + gpe01:0 40 + gpe02:0 41 + gpe03:0 42 + gpe04:0 43 + gpe05:0 44 + gpe06:0 45 + gpe07:0 46 + gpe08:0 47 + gpe09:174 48 + gpe0A:0 49 + gpe0B:0 50 + gpe0C:0 51 + gpe0D:0 52 + gpe0E:0 53 + gpe0F:0 54 + gpe10:0 55 + gpe11:60 56 + gpe12:0 57 + gpe13:0 58 + gpe14:0 59 + gpe15:0 60 + gpe16:0 61 + gpe17:0 62 + gpe18:0 63 + gpe19:7 64 + gpe1A:0 65 + gpe1B:0 66 + gpe1C:0 67 + gpe1D:0 68 + gpe1E:0 69 + gpe1F:0 70 + gpe_all:241 71 + sci:241 72 + 73 + sci - The total number of times the ACPI SCI 74 + has claimed an interrupt. 75 + 76 + gpe_all - count of SCI caused by GPEs. 77 + 78 + gpeXX - count for individual GPE source 79 + 80 + ff_gbl_lock - Global Lock 81 + 82 + ff_pmtimer - PM Timer 83 + 84 + ff_pwr_btn - Power Button 85 + 86 + ff_rt_clk - Real Time Clock 87 + 88 + ff_slp_btn - Sleep Button 89 + 90 + error - an interrupt that can't be accounted for above. 91 + 92 + Root has permission to clear any of these counters. Eg. 93 + # echo 0 > gpe11 94 + 95 + All counters can be cleared by clearing the total "sci": 96 + # echo 0 > sci 97 + 98 + None of these counters has an effect on the function 99 + of the system, they are simply statistics.
+1 -1
drivers/acpi/events/evevent.c
··· 259 259 enable_bit_mask)) { 260 260 261 261 /* Found an active (signalled) event */ 262 - 262 + acpi_os_fixed_event_count(i); 263 263 int_status |= acpi_ev_fixed_event_dispatch((u32) i); 264 264 } 265 265 }
+1 -1
drivers/acpi/events/evgpe.c
··· 627 627 628 628 ACPI_FUNCTION_TRACE(ev_gpe_dispatch); 629 629 630 - acpi_gpe_count++; 630 + acpi_os_gpe_count(gpe_number); 631 631 632 632 /* 633 633 * If edge-triggered, clear the GPE status bit now. Note that
+11 -1
drivers/acpi/osl.c
··· 337 337 338 338 static irqreturn_t acpi_irq(int irq, void *dev_id) 339 339 { 340 - return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE; 340 + u32 handled; 341 + 342 + handled = (*acpi_irq_handler) (acpi_irq_context); 343 + 344 + if (handled) { 345 + acpi_irq_handled++; 346 + return IRQ_HANDLED; 347 + } else 348 + return IRQ_NONE; 341 349 } 342 350 343 351 acpi_status ··· 353 345 void *context) 354 346 { 355 347 unsigned int irq; 348 + 349 + acpi_irq_stats_init(); 356 350 357 351 /* 358 352 * Ignore the GSI from the core, and use the value in our copy of the
+208
drivers/acpi/system.c
··· 40 40 #define ACPI_SYSTEM_CLASS "system" 41 41 #define ACPI_SYSTEM_DEVICE_NAME "System" 42 42 43 + u32 acpi_irq_handled; 44 + 43 45 /* 44 46 * Make ACPICA version work as module param 45 47 */ ··· 166 164 kobject_uevent(tables_kobj, KOBJ_ADD); 167 165 168 166 return 0; 167 + } 168 + 169 + /* 170 + * Detailed ACPI IRQ counters in /sys/firmware/acpi/interrupts/ 171 + * See Documentation/ABI/testing/sysfs-firmware-acpi 172 + */ 173 + 174 + #define COUNT_GPE 0 175 + #define COUNT_SCI 1 /* acpi_irq_handled */ 176 + #define COUNT_ERROR 2 /* other */ 177 + #define NUM_COUNTERS_EXTRA 3 178 + 179 + static u32 *all_counters; 180 + static u32 num_gpes; 181 + static u32 num_counters; 182 + static struct attribute **all_attrs; 183 + static u32 acpi_gpe_count; 184 + 185 + static struct attribute_group interrupt_stats_attr_group = { 186 + .name = "interrupts", 187 + }; 188 + static struct kobj_attribute *counter_attrs; 189 + 190 + static int count_num_gpes(void) 191 + { 192 + int count = 0; 193 + struct acpi_gpe_xrupt_info *gpe_xrupt_info; 194 + struct acpi_gpe_block_info *gpe_block; 195 + acpi_cpu_flags flags; 196 + 197 + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 198 + 199 + gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; 200 + while (gpe_xrupt_info) { 201 + gpe_block = gpe_xrupt_info->gpe_block_list_head; 202 + while (gpe_block) { 203 + count += gpe_block->register_count * 204 + ACPI_GPE_REGISTER_WIDTH; 205 + gpe_block = gpe_block->next; 206 + } 207 + gpe_xrupt_info = gpe_xrupt_info->next; 208 + } 209 + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 210 + 211 + return count; 212 + } 213 + 214 + static void delete_gpe_attr_array(void) 215 + { 216 + u32 *tmp = all_counters; 217 + 218 + all_counters = NULL; 219 + kfree(tmp); 220 + 221 + if (counter_attrs) { 222 + int i; 223 + 224 + for (i = 0; i < num_gpes; i++) 225 + kfree(counter_attrs[i].attr.name); 226 + 227 + kfree(counter_attrs); 228 + } 229 + kfree(all_attrs); 230 + 231 + return; 232 + } 233 + 234 + void acpi_os_gpe_count(u32 gpe_number) 235 + { 236 + acpi_gpe_count++; 237 + 238 + if (!all_counters) 239 + return; 240 + 241 + if (gpe_number < num_gpes) 242 + all_counters[gpe_number]++; 243 + else 244 + all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++; 245 + 246 + return; 247 + } 248 + 249 + void acpi_os_fixed_event_count(u32 event_number) 250 + { 251 + if (!all_counters) 252 + return; 253 + 254 + if (event_number < ACPI_NUM_FIXED_EVENTS) 255 + all_counters[num_gpes + event_number]++; 256 + else 257 + all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++; 258 + 259 + return; 260 + } 261 + 262 + static ssize_t counter_show(struct kobject *kobj, 263 + struct kobj_attribute *attr, char *buf) 264 + { 265 + all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] = 266 + acpi_irq_handled; 267 + all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] = 268 + acpi_gpe_count; 269 + 270 + return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]); 271 + } 272 + 273 + /* 274 + * counter_set() sets the specified counter. 275 + * setting the total "sci" file to any value clears all counters. 276 + */ 277 + static ssize_t counter_set(struct kobject *kobj, 278 + struct kobj_attribute *attr, const char *buf, size_t size) 279 + { 280 + int index = attr - counter_attrs; 281 + 282 + if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 283 + int i; 284 + for (i = 0; i < num_counters; ++i) 285 + all_counters[i] = 0; 286 + acpi_gpe_count = 0; 287 + acpi_irq_handled = 0; 288 + 289 + } else 290 + all_counters[index] = strtoul(buf, NULL, 0); 291 + 292 + return size; 293 + } 294 + 295 + void acpi_irq_stats_init(void) 296 + { 297 + int i; 298 + 299 + if (all_counters) 300 + return; 301 + 302 + num_gpes = count_num_gpes(); 303 + num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; 304 + 305 + all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), 306 + GFP_KERNEL); 307 + if (all_attrs == NULL) 308 + return; 309 + 310 + all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL); 311 + if (all_counters == NULL) 312 + goto fail; 313 + 314 + counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), 315 + GFP_KERNEL); 316 + if (counter_attrs == NULL) 317 + goto fail; 318 + 319 + for (i = 0; i < num_counters; ++i) { 320 + char buffer[10]; 321 + char *name; 322 + 323 + if (i < num_gpes) 324 + sprintf(buffer, "gpe%02X", i); 325 + else if (i == num_gpes + ACPI_EVENT_PMTIMER) 326 + sprintf(buffer, "ff_pmtimer"); 327 + else if (i == num_gpes + ACPI_EVENT_GLOBAL) 328 + sprintf(buffer, "ff_gbl_lock"); 329 + else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON) 330 + sprintf(buffer, "ff_pwr_btn"); 331 + else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON) 332 + sprintf(buffer, "ff_slp_btn"); 333 + else if (i == num_gpes + ACPI_EVENT_RTC) 334 + sprintf(buffer, "ff_rt_clk"); 335 + else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE) 336 + sprintf(buffer, "gpe_all"); 337 + else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) 338 + sprintf(buffer, "sci"); 339 + else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR) 340 + sprintf(buffer, "error"); 341 + else 342 + sprintf(buffer, "bug%02X", i); 343 + 344 + name = kzalloc(strlen(buffer) + 1, GFP_KERNEL); 345 + if (name == NULL) 346 + goto fail; 347 + strncpy(name, buffer, strlen(buffer) + 1); 348 + 349 + counter_attrs[i].attr.name = name; 350 + counter_attrs[i].attr.mode = 0644; 351 + counter_attrs[i].show = counter_show; 352 + counter_attrs[i].store = counter_set; 353 + 354 + all_attrs[i] = &counter_attrs[i].attr; 355 + } 356 + 357 + interrupt_stats_attr_group.attrs = all_attrs; 358 + sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group); 359 + return; 360 + 361 + fail: 362 + delete_gpe_attr_array(); 363 + return; 364 + } 365 + 366 + static void __exit interrupt_stats_exit(void) 367 + { 368 + sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group); 369 + 370 + delete_gpe_attr_array(); 371 + 372 + return; 169 373 } 170 374 171 375 /* --------------------------------------------------------------------------
-2
drivers/acpi/utilities/utglobal.c
··· 671 671 672 672 /* GPE support */ 673 673 674 - acpi_gpe_count = 0; 675 674 acpi_gbl_gpe_xrupt_list_head = NULL; 676 675 acpi_gbl_gpe_fadt_blocks[0] = NULL; 677 676 acpi_gbl_gpe_fadt_blocks[1] = NULL; ··· 734 735 735 736 ACPI_EXPORT_SYMBOL(acpi_dbg_level) 736 737 ACPI_EXPORT_SYMBOL(acpi_dbg_layer) 737 - ACPI_EXPORT_SYMBOL(acpi_gpe_count)
-4
include/acpi/acglobal.h
··· 117 117 118 118 extern u32 acpi_gbl_nesting_level; 119 119 120 - /* Event counters */ 121 - 122 - ACPI_EXTERN u32 acpi_gpe_count; 123 - 124 120 /* Support for dynamic control method tracing mechanism */ 125 121 126 122 ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
+3
include/acpi/acpiosxf.h
··· 181 181 acpi_status 182 182 acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine); 183 183 184 + void acpi_os_gpe_count(u32 gpe_number); 185 + void acpi_os_fixed_event_count(u32 fixed_event_number); 186 + 184 187 /* 185 188 * Threads and Scheduling 186 189 */
+2
include/linux/acpi.h
··· 114 114 115 115 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); 116 116 int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); 117 + void acpi_irq_stats_init(void); 117 118 119 + extern u32 acpi_irq_handled; 118 120 extern int acpi_mp_config; 119 121 120 122 extern struct acpi_mcfg_allocation *pci_mmcfg_config;