* [PATCH v3 0/3] lspci: Add support of JSON output format
@ 2018-02-18 23:12 Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 1/3] lspci: Add printing info in JSON format Viktor Prutyanov
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Viktor Prutyanov @ 2018-02-18 23:12 UTC (permalink / raw)
To: linux-pci, mj; +Cc: Viktor Prutyanov
This collection of patches adds support of printing PCI info in JSON
format.
1st patch adds skeleton for creating structured object which can be
printed in JSON or another structured format.
2nd patch adds output of general PCI info which prints with -m, -k,
-[v]+ options, but without capabilities.
3rd patch adds PCI-E capability.
For example, we can easily, using jq utility, check speed of a device:
lspci -Jvv | jq -r '.[][] | select(.Device == "GK107M [GeForce GT 750M]") | .capabilities.express | {s1:.LnkCap.Speed, s2:.LnkSta.Speed, w1
:.LnkCap.Width, w2:.LnkSta.Width }'
{
"s1": "8GT/s",
"s2": "5GT/s",
"w1": "x16",
"w2": "x4"
}
Viktor Prutyanov (3):
lspci: Add printing info in JSON format
lspci: Add PCI info output in JSON format
lspci: Add JSON PCI Express capabilities
Makefile | 3 +-
common.c | 2 +-
ls-caps.c | 417 +++++++++++++++++++++++++++++++++++
ls-info.c | 328 ++++++++++++++++++++++++++++
ls-kernel.c | 24 +++
lspci.c | 706 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
lspci.h | 56 +++++
lspci.man | 3 +
pciutils.h | 2 +-
9 files changed, 1537 insertions(+), 4 deletions(-)
create mode 100644 ls-info.c
--
2.14.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/3] lspci: Add printing info in JSON format
2018-02-18 23:12 [PATCH v3 0/3] lspci: Add support of JSON output format Viktor Prutyanov
@ 2018-02-18 23:12 ` Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 2/3] lspci: Add PCI info output " Viktor Prutyanov
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Viktor Prutyanov @ 2018-02-18 23:12 UTC (permalink / raw)
To: linux-pci, mj; +Cc: Viktor Prutyanov
This patch adds saving objects and lists and printing them in JSON format
Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com>
---
common.c | 2 +-
ls-info.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lspci.h | 54 ++++++++++
pciutils.h | 2 +-
4 files changed, 384 insertions(+), 2 deletions(-)
create mode 100644 ls-info.c
diff --git a/common.c b/common.c
index 8ea52fa..9654feb 100644
--- a/common.c
+++ b/common.c
@@ -45,7 +45,7 @@ xrealloc(void *ptr, unsigned int howmuch)
}
char *
-xstrdup(char *str)
+xstrdup(const char *str)
{
int len = strlen(str) + 1;
char *copy = xmalloc(len);
diff --git a/ls-info.c b/ls-info.c
new file mode 100644
index 0000000..e1430aa
--- /dev/null
+++ b/ls-info.c
@@ -0,0 +1,328 @@
+/*
+ * The PCI Utilities -- Save PCI info
+ *
+ * Copyright (c) 2017 Virtuozzo International GmbH
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "lspci.h"
+
+struct info_list *
+info_list_create(enum info_val_type type)
+{
+ struct info_list *list = xmalloc(sizeof(struct info_list));
+
+ list->node = NULL;
+ list->type = type;
+
+ return list;
+}
+
+struct info_list *
+info_list_create_in_obj(struct info_obj *parent_obj, char *key, enum info_val_type type)
+{
+ struct info_list *list = info_list_create(type);
+
+ info_obj_add_list(parent_obj, key, list);
+
+ return list;
+}
+
+static void
+info_list_delete(struct info_list *list)
+{
+ struct info_list_node *node = list->node, *next;
+
+ while (node)
+ {
+ switch (list->type)
+ {
+ case INFO_VAL_STRING:
+ free(node->val.str);
+ break;
+ case INFO_VAL_LIST:
+ info_list_delete(node->val.list);
+ break;
+ case INFO_VAL_OBJECT:
+ info_obj_delete(node->val.obj);
+ break;
+ default:
+ break;
+ }
+ next = node->next;
+ free(node);
+ node = next;
+ }
+ free(list);
+}
+
+struct info_obj *
+info_obj_create(void)
+{
+ struct info_obj *obj = xmalloc(sizeof(struct info_obj));
+
+ obj->pair = NULL;
+
+ return obj;
+}
+
+struct info_obj *
+info_obj_create_in_obj(struct info_obj *parent_obj, char *key)
+{
+ struct info_obj *obj = info_obj_create();
+
+ info_obj_add_obj(parent_obj, key, obj);
+
+ return obj;
+}
+
+static void
+info_pair_delete(struct info_pair *pair)
+{
+ switch (pair->type)
+ {
+ case INFO_VAL_STRING:
+ free(pair->val.str);
+ break;
+ case INFO_VAL_LIST:
+ info_list_delete(pair->val.list);
+ break;
+ case INFO_VAL_OBJECT:
+ info_obj_delete(pair->val.obj);
+ break;
+ default:
+ break;
+ }
+ free(pair->key);
+ free(pair);
+}
+
+void
+info_obj_delete(struct info_obj *obj)
+{
+ struct info_pair *pair = obj->pair, *next;
+
+ while (pair)
+ {
+ next = pair->next;
+ info_pair_delete(pair);
+ pair = next;
+ }
+ free(obj);
+}
+
+void
+info_obj_delete_pair(struct info_obj *obj, char *key)
+{
+ struct info_pair *pair = obj->pair, *next, *prev = NULL;
+
+ while (pair)
+ {
+ next = pair->next;
+ if (!strcmp(pair->key, key))
+ {
+ info_pair_delete(pair);
+ if (prev)
+ prev->next = next;
+ else
+ obj->pair = next;
+ break;
+ }
+ prev = pair;
+ pair = next;
+ }
+}
+
+static struct info_list_node *
+info_list_add_node(struct info_list *list)
+{
+ struct info_list_node *new_node = xmalloc(sizeof(struct info_list_node));
+
+ new_node->next = NULL;
+
+ if (list->node)
+ {
+ struct info_list_node *node;
+
+ for (node = list->node; node && node->next; node = node->next);
+ node->next = new_node;
+ }
+ else
+ list->node = new_node;
+
+ return new_node;
+}
+
+void
+info_list_add_str(struct info_list *list, const char *str)
+{
+ struct info_list_node *new_node = info_list_add_node(list);
+
+ new_node->val.str = xstrdup(str);
+}
+
+void
+info_list_add_obj(struct info_list *list, struct info_obj *obj)
+{
+ struct info_list_node *new_node = info_list_add_node(list);
+
+ new_node->val.obj = obj;
+}
+
+static struct info_pair *
+info_obj_add_pair(struct info_obj *obj, const char *key, enum info_val_type type)
+{
+ struct info_pair *new_pair = xmalloc(sizeof(struct info_pair));
+ new_pair->key = xstrdup(key);
+ new_pair->next = NULL;
+ new_pair->type = type;
+
+ if (obj->pair)
+ {
+ struct info_pair *pair;
+
+ for (pair = obj->pair; pair && pair->next; pair = pair->next);
+ pair->next = new_pair;
+ }
+ else
+ obj->pair = new_pair;
+
+ return new_pair;
+}
+
+void
+info_obj_add_flag(struct info_obj *obj, const char *key, char flag)
+{
+ struct info_pair *new_pair = info_obj_add_pair(obj, key, INFO_VAL_FLAG);
+
+ new_pair->val.flag = flag;
+}
+
+void
+info_obj_add_str(struct info_obj *obj, const char *key, const char *str)
+{
+ struct info_pair *new_pair = info_obj_add_pair(obj, key, INFO_VAL_STRING);
+
+ new_pair->val.str = xstrdup(str);
+}
+
+void
+info_obj_add_fmt_buf_str(struct info_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+
+ info_obj_add_str(obj, key, buf);
+}
+
+void
+info_obj_add_fmt_str(struct info_obj *obj, const char *key, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = xmalloc(size);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+
+ info_obj_add_str(obj, key, buf);
+ free(buf);
+}
+
+void
+info_obj_add_list(struct info_obj *obj, const char *key, struct info_list *list)
+{
+ struct info_pair *new_pair = info_obj_add_pair(obj, key, INFO_VAL_LIST);
+
+ new_pair->val.list = list;
+}
+
+void
+info_obj_add_obj(struct info_obj *obj, const char *key, struct info_obj *new_obj)
+{
+ struct info_pair *new_pair = info_obj_add_pair(obj, key, INFO_VAL_OBJECT);
+
+ new_pair->val.obj = new_obj;
+}
+
+static void
+info_pair_print_json(struct info_pair *pair);
+
+void
+info_obj_print_json(struct info_obj *obj)
+{
+ struct info_pair *pair;
+
+ printf("{");
+ for (pair = obj->pair; pair; pair = pair->next)
+ {
+ info_pair_print_json(pair);
+ if (pair->next)
+ printf(", ");
+ }
+ printf("}");
+}
+
+static void
+info_list_print_json(struct info_list *list)
+{
+ struct info_list_node *node;
+
+ printf("[");
+ for (node = list->node; node; node = node->next)
+ {
+ switch (list->type)
+ {
+ case INFO_VAL_STRING:
+ printf("\"%s\"", node->val.str);
+ break;
+ case INFO_VAL_LIST:
+ info_list_print_json(node->val.list);
+ break;
+ case INFO_VAL_OBJECT:
+ info_obj_print_json(node->val.obj);
+ break;
+ case INFO_VAL_FLAG:
+ printf("%s", node->val.flag ? "true" : "false");
+ break;
+ default:
+ break;
+ }
+ if (node->next)
+ printf(", ");
+ }
+ printf("]");
+}
+
+static void
+info_pair_print_json(struct info_pair *pair)
+{
+ printf("\"%s\": ", pair->key);
+ switch (pair->type)
+ {
+ case INFO_VAL_STRING:
+ printf("\"%s\"", pair->val.str);
+ break;
+ case INFO_VAL_LIST:
+ info_list_print_json(pair->val.list);
+ break;
+ case INFO_VAL_OBJECT:
+ info_obj_print_json(pair->val.obj);
+ break;
+ case INFO_VAL_FLAG:
+ printf("%s", (pair->val.flag == '+') ? "true" :
+ ((pair->val.flag == '-') ? "false" : "null"));
+ break;
+ default:
+ break;
+ }
+}
diff --git a/lspci.h b/lspci.h
index bcd007e..ba5a56b 100644
--- a/lspci.h
+++ b/lspci.h
@@ -74,6 +74,60 @@ void show_ext_caps(struct device *d, int type);
void show_vendor_caps(struct device *d, int where, int cap);
+/* ls-info.c */
+
+enum info_val_type {
+ INFO_VAL_STRING,
+ INFO_VAL_OBJECT,
+ INFO_VAL_LIST,
+ INFO_VAL_FLAG
+};
+
+struct info_obj {
+ struct info_pair *pair;
+};
+
+union info_val {
+ char *str;
+ struct info_obj *obj;
+ struct info_list *list;
+ char flag;
+};
+
+struct info_pair {
+ char *key;
+ enum info_val_type type;
+ union info_val val;
+ struct info_pair *next;
+};
+
+struct info_list {
+ enum info_val_type type;
+ struct info_list_node *node;
+};
+
+struct info_list_node {
+ union info_val val;
+ struct info_list_node *next;
+};
+
+struct info_obj *info_obj_create(void);
+struct info_obj *info_obj_create_in_obj(struct info_obj *parent_obj, char *key);
+void info_obj_add_str(struct info_obj *obj, const char *key, const char *str);
+void info_obj_add_list(struct info_obj *obj, const char *key, struct info_list *list);
+void info_obj_add_obj(struct info_obj *obj, const char *key, struct info_obj *new_obj);
+void info_obj_add_flag(struct info_obj *obj, const char *key, char flag);
+void info_obj_add_fmt_str(struct info_obj *obj, const char *key, size_t size, const char *fmt, ...);
+void info_obj_add_fmt_buf_str(struct info_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...);
+void info_obj_print_json(struct info_obj *obj);
+void info_obj_delete_pair(struct info_obj *obj, char *key);
+void info_obj_delete(struct info_obj *obj);
+
+struct info_list *info_list_create(enum info_val_type type);
+struct info_list *info_list_create_in_obj(struct info_obj *parent_obj, char *key, enum info_val_type type);
+void info_list_add_str(struct info_list *list, const char *str);
+void info_list_add_obj(struct info_list *list, struct info_obj *obj);
+
/* ls-kernel.c */
void show_kernel_machine(struct device *d UNUSED);
diff --git a/pciutils.h b/pciutils.h
index e433e6b..53a868b 100644
--- a/pciutils.h
+++ b/pciutils.h
@@ -22,7 +22,7 @@ extern const char program_name[];
void die(char *msg, ...) NONRET PCI_PRINTF(1,2);
void *xmalloc(unsigned int howmuch);
void *xrealloc(void *ptr, unsigned int howmuch);
-char *xstrdup(char *str);
+char *xstrdup(const char *str);
int parse_generic_option(int i, struct pci_access *pacc, char *optarg);
#ifdef PCI_HAVE_PM_INTEL_CONF
--
2.14.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/3] lspci: Add PCI info output in JSON format
2018-02-18 23:12 [PATCH v3 0/3] lspci: Add support of JSON output format Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 1/3] lspci: Add printing info in JSON format Viktor Prutyanov
@ 2018-02-18 23:12 ` Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 3/3] lspci: Add JSON PCI Express capabilities Viktor Prutyanov
2018-03-11 15:03 ` [PATCH v3 0/3] lspci: Add support of JSON output format viktor.prutyanov
3 siblings, 0 replies; 5+ messages in thread
From: Viktor Prutyanov @ 2018-02-18 23:12 UTC (permalink / raw)
To: linux-pci, mj; +Cc: Viktor Prutyanov
This patch adds '-J' option for output in JSON format.
When this option is enabled, the output contains the same data as without it,
except for capabilities.
Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com>
---
Makefile | 3 +-
ls-kernel.c | 24 +++
lspci.c | 701 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
lspci.h | 1 +
lspci.man | 3 +
5 files changed, 730 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 8c7edb7..5bdf84d 100644
--- a/Makefile
+++ b/Makefile
@@ -69,7 +69,7 @@ force:
lib/config.h lib/config.mk:
cd lib && ./configure
-lspci: lspci.o ls-vpd.o ls-caps.o ls-caps-vendor.o ls-ecaps.o ls-kernel.o ls-tree.o ls-map.o common.o lib/$(PCILIB)
+lspci: lspci.o ls-vpd.o ls-caps.o ls-caps-vendor.o ls-ecaps.o ls-kernel.o ls-tree.o ls-map.o ls-info.o common.o lib/$(PCILIB)
setpci: setpci.o common.o lib/$(PCILIB)
LSPCIINC=lspci.h pciutils.h $(PCIINC)
@@ -80,6 +80,7 @@ ls-ecaps.o: ls-ecaps.c $(LSPCIINC)
ls-kernel.o: ls-kernel.c $(LSPCIINC)
ls-tree.o: ls-tree.c $(LSPCIINC)
ls-map.o: ls-map.c $(LSPCIINC)
+ls-info.o: ls-info.c $(LSPCIINC)
setpci.o: setpci.c pciutils.h $(PCIINC)
common.o: common.c pciutils.h $(PCIINC)
diff --git a/ls-kernel.c b/ls-kernel.c
index ecacd0e..b0ded3b 100644
--- a/ls-kernel.c
+++ b/ls-kernel.c
@@ -302,6 +302,25 @@ show_kernel_machine(struct device *d)
printf("Module:\t%s\n", module);
}
+void
+fill_info_kernel(struct info_obj *dev_obj, struct device *d)
+{
+ char buf[DRIVER_BUF_SIZE];
+ const char *driver, *module;
+
+ if (driver = find_driver(d, buf))
+ info_obj_add_str(dev_obj, "Driver", driver);
+
+ if (!show_kernel_init())
+ return;
+
+ struct info_list *mod_list = info_list_create(INFO_VAL_STRING);
+ while (module = next_module_filtered(d))
+ info_list_add_str(mod_list, module);
+
+ info_obj_add_list(dev_obj, "Modules", mod_list);
+}
+
#else
void
@@ -319,5 +338,10 @@ show_kernel_cleanup(void)
{
}
+void
+fill_info_kernel(struct info_obj *dev_obj UNUSED, struct device *d UNUSED)
+{
+}
+
#endif
diff --git a/lspci.c b/lspci.c
index b50c76a..ae50a85 100644
--- a/lspci.c
+++ b/lspci.c
@@ -25,11 +25,12 @@ static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2
static int opt_kernel; /* Show kernel drivers */
static int opt_query_dns; /* Query the DNS (0=disabled, 1=enabled, 2=refresh cache) */
static int opt_query_all; /* Query the DNS for all entries */
+static int opt_json;
char *opt_pcimap; /* Override path to Linux modules.pcimap */
const char program_name[] = "lspci";
-static char options[] = "nvbxs:d:ti:mgp:qkMDQ" GENERIC_OPTIONS ;
+static char options[] = "nvbxs:d:ti:mgp:qkJMDQ" GENERIC_OPTIONS ;
static char help_msg[] =
"Usage: lspci [<switches>]\n"
@@ -48,6 +49,7 @@ static char help_msg[] =
"-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n"
"-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n"
"-D\t\tAlways show domain numbers\n"
+"-J\t\tUse JSON output format\n"
"\n"
"Resolving of device ID's to names:\n"
"-n\t\tShow numeric ID's\n"
@@ -257,6 +259,16 @@ show_slot_name(struct device *d)
printf("%02x:%02x.%d", p->bus, p->dev, p->func);
}
+static void
+fill_slot_name(struct device *d, char *buf, size_t size)
+{
+ struct pci_dev *p = d->dev;
+
+ if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2))
+ snprintf(buf, size, "%04x:", p->domain);
+ snprintf(buf, size, "%02x:%02x.%d", p->bus, p->dev, p->func);
+}
+
void
get_subid(struct device *d, word *subvp, word *subdp)
{
@@ -343,6 +355,24 @@ show_size(u64 x)
printf(" [size=%u%s]", (unsigned)x, suffix[i]);
}
+static void
+fill_size(char *buf, size_t size, u64 x)
+{
+ static const char suffix[][2] = { "", "K", "M", "G", "T" };
+ unsigned i;
+ if (!x)
+ {
+ snprintf(buf, size, "0");
+ return;
+ }
+ for (i = 0; i < (sizeof(suffix) / sizeof(*suffix) - 1); i++) {
+ if (x % 1024)
+ break;
+ x /= 1024;
+ }
+ snprintf(buf, size, "%u%s", (unsigned)x, suffix[i]);
+}
+
static void
show_range(char *prefix, u64 base, u64 limit, int is_64bit)
{
@@ -369,6 +399,21 @@ show_range(char *prefix, u64 base, u64 limit, int is_64bit)
putchar('\n');
}
+static void
+fill_range(char *buf, size_t size, u64 base, u64 limit, int is_64bit)
+{
+ if (base > limit)
+ {
+ snprintf(buf, size, "None");
+ return;
+ }
+
+ if (is_64bit)
+ snprintf(buf, size, "%016" PCI_U64_FMT_X "-%016" PCI_U64_FMT_X, base, limit);
+ else
+ snprintf(buf, size, "%08x-%08x", (unsigned) base, (unsigned) limit);
+}
+
static void
show_bases(struct device *d, int cnt)
{
@@ -840,6 +885,30 @@ show_hex_dump(struct device *d)
}
}
+static void
+fill_info_hex_dump(struct info_obj *dev_obj, struct device *d)
+{
+ unsigned int i, cnt;
+ char buf[3] = {0};
+ struct info_list *hex_dump_list = info_list_create(INFO_VAL_STRING);
+
+ cnt = d->config_cached;
+ if (opt_hex >= 3 && config_fetch(d, cnt, 256-cnt))
+ {
+ cnt = 256;
+ if (opt_hex >= 4 && config_fetch(d, 256, 4096-256))
+ cnt = 4096;
+ }
+
+ for (i=0; i<cnt; i++)
+ {
+ snprintf(buf, sizeof(buf), "%02x", get_conf_byte(d, i));
+ info_list_add_str(hex_dump_list, buf);
+ }
+
+ info_obj_add_list(dev_obj, "hexdump", hex_dump_list);
+}
+
static void
print_shell_escaped(char *c)
{
@@ -945,6 +1014,631 @@ show(void)
show_device(d);
}
+static void
+fill_info_machine(struct info_obj *dev_obj, struct device *d)
+{
+ struct pci_dev *p = d->dev;
+ int c;
+ word sv_id, sd_id;
+ char buf[128];
+
+ get_subid(d, &sv_id, &sd_id);
+
+ fill_slot_name(d, buf, sizeof(buf));
+ info_obj_add_str(dev_obj, "Slot", buf);
+
+ pci_lookup_name(pacc, buf, sizeof(buf), PCI_LOOKUP_CLASS, p->device_class);
+ info_obj_add_str(dev_obj, "Class", buf);
+ pci_lookup_name(pacc, buf, sizeof(buf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id);
+ info_obj_add_str(dev_obj, "Vendor", buf);
+ pci_lookup_name(pacc, buf, sizeof(buf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id);
+ info_obj_add_str(dev_obj, "Device", buf);
+
+ if (sv_id && sv_id != 0xffff)
+ {
+ pci_lookup_name(pacc, buf, sizeof(buf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id);
+ info_obj_add_str(dev_obj, "SVendor", buf);
+ pci_lookup_name(pacc, buf, sizeof(buf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id);
+ info_obj_add_str(dev_obj, "SDevice", buf);
+ }
+ else if (!verbose)
+ {
+ info_obj_add_str(dev_obj, "SVendor", "");
+ info_obj_add_str(dev_obj, "SDevice", "");
+ }
+
+ if (c = get_conf_byte(d, PCI_REVISION_ID))
+ {
+ snprintf(buf, sizeof(buf), "%02x", c);
+ info_obj_add_str(dev_obj, "Rev", buf);
+ }
+ if (c = get_conf_byte(d, PCI_CLASS_PROG))
+ {
+ snprintf(buf, sizeof(buf), "%02x", c);
+ info_obj_add_str(dev_obj, "ProgIf", buf);
+ }
+
+ if (opt_kernel)
+ fill_info_kernel(dev_obj, d);
+
+ if (verbose)
+ {
+ pci_fill_info(p, PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE);
+ if (p->phy_slot)
+ info_obj_add_str(dev_obj, "PhySlot", p->phy_slot);
+ if (p->numa_node != -1)
+ {
+ snprintf(buf, sizeof(buf), "%d", p->numa_node);
+ info_obj_add_str(dev_obj, "NUMAnode", buf);
+ }
+ }
+}
+
+static void
+fill_info_terse(struct info_obj *dev_obj, struct device *d)
+{
+ struct pci_dev *p = d->dev;
+
+ fill_info_machine(dev_obj, d);
+
+ if (verbose || opt_kernel)
+ {
+ word subsys_v, subsys_d;
+ char ssnamebuf[256];
+
+ if (p->label)
+ info_obj_add_str(dev_obj, "DeviceName", p->label);
+ info_obj_delete_pair(dev_obj, "SDevice");
+ info_obj_delete_pair(dev_obj, "SVendor");
+ get_subid(d, &subsys_v, &subsys_d);
+ if (subsys_v && subsys_v != 0xffff)
+ info_obj_add_str(dev_obj, "Subsystem",
+ pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
+ PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ p->vendor_id, p->device_id, subsys_v, subsys_d));
+ }
+}
+
+static void
+fill_info_rom(struct info_obj *dev_obj, struct device *d, int reg)
+{
+ struct pci_dev *p = d->dev;
+ pciaddr_t rom = p->rom_base_addr;
+ pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0;
+ pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->rom_flags : 0;
+ u32 flg = get_conf_long(d, reg);
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ int virtual = 0;
+ char buf[64];
+ struct info_obj *rom_obj;
+ struct info_list *attrs_list;
+
+ if (!rom && !flg && !len)
+ return;
+
+ rom_obj = info_obj_create_in_obj(dev_obj, "ROM");
+ attrs_list = info_list_create(INFO_VAL_STRING);
+ info_obj_add_list(rom_obj, "attrs", attrs_list);
+
+ if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
+ info_list_add_str(attrs_list, "[enhanced]");
+ else if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK))
+ {
+ info_list_add_str(attrs_list, "[virtual]");
+ flg = rom;
+ virtual = 1;
+ }
+
+ if (rom & PCI_ROM_ADDRESS_MASK)
+ info_obj_add_fmt_buf_str(rom_obj, "at", buf, sizeof(buf), PCIADDR_T_FMT, rom & PCI_ROM_ADDRESS_MASK);
+ else if (flg & PCI_ROM_ADDRESS_MASK)
+ info_list_add_str(attrs_list, "<ignored>");
+ else
+ info_list_add_str(attrs_list, "<unassigned>");
+
+ if (!(flg & PCI_ROM_ADDRESS_ENABLE))
+ info_list_add_str(attrs_list, "[disabled]");
+ else if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
+ info_list_add_str(attrs_list, "[disabled by cmd]");
+
+ fill_size(buf, sizeof(buf), len);
+ info_obj_add_str(rom_obj, "size", buf);
+}
+
+static void
+fill_info_bases(struct info_obj *dev_obj, struct device *d, int cnt)
+{
+ struct pci_dev *p = d->dev;
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ int i;
+ int virtual = 0;
+ char buf[64];
+ struct info_obj *bases_obj = info_obj_create_in_obj(dev_obj, "bases");
+ struct info_list *regions_list = info_list_create(INFO_VAL_OBJECT);
+
+ info_obj_add_list(bases_obj, "regions", regions_list);
+
+ for (i=0; i<cnt; i++)
+ {
+ struct info_obj *region_obj;
+ struct info_list *attrs_list;
+
+ pciaddr_t pos = p->base_addr[i];
+ pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0;
+ pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->flags[i] : 0;
+ u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ if (flg == 0xffffffff)
+ flg = 0;
+ if (!pos && !flg && !len)
+ continue;
+
+ region_obj = info_obj_create();
+ info_list_add_obj(regions_list, region_obj);
+ attrs_list = info_list_create(INFO_VAL_STRING);
+ info_obj_add_list(region_obj, "attrs", attrs_list);
+
+ if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
+ info_list_add_str(attrs_list, "[enhanced]");
+ else if (pos && !flg) /* Reported by the OS, but not by the device */
+ {
+ info_list_add_str(attrs_list, "[virtual]");
+ flg = pos;
+ virtual = 1;
+ }
+ if (flg & PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK;
+ if (a || (cmd & PCI_COMMAND_IO))
+ info_obj_add_fmt_buf_str(region_obj, "io-ports-at", buf, sizeof(buf), PCIADDR_PORT_FMT, a);
+ else if (flg & PCI_BASE_ADDRESS_IO_MASK)
+ info_list_add_str(attrs_list, "<ignored>");
+ else
+ info_list_add_str(attrs_list, "<unassigned>");
+ if (!virtual && !(cmd & PCI_COMMAND_IO))
+ info_list_add_str(attrs_list, "[disabled]");
+ }
+ else
+ {
+ int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ pciaddr_t a = pos & PCI_ADDR_MEM_MASK;
+ int done = 0;
+ u32 z = 0;
+
+ if (t == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ {
+ if (i >= cnt - 1)
+ {
+ info_list_add_str(attrs_list, "<invalid-64bit-slot>");
+ done = 1;
+ }
+ else
+ {
+ i++;
+ z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ }
+ }
+ if (!done)
+ {
+ if (a)
+ info_obj_add_fmt_buf_str(region_obj, "memory-at", buf, sizeof(buf), PCIADDR_T_FMT, a);
+ else
+ {
+ if ((flg & PCI_BASE_ADDRESS_MEM_MASK) || z)
+ info_list_add_str(attrs_list, "<ignored>");
+ else
+ info_list_add_str(attrs_list, "<unassigned>");
+ }
+ }
+ info_list_add_str(attrs_list,
+ (t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" :
+ (t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" :
+ (t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3");
+ info_list_add_str(attrs_list,
+ (flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "prefetchable" : "non-prefetchable");
+ if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
+ info_list_add_str(attrs_list, "[disabled]");
+ }
+ fill_size(buf, sizeof(buf), len);
+ info_obj_add_str(region_obj, "size", buf);
+ }
+}
+
+static void
+fill_info_htype0(struct info_obj *dev_obj, struct device *d)
+{
+ struct info_obj *htype0_obj = info_obj_create_in_obj(dev_obj, "htype0");
+
+ fill_info_bases(htype0_obj, d, 6);
+ fill_info_rom(htype0_obj, d, PCI_ROM_ADDRESS);
+}
+
+static void
+fill_info_htype1(struct info_obj *dev_obj, struct device *d)
+{
+ u32 io_base = get_conf_byte(d, PCI_IO_BASE);
+ u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT);
+ u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK;
+ u32 mem_base = get_conf_word(d, PCI_MEMORY_BASE);
+ u32 mem_limit = get_conf_word(d, PCI_MEMORY_LIMIT);
+ u32 mem_type = mem_base & PCI_MEMORY_RANGE_TYPE_MASK;
+ u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE);
+ u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT);
+ u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK;
+ word sec_stat = get_conf_word(d, PCI_SEC_STATUS);
+ word brc = get_conf_word(d, PCI_BRIDGE_CONTROL);
+ struct info_obj *htype1_obj = info_obj_create_in_obj(dev_obj, "htype1");
+ struct info_obj *bus_obj;
+ char buf[64];
+
+ fill_info_bases(htype1_obj, d, 2);
+
+ bus_obj = info_obj_create_in_obj(htype1_obj, "Bus");
+ info_obj_add_fmt_buf_str(bus_obj, "primary", buf, sizeof(buf), "%02x", get_conf_byte(d, PCI_PRIMARY_BUS));
+ info_obj_add_fmt_buf_str(bus_obj, "secondary", buf, sizeof(buf), "%02x", get_conf_byte(d, PCI_SECONDARY_BUS));
+ info_obj_add_fmt_buf_str(bus_obj, "subordinate", buf, sizeof(buf), "%02x", get_conf_byte(d, PCI_SUBORDINATE_BUS));
+ info_obj_add_fmt_buf_str(bus_obj, "sec-latency", buf, sizeof(buf), "%d", get_conf_byte(d, PCI_SEC_LATENCY_TIMER));
+
+ if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
+ (io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32))
+ fprintf(stderr, "\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit);
+ else
+ {
+ io_base = (io_base & PCI_IO_RANGE_MASK) << 8;
+ io_limit = (io_limit & PCI_IO_RANGE_MASK) << 8;
+ if (io_type == PCI_IO_RANGE_TYPE_32)
+ {
+ io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16);
+ io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16);
+ }
+ fill_range(buf, sizeof(buf), io_base, io_limit + 0xfff, 0);
+ info_obj_add_str(htype1_obj, "io-behind-bridge", buf);
+ }
+
+ if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
+ mem_type)
+ fprintf(stderr, "\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
+ else
+ {
+ mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16;
+ mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16;
+ fill_range(buf, sizeof(buf), mem_base, mem_limit + 0xfffff, 0);
+ info_obj_add_str(htype1_obj, "memory-behind-bridge", buf);
+ }
+
+ if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
+ (pref_type != PCI_PREF_RANGE_TYPE_32 && pref_type != PCI_PREF_RANGE_TYPE_64))
+ fprintf(stderr, "\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit);
+ else
+ {
+ u64 pref_base_64 = (pref_base & PCI_PREF_RANGE_MASK) << 16;
+ u64 pref_limit_64 = (pref_limit & PCI_PREF_RANGE_MASK) << 16;
+ if (pref_type == PCI_PREF_RANGE_TYPE_64)
+ {
+ pref_base_64 |= (u64) get_conf_long(d, PCI_PREF_BASE_UPPER32) << 32;
+ pref_limit_64 |= (u64) get_conf_long(d, PCI_PREF_LIMIT_UPPER32) << 32;
+ }
+ fill_range(buf, sizeof(buf), pref_base_64, pref_limit_64 + 0xfffff, (pref_type == PCI_PREF_RANGE_TYPE_64));
+ info_obj_add_str(htype1_obj, "prefetchable-memory-behind-bridge", buf);
+ }
+
+ if (verbose > 1)
+ {
+ struct info_obj *sec_status_obj = info_obj_create();
+
+ sec_status_obj = info_obj_create_in_obj(htype1_obj, "SecondaryStatus");
+ info_obj_add_flag(sec_status_obj, "66MHz", FLAG(sec_stat, PCI_STATUS_66MHZ));
+ info_obj_add_flag(sec_status_obj, "FastB2B", FLAG(sec_stat, PCI_STATUS_FAST_BACK));
+ info_obj_add_flag(sec_status_obj, "ParErr", FLAG(sec_stat, PCI_STATUS_PARITY));
+ info_obj_add_str(sec_status_obj, "DEVSEL=", ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
+ ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
+ ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
+ info_obj_add_flag(sec_status_obj, ">TAbort", FLAG(sec_stat, PCI_STATUS_SIG_TARGET_ABORT));
+ info_obj_add_flag(sec_status_obj, "<TAbort", FLAG(sec_stat, PCI_STATUS_REC_TARGET_ABORT));
+ info_obj_add_flag(sec_status_obj, "<MAbort", FLAG(sec_stat, PCI_STATUS_REC_MASTER_ABORT));
+ info_obj_add_flag(sec_status_obj, "<SERR", FLAG(sec_stat, PCI_STATUS_SIG_SYSTEM_ERROR));
+ info_obj_add_flag(sec_status_obj, "<PERR", FLAG(sec_stat, PCI_STATUS_DETECTED_PARITY));
+ }
+
+ fill_info_rom(htype1_obj, d, PCI_ROM_ADDRESS1);
+
+ if (verbose > 1)
+ {
+ struct info_obj *bridgectl_obj;
+
+ bridgectl_obj = info_obj_create_in_obj(htype1_obj, "BridgeCtl");
+ info_obj_add_flag(bridgectl_obj, "Parity", FLAG(brc, PCI_BRIDGE_CTL_PARITY));
+ info_obj_add_flag(bridgectl_obj, "SERR", FLAG(brc, PCI_BRIDGE_CTL_SERR));
+ info_obj_add_flag(bridgectl_obj, "NoISA", FLAG(brc, PCI_BRIDGE_CTL_NO_ISA));
+ info_obj_add_flag(bridgectl_obj, "VGA", FLAG(brc, PCI_BRIDGE_CTL_VGA));
+ info_obj_add_flag(bridgectl_obj, "VGA16", FLAG(brc, PCI_BRIDGE_CTL_VGA_16BIT));
+ info_obj_add_flag(bridgectl_obj, "MAbort", FLAG(brc, PCI_BRIDGE_CTL_MASTER_ABORT));
+ info_obj_add_flag(bridgectl_obj, ">Reset", FLAG(brc, PCI_BRIDGE_CTL_BUS_RESET));
+ info_obj_add_flag(bridgectl_obj, "FastB2B", FLAG(brc, PCI_BRIDGE_CTL_FAST_BACK));
+ info_obj_add_flag(bridgectl_obj, "PriDiscTmr", FLAG(brc, PCI_BRIDGE_CTL_PRI_DISCARD_TIMER));
+ info_obj_add_flag(bridgectl_obj, "SecDiscTmr", FLAG(brc, PCI_BRIDGE_CTL_SEC_DISCARD_TIMER));
+ info_obj_add_flag(bridgectl_obj, "DiscTmrStat", FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS));
+ info_obj_add_flag(bridgectl_obj, "DiscTmrSERREn", FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN));
+ }
+}
+
+static void
+fill_info_htype2(struct info_obj *dev_obj, struct device *d)
+{
+ int i;
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ word brc = get_conf_word(d, PCI_CB_BRIDGE_CONTROL);
+ word exca;
+ int verb = verbose > 2;
+ struct info_obj *htype2_obj = info_obj_create_in_obj(dev_obj, "htype2");
+ struct info_obj *bus_obj;
+ char buf[64];
+
+ fill_info_bases(htype2_obj, d, 1);
+
+ bus_obj = info_obj_create_in_obj(htype2_obj, "Bus");
+ info_obj_add_fmt_buf_str(bus_obj, "primary", buf, sizeof(buf), "%02x", get_conf_byte(d, PCI_CB_PRIMARY_BUS));
+ info_obj_add_fmt_buf_str(bus_obj, "secondary", buf, sizeof(buf), "%02x", get_conf_byte(d, PCI_CB_CARD_BUS));
+ info_obj_add_fmt_buf_str(bus_obj, "subordinate", buf, sizeof(buf), "%02x", get_conf_byte(d, PCI_CB_SUBORDINATE_BUS));
+ info_obj_add_fmt_buf_str(bus_obj, "sec-latency", buf, sizeof(buf), "%d", get_conf_byte(d, PCI_CB_LATENCY_TIMER));
+
+ for (i=0; i<2; i++)
+ {
+ int p = 8*i;
+ struct info_obj *mem_win_obj;
+
+ u32 base = get_conf_long(d, PCI_CB_MEMORY_BASE_0 + p);
+ u32 limit = get_conf_long(d, PCI_CB_MEMORY_LIMIT_0 + p);
+ limit = limit + 0xfff;
+ if (base <= limit || verb)
+ {
+ snprintf(buf, sizeof(buf), "memory-window-%d", i);
+ mem_win_obj = info_obj_create_in_obj(htype2_obj, buf);
+ info_obj_add_fmt_buf_str(mem_win_obj, "base", buf, sizeof(buf), "%08x", base);
+ info_obj_add_fmt_buf_str(mem_win_obj, "limit", buf, sizeof(buf), "%08x", limit);
+ info_obj_add_flag(mem_win_obj, "disabled", (cmd & PCI_COMMAND_MEMORY) ? '-' : '+');
+ info_obj_add_flag(mem_win_obj, "prefetchable", (brc & (PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 << i)) ? '-' : '+');
+ }
+ }
+ for (i=0; i<2; i++)
+ {
+ int p = 8*i;
+ struct info_obj *io_win_obj;
+
+ u32 base = get_conf_long(d, PCI_CB_IO_BASE_0 + p);
+ u32 limit = get_conf_long(d, PCI_CB_IO_LIMIT_0 + p);
+ if (!(base & PCI_IO_RANGE_TYPE_32))
+ {
+ base &= 0xffff;
+ limit &= 0xffff;
+ }
+ base &= PCI_CB_IO_RANGE_MASK;
+ limit = (limit & PCI_CB_IO_RANGE_MASK) + 3;
+ if (base <= limit || verb)
+ {
+ snprintf(buf, sizeof(buf), "io-window-%d", i);
+ io_win_obj = info_obj_create_in_obj(htype2_obj, buf);
+ info_obj_add_fmt_buf_str(io_win_obj, "base", buf, sizeof(buf), "%08x", base);
+ info_obj_add_fmt_buf_str(io_win_obj, "limit", buf, sizeof(buf), "%08x", limit);
+ info_obj_add_flag(io_win_obj, "disabled", (cmd & PCI_COMMAND_IO) ? '-' : '+');
+ }
+ }
+
+ if (get_conf_word(d, PCI_CB_SEC_STATUS) & PCI_STATUS_SIG_SYSTEM_ERROR)
+ info_obj_add_str(htype2_obj, "SecondaryStatus", "SERR");
+ if (verbose > 1)
+ {
+ struct info_obj *bridgectl_obj;
+
+ bridgectl_obj = info_obj_create_in_obj(htype2_obj, "BridgeCtl");
+ info_obj_add_flag(bridgectl_obj, "Parity", FLAG(brc, PCI_CB_BRIDGE_CTL_PARITY));
+ info_obj_add_flag(bridgectl_obj, "SERR", FLAG(brc, PCI_CB_BRIDGE_CTL_SERR));
+ info_obj_add_flag(bridgectl_obj, "ISA", FLAG(brc, PCI_CB_BRIDGE_CTL_ISA));
+ info_obj_add_flag(bridgectl_obj, "VGA", FLAG(brc, PCI_CB_BRIDGE_CTL_VGA));
+ info_obj_add_flag(bridgectl_obj, "MAbort", FLAG(brc, PCI_CB_BRIDGE_CTL_MASTER_ABORT));
+ info_obj_add_flag(bridgectl_obj, ">Reset", FLAG(brc, PCI_CB_BRIDGE_CTL_CB_RESET));
+ info_obj_add_flag(bridgectl_obj, "16bInt", FLAG(brc, PCI_CB_BRIDGE_CTL_16BIT_INT));
+ info_obj_add_flag(bridgectl_obj, "PostWrite", FLAG(brc, PCI_CB_BRIDGE_CTL_POST_WRITES));
+ }
+
+ if (d->config_cached < 128)
+ return;
+
+ exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
+ if (exca)
+ info_obj_add_fmt_buf_str(htype2_obj, "exca", buf, sizeof(buf), "%04x", exca);
+}
+
+static void
+fill_info_verbose(struct info_obj *dev_obj, struct device *d)
+{
+ struct pci_dev *p = d->dev;
+ word status = get_conf_word(d, PCI_STATUS);
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ word class = p->device_class;
+ byte bist = get_conf_byte(d, PCI_BIST);
+ byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+ byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
+ byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
+ byte max_lat, min_gnt;
+ byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
+ unsigned int irq;
+
+ fill_info_terse(dev_obj, d);
+ pci_fill_info(p, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES |
+ PCI_FILL_PHYS_SLOT | PCI_FILL_LABEL | PCI_FILL_NUMA_NODE);
+ irq = p->irq;
+
+ switch (htype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ if (class == PCI_CLASS_BRIDGE_PCI)
+ fprintf(stderr, "\t!!! Invalid class %04x for header type %02x\n", class, htype);
+ max_lat = get_conf_byte(d, PCI_MAX_LAT);
+ min_gnt = get_conf_byte(d, PCI_MIN_GNT);
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
+ fprintf(stderr, "\t!!! Invalid class %04x for header type %02x\n", class, htype);
+ min_gnt = max_lat = 0;
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
+ fprintf(stderr, "\t!!! Invalid class %04x for header type %02x\n", class, htype);
+ min_gnt = max_lat = 0;
+ break;
+ default:
+ fprintf(stderr, "\t!!! Unknown header type %02x\n", htype);
+ return;
+ }
+
+ if (p->phy_slot)
+ info_obj_add_str(dev_obj, "PhySlot", p->phy_slot);
+
+ if (verbose > 1)
+ {
+ struct info_obj *control_obj;
+ struct info_obj *status_obj;
+
+ control_obj = info_obj_create_in_obj(dev_obj, "Control");
+ info_obj_add_flag(control_obj, "I/O", FLAG(cmd, PCI_COMMAND_IO));
+ info_obj_add_flag(control_obj, "Mem", FLAG(cmd, PCI_COMMAND_MEMORY));
+ info_obj_add_flag(control_obj, "BusMaster", FLAG(cmd, PCI_COMMAND_MASTER));
+ info_obj_add_flag(control_obj, "SpecCycle", FLAG(cmd, PCI_COMMAND_SPECIAL));
+ info_obj_add_flag(control_obj, "MemWINV", FLAG(cmd, PCI_COMMAND_INVALIDATE));
+ info_obj_add_flag(control_obj, "VGASnoop", FLAG(cmd, PCI_COMMAND_VGA_PALETTE));
+ info_obj_add_flag(control_obj, "ParErr", FLAG(cmd, PCI_COMMAND_PARITY));
+ info_obj_add_flag(control_obj, "Stepping", FLAG(cmd, PCI_COMMAND_WAIT));
+ info_obj_add_flag(control_obj, "SERR", FLAG(cmd, PCI_COMMAND_SERR));
+ info_obj_add_flag(control_obj, "FastB2B", FLAG(cmd, PCI_COMMAND_FAST_BACK));
+ info_obj_add_flag(control_obj, "DisINTx", FLAG(cmd, PCI_COMMAND_DISABLE_INTx));
+
+ status_obj = info_obj_create_in_obj(dev_obj, "Status");
+ info_obj_add_flag(status_obj, "Cap", FLAG(status, PCI_STATUS_CAP_LIST));
+ info_obj_add_flag(status_obj, "66MHz", FLAG(status, PCI_STATUS_66MHZ));
+ info_obj_add_flag(status_obj, "UDF", FLAG(status, PCI_STATUS_UDF));
+ info_obj_add_flag(status_obj, "FastB2B", FLAG(status, PCI_STATUS_FAST_BACK));
+ info_obj_add_flag(status_obj, "ParErr", FLAG(status, PCI_STATUS_PARITY));
+ info_obj_add_str(status_obj, "DEVSEL=",
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
+ info_obj_add_flag(status_obj, ">TAbort", FLAG(status, PCI_STATUS_SIG_TARGET_ABORT));
+ info_obj_add_flag(status_obj, "<TAbort", FLAG(status, PCI_STATUS_REC_TARGET_ABORT));
+ info_obj_add_flag(status_obj, "<MAbort", FLAG(status, PCI_STATUS_REC_MASTER_ABORT));
+ info_obj_add_flag(status_obj, ">SERR", FLAG(status, PCI_STATUS_SIG_SYSTEM_ERROR));
+ info_obj_add_flag(status_obj, "<PERR", FLAG(status, PCI_STATUS_DETECTED_PARITY));
+ info_obj_add_flag(status_obj, "INTx", FLAG(status, PCI_STATUS_INTx));
+
+ if (cmd & PCI_COMMAND_MASTER)
+ {
+ info_obj_add_fmt_str(dev_obj, "Latency", 16, "%d", latency);
+ if (min_gnt)
+ info_obj_add_fmt_str(dev_obj, "min-gnt", 16, "%d", min_gnt*250);
+ if (max_lat)
+ info_obj_add_fmt_str(dev_obj, "max-lat", 16, "%d", max_lat*250);
+ if (cache_line)
+ info_obj_add_fmt_str(dev_obj, "CacheLineSize", 16, "%d", cache_line * 4);
+ }
+ if (int_pin || irq)
+ {
+ info_obj_add_fmt_str(dev_obj, "int-pin", 2, "%c", (int_pin ? 'A' + int_pin - 1 : '?'));
+ info_obj_add_fmt_str(dev_obj, "IRQ", 16, PCIIRQ_FMT, irq);
+ }
+ }
+ else
+ {
+ struct info_list *flags_list = info_list_create(INFO_VAL_STRING);
+
+ info_obj_add_list(dev_obj, "Flags", flags_list);
+ if (cmd & PCI_COMMAND_MASTER)
+ info_list_add_str(flags_list, "bus master");
+ if (cmd & PCI_COMMAND_VGA_PALETTE)
+ info_list_add_str(flags_list, "VGA palette snoop");
+ if (cmd & PCI_COMMAND_WAIT)
+ info_list_add_str(flags_list, "stepping");
+ if (cmd & PCI_COMMAND_FAST_BACK)
+ info_list_add_str(flags_list, "fast Back2Back");
+ if (status & PCI_STATUS_66MHZ)
+ info_list_add_str(flags_list, "66MHz");
+ if (status & PCI_STATUS_UDF)
+ info_list_add_str(flags_list, "user-definable features");
+
+ info_obj_add_str(dev_obj, "devsel",
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
+ if (cmd & PCI_COMMAND_MASTER)
+ info_obj_add_fmt_str(dev_obj, "Latency", 16, "%d", latency);
+ if (irq)
+ info_obj_add_fmt_str(dev_obj, "IRQ", 16, PCIIRQ_FMT, irq);
+ }
+
+ if (bist & PCI_BIST_CAPABLE)
+ {
+ if (bist & PCI_BIST_START)
+ info_obj_add_str(dev_obj, "BIST", "running");
+ else
+ info_obj_add_fmt_str(dev_obj, "BIST", 3, "%02x", bist & PCI_BIST_CODE_MASK);
+ }
+
+ switch (htype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ fill_info_htype0(dev_obj, d);
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ fill_info_htype1(dev_obj, d);
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ fill_info_htype2(dev_obj, d);
+ break;
+ }
+}
+
+static void
+fill_info_device(struct info_obj *dev_obj, struct device *d)
+{
+ if (opt_machine)
+ fill_info_machine(dev_obj, d);
+ else
+ {
+ if (verbose)
+ fill_info_verbose(dev_obj, d);
+ else
+ fill_info_terse(dev_obj, d);
+ if (!opt_kernel && verbose)
+ fill_info_kernel(dev_obj, d);
+ }
+ if (opt_hex)
+ fill_info_hex_dump(dev_obj, d);
+}
+
+static void
+fill_info(struct info_obj *root)
+{
+ struct device *d;
+ struct info_list *dev_list = info_list_create(INFO_VAL_OBJECT);
+
+ for (d=first_dev; d; d=d->next)
+ {
+ struct info_obj *dev_obj = info_obj_create();
+ fill_info_device(dev_obj, d);
+ info_list_add_obj(dev_list, dev_obj);
+ }
+
+ info_obj_add_list(root, "pcidevices", dev_list);
+}
+
+static void
+show_json(void)
+{
+ struct info_obj *root = info_obj_create();
+
+ fill_info(root);
+ info_obj_print_json(root);
+ info_obj_delete(root);
+}
+
/* Main */
int
@@ -1009,6 +1703,9 @@ main(int argc, char **argv)
case 'D':
opt_domains = 2;
break;
+ case 'J':
+ opt_json = 1;
+ break;
#ifdef PCI_USE_DNS
case 'q':
opt_query_dns++;
@@ -1049,6 +1746,8 @@ main(int argc, char **argv)
sort_them();
if (opt_tree)
show_forest();
+ else if (opt_json)
+ show_json();
else
show();
}
diff --git a/lspci.h b/lspci.h
index ba5a56b..fc23d32 100644
--- a/lspci.h
+++ b/lspci.h
@@ -133,6 +133,7 @@ void info_list_add_obj(struct info_list *list, struct info_obj *obj);
void show_kernel_machine(struct device *d UNUSED);
void show_kernel(struct device *d UNUSED);
void show_kernel_cleanup(void);
+void fill_info_kernel(struct info_obj *dev_obj UNUSED, struct device *d UNUSED);
/* ls-tree.c */
diff --git a/lspci.man b/lspci.man
index 9348cfc..3a126a4 100644
--- a/lspci.man
+++ b/lspci.man
@@ -51,6 +51,9 @@ See below for details.
.B -t
Show a tree-like diagram containing all buses, bridges, devices and connections
between them.
+.TP
+.B -J
+Use JSON output format.
.SS Display options
.TP
--
2.14.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 3/3] lspci: Add JSON PCI Express capabilities
2018-02-18 23:12 [PATCH v3 0/3] lspci: Add support of JSON output format Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 1/3] lspci: Add printing info in JSON format Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 2/3] lspci: Add PCI info output " Viktor Prutyanov
@ 2018-02-18 23:12 ` Viktor Prutyanov
2018-03-11 15:03 ` [PATCH v3 0/3] lspci: Add support of JSON output format viktor.prutyanov
3 siblings, 0 replies; 5+ messages in thread
From: Viktor Prutyanov @ 2018-02-18 23:12 UTC (permalink / raw)
To: linux-pci, mj; +Cc: Viktor Prutyanov
This patch adds JSON format of PCI Express capabilities
Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com>
---
ls-caps.c | 417 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lspci.c | 5 +
lspci.h | 33 ++---
3 files changed, 439 insertions(+), 16 deletions(-)
diff --git a/ls-caps.c b/ls-caps.c
index d4aebc8..9fe4b82 100644
--- a/ls-caps.c
+++ b/ls-caps.c
@@ -716,6 +716,73 @@ static void cap_express_dev(struct device *d, int where, int type)
FLAG(w, PCI_EXP_DEVSTA_TRPND));
}
+static void fill_info_express_dev(struct info_obj *exp_obj, struct device *d, int where, int type)
+{
+ u32 t;
+ u16 w;
+ struct info_obj *dev_cap_obj, *dev_ctl_obj, *dev_sta_obj, *dev_ctl_re_obj;
+ char buf[64];
+
+ t = get_conf_long(d, where + PCI_EXP_DEVCAP);
+ dev_cap_obj = info_obj_create_in_obj(exp_obj, "DevCap");
+ info_obj_add_fmt_buf_str(dev_cap_obj, "MaxPayload", buf, sizeof(buf), "%d",
+ 128 << (t & PCI_EXP_DEVCAP_PAYLOAD));
+ info_obj_add_fmt_buf_str(dev_cap_obj, "PhantFunc", buf, sizeof(buf), "%d",
+ (1 << ((t & PCI_EXP_DEVCAP_PHANTOM) >> 3)) - 1);
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END))
+ {
+ info_obj_add_str(dev_cap_obj, "L0s", latency_l0s((t & PCI_EXP_DEVCAP_L0S) >> 6));
+ info_obj_add_str(dev_cap_obj, "L1", latency_l1((t & PCI_EXP_DEVCAP_L1) >> 9));
+ }
+ info_obj_add_flag(dev_cap_obj, "ExtTag", FLAG(t, PCI_EXP_DEVCAP_EXT_TAG));
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END) ||
+ (type == PCI_EXP_TYPE_UPSTREAM) || (type == PCI_EXP_TYPE_PCI_BRIDGE))
+ {
+ info_obj_add_flag(dev_cap_obj, "AttnBtn", FLAG(t, PCI_EXP_DEVCAP_ATN_BUT));
+ info_obj_add_flag(dev_cap_obj, "AttnInd", FLAG(t, PCI_EXP_DEVCAP_ATN_IND));
+ info_obj_add_flag(dev_cap_obj, "PwrInd", FLAG(t, PCI_EXP_DEVCAP_PWR_IND));
+ }
+ info_obj_add_flag(dev_cap_obj, "RBE", FLAG(t, PCI_EXP_DEVCAP_RBE));
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END))
+ info_obj_add_flag(dev_cap_obj, "FLReset", FLAG(t, PCI_EXP_DEVCAP_FLRESET));
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_UPSTREAM) ||
+ (type == PCI_EXP_TYPE_PCI_BRIDGE))
+ info_obj_add_fmt_buf_str(dev_cap_obj, "SlotPowerLimit", buf, sizeof(buf), "%.3f",
+ power_limit((t & PCI_EXP_DEVCAP_PWR_VAL) >> 18,
+ (t & PCI_EXP_DEVCAP_PWR_SCL) >> 26));
+
+ w = get_conf_word(d, where + PCI_EXP_DEVCTL);
+ dev_ctl_obj = info_obj_create_in_obj(exp_obj, "DevCtl");
+ dev_ctl_re_obj = info_obj_create_in_obj(dev_ctl_obj, "Report-errors");
+ info_obj_add_flag(dev_ctl_re_obj, "Correctable", FLAG(w, PCI_EXP_DEVCTL_CERE));
+ info_obj_add_flag(dev_ctl_re_obj, "Non-Fatal", FLAG(w, PCI_EXP_DEVCTL_NFERE));
+ info_obj_add_flag(dev_ctl_re_obj, "Fatal", FLAG(w, PCI_EXP_DEVCTL_FERE));
+ info_obj_add_flag(dev_ctl_re_obj, "Unsupported", FLAG(w, PCI_EXP_DEVCTL_URRE));
+ info_obj_add_flag(dev_ctl_obj, "RlxdOrd", FLAG(w, PCI_EXP_DEVCTL_RELAXED));
+ info_obj_add_flag(dev_ctl_obj, "ExtTag", FLAG(w, PCI_EXP_DEVCTL_EXT_TAG));
+ info_obj_add_flag(dev_ctl_obj, "PhantFunc", FLAG(w, PCI_EXP_DEVCTL_PHANTOM));
+ info_obj_add_flag(dev_ctl_obj, "AuxPwr", FLAG(w, PCI_EXP_DEVCTL_AUX_PME));
+ info_obj_add_flag(dev_ctl_obj, "NoSnoop", FLAG(w, PCI_EXP_DEVCTL_NOSNOOP));
+ if (type == PCI_EXP_TYPE_PCI_BRIDGE)
+ info_obj_add_flag(dev_ctl_obj, "BrConfRtry", FLAG(w, PCI_EXP_DEVCTL_BCRE));
+ if (((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END)) &&
+ (t & PCI_EXP_DEVCAP_FLRESET))
+ info_obj_add_flag(dev_ctl_obj, "FLReset", FLAG(w, PCI_EXP_DEVCTL_FLRESET));
+ info_obj_add_fmt_buf_str(dev_ctl_obj, "MaxPayload", buf, sizeof(buf), "%d",
+ 128 << ((w & PCI_EXP_DEVCTL_PAYLOAD) >> 5));
+ info_obj_add_fmt_buf_str(dev_ctl_obj, "MaxReadReq", buf, sizeof(buf), "%d",
+ 128 << ((w & PCI_EXP_DEVCTL_READRQ) >> 12));
+
+ w = get_conf_word(d, where + PCI_EXP_DEVSTA);
+ dev_sta_obj = info_obj_create_in_obj(exp_obj, "DevSta");
+ info_obj_add_flag(dev_sta_obj, "CorrErr", FLAG(w, PCI_EXP_DEVSTA_CED));
+ info_obj_add_flag(dev_sta_obj, "UncorrErr", FLAG(w, PCI_EXP_DEVSTA_NFED));
+ info_obj_add_flag(dev_sta_obj, "FatalErr", FLAG(w, PCI_EXP_DEVSTA_FED));
+ info_obj_add_flag(dev_sta_obj, "UnsuppReq", FLAG(w, PCI_EXP_DEVSTA_URD));
+ info_obj_add_flag(dev_sta_obj, "AuxPwr", FLAG(w, PCI_EXP_DEVSTA_AUXPD));
+ info_obj_add_flag(dev_sta_obj, "TransPend", FLAG(w, PCI_EXP_DEVSTA_TRPND));
+}
+
static char *link_speed(int speed)
{
switch (speed)
@@ -810,6 +877,59 @@ static void cap_express_link(struct device *d, int where, int type)
FLAG(w, PCI_EXP_LNKSTA_AUTBW));
}
+static void fill_info_express_link(struct info_obj *exp_obj, struct device *d, int where, int type)
+{
+ u32 t, aspm;
+ u16 w;
+ struct info_obj *lnk_cap_obj, *lnk_ctl_obj, *lnk_sta_obj;
+ char buf[64];
+
+ t = get_conf_long(d, where + PCI_EXP_LNKCAP);
+ aspm = (t & PCI_EXP_LNKCAP_ASPM) >> 10;
+ lnk_cap_obj = info_obj_create_in_obj(exp_obj, "LnkCap");
+ info_obj_add_fmt_buf_str(lnk_cap_obj, "Port", buf, sizeof(buf), "%d", t >> 24);
+ info_obj_add_str(lnk_cap_obj, "Speed", link_speed(t & PCI_EXP_LNKCAP_SPEED));
+ info_obj_add_fmt_buf_str(lnk_cap_obj, "Width", buf, sizeof(buf), "x%d", (t & PCI_EXP_LNKCAP_WIDTH) >> 4);
+ info_obj_add_str(lnk_cap_obj, "ASPM", aspm_support(aspm));
+ if (aspm)
+ {
+ if (aspm & 1)
+ info_obj_add_str(lnk_cap_obj, "L0s", latency_l0s((t & PCI_EXP_LNKCAP_L0S) >> 12));
+ if (aspm & 2)
+ info_obj_add_str(lnk_cap_obj, "L1", latency_l1((t & PCI_EXP_LNKCAP_L1) >> 15));
+ }
+ info_obj_add_flag(lnk_cap_obj, "ClockPM", FLAG(t, PCI_EXP_LNKCAP_CLOCKPM));
+ info_obj_add_flag(lnk_cap_obj, "Surprise", FLAG(t, PCI_EXP_LNKCAP_SURPRISE));
+ info_obj_add_flag(lnk_cap_obj, "LLActRep", FLAG(t, PCI_EXP_LNKCAP_DLLA));
+ info_obj_add_flag(lnk_cap_obj, "BwNot", FLAG(t, PCI_EXP_LNKCAP_LBNC));
+ info_obj_add_flag(lnk_cap_obj, "ASPMOptComp", FLAG(t, PCI_EXP_LNKCAP_AOC));
+
+ w = get_conf_word(d, where + PCI_EXP_LNKCTL);
+ lnk_ctl_obj = info_obj_create_in_obj(exp_obj, "LnkCtl");
+ info_obj_add_str(lnk_ctl_obj, "ASPM", aspm_enabled(w & PCI_EXP_LNKCTL_ASPM));
+ if ((type == PCI_EXP_TYPE_ROOT_PORT) || (type == PCI_EXP_TYPE_ENDPOINT) ||
+ (type == PCI_EXP_TYPE_LEG_END) || (type == PCI_EXP_TYPE_PCI_BRIDGE))
+ info_obj_add_fmt_buf_str(lnk_ctl_obj, "RCB", buf, sizeof(buf), "%d", w & PCI_EXP_LNKCTL_RCB ? 128 : 64);
+ info_obj_add_flag(lnk_ctl_obj, "Disabled", FLAG(w, PCI_EXP_LNKCTL_DISABLE));
+ info_obj_add_flag(lnk_ctl_obj, "CommClk", FLAG(w, PCI_EXP_LNKCTL_CLOCK));
+ info_obj_add_flag(lnk_ctl_obj, "ExtSynch", FLAG(w, PCI_EXP_LNKCTL_XSYNCH));
+ info_obj_add_flag(lnk_ctl_obj, "ClockPM", FLAG(w, PCI_EXP_LNKCTL_CLOCKPM));
+ info_obj_add_flag(lnk_ctl_obj, "AutWidDis", FLAG(w, PCI_EXP_LNKCTL_HWAUTWD));
+ info_obj_add_flag(lnk_ctl_obj, "BWInt", FLAG(w, PCI_EXP_LNKCTL_BWMIE));
+ info_obj_add_flag(lnk_ctl_obj, "AutBWInt", FLAG(w, PCI_EXP_LNKCTL_AUTBWIE));
+
+ w = get_conf_word(d, where + PCI_EXP_LNKSTA);
+ lnk_sta_obj = info_obj_create_in_obj(exp_obj, "LnkSta");
+ info_obj_add_str(lnk_sta_obj, "Speed", link_speed(w & PCI_EXP_LNKSTA_SPEED));
+ info_obj_add_fmt_buf_str(lnk_sta_obj, "Width", buf, sizeof(buf), "x%d", (w & PCI_EXP_LNKSTA_WIDTH) >> 4);
+ info_obj_add_flag(lnk_sta_obj, "TrErr", FLAG(w, PCI_EXP_LNKSTA_TR_ERR));
+ info_obj_add_flag(lnk_sta_obj, "Train", FLAG(w, PCI_EXP_LNKSTA_TRAIN));
+ info_obj_add_flag(lnk_sta_obj, "SlotClk", FLAG(w, PCI_EXP_LNKSTA_SL_CLK));
+ info_obj_add_flag(lnk_sta_obj, "DLActive", FLAG(w, PCI_EXP_LNKSTA_DL_ACT));
+ info_obj_add_flag(lnk_sta_obj, "BWMgmt", FLAG(w, PCI_EXP_LNKSTA_BWMGMT));
+ info_obj_add_flag(lnk_sta_obj, "ABWMgmt", FLAG(w, PCI_EXP_LNKSTA_AUTBW));
+}
+
static const char *indicator(int code)
{
static const char *names[] = { "Unknown", "On", "Blink", "Off" };
@@ -865,6 +985,61 @@ static void cap_express_slot(struct device *d, int where)
FLAG(w, PCI_EXP_SLTSTA_LLCHG));
}
+static void fill_info_express_slot(struct info_obj *exp_obj, struct device *d, int where)
+{
+ u32 t;
+ u16 w;
+ struct info_obj *slt_cap_obj, *slt_ctl_obj, *slt_sta_obj;
+ struct info_obj *slt_ctl_enable_obj, *slt_ctl_control_obj;
+ struct info_obj *slt_sta_status_obj, *slt_sta_changed_obj;
+ char buf[128];
+
+ t = get_conf_long(d, where + PCI_EXP_SLTCAP);
+ slt_cap_obj = info_obj_create_in_obj(exp_obj, "SltCap");
+ info_obj_add_flag(slt_cap_obj, "AttnBtn", FLAG(t, PCI_EXP_SLTCAP_ATNB));
+ info_obj_add_flag(slt_cap_obj, "PwrCtrl", FLAG(t, PCI_EXP_SLTCAP_PWRC));
+ info_obj_add_flag(slt_cap_obj, "MRL", FLAG(t, PCI_EXP_SLTCAP_MRL));
+ info_obj_add_flag(slt_cap_obj, "AttnInd", FLAG(t, PCI_EXP_SLTCAP_ATNI));
+ info_obj_add_flag(slt_cap_obj, "PwrInd", FLAG(t, PCI_EXP_SLTCAP_PWRI));
+ info_obj_add_flag(slt_cap_obj, "HotPlug", FLAG(t, PCI_EXP_SLTCAP_HPC));
+ info_obj_add_flag(slt_cap_obj, "Surprise", FLAG(t, PCI_EXP_SLTCAP_HPS));
+ info_obj_add_fmt_buf_str(slt_cap_obj, "Slot", buf, sizeof(buf), "%d", (t & PCI_EXP_SLTCAP_PSN) >> 19);
+ info_obj_add_fmt_buf_str(slt_cap_obj, "PowerLimit", buf, sizeof(buf), "%.3f",
+ power_limit((t & PCI_EXP_SLTCAP_PWR_VAL) >> 7, (t & PCI_EXP_SLTCAP_PWR_SCL) >> 15));
+ info_obj_add_flag(slt_cap_obj, "Interlock", FLAG(t, PCI_EXP_SLTCAP_INTERLOCK));
+ info_obj_add_flag(slt_cap_obj, "NoCompl", FLAG(t, PCI_EXP_SLTCAP_NOCMDCOMP));
+
+ w = get_conf_word(d, where + PCI_EXP_SLTCTL);
+ slt_ctl_obj = info_obj_create_in_obj(exp_obj, "SltCtl");
+ slt_ctl_enable_obj = info_obj_create_in_obj(slt_ctl_obj, "Enable");
+ info_obj_add_flag(slt_ctl_enable_obj, "AttnBtn", FLAG(w, PCI_EXP_SLTCTL_ATNB));
+ info_obj_add_flag(slt_ctl_enable_obj, "PwrFlt", FLAG(w, PCI_EXP_SLTCTL_PWRF));
+ info_obj_add_flag(slt_ctl_enable_obj, "MRL", FLAG(w, PCI_EXP_SLTCTL_MRLS));
+ info_obj_add_flag(slt_ctl_enable_obj, "PresDet", FLAG(w, PCI_EXP_SLTCTL_PRSD));
+ info_obj_add_flag(slt_ctl_enable_obj, "CmdCplt", FLAG(w, PCI_EXP_SLTCTL_CMDC));
+ info_obj_add_flag(slt_ctl_enable_obj, "HPIrq", FLAG(w, PCI_EXP_SLTCTL_HPIE));
+ info_obj_add_flag(slt_ctl_enable_obj, "LinkChg", FLAG(w, PCI_EXP_SLTCTL_LLCHG));
+ slt_ctl_control_obj = info_obj_create_in_obj(slt_ctl_obj, "Control");
+ info_obj_add_str(slt_ctl_control_obj, "AttnInd", indicator((w & PCI_EXP_SLTCTL_ATNI) >> 6));
+ info_obj_add_str(slt_ctl_control_obj, "PwrInd", indicator((w & PCI_EXP_SLTCTL_PWRI) >> 8));
+ info_obj_add_flag(slt_ctl_control_obj, "Power", FLAG(w, PCI_EXP_SLTCTL_PWRC));
+ info_obj_add_flag(slt_ctl_control_obj, "Inrelock", FLAG(w, PCI_EXP_SLTCTL_INTERLOCK));
+
+ w = get_conf_word(d, where + PCI_EXP_SLTSTA);
+ slt_sta_obj = info_obj_create_in_obj(exp_obj, "SltSta");
+ slt_sta_status_obj = info_obj_create_in_obj(slt_sta_obj, "Status");
+ info_obj_add_flag(slt_sta_status_obj, "AttnBtn", FLAG(w, PCI_EXP_SLTSTA_ATNB));
+ info_obj_add_flag(slt_sta_status_obj, "PowerFlt", FLAG(w, PCI_EXP_SLTSTA_PWRF));
+ info_obj_add_flag(slt_sta_status_obj, "MRL", FLAG(w, PCI_EXP_SLTSTA_MRL_ST));
+ info_obj_add_flag(slt_sta_status_obj, "CmdCplt", FLAG(w, PCI_EXP_SLTSTA_CMDC));
+ info_obj_add_flag(slt_sta_status_obj, "PresDet", FLAG(w, PCI_EXP_SLTSTA_PRES));
+ info_obj_add_flag(slt_sta_status_obj, "Interlock", FLAG(w, PCI_EXP_SLTSTA_INTERLOCK));
+ slt_sta_changed_obj = info_obj_create_in_obj(slt_sta_obj, "Changed");
+ info_obj_add_flag(slt_sta_changed_obj, "MRL", FLAG(w, PCI_EXP_SLTSTA_MRLS));
+ info_obj_add_flag(slt_sta_changed_obj, "PresDet", FLAG(w, PCI_EXP_SLTSTA_PRSD));
+ info_obj_add_flag(slt_sta_changed_obj, "LinkState", FLAG(w, PCI_EXP_SLTSTA_LLCHG));
+}
+
static void cap_express_root(struct device *d, int where)
{
u32 w = get_conf_word(d, where + PCI_EXP_RTCTL);
@@ -886,6 +1061,29 @@ static void cap_express_root(struct device *d, int where)
FLAG(w, PCI_EXP_RTSTA_PME_PENDING));
}
+static void fill_info_express_root(struct info_obj *exp_obj, struct device *d, int where)
+{
+ struct info_obj *root_cap_obj, *root_ctl_obj, *root_sta_obj;
+
+ u32 w = get_conf_word(d, where + PCI_EXP_RTCTL);
+ root_ctl_obj = info_obj_create_in_obj(exp_obj, "RootCtl");
+ info_obj_add_flag(root_ctl_obj, "ErrCorrectable", FLAG(w, PCI_EXP_RTCTL_SECEE));
+ info_obj_add_flag(root_ctl_obj, "ErrNon-Fatal", FLAG(w, PCI_EXP_RTCTL_SENFEE));
+ info_obj_add_flag(root_ctl_obj, "ErrFatal", FLAG(w, PCI_EXP_RTCTL_SEFEE));
+ info_obj_add_flag(root_ctl_obj, "PMEIntEna", FLAG(w, PCI_EXP_RTCTL_PMEIE));
+ info_obj_add_flag(root_ctl_obj, "CRSVisible", FLAG(w, PCI_EXP_RTCTL_CRSVIS));
+
+ w = get_conf_word(d, where + PCI_EXP_RTCAP);
+ root_cap_obj = info_obj_create_in_obj(exp_obj, "RootCap");
+ info_obj_add_flag(root_cap_obj, "CRSVisible", FLAG(w, PCI_EXP_RTCAP_CRSVIS));
+
+ w = get_conf_long(d, where + PCI_EXP_RTSTA);
+ root_sta_obj = info_obj_create_in_obj(exp_obj, "RootSta");
+ info_obj_add_fmt_str(root_sta_obj, "PME-ReqID", 5, "%04x", w & PCI_EXP_RTSTA_PME_REQID);
+ info_obj_add_flag(root_sta_obj, "PMEStatus", FLAG(w, PCI_EXP_RTSTA_PME_STATUS));
+ info_obj_add_flag(root_sta_obj, "PMEPending", FLAG(w, PCI_EXP_RTSTA_PME_PENDING));
+}
+
static const char *cap_express_dev2_timeout_range(int type)
{
/* Decode Completion Timeout Ranges. */
@@ -1046,6 +1244,61 @@ static void cap_express_dev2(struct device *d, int where, int type)
}
}
+static void fill_info_express_dev2(struct info_obj *exp_obj, struct device *d, int where, int type)
+{
+ u32 l;
+ u16 w;
+ int has_mem_bar = device_has_memory_space_bar(d);
+ struct info_obj *dev_cap2_obj, *dev_ctl2_obj;
+
+ l = get_conf_long(d, where + PCI_EXP_DEVCAP2);
+ dev_cap2_obj = info_obj_create_in_obj(exp_obj, "DevCap2");
+ info_obj_add_str(dev_cap2_obj, "Completion-Timeout", cap_express_dev2_timeout_range(PCI_EXP_DEV2_TIMEOUT_RANGE(l)));
+ info_obj_add_flag(dev_cap2_obj, "TimeoutDis", FLAG(l, PCI_EXP_DEV2_TIMEOUT_DIS));
+ info_obj_add_flag(dev_cap2_obj, "LTR", FLAG(l, PCI_EXP_DEVCAP2_LTR));
+ info_obj_add_str(dev_cap2_obj, "OBFF", cap_express_devcap2_obff(PCI_EXP_DEVCAP2_OBFF(l)));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_DOWNSTREAM)
+ info_obj_add_flag(dev_cap2_obj, "ARIFwd", FLAG(l, PCI_EXP_DEV2_ARI));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM || has_mem_bar)
+ {
+ struct info_obj *dev_cap2_aoc_obj = info_obj_create_in_obj(dev_cap2_obj, "AtomicOpsCap");
+
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM)
+ info_obj_add_flag(dev_cap2_aoc_obj, "Routing", FLAG(l, PCI_EXP_DEVCAP2_ATOMICOP_ROUTING));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || has_mem_bar)
+ {
+ info_obj_add_flag(dev_cap2_aoc_obj, "32bit", FLAG(l, PCI_EXP_DEVCAP2_32BIT_ATOMICOP_COMP));
+ info_obj_add_flag(dev_cap2_aoc_obj, "64bit", FLAG(l, PCI_EXP_DEVCAP2_64BIT_ATOMICOP_COMP));
+ info_obj_add_flag(dev_cap2_aoc_obj, "128bitCAS", FLAG(l, PCI_EXP_DEVCAP2_128BIT_CAS_COMP));
+ }
+ }
+
+ w = get_conf_word(d, where + PCI_EXP_DEVCTL2);
+ dev_ctl2_obj = info_obj_create_in_obj(exp_obj, "DevCtl2");
+ info_obj_add_str(dev_ctl2_obj, "Completion-Timeout", cap_express_dev2_timeout_value(PCI_EXP_DEV2_TIMEOUT_VALUE(w)));
+ info_obj_add_flag(dev_ctl2_obj, "TimeoutDis", FLAG(w, PCI_EXP_DEV2_TIMEOUT_DIS));
+ info_obj_add_flag(dev_ctl2_obj, "LTR", FLAG(w, PCI_EXP_DEV2_LTR));
+ info_obj_add_str(dev_ctl2_obj, "OBFF", cap_express_devctl2_obff(PCI_EXP_DEV2_OBFF(w)));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_DOWNSTREAM)
+ info_obj_add_flag(dev_ctl2_obj, "ARIFwd", FLAG(w, PCI_EXP_DEV2_ARI));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_ROOT_INT_EP || type == PCI_EXP_TYPE_LEG_END)
+ {
+ struct info_obj *dev_ctl2_aoc_obj = info_obj_create_in_obj(dev_ctl2_obj, "AtomicOpsCtl");
+
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_ROOT_INT_EP || type == PCI_EXP_TYPE_LEG_END)
+ info_obj_add_flag(dev_ctl2_aoc_obj, "ReqEn", FLAG(w, PCI_EXP_DEV2_ATOMICOP_REQUESTER_EN));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM)
+ info_obj_add_flag(dev_ctl2_aoc_obj, "EgressBlck", FLAG(w, PCI_EXP_DEV2_ATOMICOP_EGRESS_BLOCK));
+ }
+}
+
+
static const char *cap_express_link2_speed(int type)
{
switch (type)
@@ -1129,6 +1382,38 @@ static void cap_express_link2(struct device *d, int where, int type)
FLAG(w, PCI_EXP_LINKSTA2_EQU_REQ));
}
+static void fill_info_express_link2(struct info_obj *exp_obj, struct device *d, int where, int type)
+{
+ u16 w;
+ struct info_obj *lnk_sta2_obj;
+
+ if (!((type == PCI_EXP_TYPE_ENDPOINT || type == PCI_EXP_TYPE_LEG_END) &&
+ (d->dev->dev != 0 || d->dev->func != 0))) {
+ struct info_obj *lnk_ctl2_obj;
+
+ w = get_conf_word(d, where + PCI_EXP_LNKCTL2);
+ lnk_ctl2_obj = info_obj_create_in_obj(exp_obj, "LnkCtl2");
+ info_obj_add_str(lnk_ctl2_obj, "Target-Link-Speed", cap_express_link2_speed(PCI_EXP_LNKCTL2_SPEED(w)));
+ info_obj_add_flag(lnk_ctl2_obj, "EnterCompliance", FLAG(w, PCI_EXP_LNKCTL2_CMPLNC));
+ info_obj_add_flag(lnk_ctl2_obj, "SpeedDis", FLAG(w, PCI_EXP_LNKCTL2_SPEED_DIS));
+ if (type == PCI_EXP_TYPE_DOWNSTREAM)
+ info_obj_add_str(lnk_ctl2_obj, "Selectable-De-emphasis", cap_express_link2_deemphasis(PCI_EXP_LNKCTL2_DEEMPHASIS(w)));
+ info_obj_add_str(lnk_ctl2_obj, "Transmit-Margin", cap_express_link2_transmargin(PCI_EXP_LNKCTL2_MARGIN(w)));
+ info_obj_add_flag(lnk_ctl2_obj, "EnterModifiedCompliance", FLAG(w, PCI_EXP_LNKCTL2_MOD_CMPLNC));
+ info_obj_add_flag(lnk_ctl2_obj, "ComplianceSOS", FLAG(w, PCI_EXP_LNKCTL2_CMPLNC_SOS));
+ info_obj_add_str(lnk_ctl2_obj, "Compliance-De-emphasis", cap_express_link2_deemphasis(PCI_EXP_LNKCTL2_COM_DEEMPHASIS(w)));
+ }
+
+ w = get_conf_word(d, where + PCI_EXP_LNKSTA2);
+ lnk_sta2_obj = info_obj_create_in_obj(exp_obj, "LnkSta2");
+ info_obj_add_str(lnk_sta2_obj, "Current-De-emphasis-Level", cap_express_link2_deemphasis(PCI_EXP_LINKSTA2_DEEMPHASIS(w)));
+ info_obj_add_flag(lnk_sta2_obj, "EqualizationComplete", FLAG(w, PCI_EXP_LINKSTA2_EQU_COMP));
+ info_obj_add_flag(lnk_sta2_obj, "EqualizationPhase1", FLAG(w, PCI_EXP_LINKSTA2_EQU_PHASE1));
+ info_obj_add_flag(lnk_sta2_obj, "EqualizationPhase2", FLAG(w, PCI_EXP_LINKSTA2_EQU_PHASE2));
+ info_obj_add_flag(lnk_sta2_obj, "EqualizationPhase3", FLAG(w, PCI_EXP_LINKSTA2_EQU_PHASE3));
+ info_obj_add_flag(lnk_sta2_obj, "LinkEqualizationRequest", FLAG(w, PCI_EXP_LINKSTA2_EQU_REQ));
+}
+
static void cap_express_slot2(struct device *d UNUSED, int where UNUSED)
{
/* No capabilities that require this field in PCIe rev2.0 spec. */
@@ -1220,6 +1505,94 @@ cap_express(struct device *d, int where, int cap)
return type;
}
+static int
+fill_info_cap_express(struct info_obj *caps_obj, struct device *d, int where, int cap)
+{
+ int type = (cap & PCI_EXP_FLAGS_TYPE) >> 4;
+ int size;
+ int slot = 0;
+ int link = 1;
+ struct info_obj *express_obj = info_obj_create_in_obj(caps_obj, "express");
+ char buf[128];
+
+ if (verbose >= 2)
+ info_obj_add_fmt_buf_str(express_obj, "ver", buf, sizeof(buf), "%d", cap & PCI_EXP_FLAGS_VERS);
+ switch (type)
+ {
+ case PCI_EXP_TYPE_ENDPOINT:
+ snprintf(buf, sizeof(buf), "Endpoint");
+ break;
+ case PCI_EXP_TYPE_LEG_END:
+ snprintf(buf, sizeof(buf), "Legacy Endpoint");
+ break;
+ case PCI_EXP_TYPE_ROOT_PORT:
+ slot = cap & PCI_EXP_FLAGS_SLOT;
+ snprintf(buf, sizeof(buf), "Root Port (Slot%c)", FLAG(cap, PCI_EXP_FLAGS_SLOT));
+ break;
+ case PCI_EXP_TYPE_UPSTREAM:
+ snprintf(buf, sizeof(buf), "Upstream Port");
+ break;
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ slot = cap & PCI_EXP_FLAGS_SLOT;
+ snprintf(buf, sizeof(buf), "Downstream Port (Slot%c)", FLAG(cap, PCI_EXP_FLAGS_SLOT));
+ break;
+ case PCI_EXP_TYPE_PCI_BRIDGE:
+ snprintf(buf, sizeof(buf), "PCI-Express to PCI/PCI-X Bridge");
+ break;
+ case PCI_EXP_TYPE_PCIE_BRIDGE:
+ slot = cap & PCI_EXP_FLAGS_SLOT;
+ snprintf(buf, sizeof(buf), "PCI/PCI-X to PCI-Express Bridge (Slot%c)",
+ FLAG(cap, PCI_EXP_FLAGS_SLOT));
+ break;
+ case PCI_EXP_TYPE_ROOT_INT_EP:
+ link = 0;
+ snprintf(buf, sizeof(buf), "Root Complex Integrated Endpoint");
+ break;
+ case PCI_EXP_TYPE_ROOT_EC:
+ link = 0;
+ snprintf(buf, sizeof(buf), "Root Complex Event Collector");
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "Unknown type %d", type);
+ }
+ info_obj_add_str(express_obj, "type", buf);
+ info_obj_add_fmt_buf_str(express_obj, "MSI", buf, sizeof(buf), "%02x", (cap & PCI_EXP_FLAGS_IRQ) >> 9);
+
+ if (verbose < 2)
+ return type;
+
+ size = 16;
+ if (slot)
+ size = 24;
+ if (type == PCI_EXP_TYPE_ROOT_PORT)
+ size = 32;
+ if (!config_fetch(d, where + PCI_EXP_DEVCAP, size))
+ return type;
+
+ fill_info_express_dev(express_obj, d, where, type);
+ if (link)
+ fill_info_express_link(express_obj, d, where, type);
+ if (slot)
+ fill_info_express_slot(express_obj, d, where);
+ if (type == PCI_EXP_TYPE_ROOT_PORT)
+ fill_info_express_root(express_obj, d, where);
+
+ if ((cap & PCI_EXP_FLAGS_VERS) < 2)
+ return type;
+
+ size = 16;
+ if (slot)
+ size = 24;
+ if (!config_fetch(d, where + PCI_EXP_DEVCAP2, size))
+ return type;
+
+ fill_info_express_dev2(express_obj, d, where, type);
+ if (link)
+ fill_info_express_link2(express_obj, d, where, type);
+
+ return type;
+}
+
static void
cap_msix(struct device *d, int where, int cap)
{
@@ -1577,3 +1950,47 @@ show_caps(struct device *d, int where)
if (can_have_ext_caps)
show_ext_caps(d, type);
}
+
+void
+fill_info_caps(struct info_obj *dev_obj, struct device *d, int where)
+{
+ struct info_obj *caps_obj = info_obj_create_in_obj(dev_obj, "capabilities");
+
+ if (get_conf_word(d, PCI_STATUS) & PCI_STATUS_CAP_LIST)
+ {
+ byte been_there[256];
+ where = get_conf_byte(d, where) & ~3;
+ memset(been_there, 0, 256);
+ while (where)
+ {
+ int id, next, cap;
+ if (!config_fetch(d, where, 4))
+ {
+ fputs("<access denied>", stderr);
+ break;
+ }
+ id = get_conf_byte(d, where + PCI_CAP_LIST_ID);
+ next = get_conf_byte(d, where + PCI_CAP_LIST_NEXT) & ~3;
+ cap = get_conf_word(d, where + PCI_CAP_FLAGS);
+ if (been_there[where]++)
+ {
+ fprintf(stderr, "<chain looped>\n");
+ break;
+ }
+ if (id == 0xff)
+ {
+ fprintf(stderr, "<chain broken>\n");
+ break;
+ }
+ switch (id)
+ {
+ case PCI_CAP_ID_EXP:
+ fill_info_cap_express(caps_obj, d, where, cap);
+ break;
+ default:
+ break;
+ }
+ where = next;
+ }
+ }
+}
diff --git a/lspci.c b/lspci.c
index ae50a85..d5a02e8 100644
--- a/lspci.c
+++ b/lspci.c
@@ -1250,6 +1250,7 @@ fill_info_htype0(struct info_obj *dev_obj, struct device *d)
fill_info_bases(htype0_obj, d, 6);
fill_info_rom(htype0_obj, d, PCI_ROM_ADDRESS);
+ fill_info_caps(dev_obj, d, PCI_CAPABILITY_LIST);
}
static void
@@ -1359,6 +1360,8 @@ fill_info_htype1(struct info_obj *dev_obj, struct device *d)
info_obj_add_flag(bridgectl_obj, "DiscTmrStat", FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS));
info_obj_add_flag(bridgectl_obj, "DiscTmrSERREn", FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN));
}
+
+ fill_info_caps(dev_obj, d, PCI_CAPABILITY_LIST);
}
static void
@@ -1446,6 +1449,8 @@ fill_info_htype2(struct info_obj *dev_obj, struct device *d)
exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
if (exca)
info_obj_add_fmt_buf_str(htype2_obj, "exca", buf, sizeof(buf), "%04x", exca);
+
+ fill_info_caps(dev_obj, d, PCI_CB_CAPABILITY_LIST);
}
static void
diff --git a/lspci.h b/lspci.h
index fc23d32..1646f99 100644
--- a/lspci.h
+++ b/lspci.h
@@ -58,22 +58,6 @@ void get_subid(struct device *d, word *subvp, word *subdp);
#define BITS(x,at,width) (((x) >> (at)) & ((1 << (width)) - 1))
#define TABLE(tab,x,buf) ((x) < sizeof(tab)/sizeof((tab)[0]) ? (tab)[x] : (sprintf((buf), "??%d", (x)), (buf)))
-/* ls-vpd.c */
-
-void cap_vpd(struct device *d);
-
-/* ls-caps.c */
-
-void show_caps(struct device *d, int where);
-
-/* ls-ecaps.c */
-
-void show_ext_caps(struct device *d, int type);
-
-/* ls-caps-vendor.c */
-
-void show_vendor_caps(struct device *d, int where, int cap);
-
/* ls-info.c */
enum info_val_type {
@@ -128,6 +112,23 @@ struct info_list *info_list_create_in_obj(struct info_obj *parent_obj, char *key
void info_list_add_str(struct info_list *list, const char *str);
void info_list_add_obj(struct info_list *list, struct info_obj *obj);
+/* ls-vpd.c */
+
+void cap_vpd(struct device *d);
+
+/* ls-caps.c */
+
+void show_caps(struct device *d, int where);
+void fill_info_caps(struct info_obj *dev_obj, struct device *d, int where);
+
+/* ls-ecaps.c */
+
+void show_ext_caps(struct device *d, int type);
+
+/* ls-caps-vendor.c */
+
+void show_vendor_caps(struct device *d, int where, int cap);
+
/* ls-kernel.c */
void show_kernel_machine(struct device *d UNUSED);
--
2.14.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/3] lspci: Add support of JSON output format
2018-02-18 23:12 [PATCH v3 0/3] lspci: Add support of JSON output format Viktor Prutyanov
` (2 preceding siblings ...)
2018-02-18 23:12 ` [PATCH v3 3/3] lspci: Add JSON PCI Express capabilities Viktor Prutyanov
@ 2018-03-11 15:03 ` viktor.prutyanov
3 siblings, 0 replies; 5+ messages in thread
From: viktor.prutyanov @ 2018-03-11 15:03 UTC (permalink / raw)
To: linux-pci, mj
=D0=92 Mon, 19 Feb 2018 02:12:48 +0300
Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> =D0=BF=D0=B8=D1=88=D0=B5=
=D1=82:
ping
> This collection of patches adds support of printing PCI info in JSON
> format.
>=20
> 1st patch adds skeleton for creating structured object which can be
> printed in JSON or another structured format.
> 2nd patch adds output of general PCI info which prints with -m, -k,
> -[v]+ options, but without capabilities.
> 3rd patch adds PCI-E capability.
>=20
> For example, we can easily, using jq utility, check speed of a device:
> lspci -Jvv | jq -r '.[][] | select(.Device =3D=3D "GK107M [GeForce GT
> 750M]") | .capabilities.express | {s1:.LnkCap.Speed,
> s2:.LnkSta.Speed, w1 :.LnkCap.Width, w2:.LnkSta.Width }'
>=20
> {
> "s1": "8GT/s",
> "s2": "5GT/s",
> "w1": "x16",
> "w2": "x4"
> }
>=20
> Viktor Prutyanov (3):
> lspci: Add printing info in JSON format
> lspci: Add PCI info output in JSON format
> lspci: Add JSON PCI Express capabilities
>=20
> Makefile | 3 +-
> common.c | 2 +-
> ls-caps.c | 417 +++++++++++++++++++++++++++++++++++
> ls-info.c | 328 ++++++++++++++++++++++++++++
> ls-kernel.c | 24 +++
> lspci.c | 706
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> lspci.h | 56 +++++ lspci.man | 3 +
> pciutils.h | 2 +-
> 9 files changed, 1537 insertions(+), 4 deletions(-)
> create mode 100644 ls-info.c
>=20
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2018-03-11 15:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-18 23:12 [PATCH v3 0/3] lspci: Add support of JSON output format Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 1/3] lspci: Add printing info in JSON format Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 2/3] lspci: Add PCI info output " Viktor Prutyanov
2018-02-18 23:12 ` [PATCH v3 3/3] lspci: Add JSON PCI Express capabilities Viktor Prutyanov
2018-03-11 15:03 ` [PATCH v3 0/3] lspci: Add support of JSON output format viktor.prutyanov
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.