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