>From fc1c610dc2245708a8a69d57523ba7c90790f250 Mon Sep 17 00:00:00 2001 From: zhangyanfei Date: Wed, 11 Jan 2012 09:58:16 +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 --- defs.h | 6 ++ help.c | 40 ++++++++++- kernel.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++---------------- x86.c | 3 + x86_64.c | 17 +++++ 5 files changed, 238 insertions(+), 63 deletions(-) diff --git a/defs.h b/defs.h index 381e8c2..6f4d63a 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); @@ -1189,6 +1190,7 @@ struct offset_table { /* stash of commonly-used offsets */ long irq_desc_t_chip; long irq_desc_t_action; long irq_desc_t_depth; + long irq_desc_t_affinity; long irqdesc_action; long irqdesc_ctl; long irqdesc_level; @@ -3023,6 +3025,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 +4050,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 ", " [7] ffffffff81058830 ", " [8] ffffffff81087f00 ", -" [9] ffffffff810ca7a0 ", +" [9] ffffffff810ca7a0 \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..4fd940a 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); @@ -353,6 +354,7 @@ kernel_init() 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"); + MEMBER_OFFSET_INIT(irq_desc_t_affinity, irq_desc_type_name, "affinity"); if (STRUCT_EXISTS("hw_interrupt_type")) { MEMBER_OFFSET_INIT(hw_interrupt_type_typename, "hw_interrupt_type", "typename"); @@ -4707,7 +4709,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 +4756,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 +4806,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 +4909,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,38 +4919,12 @@ 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); + irq_desc_addr = get_irq_desc_addr(irq); + if (!irq_desc_addr) { + if (!(pc->curcmd_flags & IRQ_IN_USE)) + fprintf(fp, " IRQ: %d (unused)\n\n", irq); + return; } else { - irq_desc_addr = 0; - error(FATAL, - "neither irq_desc, _irq_desc, irq_desc_ptrs " - "or irq_desc_tree symbols exist\n"); - } - - if (irq_desc_addr) { if (VALID_MEMBER(irq_desc_t_status)) readmem(irq_desc_addr + OFFSET(irq_desc_t_status), KVADDR, &status, sizeof(int), "irq_desc status", @@ -4896,12 +4949,6 @@ generic_dump_irq(int irq) if ((handler == UNINITIALIZED) && VALID_STRUCT(irq_data)) goto irq_desc_format_v2; - if (!irq_desc_addr) { - if (!(pc->curcmd_flags & IRQ_IN_USE)) - fprintf(fp, " IRQ: %d (unused)\n\n", irq); - return; - } - fprintf(fp, " IRQ: %d\n", irq); fprintf(fp, " STATUS: %x %s", status, status ? "(" : ""); others = 0; @@ -5362,6 +5409,76 @@ 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 handler, action, name; + char buf[BUFSIZE]; + char name_buf[BUFSIZE]; + + affinity = NULL; + 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 ((len = STRUCT_SIZE("cpumask_t")) < 0) + len = DIV_ROUND_UP(kt->cpus, BITS_PER_LONG) * sizeof(ulong); + + if (VALID_MEMBER(irq_desc_t_affinity)) { + affinity = (ulong *)GETBUF(len); + + if (symbol_exists("alloc_cpumask_var")) /* pointer member */ + readmem(irq_desc_addr + OFFSET(irq_desc_t_affinity), + KVADDR, &affinity_ptr, sizeof(ulong), + "irq_desc affinity", FAULT_ON_ERROR); + else /* array member */ + affinity_ptr = irq_desc_addr + + OFFSET(irq_desc_t_affinity); + + 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"); + + if (affinity) + 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