Hello Dave,

The subcommand irq can dump the most of the irq information. Here I add
some options to make some improvements for irq.
1. option '-s': display the cpu affinity for in-use IRQs.
2. option '-S' and '-c': display the percpu irq stats. -c is used to
specify the cpu for which irq stats should be displayed. Without option
-c, 'irq -S' displays the irq stats for all cpus. The output of this
option is just like 'cat /proc/interrupts' shows.

Two patches attched:
-s: 0001-Add-s-option-for-irq-to-dump-the-cpu-affinity-of-in-.patch
-S and -c: 0002-Add-S-and-c-option-for-irq-to-dump-the-kernel-irq-st.patch
And the second patch is made at the base of the first patch.

Thanks,
Zhang Yanfei

-- 
> Regards
> Zhang Yanfei
> --------------------------------------------------
> Development Dept.I
> Nanjing Fujitsu Nanda Software Tech. Co., Ltd.(FNST)
> No. 6 Zhushan Road, Nanjing, 210012, China
> TEL: +86+25-86630566-8529
> FUJITSU INTERNAL: 7998-8529
> EMail: [email protected]
> --------------------------------------------------
>From fc1c610dc2245708a8a69d57523ba7c90790f250 Mon Sep 17 00:00:00 2001
From: zhangyanfei <[email protected]>
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 <[email protected]>
---
 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  <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..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

>From 57a10fd74d6040b832d26909017a72fb7330b70a Mon Sep 17 00:00:00 2001
From: zhangyanfei <[email protected]>
Date: Wed, 11 Jan 2012 10:09:03 +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 <[email protected]>
---
 defs.h   |    6 ++
 help.c   |   30 ++++++++--
 kernel.c |  181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 tools.c  |   48 ++++++++++++++++
 x86.c    |    3 +
 x86_64.c |   17 ++++++
 6 files changed, 278 insertions(+), 7 deletions(-)

diff --git a/defs.h b/defs.h
index 6f4d63a..1308df0 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);
@@ -1185,12 +1186,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_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 kernel_stat_irqs;
        long irqdesc_action;
        long irqdesc_ctl;
        long irqdesc_level;
@@ -1682,6 +1685,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;
@@ -3663,6 +3667,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 
@@ -4051,6 +4056,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 4fd940a..bd7f919 100755
--- a/kernel.c
+++ b/kernel.c
@@ -347,6 +347,9 @@ 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, "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");
@@ -355,6 +358,10 @@ kernel_init()
        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");
+
+       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");
@@ -4708,8 +4715,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':
@@ -4769,6 +4785,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;
@@ -4784,6 +4815,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);
@@ -5479,6 +5543,121 @@ 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);
+               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);
+
+       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) {
+               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
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to