-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This GDB script prints the interrupts in the system in the same way that /proc/interrupts does. This does include the architecture specific part done by arch_show_interrupts() for x86, ARM, ARM64 and MIPS. Example output from an ARM64 system: (gdb) lx-interruptlist CPU0 CPU1 CPU2 CPU3 10: 3167 1225 1276 2629 GICv2 30 Level arch_timer 13: 0 0 0 0 GICv2 36 Level arm-pmu 14: 0 0 0 0 GICv2 37 Level arm-pmu 15: 0 0 0 0 GICv2 38 Level arm-pmu 16: 0 0 0 0 GICv2 39 Level arm-pmu 28: 0 0 0 0 interrupt-controller@8410640 5 Edge brcmstb-gpio-wake 30: 125 0 0 0 GICv2 128 Level ttyS0 31: 0 0 0 0 interrupt-controller@8416000 0 Level mspi_done 32: 0 0 0 0 interrupt-controller@8410640 3 Edge brcmstb-waketimer 33: 0 0 0 0 interrupt-controller@8418580 8 Edge brcmstb-waketimer-rtc 34: 872 0 0 0 GICv2 230 Level brcm_scmi@0 35: 0 0 0 0 interrupt-controller@8410640 10 Edge 8d0f200.usb-phy 37: 0 0 0 0 GICv2 97 Level PCIe PME 42: 0 0 0 0 GICv2 145 Level xhci-hcd:usb1 43: 94 0 0 0 GICv2 71 Level mmc1 44: 0 0 0 0 GICv2 70 Level mmc0 IPI0: 23 666 154 98 Rescheduling interrupts IPI1: 247 1053 1701 634 Function call interrupts IPI2: 0 0 0 0 CPU stop interrupts IPI3: 0 0 0 0 CPU stop (for crash dump) interrupts IPI4: 0 0 0 0 Timer broadcast interrupts IPI5: 7 9 5 0 IRQ work interrupts IPI6: 0 0 0 0 CPU wake-up interrupts ERR: 0 Link: https://lkml.kernel.org/r/20230406220451.1583239-1-f.fainelli@gmail.com Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Cc: Jan Kiszka <jan.kiszka@siemens.com> Cc: Kieran Bingham <kbingham@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
- Loading branch information
Florian Fainelli
authored and
Andrew Morton
committed
Apr 18, 2023
1 parent
8af055a
commit b0969d7
Showing
3 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# | ||
# Copyright 2023 Broadcom | ||
|
||
import gdb | ||
|
||
from linux import constants | ||
from linux import cpus | ||
from linux import utils | ||
from linux import radixtree | ||
|
||
irq_desc_type = utils.CachedType("struct irq_desc") | ||
|
||
def irq_settings_is_hidden(desc): | ||
return desc['status_use_accessors'] & constants.LX_IRQ_HIDDEN | ||
|
||
def irq_desc_is_chained(desc): | ||
return desc['action'] and desc['action'] == gdb.parse_and_eval("&chained_action") | ||
|
||
def irqd_is_level(desc): | ||
return desc['irq_data']['common']['state_use_accessors'] & constants.LX_IRQD_LEVEL | ||
|
||
def show_irq_desc(prec, irq): | ||
text = "" | ||
|
||
desc = radixtree.lookup(gdb.parse_and_eval("&irq_desc_tree"), irq) | ||
if desc is None: | ||
return text | ||
|
||
desc = desc.cast(irq_desc_type.get_type()) | ||
if desc is None: | ||
return text | ||
|
||
if irq_settings_is_hidden(desc): | ||
return text | ||
|
||
any_count = 0 | ||
if desc['kstat_irqs']: | ||
for cpu in cpus.each_online_cpu(): | ||
any_count += cpus.per_cpu(desc['kstat_irqs'], cpu) | ||
|
||
if (desc['action'] == 0 or irq_desc_is_chained(desc)) and any_count == 0: | ||
return text; | ||
|
||
text += "%*d: " % (prec, irq) | ||
for cpu in cpus.each_online_cpu(): | ||
if desc['kstat_irqs']: | ||
count = cpus.per_cpu(desc['kstat_irqs'], cpu) | ||
else: | ||
count = 0 | ||
text += "%10u" % (count) | ||
|
||
name = "None" | ||
if desc['irq_data']['chip']: | ||
chip = desc['irq_data']['chip'] | ||
if chip['name']: | ||
name = chip['name'].string() | ||
else: | ||
name = "-" | ||
|
||
text += " %8s" % (name) | ||
|
||
if desc['irq_data']['domain']: | ||
text += " %*lu" % (prec, desc['irq_data']['hwirq']) | ||
else: | ||
text += " %*s" % (prec, "") | ||
|
||
if constants.LX_CONFIG_GENERIC_IRQ_SHOW_LEVEL: | ||
text += " %-8s" % ("Level" if irqd_is_level(desc) else "Edge") | ||
|
||
if desc['name']: | ||
text += "-%-8s" % (desc['name'].string()) | ||
|
||
""" Some toolchains may not be able to provide information about irqaction """ | ||
try: | ||
gdb.lookup_type("struct irqaction") | ||
action = desc['action'] | ||
if action is not None: | ||
text += " %s" % (action['name'].string()) | ||
while True: | ||
action = action['next'] | ||
if action is not None: | ||
break | ||
if action['name']: | ||
text += ", %s" % (action['name'].string()) | ||
except: | ||
pass | ||
|
||
text += "\n" | ||
|
||
return text | ||
|
||
def show_irq_err_count(prec): | ||
cnt = utils.gdb_eval_or_none("irq_err_count") | ||
text = "" | ||
if cnt is not None: | ||
text += "%*s: %10u\n" % (prec, "ERR", cnt['counter']) | ||
return text | ||
|
||
def x86_show_irqstat(prec, pfx, field, desc): | ||
irq_stat = gdb.parse_and_eval("&irq_stat") | ||
text = "%*s: " % (prec, pfx) | ||
for cpu in cpus.each_online_cpu(): | ||
stat = cpus.per_cpu(irq_stat, cpu) | ||
text += "%10u " % (stat[field]) | ||
text += " %s\n" % (desc) | ||
return text | ||
|
||
def x86_show_mce(prec, var, pfx, desc): | ||
pvar = gdb.parse_and_eval(var) | ||
text = "%*s: " % (prec, pfx) | ||
for cpu in cpus.each_online_cpu(): | ||
text += "%10u " % (cpus.per_cpu(pvar, cpu)) | ||
text += " %s\n" % (desc) | ||
return text | ||
|
||
def x86_show_interupts(prec): | ||
text = x86_show_irqstat(prec, "NMI", '__nmi_count', 'Non-maskable interrupts') | ||
|
||
if constants.LX_CONFIG_X86_LOCAL_APIC: | ||
text += x86_show_irqstat(prec, "LOC", 'apic_timer_irqs', "Local timer interrupts") | ||
text += x86_show_irqstat(prec, "SPU", 'irq_spurious_count', "Spurious interrupts") | ||
text += x86_show_irqstat(prec, "PMI", 'apic_perf_irqs', "Performance monitoring interrupts") | ||
text += x86_show_irqstat(prec, "IWI", 'apic_irq_work_irqs', "IRQ work interrupts") | ||
text += x86_show_irqstat(prec, "RTR", 'icr_read_retry_count', "APIC ICR read retries") | ||
if utils.gdb_eval_or_none("x86_platform_ipi_callback") is not None: | ||
text += x86_show_irqstat(prec, "PLT", 'x86_platform_ipis', "Platform interrupts") | ||
|
||
if constants.LX_CONFIG_SMP: | ||
text += x86_show_irqstat(prec, "RES", 'irq_resched_count', "Rescheduling interrupts") | ||
text += x86_show_irqstat(prec, "CAL", 'irq_call_count', "Function call interrupts") | ||
text += x86_show_irqstat(prec, "TLB", 'irq_tlb_count', "TLB shootdowns") | ||
|
||
if constants.LX_CONFIG_X86_THERMAL_VECTOR: | ||
text += x86_show_irqstat(prec, "TRM", 'irq_thermal_count', "Thermal events interrupts") | ||
|
||
if constants.LX_CONFIG_X86_MCE_THRESHOLD: | ||
text += x86_show_irqstat(prec, "THR", 'irq_threshold_count', "Threshold APIC interrupts") | ||
|
||
if constants.LX_CONFIG_X86_MCE_AMD: | ||
text += x86_show_irqstat(prec, "DFR", 'irq_deferred_error_count', "Deferred Error APIC interrupts") | ||
|
||
if constants.LX_CONFIG_X86_MCE: | ||
text += x86_show_mce(prec, "&mce_exception_count", "MCE", "Machine check exceptions") | ||
text == x86_show_mce(prec, "&mce_poll_count", "MCP", "Machine check polls") | ||
|
||
text += show_irq_err_count(prec) | ||
|
||
if constants.LX_CONFIG_X86_IO_APIC: | ||
cnt = utils.gdb_eval_or_none("irq_mis_count") | ||
if cnt is not None: | ||
text += "%*s: %10u\n" % (prec, "MIS", cnt['counter']) | ||
|
||
if constants.LX_CONFIG_HAVE_KVM: | ||
text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event') | ||
text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event') | ||
text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event') | ||
|
||
return text | ||
|
||
def arm_common_show_interrupts(prec): | ||
text = "" | ||
nr_ipi = utils.gdb_eval_or_none("nr_ipi") | ||
ipi_desc = utils.gdb_eval_or_none("ipi_desc") | ||
ipi_types = utils.gdb_eval_or_none("ipi_types") | ||
if nr_ipi is None or ipi_desc is None or ipi_types is None: | ||
return text | ||
|
||
if prec >= 4: | ||
sep = " " | ||
else: | ||
sep = "" | ||
|
||
for ipi in range(nr_ipi): | ||
text += "%*s%u:%s" % (prec - 1, "IPI", ipi, sep) | ||
desc = ipi_desc[ipi].cast(irq_desc_type.get_type().pointer()) | ||
if desc == 0: | ||
continue | ||
for cpu in cpus.each_online_cpu(): | ||
text += "%10u" % (cpus.per_cpu(desc['kstat_irqs'], cpu)) | ||
text += " %s" % (ipi_types[ipi].string()) | ||
text += "\n" | ||
return text | ||
|
||
def aarch64_show_interrupts(prec): | ||
text = arm_common_show_interrupts(prec) | ||
text += "%*s: %10lu\n" % (prec, "ERR", gdb.parse_and_eval("irq_err_count")) | ||
return text | ||
|
||
def arch_show_interrupts(prec): | ||
text = "" | ||
if utils.is_target_arch("x86"): | ||
text += x86_show_interupts(prec) | ||
elif utils.is_target_arch("aarch64"): | ||
text += aarch64_show_interrupts(prec) | ||
elif utils.is_target_arch("arm"): | ||
text += arm_common_show_interrupts(prec) | ||
elif utils.is_target_arch("mips"): | ||
text += show_irq_err_count(prec) | ||
else: | ||
raise gdb.GdbError("Unsupported architecture: {}".format(target_arch)) | ||
|
||
return text | ||
|
||
class LxInterruptList(gdb.Command): | ||
"""Print /proc/interrupts""" | ||
|
||
def __init__(self): | ||
super(LxInterruptList, self).__init__("lx-interruptlist", gdb.COMMAND_DATA) | ||
|
||
def invoke(self, arg, from_tty): | ||
nr_irqs = gdb.parse_and_eval("nr_irqs") | ||
prec = 3 | ||
j = 1000 | ||
while prec < 10 and j <= nr_irqs: | ||
prec += 1 | ||
j *= 10 | ||
|
||
gdb.write("%*s" % (prec + 8, "")) | ||
for cpu in cpus.each_online_cpu(): | ||
gdb.write("CPU%-8d" % cpu) | ||
gdb.write("\n") | ||
|
||
if utils.gdb_eval_or_none("&irq_desc_tree") is None: | ||
return | ||
|
||
for irq in range(nr_irqs): | ||
gdb.write(show_irq_desc(prec, irq)) | ||
gdb.write(arch_show_interrupts(prec)) | ||
|
||
|
||
LxInterruptList() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,3 +42,4 @@ | |
import linux.device | ||
import linux.mm | ||
import linux.radixtree | ||
import linux.interrupts |