[PATCH v3] add option -s and -S for subcommand irq

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux