mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-23 07:23:12 +02:00
scripts/gdb: fix interrupts.py after maple tree conversion
In commit721255b982("genirq: Use a maple tree for interrupt descriptor management"), the irq_desc_tree was replaced with a sparse_irqs tree using a maple tree structure. Since the script looked for the irq_desc_tree symbol which is no longer available, no interrupts would be printed and the script output would not be useful anymore. In addition to looking up the correct symbol (sparse_irqs), a new module (mapletree.py) is added whose mtree_load() implementation is largely copied after the C version and uses the same variable and intermediate function names wherever possible to ensure that both the C and Python version be updated in the future. This restores the scripts' output to match that of /proc/interrupts. Link: https://lkml.kernel.org/r/20250625021020.1056930-1-florian.fainelli@broadcom.com Fixes:721255b982("genirq: Use a maple tree for interrupt descriptor management") Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com> Cc: Jan Kiszka <jan.kiszka@siemens.com> Cc: Kieran Bingham <kbingham@kernel.org> Cc: Shanker Donthineni <sdonthineni@nvidia.com> Cc: Thomas Gleinxer <tglx@linutronix.de> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
ea9b77f98d
commit
a02b0cde8e
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/of_fdt.h>
|
#include <linux/of_fdt.h>
|
||||||
#include <linux/page_ext.h>
|
#include <linux/page_ext.h>
|
||||||
#include <linux/radix-tree.h>
|
#include <linux/radix-tree.h>
|
||||||
|
#include <linux/maple_tree.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/threads.h>
|
#include <linux/threads.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
|
@ -93,6 +94,12 @@ LX_GDBPARSED(RADIX_TREE_MAP_SIZE)
|
||||||
LX_GDBPARSED(RADIX_TREE_MAP_SHIFT)
|
LX_GDBPARSED(RADIX_TREE_MAP_SHIFT)
|
||||||
LX_GDBPARSED(RADIX_TREE_MAP_MASK)
|
LX_GDBPARSED(RADIX_TREE_MAP_MASK)
|
||||||
|
|
||||||
|
/* linux/maple_tree.h */
|
||||||
|
LX_VALUE(MAPLE_NODE_SLOTS)
|
||||||
|
LX_VALUE(MAPLE_RANGE64_SLOTS)
|
||||||
|
LX_VALUE(MAPLE_ARANGE64_SLOTS)
|
||||||
|
LX_GDBPARSED(MAPLE_NODE_MASK)
|
||||||
|
|
||||||
/* linux/vmalloc.h */
|
/* linux/vmalloc.h */
|
||||||
LX_VALUE(VM_IOREMAP)
|
LX_VALUE(VM_IOREMAP)
|
||||||
LX_VALUE(VM_ALLOC)
|
LX_VALUE(VM_ALLOC)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import gdb
|
||||||
from linux import constants
|
from linux import constants
|
||||||
from linux import cpus
|
from linux import cpus
|
||||||
from linux import utils
|
from linux import utils
|
||||||
from linux import radixtree
|
from linux import mapletree
|
||||||
|
|
||||||
irq_desc_type = utils.CachedType("struct irq_desc")
|
irq_desc_type = utils.CachedType("struct irq_desc")
|
||||||
|
|
||||||
|
|
@ -23,12 +23,12 @@ def irqd_is_level(desc):
|
||||||
def show_irq_desc(prec, irq):
|
def show_irq_desc(prec, irq):
|
||||||
text = ""
|
text = ""
|
||||||
|
|
||||||
desc = radixtree.lookup(gdb.parse_and_eval("&irq_desc_tree"), irq)
|
desc = mapletree.mtree_load(gdb.parse_and_eval("&sparse_irqs"), irq)
|
||||||
if desc is None:
|
if desc is None:
|
||||||
return text
|
return text
|
||||||
|
|
||||||
desc = desc.cast(irq_desc_type.get_type())
|
desc = desc.cast(irq_desc_type.get_type().pointer())
|
||||||
if desc is None:
|
if desc == 0:
|
||||||
return text
|
return text
|
||||||
|
|
||||||
if irq_settings_is_hidden(desc):
|
if irq_settings_is_hidden(desc):
|
||||||
|
|
@ -221,8 +221,8 @@ class LxInterruptList(gdb.Command):
|
||||||
gdb.write("CPU%-8d" % cpu)
|
gdb.write("CPU%-8d" % cpu)
|
||||||
gdb.write("\n")
|
gdb.write("\n")
|
||||||
|
|
||||||
if utils.gdb_eval_or_none("&irq_desc_tree") is None:
|
if utils.gdb_eval_or_none("&sparse_irqs") is None:
|
||||||
return
|
raise gdb.GdbError("Unable to find the sparse IRQ tree, is CONFIG_SPARSE_IRQ enabled?")
|
||||||
|
|
||||||
for irq in range(nr_irqs):
|
for irq in range(nr_irqs):
|
||||||
gdb.write(show_irq_desc(prec, irq))
|
gdb.write(show_irq_desc(prec, irq))
|
||||||
|
|
|
||||||
252
scripts/gdb/linux/mapletree.py
Normal file
252
scripts/gdb/linux/mapletree.py
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# Maple tree helpers
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Broadcom
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Florian Fainelli <florian.fainelli@broadcom.com>
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
from linux import utils
|
||||||
|
from linux import constants
|
||||||
|
from linux import xarray
|
||||||
|
|
||||||
|
maple_tree_root_type = utils.CachedType("struct maple_tree")
|
||||||
|
maple_node_type = utils.CachedType("struct maple_node")
|
||||||
|
maple_enode_type = utils.CachedType("void")
|
||||||
|
|
||||||
|
maple_dense = 0
|
||||||
|
maple_leaf_64 = 1
|
||||||
|
maple_range_64 = 2
|
||||||
|
maple_arange_64 = 3
|
||||||
|
|
||||||
|
class Mas(object):
|
||||||
|
ma_active = 0
|
||||||
|
ma_start = 1
|
||||||
|
ma_root = 2
|
||||||
|
ma_none = 3
|
||||||
|
ma_pause = 4
|
||||||
|
ma_overflow = 5
|
||||||
|
ma_underflow = 6
|
||||||
|
ma_error = 7
|
||||||
|
|
||||||
|
def __init__(self, mt, first, end):
|
||||||
|
if mt.type == maple_tree_root_type.get_type().pointer():
|
||||||
|
self.tree = mt.dereference()
|
||||||
|
elif mt.type != maple_tree_root_type.get_type():
|
||||||
|
raise gdb.GdbError("must be {} not {}"
|
||||||
|
.format(maple_tree_root_type.get_type().pointer(), mt.type))
|
||||||
|
self.tree = mt
|
||||||
|
self.index = first
|
||||||
|
self.last = end
|
||||||
|
self.node = None
|
||||||
|
self.status = self.ma_start
|
||||||
|
self.min = 0
|
||||||
|
self.max = -1
|
||||||
|
|
||||||
|
def is_start(self):
|
||||||
|
# mas_is_start()
|
||||||
|
return self.status == self.ma_start
|
||||||
|
|
||||||
|
def is_ptr(self):
|
||||||
|
# mas_is_ptr()
|
||||||
|
return self.status == self.ma_root
|
||||||
|
|
||||||
|
def is_none(self):
|
||||||
|
# mas_is_none()
|
||||||
|
return self.status == self.ma_none
|
||||||
|
|
||||||
|
def root(self):
|
||||||
|
# mas_root()
|
||||||
|
return self.tree['ma_root'].cast(maple_enode_type.get_type().pointer())
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
# mas_start()
|
||||||
|
if self.is_start() is False:
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.min = 0
|
||||||
|
self.max = ~0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.depth = 0
|
||||||
|
root = self.root()
|
||||||
|
if xarray.xa_is_node(root):
|
||||||
|
self.depth = 0
|
||||||
|
self.status = self.ma_active
|
||||||
|
self.node = mte_safe_root(root)
|
||||||
|
self.offset = 0
|
||||||
|
if mte_dead_node(self.node) is True:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.node = None
|
||||||
|
# Empty tree
|
||||||
|
if root is None:
|
||||||
|
self.status = self.ma_none
|
||||||
|
self.offset = constants.LX_MAPLE_NODE_SLOTS
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Single entry tree
|
||||||
|
self.status = self.ma_root
|
||||||
|
self.offset = constants.LX_MAPLE_NODE_SLOTS
|
||||||
|
|
||||||
|
if self.index != 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
# mas_reset()
|
||||||
|
self.status = self.ma_start
|
||||||
|
self.node = None
|
||||||
|
|
||||||
|
def mte_safe_root(node):
|
||||||
|
if node.type != maple_enode_type.get_type().pointer():
|
||||||
|
raise gdb.GdbError("{} must be {} not {}"
|
||||||
|
.format(mte_safe_root.__name__, maple_enode_type.get_type().pointer(), node.type))
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
indirect_ptr = node.cast(ulong_type) & ~0x2
|
||||||
|
val = indirect_ptr.cast(maple_enode_type.get_type().pointer())
|
||||||
|
return val
|
||||||
|
|
||||||
|
def mte_node_type(entry):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
val = None
|
||||||
|
if entry.type == maple_enode_type.get_type().pointer():
|
||||||
|
val = entry.cast(ulong_type)
|
||||||
|
elif entry.type == ulong_type:
|
||||||
|
val = entry
|
||||||
|
else:
|
||||||
|
raise gdb.GdbError("{} must be {} not {}"
|
||||||
|
.format(mte_node_type.__name__, maple_enode_type.get_type().pointer(), entry.type))
|
||||||
|
return (val >> 0x3) & 0xf
|
||||||
|
|
||||||
|
def ma_dead_node(node):
|
||||||
|
if node.type != maple_node_type.get_type().pointer():
|
||||||
|
raise gdb.GdbError("{} must be {} not {}"
|
||||||
|
.format(ma_dead_node.__name__, maple_node_type.get_type().pointer(), node.type))
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
parent = node['parent']
|
||||||
|
indirect_ptr = node['parent'].cast(ulong_type) & ~constants.LX_MAPLE_NODE_MASK
|
||||||
|
return indirect_ptr == node
|
||||||
|
|
||||||
|
def mte_to_node(enode):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
if enode.type == maple_enode_type.get_type().pointer():
|
||||||
|
indirect_ptr = enode.cast(ulong_type)
|
||||||
|
elif enode.type == ulong_type:
|
||||||
|
indirect_ptr = enode
|
||||||
|
else:
|
||||||
|
raise gdb.GdbError("{} must be {} not {}"
|
||||||
|
.format(mte_to_node.__name__, maple_enode_type.get_type().pointer(), enode.type))
|
||||||
|
indirect_ptr = indirect_ptr & ~constants.LX_MAPLE_NODE_MASK
|
||||||
|
return indirect_ptr.cast(maple_node_type.get_type().pointer())
|
||||||
|
|
||||||
|
def mte_dead_node(enode):
|
||||||
|
if enode.type != maple_enode_type.get_type().pointer():
|
||||||
|
raise gdb.GdbError("{} must be {} not {}"
|
||||||
|
.format(mte_dead_node.__name__, maple_enode_type.get_type().pointer(), enode.type))
|
||||||
|
node = mte_to_node(enode)
|
||||||
|
return ma_dead_node(node)
|
||||||
|
|
||||||
|
def ma_is_leaf(tp):
|
||||||
|
result = tp < maple_range_64
|
||||||
|
return tp < maple_range_64
|
||||||
|
|
||||||
|
def mt_pivots(t):
|
||||||
|
if t == maple_dense:
|
||||||
|
return 0
|
||||||
|
elif t == maple_leaf_64 or t == maple_range_64:
|
||||||
|
return constants.LX_MAPLE_RANGE64_SLOTS - 1
|
||||||
|
elif t == maple_arange_64:
|
||||||
|
return constants.LX_MAPLE_ARANGE64_SLOTS - 1
|
||||||
|
|
||||||
|
def ma_pivots(node, t):
|
||||||
|
if node.type != maple_node_type.get_type().pointer():
|
||||||
|
raise gdb.GdbError("{}: must be {} not {}"
|
||||||
|
.format(ma_pivots.__name__, maple_node_type.get_type().pointer(), node.type))
|
||||||
|
if t == maple_arange_64:
|
||||||
|
return node['ma64']['pivot']
|
||||||
|
elif t == maple_leaf_64 or t == maple_range_64:
|
||||||
|
return node['mr64']['pivot']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def ma_slots(node, tp):
|
||||||
|
if node.type != maple_node_type.get_type().pointer():
|
||||||
|
raise gdb.GdbError("{}: must be {} not {}"
|
||||||
|
.format(ma_slots.__name__, maple_node_type.get_type().pointer(), node.type))
|
||||||
|
if tp == maple_arange_64:
|
||||||
|
return node['ma64']['slot']
|
||||||
|
elif tp == maple_range_64 or tp == maple_leaf_64:
|
||||||
|
return node['mr64']['slot']
|
||||||
|
elif tp == maple_dense:
|
||||||
|
return node['slot']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def mt_slot(mt, slots, offset):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
return slots[offset].cast(ulong_type)
|
||||||
|
|
||||||
|
def mtree_lookup_walk(mas):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
n = mas.node
|
||||||
|
|
||||||
|
while True:
|
||||||
|
node = mte_to_node(n)
|
||||||
|
tp = mte_node_type(n)
|
||||||
|
pivots = ma_pivots(node, tp)
|
||||||
|
end = mt_pivots(tp)
|
||||||
|
offset = 0
|
||||||
|
while True:
|
||||||
|
if pivots[offset] >= mas.index:
|
||||||
|
break
|
||||||
|
if offset >= end:
|
||||||
|
break
|
||||||
|
offset += 1
|
||||||
|
|
||||||
|
slots = ma_slots(node, tp)
|
||||||
|
n = mt_slot(mas.tree, slots, offset)
|
||||||
|
if ma_dead_node(node) is True:
|
||||||
|
mas.reset()
|
||||||
|
return None
|
||||||
|
break
|
||||||
|
|
||||||
|
if ma_is_leaf(tp) is True:
|
||||||
|
break
|
||||||
|
|
||||||
|
return n
|
||||||
|
|
||||||
|
def mtree_load(mt, index):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
# MT_STATE(...)
|
||||||
|
mas = Mas(mt, index, index)
|
||||||
|
entry = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
entry = mas.start()
|
||||||
|
if mas.is_none():
|
||||||
|
return None
|
||||||
|
|
||||||
|
if mas.is_ptr():
|
||||||
|
if index != 0:
|
||||||
|
entry = None
|
||||||
|
return entry
|
||||||
|
|
||||||
|
entry = mtree_lookup_walk(mas)
|
||||||
|
if entry is None and mas.is_start():
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if xarray.xa_is_zero(entry):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return entry
|
||||||
28
scripts/gdb/linux/xarray.py
Normal file
28
scripts/gdb/linux/xarray.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# Xarray helpers
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Broadcom
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Florian Fainelli <florian.fainelli@broadcom.com>
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
from linux import utils
|
||||||
|
from linux import constants
|
||||||
|
|
||||||
|
def xa_is_internal(entry):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
return ((entry.cast(ulong_type) & 3) == 2)
|
||||||
|
|
||||||
|
def xa_mk_internal(v):
|
||||||
|
return ((v << 2) | 2)
|
||||||
|
|
||||||
|
def xa_is_zero(entry):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
return entry.cast(ulong_type) == xa_mk_internal(257)
|
||||||
|
|
||||||
|
def xa_is_node(entry):
|
||||||
|
ulong_type = utils.get_ulong_type()
|
||||||
|
return xa_is_internal(entry) and (entry.cast(ulong_type) > 4096)
|
||||||
Loading…
Reference in New Issue
Block a user