]>
Commit | Line | Data |
---|---|---|
b0969d76 FF |
1 | # SPDX-License-Identifier: GPL-2.0 |
2 | # | |
3 | # Copyright 2023 Broadcom | |
4 | ||
5 | import gdb | |
6 | ||
7 | from linux import constants | |
8 | from linux import cpus | |
9 | from linux import utils | |
10 | from linux import radixtree | |
11 | ||
12 | irq_desc_type = utils.CachedType("struct irq_desc") | |
13 | ||
14 | def irq_settings_is_hidden(desc): | |
15 | return desc['status_use_accessors'] & constants.LX_IRQ_HIDDEN | |
16 | ||
17 | def irq_desc_is_chained(desc): | |
18 | return desc['action'] and desc['action'] == gdb.parse_and_eval("&chained_action") | |
19 | ||
20 | def irqd_is_level(desc): | |
21 | return desc['irq_data']['common']['state_use_accessors'] & constants.LX_IRQD_LEVEL | |
22 | ||
23 | def show_irq_desc(prec, irq): | |
24 | text = "" | |
25 | ||
26 | desc = radixtree.lookup(gdb.parse_and_eval("&irq_desc_tree"), irq) | |
27 | if desc is None: | |
28 | return text | |
29 | ||
30 | desc = desc.cast(irq_desc_type.get_type()) | |
31 | if desc is None: | |
32 | return text | |
33 | ||
34 | if irq_settings_is_hidden(desc): | |
35 | return text | |
36 | ||
37 | any_count = 0 | |
38 | if desc['kstat_irqs']: | |
39 | for cpu in cpus.each_online_cpu(): | |
40 | any_count += cpus.per_cpu(desc['kstat_irqs'], cpu) | |
41 | ||
42 | if (desc['action'] == 0 or irq_desc_is_chained(desc)) and any_count == 0: | |
43 | return text; | |
44 | ||
45 | text += "%*d: " % (prec, irq) | |
46 | for cpu in cpus.each_online_cpu(): | |
47 | if desc['kstat_irqs']: | |
48 | count = cpus.per_cpu(desc['kstat_irqs'], cpu) | |
49 | else: | |
50 | count = 0 | |
51 | text += "%10u" % (count) | |
52 | ||
53 | name = "None" | |
54 | if desc['irq_data']['chip']: | |
55 | chip = desc['irq_data']['chip'] | |
56 | if chip['name']: | |
57 | name = chip['name'].string() | |
58 | else: | |
59 | name = "-" | |
60 | ||
61 | text += " %8s" % (name) | |
62 | ||
63 | if desc['irq_data']['domain']: | |
64 | text += " %*lu" % (prec, desc['irq_data']['hwirq']) | |
65 | else: | |
66 | text += " %*s" % (prec, "") | |
67 | ||
68 | if constants.LX_CONFIG_GENERIC_IRQ_SHOW_LEVEL: | |
69 | text += " %-8s" % ("Level" if irqd_is_level(desc) else "Edge") | |
70 | ||
71 | if desc['name']: | |
72 | text += "-%-8s" % (desc['name'].string()) | |
73 | ||
74 | """ Some toolchains may not be able to provide information about irqaction """ | |
75 | try: | |
76 | gdb.lookup_type("struct irqaction") | |
77 | action = desc['action'] | |
78 | if action is not None: | |
79 | text += " %s" % (action['name'].string()) | |
80 | while True: | |
81 | action = action['next'] | |
82 | if action is not None: | |
83 | break | |
84 | if action['name']: | |
85 | text += ", %s" % (action['name'].string()) | |
86 | except: | |
87 | pass | |
88 | ||
89 | text += "\n" | |
90 | ||
91 | return text | |
92 | ||
93 | def show_irq_err_count(prec): | |
94 | cnt = utils.gdb_eval_or_none("irq_err_count") | |
95 | text = "" | |
96 | if cnt is not None: | |
97 | text += "%*s: %10u\n" % (prec, "ERR", cnt['counter']) | |
98 | return text | |
99 | ||
100 | def x86_show_irqstat(prec, pfx, field, desc): | |
101 | irq_stat = gdb.parse_and_eval("&irq_stat") | |
102 | text = "%*s: " % (prec, pfx) | |
103 | for cpu in cpus.each_online_cpu(): | |
104 | stat = cpus.per_cpu(irq_stat, cpu) | |
105 | text += "%10u " % (stat[field]) | |
106 | text += " %s\n" % (desc) | |
107 | return text | |
108 | ||
109 | def x86_show_mce(prec, var, pfx, desc): | |
110 | pvar = gdb.parse_and_eval(var) | |
111 | text = "%*s: " % (prec, pfx) | |
112 | for cpu in cpus.each_online_cpu(): | |
113 | text += "%10u " % (cpus.per_cpu(pvar, cpu)) | |
114 | text += " %s\n" % (desc) | |
115 | return text | |
116 | ||
117 | def x86_show_interupts(prec): | |
118 | text = x86_show_irqstat(prec, "NMI", '__nmi_count', 'Non-maskable interrupts') | |
119 | ||
120 | if constants.LX_CONFIG_X86_LOCAL_APIC: | |
121 | text += x86_show_irqstat(prec, "LOC", 'apic_timer_irqs', "Local timer interrupts") | |
122 | text += x86_show_irqstat(prec, "SPU", 'irq_spurious_count', "Spurious interrupts") | |
123 | text += x86_show_irqstat(prec, "PMI", 'apic_perf_irqs', "Performance monitoring interrupts") | |
124 | text += x86_show_irqstat(prec, "IWI", 'apic_irq_work_irqs', "IRQ work interrupts") | |
125 | text += x86_show_irqstat(prec, "RTR", 'icr_read_retry_count', "APIC ICR read retries") | |
126 | if utils.gdb_eval_or_none("x86_platform_ipi_callback") is not None: | |
127 | text += x86_show_irqstat(prec, "PLT", 'x86_platform_ipis', "Platform interrupts") | |
128 | ||
129 | if constants.LX_CONFIG_SMP: | |
130 | text += x86_show_irqstat(prec, "RES", 'irq_resched_count', "Rescheduling interrupts") | |
131 | text += x86_show_irqstat(prec, "CAL", 'irq_call_count', "Function call interrupts") | |
132 | text += x86_show_irqstat(prec, "TLB", 'irq_tlb_count', "TLB shootdowns") | |
133 | ||
134 | if constants.LX_CONFIG_X86_THERMAL_VECTOR: | |
135 | text += x86_show_irqstat(prec, "TRM", 'irq_thermal_count', "Thermal events interrupts") | |
136 | ||
137 | if constants.LX_CONFIG_X86_MCE_THRESHOLD: | |
138 | text += x86_show_irqstat(prec, "THR", 'irq_threshold_count', "Threshold APIC interrupts") | |
139 | ||
140 | if constants.LX_CONFIG_X86_MCE_AMD: | |
141 | text += x86_show_irqstat(prec, "DFR", 'irq_deferred_error_count', "Deferred Error APIC interrupts") | |
142 | ||
143 | if constants.LX_CONFIG_X86_MCE: | |
144 | text += x86_show_mce(prec, "&mce_exception_count", "MCE", "Machine check exceptions") | |
145 | text == x86_show_mce(prec, "&mce_poll_count", "MCP", "Machine check polls") | |
146 | ||
147 | text += show_irq_err_count(prec) | |
148 | ||
149 | if constants.LX_CONFIG_X86_IO_APIC: | |
150 | cnt = utils.gdb_eval_or_none("irq_mis_count") | |
151 | if cnt is not None: | |
152 | text += "%*s: %10u\n" % (prec, "MIS", cnt['counter']) | |
153 | ||
dcf0926e | 154 | if constants.LX_CONFIG_KVM: |
b0969d76 FF |
155 | text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event') |
156 | text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event') | |
157 | text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event') | |
158 | ||
159 | return text | |
160 | ||
161 | def arm_common_show_interrupts(prec): | |
162 | text = "" | |
163 | nr_ipi = utils.gdb_eval_or_none("nr_ipi") | |
164 | ipi_desc = utils.gdb_eval_or_none("ipi_desc") | |
165 | ipi_types = utils.gdb_eval_or_none("ipi_types") | |
166 | if nr_ipi is None or ipi_desc is None or ipi_types is None: | |
167 | return text | |
168 | ||
169 | if prec >= 4: | |
170 | sep = " " | |
171 | else: | |
172 | sep = "" | |
173 | ||
174 | for ipi in range(nr_ipi): | |
175 | text += "%*s%u:%s" % (prec - 1, "IPI", ipi, sep) | |
176 | desc = ipi_desc[ipi].cast(irq_desc_type.get_type().pointer()) | |
177 | if desc == 0: | |
178 | continue | |
179 | for cpu in cpus.each_online_cpu(): | |
180 | text += "%10u" % (cpus.per_cpu(desc['kstat_irqs'], cpu)) | |
181 | text += " %s" % (ipi_types[ipi].string()) | |
182 | text += "\n" | |
183 | return text | |
184 | ||
185 | def aarch64_show_interrupts(prec): | |
186 | text = arm_common_show_interrupts(prec) | |
187 | text += "%*s: %10lu\n" % (prec, "ERR", gdb.parse_and_eval("irq_err_count")) | |
188 | return text | |
189 | ||
190 | def arch_show_interrupts(prec): | |
191 | text = "" | |
192 | if utils.is_target_arch("x86"): | |
193 | text += x86_show_interupts(prec) | |
194 | elif utils.is_target_arch("aarch64"): | |
195 | text += aarch64_show_interrupts(prec) | |
196 | elif utils.is_target_arch("arm"): | |
197 | text += arm_common_show_interrupts(prec) | |
198 | elif utils.is_target_arch("mips"): | |
199 | text += show_irq_err_count(prec) | |
200 | else: | |
201 | raise gdb.GdbError("Unsupported architecture: {}".format(target_arch)) | |
202 | ||
203 | return text | |
204 | ||
205 | class LxInterruptList(gdb.Command): | |
206 | """Print /proc/interrupts""" | |
207 | ||
208 | def __init__(self): | |
209 | super(LxInterruptList, self).__init__("lx-interruptlist", gdb.COMMAND_DATA) | |
210 | ||
211 | def invoke(self, arg, from_tty): | |
212 | nr_irqs = gdb.parse_and_eval("nr_irqs") | |
213 | prec = 3 | |
214 | j = 1000 | |
215 | while prec < 10 and j <= nr_irqs: | |
216 | prec += 1 | |
217 | j *= 10 | |
218 | ||
219 | gdb.write("%*s" % (prec + 8, "")) | |
220 | for cpu in cpus.each_online_cpu(): | |
221 | gdb.write("CPU%-8d" % cpu) | |
222 | gdb.write("\n") | |
223 | ||
224 | if utils.gdb_eval_or_none("&irq_desc_tree") is None: | |
225 | return | |
226 | ||
227 | for irq in range(nr_irqs): | |
228 | gdb.write(show_irq_desc(prec, irq)) | |
229 | gdb.write(arch_show_interrupts(prec)) | |
230 | ||
231 | ||
232 | LxInterruptList() |