|
|
| [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] |
Re-posting two patch as attachments. I'm sorry for the problems on the first pass. I have tested the two patches on RHEL 5.8beta (x86, x86_64) , RHEL 6.2ga (x86, x86_64), and RHEL 6.2ga with kernel 3.2 (x86, x86_64). -- 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
>From 6ed496fd5454706cf85f695de3a3856c99ee96e4 Mon Sep 17 00:00:00 2001
From: zhangyanfei <zhangyanfei@xxxxxxxxxxxxxx>
Date: Fri, 13 Jan 2012 14:21:49 +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 | 241 +++++++++++++++++++++++++++++++++++++++++++++++---------------
x86.c | 3 +
x86_64.c | 17 +++++
5 files changed, 246 insertions(+), 63 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..89737a9 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,38 +4924,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 +4954,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 +5414,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 a68b30028c2d38227722581b1a55ea68ef33ce6c Mon Sep 17 00:00:00 2001
From: zhangyanfei <zhangyanfei@xxxxxxxxxxxxxx>
Date: Fri, 13 Jan 2012 15:35:27 +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 89737a9..36f6685 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);
@@ -5485,6 +5551,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
[Home] [Fedora Legacy List] [Fedora Maintainers] [Fedora Desktop] [Red Hat 9 Bible] [Fedora Bible] [Fedora SELinux] [Big List of Linux Books] [Yosemite News] [Yosemite Photos] [KDE Users] [Fedora Tools]
![]() |