Note that I moved the new offset_table entries to the end of the structure so
that previously-compiled extension modules using OFFSET() will not break.
Thanks,
Dave
----- Original Message -----
From: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
dev -p supports to show the PCI information, however, it works
in old kernel only. This patch gets it available in recently kernel.
And also it will show the PCI BUS information. The BUS information
may be useful for investigation of PCI hotplug issue to track the
PCI bridge.
Signed-off-by: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
---
defs.h | 11 ++
dev.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 338 insertions(+), 6 deletions(-)
diff --git a/defs.h b/defs.h
index d6492c5..e7d9bb2 100644
--- a/defs.h
+++ b/defs.h
@@ -1624,11 +1624,20 @@ struct offset_table { /* stash of
commonly-used offsets */
long pci_dev_global_list;
long pci_dev_next;
long pci_dev_bus;
+ long pci_dev_dev;
long pci_dev_devfn;
long pci_dev_class;
long pci_dev_device;
+ long pci_dev_hdr_type;
+ long pci_dev_pcie_flags_reg;
long pci_dev_vendor;
long pci_bus_number;
+ long pci_bus_node;
+ long pci_bus_devices;
+ long pci_bus_dev;
+ long pci_bus_children;
+ long pci_bus_parent;
+ long pci_bus_self;
long resource_entry_t_from;
long resource_entry_t_num;
long resource_entry_t_name;
@@ -1832,6 +1841,7 @@ struct offset_table { /* stash of
commonly-used offsets */
long class_private_devices;
long device_knode_class;
long device_node;
+ long device_kobj;
long gendisk_dev;
long gendisk_kobj;
long gendisk_part0;
@@ -1841,6 +1851,7 @@ struct offset_table { /* stash of
commonly-used offsets */
long klist_node_n_klist;
long klist_node_n_node;
long kobject_entry;
+ long kobject_name;
long kset_list;
long request_list_count;
long request_queue_in_flight;
diff --git a/dev.c b/dev.c
index 3db898a..7ce2422 100644
--- a/dev.c
+++ b/dev.c
@@ -24,6 +24,7 @@ static void dump_blkdevs_v3(ulong);
static ulong search_cdev_map_probes(char *, int, int, ulong *);
static ulong search_bdev_map_probes(char *, int, int, ulong *);
static void do_pci(void);
+static void do_pci2(void);
static void do_io(void);
static void do_resource_list(ulong, char *, int);
@@ -51,11 +52,23 @@ dev_init(void)
MEMBER_OFFSET_INIT(pci_dev_global_list, "pci_dev",
"global_list");
MEMBER_OFFSET_INIT(pci_dev_next, "pci_dev", "next");
MEMBER_OFFSET_INIT(pci_dev_bus, "pci_dev", "bus");
+ MEMBER_OFFSET_INIT(pci_dev_dev, "pci_dev", "dev");
MEMBER_OFFSET_INIT(pci_dev_devfn, "pci_dev", "devfn");
MEMBER_OFFSET_INIT(pci_dev_class, "pci_dev", "class");
MEMBER_OFFSET_INIT(pci_dev_device, "pci_dev", "device");
+ MEMBER_OFFSET_INIT(pci_dev_hdr_type, "pci_dev", "hdr_type");
+ MEMBER_OFFSET_INIT(pci_dev_pcie_flags_reg, "pci_dev",
"pcie_flags_reg");
MEMBER_OFFSET_INIT(pci_dev_vendor, "pci_dev", "vendor");
MEMBER_OFFSET_INIT(pci_bus_number, "pci_bus", "number");
+ MEMBER_OFFSET_INIT(pci_bus_node, "pci_bus", "node");
+ MEMBER_OFFSET_INIT(pci_bus_devices, "pci_bus", "devices");
+ MEMBER_OFFSET_INIT(pci_bus_dev, "pci_bus", "dev");
+ MEMBER_OFFSET_INIT(pci_bus_children, "pci_bus", "children");
+ MEMBER_OFFSET_INIT(pci_bus_parent, "pci_bus", "parent");
+ MEMBER_OFFSET_INIT(pci_bus_self, "pci_bus", "self");
+
+ MEMBER_OFFSET_INIT(device_kobj, "device", "kobj");
+ MEMBER_OFFSET_INIT(kobject_name, "kobject", "name");
STRUCT_SIZE_INIT(resource, "resource");
if ((VALID_STRUCT(resource) && symbol_exists("do_resource_list")) ||
@@ -114,10 +127,14 @@ cmd_dev(void)
return;
case 'p':
- if (machine_type("S390X") ||
- (THIS_KERNEL_VERSION >= LINUX(2,6,26)))
+ if (machine_type("S390X"))
+ option_not_supported(c);
+ if (symbol_exists("pci_devices"))
+ do_pci();
+ else if (symbol_exists("pci_root_buses"))
+ do_pci2();
+ else
option_not_supported(c);
- do_pci();
return;
default:
@@ -2217,6 +2234,313 @@ do_resource_list(ulong first_entry, char
*resource_buf, int size)
#endif /* USE_2_2_17_PCI_H */
+#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
+#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */
+#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */
+#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
+#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
+#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
+#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */
+#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */
+#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint
*/
+#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */
+
+static void
+fill_dev_name(ulong pci_dev, char *name)
+{
+ ulong kobj, value;
+
+ memset(name, 0, sizeof(*name) * BUFSIZE);
+
+ kobj = pci_dev + OFFSET(pci_dev_dev) + OFFSET(device_kobj);
+
+ readmem(kobj + OFFSET(kobject_name),
+ KVADDR, &value, sizeof(void *), "kobject name",
+ FAULT_ON_ERROR);
+
+ read_string(value, name, BUFSIZE-1);
+}
+
+static void
+fill_bus_name(ulong pci_bus, char *name)
+{
+ ulong kobj, value;
+
+ memset(name, 0, sizeof(*name) * BUFSIZE);
+
+ kobj = pci_bus + OFFSET(pci_bus_dev) + OFFSET(device_kobj);
+
+ readmem(kobj + OFFSET(kobject_name),
+ KVADDR, &value, sizeof(void *), "kobject name",
+ FAULT_ON_ERROR);
+
+ read_string(value, name, BUFSIZE-1);
+}
+
+static void
+fill_dev_id(ulong pci_dev, char *id)
+{
+ unsigned short device, vendor;
+
+ memset(id, 0, sizeof(*id) * BUFSIZE);
+
+ readmem(pci_dev + OFFSET(pci_dev_device),
+ KVADDR, &device, sizeof(short), "pci dev device",
+ FAULT_ON_ERROR);
+ readmem(pci_dev + OFFSET(pci_dev_vendor), KVADDR,
+ &vendor, sizeof(short), "pci dev vendor", FAULT_ON_ERROR);
+
+ sprintf(id, "%x:%x", vendor, device);
+}
+
+static void
+fill_dev_class(ulong pci_dev, char *c)
+{
+ unsigned int class;
+
+ memset(c, 0, sizeof(*c) * BUFSIZE);
+ readmem(pci_dev + OFFSET(pci_dev_class), KVADDR,
+ &class, sizeof(int), "pci class", FAULT_ON_ERROR);
+
+ class >>= 8;
+
+ sprintf(c, "%04x", class);
+}
+
+static int
+pci_pcie_type(ulong cap)
+{
+ return (cap & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
+static int
+pci_is_bridge(unsigned char hdr_type)
+{
+ return hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ hdr_type == PCI_HEADER_TYPE_CARDBUS;
+}
+
+static void
+fill_pcie_type(ulong pcidev, char *t)
+{
+ int type, bufidx = 0;
+ unsigned short pciecap;
+ unsigned char hdr_type;
+
+ memset(t, 0, sizeof(*t) * BUFSIZE);
+
+ readmem(pcidev + OFFSET(pci_dev_hdr_type), KVADDR, &hdr_type,
+ sizeof(char), "pci dev hdr_type", FAULT_ON_ERROR);
+
+ if (!VALID_MEMBER(pci_dev_pcie_flags_reg))
+ goto bridge_chk;
+
+ readmem(pcidev + OFFSET(pci_dev_pcie_flags_reg), KVADDR, &pciecap,
+ sizeof(unsigned short), "pci dev pcie_flags_reg", FAULT_ON_ERROR);
+
+ type = pci_pcie_type(pciecap);
+
+ if (type == PCI_EXP_TYPE_ENDPOINT)
+ bufidx = sprintf(t, "ENDPOINT");
+ else if (type == PCI_EXP_TYPE_LEG_END)
+ bufidx = sprintf(t, "LEG_END");
+ else if (type == PCI_EXP_TYPE_ROOT_PORT)
+ bufidx = sprintf(t, "ROOT_PORT");
+ else if (type == PCI_EXP_TYPE_UPSTREAM)
+ bufidx = sprintf(t, "UPSTREAM");
+ else if (type == PCI_EXP_TYPE_DOWNSTREAM)
+ bufidx = sprintf(t, "DOWNSTREAM");
+ else if (type == PCI_EXP_TYPE_PCI_BRIDGE)
+ bufidx = sprintf(t, "PCI_BRIDGE");
+ else if (type == PCI_EXP_TYPE_PCIE_BRIDGE)
+ bufidx = sprintf(t, "PCIE_BRIDGE");
+ else if (type == PCI_EXP_TYPE_RC_END)
+ bufidx = sprintf(t, "RC_END");
+ else if (type == PCI_EXP_TYPE_RC_EC)
+ bufidx = sprintf(t, "RC_EC");
+
+bridge_chk:
+ if (pci_is_bridge(hdr_type))
+ sprintf(t + bufidx, " [BRIDGE]");
+}
+
+static void
+walk_devices(ulong pci_bus)
+{
+ struct list_data list_data, *ld;
+ int devcnt, i;
+ ulong *devlist, self;
+ char name[BUFSIZE], class[BUFSIZE], id[BUFSIZE], type[BUFSIZE];
+ char pcidev_hdr[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+ char buf4[BUFSIZE];
+ char buf5[BUFSIZE];
+
+ ld = &list_data;
+
+ BZERO(ld, sizeof(struct list_data));
+
+ readmem(pci_bus + OFFSET(pci_bus_devices), KVADDR,
+ &ld->start, sizeof(void *), "pci bus devices",
+ FAULT_ON_ERROR);
+
+ if (VALID_MEMBER(pci_dev_pcie_flags_reg))
+ snprintf(pcidev_hdr, sizeof(pcidev_hdr), "%s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER, "PCI DEV"),
+ mkstring(buf2, strlen("0000:00:00.0"), CENTER, "DO:BU:SL.FN"),
+ mkstring(buf3, strlen("0000") + 2, CENTER, "CLASS"),
+ mkstring(buf4, strlen("0000:0000"), CENTER, "PCI_ID"),
+ mkstring(buf5, 10, CENTER, "TYPE"));
+ else
+ snprintf(pcidev_hdr, sizeof(pcidev_hdr), "%s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER, "PCI DEV"),
+ mkstring(buf2, strlen("0000:00:00.0"), CENTER, "DO:BU:SL.FN"),
+ mkstring(buf3, strlen("0000") + 2, CENTER, "CLASS"),
+ mkstring(buf4, strlen("0000:0000"), CENTER, "PCI_ID"));
+
+ fprintf(fp, " %s", pcidev_hdr);
+
+ readmem(pci_bus + OFFSET(pci_bus_self), KVADDR, &self,
+ sizeof(void *), "pci bus self", FAULT_ON_ERROR);
+ if (self) {
+ fill_dev_name(self, name);
+ fill_dev_class(self, class);
+ fill_dev_id(self, id);
+ fill_pcie_type(self, type);
+ fprintf(fp, " %s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(self)),
+ mkstring(buf2, strlen("0000:00:00.0"), CENTER, name),
+ mkstring(buf3, strlen("0000") + 2, CENTER, class),
+ mkstring(buf4, strlen("0000:0000"), CENTER, id),
+ mkstring(buf5, 10, CENTER, type));
+ }
+
+ if (ld->start == (pci_bus + OFFSET(pci_bus_devices)))
+ return;
+
+ ld->end = pci_bus + OFFSET(pci_bus_devices);
+ hq_open();
+ devcnt = do_list(ld);
+ devlist = (ulong *)GETBUF(devcnt * sizeof(ulong));
+ devcnt = retrieve_list(devlist, devcnt);
+ hq_close();
+
+ for (i = 0; i < devcnt; i++) {
+ fill_dev_name(devlist[i], name);
+ fill_dev_class(devlist[i], class);
+ fill_dev_id(devlist[i], id);
+ fill_pcie_type(devlist[i], type);
+ fprintf(fp, " %s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(devlist[i])),
+ mkstring(buf2, strlen("0000:00:00.0"), CENTER, name),
+ mkstring(buf3, strlen("0000") + 2, CENTER, class),
+ mkstring(buf4, strlen("0000:0000"), CENTER, id),
+ mkstring(buf5, 10, CENTER, type));
+ }
+ FREEBUF(devlist);
+}
+
+static void
+walk_buses(ulong pci_bus)
+{
+ struct list_data list_data, *ld;
+ int buscnt, i;
+ ulong *buslist, parent;
+ char pcibus_hdr[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+
+ ld = &list_data;
+
+ BZERO(ld, sizeof(struct list_data));
+
+ readmem(pci_bus + OFFSET(pci_bus_children), KVADDR,
+ &ld->start, sizeof(void *), "pci bus children",
+ FAULT_ON_ERROR);
+
+ if (ld->start == (pci_bus + OFFSET(pci_bus_children)))
+ return;
+
+ ld->end = pci_bus + OFFSET(pci_bus_children);
+ hq_open();
+ buscnt = do_list(ld);
+ buslist = (ulong *)GETBUF(buscnt * sizeof(ulong));
+ buscnt = retrieve_list(buslist, buscnt);
+ hq_close();
+
+ snprintf(pcibus_hdr, sizeof(pcibus_hdr), "%s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER, "PCI BUS"),
+ mkstring(buf2, VADDR_PRLEN, CENTER, "PARENT BUS"));
+
+ for (i = 0; i < buscnt; i++) {
+ readmem(buslist[i] + OFFSET(pci_bus_parent), KVADDR, &parent,
+ sizeof(void *), "pci bus parent", FAULT_ON_ERROR);
+
+ fprintf(fp, " %s", pcibus_hdr);
+
+ fprintf(fp, " %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(buslist[i])),
+ mkstring(buf2, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(parent)));
+ walk_devices(buslist[i]);
+ fprintf(fp, "\n");
+ walk_buses(buslist[i]);
+ }
+ FREEBUF(buslist);
+}
+
+static void
+do_pci2(void)
+{
+ struct list_data list_data, *ld;
+ int rootbuscnt, i;
+ ulong *rootbuslist;
+ unsigned long pci_root_bus_addr = symbol_value("pci_root_buses");
+ char name[BUFSIZE];
+ char pcirootbus_hdr[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+
+ ld = &list_data;
+ BZERO(ld, sizeof(struct list_data));
+
+ get_symbol_data("pci_root_buses", sizeof(void *), &ld->start);
+
+ if (ld->start == pci_root_bus_addr)
+ error(FATAL, "no PCI devices found on this system.\n");
+
+ ld->end = pci_root_bus_addr;
+
+ hq_open();
+ rootbuscnt = do_list(ld);
+ rootbuslist = (ulong *)GETBUF(rootbuscnt * sizeof(ulong));
+ rootbuscnt = retrieve_list(rootbuslist, rootbuscnt);
+ hq_close();
+
+ snprintf(pcirootbus_hdr, sizeof(pcirootbus_hdr), "%s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER, "ROOT BUS"),
+ mkstring(buf2, strlen("0000:00"), CENTER, "BUSNAME"));
+
+ for (i = 0; i < rootbuscnt; i++) {
+ fprintf(fp, "%s", pcirootbus_hdr);
+ fill_bus_name(rootbuslist[i], name);
+ fprintf(fp, "%s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(rootbuslist[i])),
+ mkstring(buf2, strlen("0000:00"), CENTER, name));
+ walk_devices(rootbuslist[i]);
+ walk_buses(rootbuslist[i]);
+
+ fprintf(fp, "\n");
+ }
+ FREEBUF(rootbuslist);
+}
+
static void
do_pci(void)
{
@@ -2230,9 +2554,6 @@ do_pci(void)
char buf2[BUFSIZE];
char buf3[BUFSIZE];
- if (!symbol_exists("pci_devices"))
- error(FATAL, "no PCI devices found on this system.\n");
-
BZERO(&pcilist_data, sizeof(struct list_data));
if (VALID_MEMBER(pci_dev_global_list)) {
--
2.19.0
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility