Hello, Dave Re-posting two patches as attachments. Very sorry for incorrectly changing the behaviour of the original "irq" command in the last patches. Thanks, Zhang Yanfei
>From f24d14c1819e1d2b28290e86e0085c0143665e28 Mon Sep 17 00:00:00 2001 From: zhangyanfei <zhangyanfei@xxxxxxxxxxxxxx> Date: Wed, 18 Jan 2012 10:55:05 +0800 Subject: [PATCH 1/2] Add -s option for irq to dump the cpu affinity of in-use IRQS in x86 and x86_64. Rewrite functions get_irq_desc_addr and generic_dump_irqs to reduce redundancy. Signed-off-by: zhangyanfei <zhangyanfei@xxxxxxxxxxxxxx> --- defs.h | 8 ++ help.c | 40 ++++++++++- kernel.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- x86.c | 3 + x86_64.c | 17 +++++ 5 files changed, 246 insertions(+), 55 deletions(-) diff --git a/defs.h b/defs.h index 381e8c2..d0c609c 100755 --- a/defs.h +++ b/defs.h @@ -814,6 +814,7 @@ struct machdep_table { int (*kvtop)(struct task_context *, ulong, physaddr_t *, int); ulong (*get_task_pgd)(ulong); void (*dump_irq)(int); + void (*get_irq_affinity)(int); void (*get_stack_frame)(struct bt_info *, ulong *, ulong *); ulong (*get_stackbase)(ulong); ulong (*get_stacktop)(ulong); @@ -1184,11 +1185,14 @@ struct offset_table { /* stash of commonly-used offsets */ long block_device_bd_inode; long block_device_bd_list; long block_device_bd_disk; + long irq_desc_t_irq_data; long irq_desc_t_status; long irq_desc_t_handler; long irq_desc_t_chip; long irq_desc_t_action; long irq_desc_t_depth; + long irq_desc_t_affinity; + long irq_data_affinity; long irqdesc_action; long irqdesc_ctl; long irqdesc_level; @@ -3023,6 +3027,9 @@ struct efi_memory_desc_t { #define BITS_PER_BYTE (8) #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define NUM_TO_BIT(x) (1UL<<((x)%BITS_PER_LONG)) +#define NUM_IN_BITMAP(bitmap, x) (bitmap[(x)/BITS_PER_LONG] & NUM_TO_BIT(x)) +#define SET_BIT(bitmap, x) (bitmap[(x)/BITS_PER_LONG] |= NUM_TO_BIT(x)) /* * precision lengths for fprintf @@ -4045,6 +4052,7 @@ void unlink_module(struct load_module *); int check_specified_module_tree(char *, char *); int is_system_call(char *, ulong); void generic_dump_irq(int); +void generic_get_irq_affinity(int); int generic_dis_filter(ulong, char *, unsigned int); int kernel_BUG_encoding_bytes(void); void display_sys_stats(void); diff --git a/help.c b/help.c index bb552d9..e37c6e0 100755 --- a/help.c +++ b/help.c @@ -2460,19 +2460,21 @@ NULL char *help_irq[] = { "irq", "IRQ data", -"[[[index ...] | -u] | -d | -b]", +"[[[index ...] | -u] | -d | -b | -s]", " This command collaborates the data in an irq_desc_t, along with its", " associated hw_interrupt_type and irqaction structure data, into a", " consolidated per-IRQ display. For kernel versions 2.6.37 and later", " the display consists of the irq_desc/irq_data address, its irqaction", " address(es), and the irqaction name strings. Alternatively, the", " intel interrupt descriptor table may be dumped, or bottom half data", -" may be displayed. If no index value argument(s) nor any options are", -" entered, the IRQ data for all IRQs will be displayed.\n", +" may be displayed, or cpu affinity for in-use irqs may be displayed.", +" If no index value argument(s) nor any options are entered, the", +" IRQ data for all IRQs will be displayed.\n", " index a valid IRQ index.", " -u dump data for in-use IRQs only.", " -d dump the intel interrupt descriptor table.", " -b dump bottom half data.", +" -s dump cpu affinity for in-use IRQs.", "\nEXAMPLES", " Display the relevant data for IRQ 18 from a pre-2.6.37 kernel:\n", " %s> irq 18", @@ -2550,7 +2552,37 @@ char *help_irq[] = { " [6] ffffffff81069090 <tasklet_action> ", " [7] ffffffff81058830 <run_rebalance_domains> ", " [8] ffffffff81087f00 <run_hrtimer_softirq> ", -" [9] ffffffff810ca7a0 <rcu_process_callbacks> ", +" [9] ffffffff810ca7a0 <rcu_process_callbacks> \n", +" Display the cpu affinity for in-use IRQs:\n", +" %s> irq -s", +" IRQ NAME AFFINITY", +" 0 timer 0-23", +" 1 i8042 0-23", +" 8 rtc0 0-23", +" 9 acpi 0-23", +" 16 ehci_hcd:usb2,uhci_hcd:usb3,uhci_hcd:usb6 0,6,18", +" 17 uhci_hcd:usb4,uhci_hcd:usb7 0-23", +" 18 ehci_hcd:usb1,uhci_hcd:usb5,uhci_hcd:usb8,ioc0 0,11,23", +" 24 dmar0 0", +" 35 pciehp 0-23", +" 36 pciehp 0-23", +" 37 pciehp 0-23", +" 38 pciehp 0-23", +" 39 megasas 0-5,12-17", +" 40 lpfc:sp 0-5,12-17", +" 41 lpfc:fp 0,6-11,18-23", +" 42 lpfc:sp 0,6-11,18-23", +" 43 lpfc:fp 0,6-11,18-23", +" ...\n", +" 80 ioat-msix 0-23", +" 81 ioat-msix 0-23", +" 82 ioat-msix 0-23", +" 83 ioat-msix 0-23", +" 84 ioat-msix 0-23", +" 85 ioat-msix 0-23", +" 86 ioat-msix 0-23", +" 87 ioat-msix 0-23", +" 88 eth4 0,17", NULL }; diff --git a/kernel.c b/kernel.c index 2375911..0a93f8a 100755 --- a/kernel.c +++ b/kernel.c @@ -27,6 +27,7 @@ static void get_lkcd_regs(struct bt_info *, ulong *, ulong *); static void dump_sys_call_table(char *, int); static int get_NR_syscalls(int *); static ulong get_irq_desc_addr(int); +static void display_cpu_affinity(ulong *); static void display_bh_1(void); static void display_bh_2(void); static void display_bh_3(void); @@ -346,6 +347,10 @@ kernel_init() irq_desc_type_name = "irq_desc"; STRUCT_SIZE_INIT(irq_desc_t, irq_desc_type_name); + if (MEMBER_EXISTS(irq_desc_type_name, "irq_data")) + MEMBER_OFFSET_INIT(irq_desc_t_irq_data, irq_desc_type_name, "irq_data"); + else + MEMBER_OFFSET_INIT(irq_desc_t_affinity, irq_desc_type_name, "affinity"); MEMBER_OFFSET_INIT(irq_desc_t_status, irq_desc_type_name, "status"); if (MEMBER_EXISTS(irq_desc_type_name, "handler")) MEMBER_OFFSET_INIT(irq_desc_t_handler, irq_desc_type_name, "handler"); @@ -417,6 +422,8 @@ kernel_init() if (kernel_symbol_exists("irq_desc_tree")) kt->flags |= IRQ_DESC_TREE; STRUCT_SIZE_INIT(irq_data, "irq_data"); + if (VALID_STRUCT(irq_data)) + MEMBER_OFFSET_INIT(irq_data_affinity, "irq_data", "affinity"); STRUCT_SIZE_INIT(irq_cpustat_t, "irq_cpustat_t"); MEMBER_OFFSET_INIT(irq_cpustat_t___softirq_active, @@ -4707,7 +4714,7 @@ cmd_irq(void) int i, c; int nr_irqs; - while ((c = getopt(argcnt, args, "dbu")) != EOF) { + while ((c = getopt(argcnt, args, "dbus")) != EOF) { switch(c) { case 'd': @@ -4754,7 +4761,20 @@ cmd_irq(void) "irq: -u option ignored: \"no_irq_chip\" or \"no_irq_type\" symbols do not exist\n"); break; - default: + case 's': + if (!(machine_type("X86") || machine_type("X86_64"))) + command_not_supported(); + + if ((nr_irqs = machdep->nr_irqs) == 0) + error(FATAL, "cannot determine number of IRQs\n"); + + fprintf(fp, "IRQ NAME AFFINITY\n"); + for (i = 0; i < nr_irqs; i++) + machdep->get_irq_affinity(i); + + return; + + default: argerrs++; break; } @@ -4791,34 +4811,100 @@ static ulong get_irq_desc_addr(int irq) { int c; - ulong cnt, addr; + ulong cnt, addr, ptr; + long len; struct radix_tree_pair *rtp; addr = 0; + rtp = NULL; - if (kt->highest_irq && (irq > kt->highest_irq)) - return addr; + if (!VALID_STRUCT(irq_desc_t)) + error(FATAL, "cannot determine size of irq_desc_t\n"); + len = SIZE(irq_desc_t); - cnt = do_radix_tree(symbol_value("irq_desc_tree"), RADIX_TREE_COUNT, NULL); - rtp = (struct radix_tree_pair *)GETBUF(sizeof(struct radix_tree_pair) * (cnt+1)); - rtp[0].index = cnt; - cnt = do_radix_tree(symbol_value("irq_desc_tree"), RADIX_TREE_GATHER, rtp); + if (symbol_exists("irq_desc")) + addr = symbol_value("irq_desc") + (len * irq); + else if (symbol_exists("_irq_desc")) + addr = symbol_value("_irq_desc") + (len * irq); + else if (symbol_exists("irq_desc_ptrs")) { + if (get_symbol_type("irq_desc_ptrs", NULL, NULL) == TYPE_CODE_PTR) + get_symbol_data("irq_desc_ptrs", sizeof(void *), &ptr); + else + ptr = symbol_value("irq_desc_ptrs"); + ptr += (irq * sizeof(void *)); + readmem(ptr, KVADDR, &addr, + sizeof(void *), "irq_desc_ptrs entry", + FAULT_ON_ERROR); + } else if (kt->flags & IRQ_DESC_TREE) { + if (kt->highest_irq && (irq > kt->highest_irq)) + return addr; + + cnt = do_radix_tree(symbol_value("irq_desc_tree"), + RADIX_TREE_COUNT, NULL); + len = sizeof(struct radix_tree_pair) * (cnt+1); + rtp = (struct radix_tree_pair *)GETBUF(len); + rtp[0].index = cnt; + cnt = do_radix_tree(symbol_value("irq_desc_tree"), + RADIX_TREE_GATHER, rtp); + + if (kt->highest_irq == 0) + kt->highest_irq = rtp[cnt-1].index; + + for (c = 0; c < cnt; c++) { + if (rtp[c].index == irq) { + if (CRASHDEBUG(1)) + fprintf(fp, "index: %ld value: %lx\n", + rtp[c].index, (ulong)rtp[c].value); + addr = (ulong)rtp[c].value; + break; + } + } - if (kt->highest_irq == 0) - kt->highest_irq = rtp[cnt-1].index; + FREEBUF(rtp); + } else { + error(FATAL, + "neither irq_desc, _irq_desc, irq_desc_ptrs " + "or irq_desc_tree symbols exist\n"); + } - for (c = 0; c < cnt; c++) { - if (rtp[c].index == irq) { - if (CRASHDEBUG(1)) - fprintf(fp, "index: %ld value: %lx\n", - rtp[c].index, (ulong)rtp[c].value); - addr = (ulong)rtp[c].value; - break; + return addr; +} + +static void +display_cpu_affinity(ulong *mask) +{ + int cpu, seq, start, count; + + seq = FALSE; + start = 0; + count = 0; + + for (cpu = 0; cpu < kt->cpus; ++cpu) { + if (NUM_IN_BITMAP(mask, cpu)) { + if (seq) + continue; + start = cpu; + seq = TRUE; + } else if (seq) { + if (count) + fprintf(fp, ","); + if (start == cpu - 1) + fprintf(fp, "%d", cpu - 1); + else + fprintf(fp, "%d-%d", start, cpu - 1); + count++; + seq = FALSE; } } - FREEBUF(rtp); - return addr; + if (seq) { + if (count) + fprintf(fp, ","); + if (start == kt->cpus - 1) + fprintf(fp, "%d", kt->cpus - 1); + else + fprintf(fp, "%d-%d", start, kt->cpus - 1); + } } /* @@ -4828,8 +4914,6 @@ void generic_dump_irq(int irq) { ulong irq_desc_addr; - ulong irq_desc_ptr; - long len; char buf[BUFSIZE]; char buf1[BUFSIZE]; char buf2[BUFSIZE]; @@ -4840,35 +4924,11 @@ generic_dump_irq(int irq) handler = UNINITIALIZED; - if (!VALID_STRUCT(irq_desc_t)) - error(FATAL, "cannot determine size of irq_desc_t\n"); - len = SIZE(irq_desc_t); - - if (symbol_exists("irq_desc")) - irq_desc_addr = symbol_value("irq_desc") + (len * irq); - else if (symbol_exists("_irq_desc")) - irq_desc_addr = symbol_value("_irq_desc") + (len * irq); - else if (symbol_exists("irq_desc_ptrs")) { - if (get_symbol_type("irq_desc_ptrs", NULL, NULL) == TYPE_CODE_PTR) - get_symbol_data("irq_desc_ptrs", sizeof(void *), &irq_desc_ptr); - else - irq_desc_ptr = symbol_value("irq_desc_ptrs"); - irq_desc_ptr += (irq * sizeof(void *)); - readmem(irq_desc_ptr, KVADDR, &irq_desc_addr, - sizeof(void *), "irq_desc_ptrs entry", - FAULT_ON_ERROR); - if (!irq_desc_addr) { - if (!(pc->curcmd_flags & IRQ_IN_USE)) - fprintf(fp, " IRQ: %d (unused)\n\n", irq); - return; - } - } else if (kt->flags & IRQ_DESC_TREE) { - irq_desc_addr = get_irq_desc_addr(irq); - } else { - irq_desc_addr = 0; - error(FATAL, - "neither irq_desc, _irq_desc, irq_desc_ptrs " - "or irq_desc_tree symbols exist\n"); + irq_desc_addr = get_irq_desc_addr(irq); + if (!irq_desc_addr && symbol_exists("irq_desc_ptrs")) { + if (!(pc->curcmd_flags & IRQ_IN_USE)) + fprintf(fp, " IRQ: %d (unused)\n\n", irq); + return; } if (irq_desc_addr) { @@ -5362,6 +5422,77 @@ do_linked_action_v2: fprintf(fp, "\n"); } +void +generic_get_irq_affinity(int irq) +{ + ulong irq_desc_addr; + long len; + ulong affinity_ptr; + ulong *affinity; + ulong tmp_addr; + ulong action, name; + char buf[BUFSIZE]; + char name_buf[BUFSIZE]; + + affinity = NULL; + + irq_desc_addr = get_irq_desc_addr(irq); + if (!irq_desc_addr) + return; + + readmem(irq_desc_addr + OFFSET(irq_desc_t_action), KVADDR, + &action, sizeof(long), "irq_desc action", FAULT_ON_ERROR); + + if (!action) + return; + + if ((len = STRUCT_SIZE("cpumask_t")) < 0) + len = DIV_ROUND_UP(kt->cpus, BITS_PER_LONG) * sizeof(ulong); + + affinity = (ulong *)GETBUF(len); + if (VALID_STRUCT(irq_data)) + tmp_addr = irq_desc_addr + \ + OFFSET(irq_data_affinity); + else + tmp_addr = irq_desc_addr + \ + OFFSET(irq_desc_t_affinity); + + if (symbol_exists("alloc_cpumask_var")) /* pointer member */ + readmem(tmp_addr,KVADDR, &affinity_ptr, sizeof(ulong), + "irq_desc affinity", FAULT_ON_ERROR); + else /* array member */ + affinity_ptr = tmp_addr; + + readmem(affinity_ptr, KVADDR, affinity, len, + "irq_desc affinity", FAULT_ON_ERROR); + + fprintf(fp, "%3d ", irq); + + BZERO(name_buf, BUFSIZE); + + while (action) { + readmem(action+OFFSET(irqaction_name), KVADDR, + &name, sizeof(void *), + "irqaction name", FAULT_ON_ERROR); + BZERO(buf, BUFSIZE); + if (read_string(name, buf, BUFSIZE-1)) { + if (strlen(name_buf) != 0) + strncat(name_buf, ",", 2); + strncat(name_buf, buf, strlen(buf)); + } + + readmem(action+OFFSET(irqaction_next), KVADDR, + &action, sizeof(void *), + "irqaction dev_id", FAULT_ON_ERROR); + } + + fprintf(fp, "%-20s ", name_buf); + display_cpu_affinity(affinity); + fprintf(fp, "\n"); + + FREEBUF(affinity); +} + /* * Dump the earlier 2.2 Linux version's bottom-half essentials. */ diff --git a/x86.c b/x86.c index df91110..da5e5ba 100755 --- a/x86.c +++ b/x86.c @@ -1801,6 +1801,7 @@ x86_init(int when) machdep->processor_speed = x86_processor_speed; machdep->get_task_pgd = x86_get_task_pgd; machdep->dump_irq = generic_dump_irq; + machdep->get_irq_affinity = generic_get_irq_affinity; machdep->get_stack_frame = x86_get_stack_frame; machdep->get_stackbase = generic_get_stackbase; machdep->get_stacktop = generic_get_stacktop; @@ -3403,6 +3404,7 @@ x86_dump_machdep_table(ulong arg) } fprintf(fp, " get_task_pgd: x86_get_task_pgd()\n"); fprintf(fp, " dump_irq: generic_dump_irq()\n"); + fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n"); fprintf(fp, " get_stack_frame: x86_get_stack_frame()\n"); fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); @@ -5340,6 +5342,7 @@ x86_init_hyper(int when) machdep->back_trace = x86_back_trace_cmd; machdep->processor_speed = x86_processor_speed; /* ODA: check */ machdep->dump_irq = generic_dump_irq; /* ODA: check */ + machdep->get_irq_affinity = generic_get_irq_affinity; machdep->get_stack_frame = x86_get_stack_frame_hyper; machdep->get_stackbase = x86_get_stackbase_hyper; machdep->get_stacktop = x86_get_stacktop_hyper; diff --git a/x86_64.c b/x86_64.c index e0b62c9..536f256 100755 --- a/x86_64.c +++ b/x86_64.c @@ -56,6 +56,7 @@ static int x86_64_print_stack_entry(struct bt_info *, FILE *, int, int, ulong); static void x86_64_display_full_frame(struct bt_info *, ulong, FILE *); static void x86_64_do_bt_reference_check(struct bt_info *, ulong,char *); static void x86_64_dump_irq(int); +static void x86_64_get_irq_affinity(int); static char *x86_64_extract_idt_function(ulong *, char *, ulong *); static ulong x86_64_get_pc(struct bt_info *); static ulong x86_64_get_sp(struct bt_info *); @@ -471,6 +472,7 @@ x86_64_init(int when) else machdep->nr_irqs = 224; /* NR_IRQS (at least) */ machdep->dump_irq = x86_64_dump_irq; + machdep->get_irq_affinity = x86_64_get_irq_affinity; if (!machdep->hz) { machdep->hz = HZ; if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) @@ -631,6 +633,7 @@ x86_64_dump_machdep_table(ulong arg) fprintf(fp, "\n"); fprintf(fp, " get_task_pgd: x86_64_get_task_pgd()\n"); fprintf(fp, " dump_irq: x86_64_dump_irq()\n"); + fprintf(fp, " get_irq_affinity: x86_64_get_irq_affinity()\n"); fprintf(fp, " get_stack_frame: x86_64_get_stack_frame()\n"); fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); @@ -4536,6 +4539,20 @@ x86_64_dump_irq(int irq) "x86_64_dump_irq: irq_desc[] or irq_desc_tree do not exist?\n"); } +static void +x86_64_get_irq_affinity(int irq) +{ + if (symbol_exists("irq_desc") || + kernel_symbol_exists("irq_desc_ptrs") || + kernel_symbol_exists("irq_desc_tree")) { + machdep->get_irq_affinity = generic_get_irq_affinity; + return(generic_get_irq_affinity(irq)); + } + + error(FATAL, + "x86_64_get_irq_affinity: irq_desc[] or irq_desc_tree do not exist?\n"); +} + /* * Do the work for irq -d */ -- 1.7.1
>From 9b24c169134b72b642d5c9bc524108e37f7a9743 Mon Sep 17 00:00:00 2001 From: zhangyanfei <zhangyanfei@xxxxxxxxxxxxxx> Date: Wed, 18 Jan 2012 10:57:22 +0800 Subject: [PATCH 2/2] Add -S and -c option for irq to dump the kernel irq stats in x86 and x86_64. Signed-off-by: zhangyanfei <zhangyanfei@xxxxxxxxxxxxxx> --- defs.h | 7 ++ help.c | 30 +++++++-- kernel.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- tools.c | 48 +++++++++++++++ x86.c | 3 + x86_64.c | 17 +++++ 6 files changed, 299 insertions(+), 9 deletions(-) diff --git a/defs.h b/defs.h index d0c609c..a45af1f 100755 --- a/defs.h +++ b/defs.h @@ -815,6 +815,7 @@ struct machdep_table { ulong (*get_task_pgd)(ulong); void (*dump_irq)(int); void (*get_irq_affinity)(int); + void (*show_interrupts)(int, ulong *); void (*get_stack_frame)(struct bt_info *, ulong *, ulong *); ulong (*get_stackbase)(ulong); ulong (*get_stacktop)(ulong); @@ -1186,13 +1187,16 @@ struct offset_table { /* stash of commonly-used offsets */ long block_device_bd_list; long block_device_bd_disk; long irq_desc_t_irq_data; + long irq_desc_t_kstat_irqs; long irq_desc_t_status; long irq_desc_t_handler; long irq_desc_t_chip; long irq_desc_t_action; long irq_desc_t_depth; long irq_desc_t_affinity; + long irq_data_chip; long irq_data_affinity; + long kernel_stat_irqs; long irqdesc_action; long irqdesc_ctl; long irqdesc_level; @@ -1684,6 +1688,7 @@ struct size_table { /* stash of commonly-used sizes */ long resource; long runqueue; long irq_desc_t; + long kernel_stat; long task_union; long thread_union; long prio_array; @@ -3665,6 +3670,7 @@ int calculate(char *, ulong *, ulonglong *, ulong); int endian_mismatch(char *, char, ulong); uint16_t swap16(uint16_t, int); uint32_t swap32(uint32_t, int); +int make_cpumask(char *, ulong *, int, int *); /* * symbols.c @@ -4053,6 +4059,7 @@ int check_specified_module_tree(char *, char *); int is_system_call(char *, ulong); void generic_dump_irq(int); void generic_get_irq_affinity(int); +void generic_show_interrupts(int, ulong *); int generic_dis_filter(ulong, char *, unsigned int); int kernel_BUG_encoding_bytes(void); void display_sys_stats(void); diff --git a/help.c b/help.c index e37c6e0..9ed2057 100755 --- a/help.c +++ b/help.c @@ -2460,21 +2460,26 @@ NULL char *help_irq[] = { "irq", "IRQ data", -"[[[index ...] | -u] | -d | -b | -s]", +"[[[index ...] | -u | -c cpu ] | -d | -b | -s | -S]", " This command collaborates the data in an irq_desc_t, along with its", " associated hw_interrupt_type and irqaction structure data, into a", " consolidated per-IRQ display. For kernel versions 2.6.37 and later", " the display consists of the irq_desc/irq_data address, its irqaction", " address(es), and the irqaction name strings. Alternatively, the", " intel interrupt descriptor table may be dumped, or bottom half data", -" may be displayed, or cpu affinity for in-use irqs may be displayed.", -" If no index value argument(s) nor any options are entered, the", -" IRQ data for all IRQs will be displayed.\n", +" may be displayed, or cpu affinity for in-use irqs may be displayed,", +" or the kernel irq stats may be displayed. If no index value argument(s)", +" nor any options are entered, the IRQ data for all IRQs will be displayed.\n", " index a valid IRQ index.", -" -u dump data for in-use IRQs only.", +" -u dump data for in-use IRQs only.", +" -c cpu only dump the irq stats of the specified cpu. This option must", +" be specified with -S option. cpu can be specified as \"1,3,5\",", +" \"1-3\", or \"1,3,5-7,10\".", " -d dump the intel interrupt descriptor table.", " -b dump bottom half data.", " -s dump cpu affinity for in-use IRQs.", +" -S dump the kernel irq stats. If no cpu specified, the irq stats", +" of all cpus will be displayed.", "\nEXAMPLES", " Display the relevant data for IRQ 18 from a pre-2.6.37 kernel:\n", " %s> irq 18", @@ -2582,7 +2587,20 @@ char *help_irq[] = { " 85 ioat-msix 0-23", " 86 ioat-msix 0-23", " 87 ioat-msix 0-23", -" 88 eth4 0,17", +" 88 eth4 0,17\n", +" Display the kernel irq stats:\n", +" %s>irq -c 0,2 -S", +" CPU0 CPU2 ", +" 0: 2068161471 0 IR-IO-APIC-edge timer", +" 1: 9 0 IR-IO-APIC-edge i8042", +" 8: 1 0 IR-IO-APIC-edge rtc0", +" 9: 0 0 IR-IO-APIC-fasteoi acpi", +" 16: 36 0 IR-IO-APIC-fasteoi ehci_hcd:usb2", +" ...\n", +" 85: 3 0 IR-PCI-MSI-edge ioat-msix", +" 86: 3 0 IR-PCI-MSI-edge ioat-msix", +" 87: 3 0 IR-PCI-MSI-edge ioat-msix", +" 88: 24 295 IR-PCI-MSI-edge eth4", NULL }; diff --git a/kernel.c b/kernel.c index 0a93f8a..872e7ce 100755 --- a/kernel.c +++ b/kernel.c @@ -351,13 +351,20 @@ kernel_init() MEMBER_OFFSET_INIT(irq_desc_t_irq_data, irq_desc_type_name, "irq_data"); else MEMBER_OFFSET_INIT(irq_desc_t_affinity, irq_desc_type_name, "affinity"); + if (MEMBER_EXISTS(irq_desc_type_name, "kstat_irqs")) + MEMBER_OFFSET_INIT(irq_desc_t_kstat_irqs, irq_desc_type_name, "kstat_irqs"); + MEMBER_OFFSET_INIT(irq_desc_t_name, irq_desc_type_name, "name"); MEMBER_OFFSET_INIT(irq_desc_t_status, irq_desc_type_name, "status"); if (MEMBER_EXISTS(irq_desc_type_name, "handler")) MEMBER_OFFSET_INIT(irq_desc_t_handler, irq_desc_type_name, "handler"); - else + else if (MEMBER_EXISTS(irq_desc_type_name, "chip")) MEMBER_OFFSET_INIT(irq_desc_t_chip, irq_desc_type_name, "chip"); MEMBER_OFFSET_INIT(irq_desc_t_action, irq_desc_type_name, "action"); MEMBER_OFFSET_INIT(irq_desc_t_depth, irq_desc_type_name, "depth"); + + STRUCT_SIZE_INIT(kernel_stat, "kernel_stat"); + MEMBER_OFFSET_INIT(kernel_stat_irqs, "kernel_stat", "irqs"); + if (STRUCT_EXISTS("hw_interrupt_type")) { MEMBER_OFFSET_INIT(hw_interrupt_type_typename, "hw_interrupt_type", "typename"); @@ -422,8 +429,10 @@ kernel_init() if (kernel_symbol_exists("irq_desc_tree")) kt->flags |= IRQ_DESC_TREE; STRUCT_SIZE_INIT(irq_data, "irq_data"); - if (VALID_STRUCT(irq_data)) + if (VALID_STRUCT(irq_data)) { + MEMBER_OFFSET_INIT(irq_data_chip, "irq_data", "chip"); MEMBER_OFFSET_INIT(irq_data_affinity, "irq_data", "affinity"); + } STRUCT_SIZE_INIT(irq_cpustat_t, "irq_cpustat_t"); MEMBER_OFFSET_INIT(irq_cpustat_t___softirq_active, @@ -4713,8 +4722,17 @@ cmd_irq(void) { int i, c; int nr_irqs; + ulong *cpus; + int len; + int show_intr, choose_cpu; + char buf[10]; + char arg_buf[BUFSIZE]; - while ((c = getopt(argcnt, args, "dbus")) != EOF) { + cpus = NULL; + show_intr = 0; + choose_cpu = 0; + + while ((c = getopt(argcnt, args, "dbusSc:")) != EOF) { switch(c) { case 'd': @@ -4774,6 +4792,21 @@ cmd_irq(void) return; + case 'S': + show_intr = 1; + break; + + case 'c': + if (choose_cpu) { + error(INFO, "only one -c option allowed\n"); + argerrs++; + } else { + choose_cpu = 1; + BZERO(arg_buf, BUFSIZE); + strncpy(arg_buf, optarg, strlen(optarg)); + } + break; + default: argerrs++; break; @@ -4789,6 +4822,39 @@ cmd_irq(void) if ((nr_irqs = machdep->nr_irqs) == 0) error(FATAL, "cannot determine number of IRQs\n"); + if (show_intr) { + if (!(machine_type("X86") || machine_type("X86_64"))) + command_not_supported(); + + if ((len = STRUCT_SIZE("cpumask_t")) < 0) + len = DIV_ROUND_UP(kt->cpus, BITS_PER_LONG) * sizeof(ulong); + cpus = (ulong *)GETBUF(len); + + if (choose_cpu) { + make_cpumask(arg_buf, cpus, FAULT_ON_ERROR, NULL); + } else { + for (i = 0; i < kt->cpus; i++) + SET_BIT(cpus, i); + } + + fprintf(fp, " "); + BZERO(buf, 10); + for (i = 0; i < kt->cpus; i++) { + if (NUM_IN_BITMAP(cpus, i)) { + sprintf(buf, "CPU%d", i); + fprintf(fp, "%10s ", buf); + } + } + fprintf(fp, "\n"); + + for (i = 0; i < nr_irqs; i++) + machdep->show_interrupts(i, cpus); + + if (choose_cpu) + FREEBUF(cpus); + return; + } + if (!args[optind]) { for (i = 0; i < nr_irqs; i++) machdep->dump_irq(i); @@ -5493,6 +5559,137 @@ generic_get_irq_affinity(int irq) FREEBUF(affinity); } +void +generic_show_interrupts(int irq, ulong *cpus) +{ + int i; + ulong irq_desc_addr; + ulong handler, action, name; + uint kstat_irq; + uint kstat_irqs[kt->cpus]; + ulong kstat_irqs_ptr; + struct syment *percpu_sp; + ulong tmp, tmp1; + char buf[BUFSIZE]; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char name_buf[BUFSIZE]; + + handler = UNINITIALIZED; + + irq_desc_addr = get_irq_desc_addr(irq); + if (!irq_desc_addr) + return; + + readmem(irq_desc_addr + OFFSET(irq_desc_t_action), KVADDR, + &action, sizeof(long), "irq_desc action", FAULT_ON_ERROR); + + if (!action) + return; + + if (!symbol_exists("kstat_irqs_cpu")) { /* for RHEL5 or earlier */ + if (!(percpu_sp = per_cpu_symbol_search("kstat"))) + return; + + for (i = 0; i < kt->cpus; i++) { + if (!(NUM_IN_BITMAP(cpus, i))) + continue; + + tmp = percpu_sp->value + kt->__per_cpu_offset[i]; + readmem(tmp + OFFSET(kernel_stat_irqs) + sizeof(uint) * irq, + KVADDR, &kstat_irq, sizeof(uint), + "kernel_stat irqs", FAULT_ON_ERROR); + kstat_irqs[i] = kstat_irq; + } + } else { + readmem(irq_desc_addr + OFFSET(irq_desc_t_kstat_irqs), + KVADDR, &kstat_irqs_ptr, sizeof(long), + "irq_desc kstat_irqs", FAULT_ON_ERROR); + if (THIS_KERNEL_VERSION > LINUX(2,6,37)) { + for (i = 0; i < kt->cpus; i++) { + if (!(NUM_IN_BITMAP(cpus, i))) + continue; + + tmp = kstat_irqs_ptr + kt->__per_cpu_offset[i]; + readmem(tmp, KVADDR, &kstat_irq, sizeof(uint), + "kernel_stat irqs", FAULT_ON_ERROR); + kstat_irqs[i] = kstat_irq; + } + } else + readmem(kstat_irqs_ptr, KVADDR, kstat_irqs, + sizeof(kstat_irqs), "kstat_irqs", + FAULT_ON_ERROR); + } + if (VALID_MEMBER(irq_desc_t_handler)) + readmem(irq_desc_addr + OFFSET(irq_desc_t_handler), + KVADDR, &handler, sizeof(long), "irq_desc handler", + FAULT_ON_ERROR); + else if (VALID_MEMBER(irq_desc_t_chip)) + readmem(irq_desc_addr + OFFSET(irq_desc_t_chip), KVADDR, + &handler, sizeof(long), "irq_desc chip", + FAULT_ON_ERROR); + else if (VALID_MEMBER(irq_data_chip)) + readmem(irq_desc_addr + OFFSET(irq_data_chip), KVADDR, + &handler, sizeof(long), "irq_data chip", + FAULT_ON_ERROR); + + fprintf(fp, "%3d: ", irq); + + for (i = 0; i < kt->cpus; i++) { + if (NUM_IN_BITMAP(cpus, i)) + fprintf(fp, "%10u ", kstat_irqs[i]); + } + + if (handler != UNINITIALIZED) { + if (VALID_MEMBER(hw_interrupt_type_typename)) { + readmem(handler+OFFSET(hw_interrupt_type_typename), + KVADDR, &tmp, sizeof(void *), + "hw_interrupt_type typename", FAULT_ON_ERROR); + + BZERO(buf, BUFSIZE); + if (read_string(tmp, buf, BUFSIZE-1)) + fprintf(fp, "%14s", buf); + } + else if (VALID_MEMBER(irq_chip_typename)) { + readmem(handler+OFFSET(irq_chip_typename), + KVADDR, &tmp, sizeof(void *), + "hw_interrupt_type typename", FAULT_ON_ERROR); + + BZERO(buf, BUFSIZE); + if (read_string(tmp, buf, BUFSIZE-1)) + fprintf(fp, "%8s", buf); + BZERO(buf1, BUFSIZE); + if (VALID_MEMBER(irq_desc_t_name)) + readmem(irq_desc_addr+OFFSET(irq_desc_t_name), + KVADDR, &tmp1, sizeof(void *), + "irq_desc name", FAULT_ON_ERROR); + if (read_string(tmp1, buf1, BUFSIZE-1)) + fprintf(fp, "-%-8s", buf1); + } + } + + BZERO(name_buf, BUFSIZE); + + while (action) { + readmem(action+OFFSET(irqaction_name), KVADDR, + &name, sizeof(void *), + "irqaction name", FAULT_ON_ERROR); + BZERO(buf2, BUFSIZE); + if (read_string(name, buf2, BUFSIZE-1)) { + if (strlen(name_buf) != 0) + strncat(name_buf, ",", 2); + strncat(name_buf, buf2, strlen(buf2)); + } + + readmem(action+OFFSET(irqaction_next), KVADDR, + &action, sizeof(void *), + "irqaction dev_id", FAULT_ON_ERROR); + } + + fprintf(fp, " %-20s ", name_buf); + fprintf(fp, "\n"); +} + /* * Dump the earlier 2.2 Linux version's bottom-half essentials. */ diff --git a/tools.c b/tools.c index 5208181..d8c7045 100755 --- a/tools.c +++ b/tools.c @@ -4841,3 +4841,51 @@ swap32(uint32_t val, int swap) else return val; } + +int +make_cpumask(char *s, ulong *mask, int flags, int *errptr) +{ + char *p, *q; + int start, end; + int i; + + if (s == NULL) { + if (!(flags & QUIET)) + error(INFO, "received NULL string\n"); + goto make_cpumask_error; + } + + p = strtok(s, ","); + while (p) { + s = strtok(NULL, ""); + start = end = -1; + q = strtok(p, "-"); + start = dtoi(q, flags, errptr); + if ((q = strtok(NULL, "-"))) + end = dtoi(q, flags, errptr); + + if (end == -1) + end = start; + + for (i = start; i <= end; i++) + SET_BIT(mask, i); + + p = strtok(s, ","); + } + + return TRUE; + +make_cpumask_error: + switch (flags & (FAULT_ON_ERROR|RETURN_ON_ERROR)) + { + case FAULT_ON_ERROR: + RESTART(); + + case RETURN_ON_ERROR: + if (errptr) + *errptr = TRUE; + break; + } + + return UNUSED; +} diff --git a/x86.c b/x86.c index da5e5ba..6497186 100755 --- a/x86.c +++ b/x86.c @@ -1802,6 +1802,7 @@ x86_init(int when) machdep->get_task_pgd = x86_get_task_pgd; machdep->dump_irq = generic_dump_irq; machdep->get_irq_affinity = generic_get_irq_affinity; + machdep->show_interrupts = generic_show_interrupts; machdep->get_stack_frame = x86_get_stack_frame; machdep->get_stackbase = generic_get_stackbase; machdep->get_stacktop = generic_get_stacktop; @@ -3405,6 +3406,7 @@ x86_dump_machdep_table(ulong arg) fprintf(fp, " get_task_pgd: x86_get_task_pgd()\n"); fprintf(fp, " dump_irq: generic_dump_irq()\n"); fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n"); + fprintf(fp, " show_interrupts: generic_show_interrupts()\n"); fprintf(fp, " get_stack_frame: x86_get_stack_frame()\n"); fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); @@ -5343,6 +5345,7 @@ x86_init_hyper(int when) machdep->processor_speed = x86_processor_speed; /* ODA: check */ machdep->dump_irq = generic_dump_irq; /* ODA: check */ machdep->get_irq_affinity = generic_get_irq_affinity; + machdep->show_interrupts = generic_show_interrupts; machdep->get_stack_frame = x86_get_stack_frame_hyper; machdep->get_stackbase = x86_get_stackbase_hyper; machdep->get_stacktop = x86_get_stacktop_hyper; diff --git a/x86_64.c b/x86_64.c index 536f256..a9ec5f5 100755 --- a/x86_64.c +++ b/x86_64.c @@ -57,6 +57,7 @@ static void x86_64_display_full_frame(struct bt_info *, ulong, FILE *); static void x86_64_do_bt_reference_check(struct bt_info *, ulong,char *); static void x86_64_dump_irq(int); static void x86_64_get_irq_affinity(int); +static void x86_64_show_interrupts(int, ulong *); static char *x86_64_extract_idt_function(ulong *, char *, ulong *); static ulong x86_64_get_pc(struct bt_info *); static ulong x86_64_get_sp(struct bt_info *); @@ -473,6 +474,7 @@ x86_64_init(int when) machdep->nr_irqs = 224; /* NR_IRQS (at least) */ machdep->dump_irq = x86_64_dump_irq; machdep->get_irq_affinity = x86_64_get_irq_affinity; + machdep->show_interrupts = x86_64_show_interrupts; if (!machdep->hz) { machdep->hz = HZ; if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) @@ -634,6 +636,7 @@ x86_64_dump_machdep_table(ulong arg) fprintf(fp, " get_task_pgd: x86_64_get_task_pgd()\n"); fprintf(fp, " dump_irq: x86_64_dump_irq()\n"); fprintf(fp, " get_irq_affinity: x86_64_get_irq_affinity()\n"); + fprintf(fp, " show_interrupts: x86_64_show_interrupts()\n"); fprintf(fp, " get_stack_frame: x86_64_get_stack_frame()\n"); fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); @@ -4553,6 +4556,20 @@ x86_64_get_irq_affinity(int irq) "x86_64_get_irq_affinity: irq_desc[] or irq_desc_tree do not exist?\n"); } +static void +x86_64_show_interrupts(int irq, ulong *cpus) +{ + if (symbol_exists("irq_desc") || + kernel_symbol_exists("irq_desc_ptrs") || + kernel_symbol_exists("irq_desc_tree")) { + machdep->show_interrupts = generic_show_interrupts; + return(generic_show_interrupts(irq, cpus)); + } + + error(FATAL, + "x86_64_show_interrupts: irq_desc[] or irq_desc_tree do not exist?\n"); +} + /* * Do the work for irq -d */ -- 1.7.1
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility