|
|
99c779 |
From a5fb8431d9888cbd4b40e6435d4379bf0c86cdec Mon Sep 17 00:00:00 2001
|
|
|
99c779 |
From: Lyonel Vincent <lyonel@ezix.org>
|
|
|
99c779 |
Date: Thu, 20 Oct 2016 00:27:58 +0200
|
|
|
99c779 |
Subject: [PATCH 18/43] merge github pull request 23: parse CPU information
|
|
|
99c779 |
|
|
|
99c779 |
FIXME: `dimminfo` magic needs cleansing, ugly code getting uglier
|
|
|
99c779 |
---
|
|
|
99c779 |
src/core/device-tree.cc | 267 ++++++++++++++++++++++++++++++++++++++++++------
|
|
|
99c779 |
1 file changed, 237 insertions(+), 30 deletions(-)
|
|
|
99c779 |
|
|
|
99c779 |
diff --git a/src/core/device-tree.cc b/src/core/device-tree.cc
|
|
|
99c779 |
index c2b7d15..700dff0 100644
|
|
|
99c779 |
--- a/src/core/device-tree.cc
|
|
|
99c779 |
+++ b/src/core/device-tree.cc
|
|
|
99c779 |
@@ -26,6 +26,8 @@
|
|
|
99c779 |
#include <string.h>
|
|
|
99c779 |
#include <unistd.h>
|
|
|
99c779 |
#include <dirent.h>
|
|
|
99c779 |
+#include <utility>
|
|
|
99c779 |
+#include <map>
|
|
|
99c779 |
|
|
|
99c779 |
__ID("@(#) $Id$");
|
|
|
99c779 |
|
|
|
99c779 |
@@ -227,6 +229,42 @@ static string cpubusinfo(int cpu)
|
|
|
99c779 |
}
|
|
|
99c779 |
|
|
|
99c779 |
|
|
|
99c779 |
+static void set_cpu(hwNode & cpu, int currentcpu, const string & basepath)
|
|
|
99c779 |
+{
|
|
|
99c779 |
+ cpu.setProduct(get_string(basepath + "/name"));
|
|
|
99c779 |
+ cpu.claim();
|
|
|
99c779 |
+ cpu.setBusInfo(cpubusinfo(currentcpu));
|
|
|
99c779 |
+
|
|
|
99c779 |
+ cpu.setSize(get_u32(basepath + "/clock-frequency"));
|
|
|
99c779 |
+ cpu.setClock(get_u32(basepath + "/bus-frequency"));
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(basepath + "/altivec"))
|
|
|
99c779 |
+ cpu.addCapability("altivec");
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(basepath + "/performance-monitor"))
|
|
|
99c779 |
+ cpu.addCapability("performance-monitor");
|
|
|
99c779 |
+}
|
|
|
99c779 |
+
|
|
|
99c779 |
+
|
|
|
99c779 |
+static void fill_cache_info(string cache_type, string cachebase,
|
|
|
99c779 |
+ hwNode & cache, hwNode & icache)
|
|
|
99c779 |
+{
|
|
|
99c779 |
+ cache.claim();
|
|
|
99c779 |
+ cache.setDescription(cache_type);
|
|
|
99c779 |
+ cache.setSize(get_u32(cachebase + "/d-cache-size"));
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(cachebase + "/cache-unified"))
|
|
|
99c779 |
+ cache.setDescription(cache.getDescription() + " (unified)");
|
|
|
99c779 |
+ else
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ icache = cache;
|
|
|
99c779 |
+ cache.setDescription(cache.getDescription() + " (data)");
|
|
|
99c779 |
+ icache.setDescription(icache.getDescription() + " (instruction)");
|
|
|
99c779 |
+ icache.setSize(get_u32(cachebase + "/i-cache-size"));
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+}
|
|
|
99c779 |
+
|
|
|
99c779 |
+
|
|
|
99c779 |
static void scan_devtree_cpu(hwNode & core)
|
|
|
99c779 |
{
|
|
|
99c779 |
struct dirent **namelist;
|
|
|
99c779 |
@@ -254,14 +292,8 @@ static void scan_devtree_cpu(hwNode & core)
|
|
|
99c779 |
hw::strip(get_string(basepath + "/device_type")) != "cpu")
|
|
|
99c779 |
break; // oops, not a CPU!
|
|
|
99c779 |
|
|
|
99c779 |
- cpu.setProduct(get_string(basepath + "/name"));
|
|
|
99c779 |
cpu.setDescription("CPU");
|
|
|
99c779 |
- cpu.claim();
|
|
|
99c779 |
- cpu.setBusInfo(cpubusinfo(currentcpu++));
|
|
|
99c779 |
- cpu.setSize(get_u32(basepath + "/clock-frequency"));
|
|
|
99c779 |
- cpu.setClock(get_u32(basepath + "/bus-frequency"));
|
|
|
99c779 |
- if (exists(basepath + "/altivec"))
|
|
|
99c779 |
- cpu.addCapability("altivec");
|
|
|
99c779 |
+ set_cpu(cpu, currentcpu++, basepath);
|
|
|
99c779 |
|
|
|
99c779 |
version = get_u32(basepath + "/cpu-version");
|
|
|
99c779 |
if (version != 0)
|
|
|
99c779 |
@@ -273,14 +305,11 @@ static void scan_devtree_cpu(hwNode & core)
|
|
|
99c779 |
snprintf(buffer, sizeof(buffer), "%lx.%d.%d",
|
|
|
99c779 |
(version & 0xffff0000) >> 16, major, minor);
|
|
|
99c779 |
cpu.setVersion(buffer);
|
|
|
99c779 |
-
|
|
|
99c779 |
}
|
|
|
99c779 |
+
|
|
|
99c779 |
if (hw::strip(get_string(basepath + "/state")) != "running")
|
|
|
99c779 |
cpu.disable();
|
|
|
99c779 |
|
|
|
99c779 |
- if (exists(basepath + "/performance-monitor"))
|
|
|
99c779 |
- cpu.addCapability("performance-monitor");
|
|
|
99c779 |
-
|
|
|
99c779 |
if (exists(basepath + "/d-cache-size"))
|
|
|
99c779 |
{
|
|
|
99c779 |
hwNode cache("cache",
|
|
|
99c779 |
@@ -302,29 +331,19 @@ static void scan_devtree_cpu(hwNode & core)
|
|
|
99c779 |
{
|
|
|
99c779 |
hwNode cache("cache",
|
|
|
99c779 |
hw::memory);
|
|
|
99c779 |
+ hwNode icache("cache",
|
|
|
99c779 |
+ hw::memory);
|
|
|
99c779 |
string cachebase = basepath + "/" + cachelist[j]->d_name;
|
|
|
99c779 |
|
|
|
99c779 |
if (hw::strip(get_string(cachebase + "/device_type")) != "cache" &&
|
|
|
99c779 |
hw::strip(get_string(cachebase + "/device_type")) != "l2-cache")
|
|
|
99c779 |
break; // oops, not a cache!
|
|
|
99c779 |
|
|
|
99c779 |
- cache.claim();
|
|
|
99c779 |
- cache.setDescription("L2 Cache");
|
|
|
99c779 |
- cache.setSize(get_u32(cachebase + "/d-cache-size"));
|
|
|
99c779 |
- cache.setClock(get_u32(cachebase + "/clock-frequency"));
|
|
|
99c779 |
+ cache.setClock(get_u32(cachebase + "/clock-frequency"));
|
|
|
99c779 |
+ fill_cache_info("L2 Cache", cachebase, cache, icache);
|
|
|
99c779 |
|
|
|
99c779 |
- if (exists(cachebase + "/cache-unified"))
|
|
|
99c779 |
- cache.setDescription(cache.getDescription() + " (unified)");
|
|
|
99c779 |
- else
|
|
|
99c779 |
- {
|
|
|
99c779 |
- hwNode icache = cache;
|
|
|
99c779 |
- cache.setDescription(cache.getDescription() + " (data)");
|
|
|
99c779 |
- icache.setDescription(icache.getDescription() + " (instruction)");
|
|
|
99c779 |
- icache.setSize(get_u32(cachebase + "/i-cache-size"));
|
|
|
99c779 |
-
|
|
|
99c779 |
- if (icache.getSize() > 0)
|
|
|
99c779 |
- cpu.addChild(icache);
|
|
|
99c779 |
- }
|
|
|
99c779 |
+ if (icache.getSize() > 0)
|
|
|
99c779 |
+ cpu.addChild(icache);
|
|
|
99c779 |
|
|
|
99c779 |
if (cache.getSize() > 0)
|
|
|
99c779 |
cpu.addChild(cache);
|
|
|
99c779 |
@@ -342,6 +361,191 @@ static void scan_devtree_cpu(hwNode & core)
|
|
|
99c779 |
}
|
|
|
99c779 |
}
|
|
|
99c779 |
|
|
|
99c779 |
+static void set_cpu_config_threads(hwNode & cpu, const string & basepath)
|
|
|
99c779 |
+{
|
|
|
99c779 |
+ static int threads_per_cpu = 0;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ /* In power systems, there are equal no. of threads per cpu-core */
|
|
|
99c779 |
+ if (threads_per_cpu == 0)
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ int rc;
|
|
|
99c779 |
+ struct stat sbuf;
|
|
|
99c779 |
+ string p = hw::strip(basepath + string("/ibm,ppc-interrupt-server#s"));
|
|
|
99c779 |
+
|
|
|
99c779 |
+ /*
|
|
|
99c779 |
+ * This file contains as many 32 bit interrupt server numbers, as the
|
|
|
99c779 |
+ * number of threads per CPU (in hexadecimal format). st_size gives size
|
|
|
99c779 |
+ * in bytes of a file. Hence, grouping by 4 bytes, we get the thread
|
|
|
99c779 |
+ * count.
|
|
|
99c779 |
+ */
|
|
|
99c779 |
+ rc = stat(p.c_str(), &sbuf);
|
|
|
99c779 |
+ if (!rc)
|
|
|
99c779 |
+ threads_per_cpu = sbuf.st_size / 4;
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+
|
|
|
99c779 |
+ cpu.setConfig("threads", threads_per_cpu);
|
|
|
99c779 |
+}
|
|
|
99c779 |
+
|
|
|
99c779 |
+
|
|
|
99c779 |
+static void scan_devtree_cpu_power(hwNode & core)
|
|
|
99c779 |
+{
|
|
|
99c779 |
+ int n;
|
|
|
99c779 |
+ int currentcpu = 0;
|
|
|
99c779 |
+ struct dirent **namelist;
|
|
|
99c779 |
+ map <uint32_t, pair<uint32_t, vector <hwNode> > > l2_caches;
|
|
|
99c779 |
+ map <uint32_t, vector <hwNode> > l3_caches;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ pushd(DEVICETREE "/cpus");
|
|
|
99c779 |
+ n = scandir(".", &namelist, selectdir, alphasort);
|
|
|
99c779 |
+ popd();
|
|
|
99c779 |
+ if (n < 0)
|
|
|
99c779 |
+ return;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ /*
|
|
|
99c779 |
+ * 'cpus' node contains CPU, L2 and L3 cache nodes. L1 cache information is
|
|
|
99c779 |
+ * available under CPU node itself. l2-cache (or next-level-cache) property
|
|
|
99c779 |
+ * contains next level cache node phandle/ibm,phanle number.
|
|
|
99c779 |
+ * First pass creates cache nodes and second pass will link cache nodes to
|
|
|
99c779 |
+ * corresponding CPU nodes.
|
|
|
99c779 |
+ */
|
|
|
99c779 |
+ for (int i = 0; i < n; i++)
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ string product;
|
|
|
99c779 |
+ string basepath = string(DEVICETREE "/cpus/") + string(namelist[i]->d_name);
|
|
|
99c779 |
+ hwNode cache("cache", hw::memory);
|
|
|
99c779 |
+ hwNode icache("cache", hw::memory);
|
|
|
99c779 |
+ vector <hwNode> value;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (!exists(basepath + "/device_type"))
|
|
|
99c779 |
+ continue;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (hw::strip(get_string(basepath + "/device_type")) != "cache")
|
|
|
99c779 |
+ continue;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ product = hw::strip(get_string(basepath + "/name"));
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (hw::strip(get_string(basepath + "/status")) != "okay")
|
|
|
99c779 |
+ cache.disable();
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (product == "l2-cache")
|
|
|
99c779 |
+ fill_cache_info("L2 Cache", basepath, cache, icache);
|
|
|
99c779 |
+ else
|
|
|
99c779 |
+ fill_cache_info("L3 Cache", basepath, cache, icache);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (icache.getSize() > 0)
|
|
|
99c779 |
+ value.insert(value.begin(), icache);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (cache.getSize() > 0)
|
|
|
99c779 |
+ value.insert(value.begin(), cache);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (value.size() > 0)
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ uint32_t phandle = 0;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(basepath + "/phandle"))
|
|
|
99c779 |
+ phandle = get_u32(basepath + "/phandle");
|
|
|
99c779 |
+ else if (exists(basepath + "/ibm,phandle")) // on pSeries LPARs
|
|
|
99c779 |
+ phandle = get_u32(basepath + "/ibm,phandle");
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (!phandle)
|
|
|
99c779 |
+ continue;
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (product == "l2-cache")
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ uint32_t l3_key = 0; // 0 indicating no next level of cache
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(basepath + "/l2-cache"))
|
|
|
99c779 |
+ l3_key = get_u32(basepath + "/l2-cache");
|
|
|
99c779 |
+ else if (exists(basepath + "/next-level-cache")) //on OpenPOWER systems
|
|
|
99c779 |
+ l3_key = get_u32(basepath + "/next-level-cache");
|
|
|
99c779 |
+
|
|
|
99c779 |
+ pair <uint32_t, vector <hwNode> > p (l3_key, value);
|
|
|
99c779 |
+ l2_caches[phandle] = p;
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+ else if (product == "l3-cache")
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ l3_caches[phandle] = value;
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+ } // first pass end
|
|
|
99c779 |
+
|
|
|
99c779 |
+ for (int i = 0; i < n; i++) //second and final pass
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ uint32_t l2_key = 0;
|
|
|
99c779 |
+ uint32_t version = 0;
|
|
|
99c779 |
+ string basepath = string(DEVICETREE "/cpus/") + string(namelist[i]->d_name);
|
|
|
99c779 |
+ hwNode cpu("cpu", hw::processor);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (!exists(basepath + "/device_type"))
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ free(namelist[i]);
|
|
|
99c779 |
+ continue;
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (hw::strip(get_string(basepath + "/device_type")) != "cpu")
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ free(namelist[i]);
|
|
|
99c779 |
+ continue;
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+
|
|
|
99c779 |
+ cpu.setDescription("CPU");
|
|
|
99c779 |
+ set_cpu(cpu, currentcpu++, basepath);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ version = get_u32(basepath + "/cpu-version");
|
|
|
99c779 |
+ if (version != 0)
|
|
|
99c779 |
+ cpu.setVersion(tostring(version));
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (hw::strip(get_string(basepath + "/status")) != "okay")
|
|
|
99c779 |
+ cpu.disable();
|
|
|
99c779 |
+
|
|
|
99c779 |
+ set_cpu_config_threads(cpu, basepath);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(basepath + "/d-cache-size"))
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ hwNode cache("cache", hw::memory);
|
|
|
99c779 |
+ hwNode icache("cache", hw::memory);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ fill_cache_info("L1 Cache", basepath, cache, icache);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (icache.getSize() > 0)
|
|
|
99c779 |
+ cpu.addChild(icache);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (cache.getSize() > 0)
|
|
|
99c779 |
+ cpu.addChild(cache);
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (exists(basepath + "/l2-cache"))
|
|
|
99c779 |
+ l2_key = get_u32(basepath + "/l2-cache");
|
|
|
99c779 |
+ else if (exists(basepath + "/next-level-cache"))
|
|
|
99c779 |
+ l2_key = get_u32(basepath + "/next-level-cache");
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (l2_key != 0)
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ map <uint32_t, pair <uint32_t, vector <hwNode> > >::
|
|
|
99c779 |
+ const_iterator got = l2_caches.find(l2_key);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (!(got == l2_caches.end()))
|
|
|
99c779 |
+ for (uint32_t j = 0; j < (got->second).second.size(); j++)
|
|
|
99c779 |
+ cpu.addChild((got->second).second[j]);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if ((got->second).first != 0) // we have another level of cache
|
|
|
99c779 |
+ {
|
|
|
99c779 |
+ map <uint32_t, vector <hwNode> >::const_iterator got_l3 =
|
|
|
99c779 |
+ l3_caches.find ((got->second).first);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ if (!(got_l3 == l3_caches.end()))
|
|
|
99c779 |
+ for (uint32_t j = 0; j < (got_l3->second).size(); j++)
|
|
|
99c779 |
+ cpu.addChild((got_l3->second)[j]);
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+
|
|
|
99c779 |
+ core.addChild(cpu);
|
|
|
99c779 |
+
|
|
|
99c779 |
+ free(namelist[i]);
|
|
|
99c779 |
+ }
|
|
|
99c779 |
+ free(namelist);
|
|
|
99c779 |
+}
|
|
|
99c779 |
+
|
|
|
99c779 |
void add_memory_bank(string name, string path, hwNode & core)
|
|
|
99c779 |
{
|
|
|
99c779 |
struct dirent **dirlist;
|
|
|
99c779 |
@@ -728,7 +932,7 @@ bool scan_device_tree(hwNode & n)
|
|
|
99c779 |
core->addHint("icon", string("board"));
|
|
|
99c779 |
scan_devtree_root(*core);
|
|
|
99c779 |
scan_devtree_memory_powernv(*core);
|
|
|
99c779 |
- scan_devtree_cpu(*core);
|
|
|
99c779 |
+ scan_devtree_cpu_power(*core);
|
|
|
99c779 |
n.addCapability("powernv", "Non-virtualized");
|
|
|
99c779 |
n.addCapability("opal", "OPAL firmware");
|
|
|
99c779 |
}
|
|
|
99c779 |
@@ -764,7 +968,7 @@ bool scan_device_tree(hwNode & n)
|
|
|
99c779 |
{
|
|
|
99c779 |
core->addHint("icon", string("board"));
|
|
|
99c779 |
scan_devtree_root(*core);
|
|
|
99c779 |
- scan_devtree_cpu(*core);
|
|
|
99c779 |
+ scan_devtree_cpu_power(*core);
|
|
|
99c779 |
core->addCapability("qemu", "QEMU virtualization");
|
|
|
99c779 |
core->addCapability("guest", "Virtualization guest");
|
|
|
99c779 |
}
|
|
|
99c779 |
@@ -779,7 +983,10 @@ bool scan_device_tree(hwNode & n)
|
|
|
99c779 |
scan_devtree_root(*core);
|
|
|
99c779 |
scan_devtree_bootrom(*core);
|
|
|
99c779 |
scan_devtree_memory(*core);
|
|
|
99c779 |
- scan_devtree_cpu(*core);
|
|
|
99c779 |
+ if (exists(DEVICETREE "/ibm,lpar-capable"))
|
|
|
99c779 |
+ scan_devtree_cpu_power(*core);
|
|
|
99c779 |
+ else
|
|
|
99c779 |
+ scan_devtree_cpu(*core);
|
|
|
99c779 |
}
|
|
|
99c779 |
}
|
|
|
99c779 |
|
|
|
99c779 |
--
|
|
|
99c779 |
2.10.2
|
|
|
99c779 |
|