From 0d74586cb621b9f8a1211e673b016cc5d423a157 Mon Sep 17 00:00:00 2001
From: Kyle Yan <kyan@codeaurora.org>
Date: Mon, 25 Apr 2016 11:44:17 -0700
Subject: [PATCH] lrdp-v2: Timerlist support for kernel 4.2 onwards

Timerlist structure changed for kernel 4.2. Added extra
parsing function to get timerlist dumps for kernel 4.2
Commit ID for kernel changes:

1dabbcec2: timer: Use hlist for the timer wheel hash buckets
0eeda71bc: timer: Replace timer base by a cpu index

CRs-Fixed: 981273
Change-Id: I163ef37d118914486c6e9b77ee80b2317c37c5b6
---
 linux-ramdump-parser-v2/parsers/timerlist.py | 45 ++++++++++++++++----
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/linux-ramdump-parser-v2/parsers/timerlist.py b/linux-ramdump-parser-v2/parsers/timerlist.py
index 0429112..895638e 100755
--- a/linux-ramdump-parser-v2/parsers/timerlist.py
+++ b/linux-ramdump-parser-v2/parsers/timerlist.py
@@ -21,6 +21,13 @@ class TimerList(RamParser) :
         super(TimerList, self).__init__(*args)
         self.vectors = {'tv1': 256, 'tv2': 64, 'tv3': 64, 'tv4': 64, 'tv5': 64}
         self.output = []
+        self.timer_42 = False
+
+        # Timerlist structure changed in kernel 4.2
+        # Requires separate processing
+        if self.ramdump.kernel_version[0] >= 4:
+            if self.ramdump.kernel_version[1] >= 2:
+                self.timer_42 = True
 
     def timer_list_walker(self, node, type, index, base):
         if node == self.head:
@@ -30,7 +37,6 @@ class TimerList(RamParser) :
         function_addr = node + self.ramdump.field_offset('struct timer_list', 'function')
         expires_addr = node + self.ramdump.field_offset('struct timer_list', 'expires')
         data_addr = node + self.ramdump.field_offset('struct timer_list', 'data')
-        timer_base_addr = node + self.ramdump.field_offset('struct timer_list', 'base')
 
         function =  self.ramdump.unwind_lookup(self.ramdump.read_word(function_addr))[0]
         expires = self.ramdump.read_word(expires_addr)
@@ -40,7 +46,6 @@ class TimerList(RamParser) :
             self.output_file.write("+ Corruption detected at index {0} in {1} list, found corrupted value: {2:x}\n".format(index, type, data_addr))
             return
 
-        timer_base = self.ramdump.read_word(timer_base_addr) & ~3
 
         if function == "delayed_work_timer_fn":
             timer_list_offset = self.ramdump.field_offset('struct delayed_work', 'timer')
@@ -49,8 +54,12 @@ class TimerList(RamParser) :
             work_func = self.ramdump.unwind_lookup(self.ramdump.read_word(func_addr))[0]
             data += " / " + work_func
 
-        if timer_base != base:
-            remarks += "Timer Base Mismatch detected"
+        if not self.timer_42:
+            timer_base_addr = node + self.ramdump.field_offset(
+                'struct timer_list', 'base')
+            timer_base = self.ramdump.read_word(timer_base_addr) & ~3
+            if timer_base != base:
+                remarks += "Timer Base Mismatch detected"
 
         output = "\t{0:<6} {1:<18x} {2:<14} {3:<40} {4:<52} {5}\n".format(index, node, expires, function, data, remarks)
         self.output.append(output)
@@ -64,6 +73,19 @@ class TimerList(RamParser) :
             timer_list_walker = linux_list.ListWalker(self.ramdump, index, node_offset)
             timer_list_walker.walk(index, self.timer_list_walker, type, i, base)
 
+    def iterate_vec_v2(self, type, base):
+        vec_addr = base + self.ramdump.field_offset('struct tvec_base', type)
+        for i in range(0, self.vectors[type]):
+            index = self.ramdump.array_index(vec_addr, 'struct hlist_head', i)
+            self.head = index
+            index = self.ramdump.read_word(index)
+            node_offset = self.ramdump.field_offset(
+                'struct hlist_node', 'next')
+            timer_list_walker = linux_list.ListWalker(self.ramdump, index,
+                                                      node_offset)
+            timer_list_walker.walk(index, self.timer_list_walker, type, i,
+                                   base)
+
     def print_vec(self, type):
         if len(self.output):
             self.output_file.write("+ {0} Timers ({1})\n\n".format(type, len(self.output)))
@@ -78,18 +100,23 @@ class TimerList(RamParser) :
         self.output_file.write("Timer List Dump\n\n")
 
         tvec_bases_addr = self.ramdump.address_of('tvec_bases')
+
         for cpu in range(0, self.ramdump.get_num_cpus()):
             title = "CPU {0}".format(cpu)
 
             base_addr = tvec_bases_addr + self.ramdump.per_cpu_offset(cpu)
-            base = self.ramdump.read_word(base_addr)
+            if self.timer_42:
+                base = base_addr
+            else:
+                base = self.ramdump.read_word(base_addr)
+
             title += "(tvec_base: {0:x} ".format(base)
 
             timer_jiffies_addr = base + self.ramdump.field_offset('struct tvec_base', 'timer_jiffies')
             next_timer_addr = base + self.ramdump.field_offset('struct tvec_base', 'next_timer')
+
             timer_jiffies = self.ramdump.read_word(timer_jiffies_addr)
             next_timer = self.ramdump.read_word(next_timer_addr)
-
             active_timers_offset = self.ramdump.field_offset('struct tvec_base', 'active_timers')
             if active_timers_offset is not None:
                 active_timers_addr = base + self.ramdump.field_offset('struct tvec_base', 'active_timers')
@@ -104,12 +131,14 @@ class TimerList(RamParser) :
 
             for vec in sorted(self.vectors):
                 self.output = []
-                self.iterate_vec(vec, base)
+                if self.timer_42:
+                    self.iterate_vec_v2(vec, base)
+                else:
+                    self.iterate_vec(vec, base)
                 self.print_vec(vec)
 
     def parse(self):
         self.output_file = self.ramdump.open_file('timerlist.txt')
-
         self.get_timer_list()
 
         self.output_file.close()
-- 
GitLab