PERFORCE change 227289 for review
Brooks Davis
brooks at FreeBSD.org
Mon Apr 1 20:09:24 UTC 2013
http://p4web.freebsd.org/@@227289?ac=10
Change 227289 by brooks at brooks_zenith on 2013/04/01 20:08:35
Record the interrupt-parent of devices that have one in
struct device. Use this to improve reporting of interrupt-parents
in two ways:
Add an indication of the interrupt-parent when printing the
child's resources:
altera_jtag_uart0: <Altera JTAG UART> mem 0x900000007f000000-0x900000007f00003f irq 0 (beripic0) on simplebus0
Extend struct u_device and the hw.bus.devices sysctl used
by libdevinfo to include the device parent. This is done
in a fully foward and backward compatible manner. The
kernel can now return a partial structure when an old
libdevinfo requests a u_device that is shorter than the
current version. Each new field or set of fields in
u_device is indicated by a bit in the dv_fields entry.
Use this new functionality to add a -i option to devinfo
that shows the device tree by interrupt-parent rather than
bus. Resources described as "Interrupt" are always shown
in -i mode
Affected files ...
.. //depot/projects/ctsrd/beribsd/src/lib/libdevinfo/devinfo.3#3 edit
.. //depot/projects/ctsrd/beribsd/src/lib/libdevinfo/devinfo.c#3 edit
.. //depot/projects/ctsrd/beribsd/src/lib/libdevinfo/devinfo.h#3 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/simplebus.c#5 edit
.. //depot/projects/ctsrd/beribsd/src/sys/kern/subr_bus.c#6 edit
.. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_pic.c#3 edit
.. //depot/projects/ctsrd/beribsd/src/sys/sys/bus.h#4 edit
.. //depot/projects/ctsrd/beribsd/src/usr.sbin/devinfo/devinfo.c#3 edit
Differences ...
==== //depot/projects/ctsrd/beribsd/src/lib/libdevinfo/devinfo.3#3 (text+ko) ====
@@ -36,6 +36,7 @@
.Nm devinfo_handle_to_resource ,
.Nm devinfo_handle_to_rman ,
.Nm devinfo_foreach_device_child ,
+.Nm devinfo_foreach_device_intr_child ,
.Nm devinfo_foreach_device_resource ,
.Nm devinfo_foreach_rman_resource ,
.Nm devinfo_foreach_rman
@@ -61,6 +62,12 @@
.Fa "void *arg"
.Fc
.Ft int
+.Fo devinfo_foreach_device_intr_child
+.Fa "struct devinfo_dev *parent"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_dev *child, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
.Fo devinfo_foreach_device_resource
.Fa "struct devinfo_dev *dev"
.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_dev *dev, \:struct devinfo_res *res, void *arg\*[rp]"
@@ -163,9 +170,11 @@
it will return the handle to the root of the device tree.
.Pp
.Fn devinfo_foreach_device_child
-invokes its callback argument
+and
+.Fn devinfo_foreach_device_intr_child
+invoke its callback argument
.Fa fn
-on every device which is an immediate child of
+on every device which is an immediate child or interrupt child of
.Fa device .
The
.Fa fn
==== //depot/projects/ctsrd/beribsd/src/lib/libdevinfo/devinfo.c#3 (text+ko) ====
@@ -171,7 +171,7 @@
int dev_ptr;
int name2oid[2];
int oid[CTL_MAXNAME + 12];
- size_t oidlen, rlen;
+ size_t newfields, oidlen, rlen;
char *name;
int error;
@@ -217,6 +217,12 @@
warn("sysctl hw.bus.devices.%d", dev_idx);
return(errno);
}
+ if (rlen < sizeof(struct ou_device)) {
+ warnx("impossibly small u_device");
+ return(EINVAL);
+ }
+ if (rlen > sizeof(struct ou_device))
+ newfields = 1;
if ((dd = malloc(sizeof(*dd))) == NULL)
return(ENOMEM);
dd->dd_dev.dd_handle = udev.dv_handle;
@@ -237,6 +243,11 @@
dd->dd_dev.dd_devflags = udev.dv_devflags;
dd->dd_dev.dd_flags = udev.dv_flags;
dd->dd_dev.dd_state = udev.dv_state;
+ if (newfields && (udev.dv_fields & DV_FIELD_INTR_PARENT) &&
+ udev.dv_intr_parent != 0)
+ dd->dd_dev.dd_intr_parent = udev.dv_intr_parent;
+ else
+ dd->dd_dev.dd_intr_parent = udev.dv_parent;
TAILQ_INSERT_TAIL(&devinfo_dev, dd, dd_link);
}
debug("fetched %d devices", dev_idx);
@@ -448,6 +459,25 @@
}
/*
+ * Iterate over the interrupt children of a device, calling (fn) on each.
+ * If (fn) returns nonzero, abort the scan and return.
+ */
+int
+devinfo_foreach_device_intr_child(struct devinfo_dev *parent,
+ int (* fn)(struct devinfo_dev *child, void *arg),
+ void *arg)
+{
+ struct devinfo_i_dev *dd;
+ int error;
+
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_intr_parent == parent->dd_handle)
+ if ((error = fn(&dd->dd_dev, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
* Iterate over all the resources owned by a device, calling (fn) on each.
* If (fn) returns nonzero, abort the scan and return.
*/
==== //depot/projects/ctsrd/beribsd/src/lib/libdevinfo/devinfo.h#3 (text+ko) ====
@@ -51,6 +51,7 @@
uint32_t dd_devflags; /* API flags */
uint16_t dd_flags; /* internal dev flags */
devinfo_state_t dd_state; /* attacement state of dev */
+ devinfo_handle_t dd_intr_parent; /* Interrupt parent */
};
struct devinfo_rman {
@@ -108,6 +109,15 @@
void *arg);
/*
+ * Iterate over the interrupt children of a device, calling (fn) on each. If
+ * If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_device_intr_child(struct devinfo_dev *parent,
+ int (* fn)(struct devinfo_dev *child, void *arg),
+ void *arg);
+
+/*
* Iterate over all the resources owned by a device, calling (fn) on each.
* If (fn) returns nonzero, abort the scan and return.
*/
==== //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/simplebus.c#5 (text+ko) ====
@@ -228,6 +228,7 @@
static int
simplebus_print_child(device_t dev, device_t child)
{
+ device_t ip;
struct simplebus_devinfo *di;
struct resource_list *rl;
int rv;
@@ -239,6 +240,8 @@
rv += bus_print_child_header(dev, child);
rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ if ((ip = simplebus_get_interrupt_parent(child)) != NULL)
+ rv += printf(" (%s)", device_get_nameunit(ip));
rv += bus_print_child_footer(dev, child);
return (rv);
@@ -335,9 +338,14 @@
{
struct simplebus_devinfo *di;
struct fdt_ic *ic;
+ device_t ip;
ihandle_t iph;
phandle_t ph;
+ ip = device_get_intr_parent(dev);
+ if (ip != NULL)
+ return (ip);
+
di = device_get_ivars(dev);
if (di == NULL)
return (NULL);
@@ -347,11 +355,14 @@
iph = fdt32_to_cpu(iph);
ph = OF_instance_to_package(iph);
SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) {
- if (ic->iph == ph)
- return (ic->dev);
+ if (ic->iph == ph) {
+ ip = ic->dev;
+ device_set_intr_parent(dev, ip);
+ break;
+ }
}
}
- return (NULL);
+ return (ip);
}
static int
==== //depot/projects/ctsrd/beribsd/src/sys/kern/subr_bus.c#6 (text+ko) ====
@@ -108,6 +108,7 @@
TAILQ_ENTRY(device) link; /**< list of devices in parent */
TAILQ_ENTRY(device) devlink; /**< global device list membership */
device_t parent; /**< parent of this device */
+ device_t intr_parent; /**< interrupt parent of this device */
device_list_t children; /**< list of child devices */
/*
@@ -2162,6 +2163,24 @@
}
/**
+ * @brief Return the interrupt parent of a device
+ */
+device_t
+device_get_intr_parent(device_t dev)
+{
+ return (dev->intr_parent);
+}
+
+/**
+ * @brief Set the interrupt parent of a device
+ */
+void
+device_set_intr_parent(device_t dev, device_t intr_parent)
+{
+ dev->intr_parent = intr_parent;
+}
+
+/**
* @brief Get a list of children of a device
*
* An array containing a list of all the children of the given device
@@ -4805,7 +4824,9 @@
udev.dv_devflags = dev->devflags;
udev.dv_flags = dev->flags;
udev.dv_state = dev->state;
- error = SYSCTL_OUT(req, &udev, sizeof(udev));
+ udev.dv_fields = DV_FIELDS;
+ udev.dv_intr_parent = (uintptr_t)dev->intr_parent;
+ error = SYSCTL_OUT(req, &udev, MIN(req->oldlen, sizeof(udev)));
return (error);
}
==== //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_pic.c#3 (text+ko) ====
@@ -425,7 +425,7 @@
sc->bp_src_rman.rm_start = 0;
sc->bp_src_rman.rm_end = sc->bp_nsrcs - 1;
sc->bp_src_rman.rm_type = RMAN_ARRAY;
- sc->bp_src_rman.rm_descr = "Interrupt sources";
+ sc->bp_src_rman.rm_descr = "Interrupt source";
if (rman_init(&(sc->bp_src_rman)) != 0 ||
rman_manage_region(&(sc->bp_src_rman), 0, sc->bp_nsrcs - 1) != 0) {
device_printf(dev, "Failed to set up sources rman");
==== //depot/projects/ctsrd/beribsd/src/sys/sys/bus.h#4 (text+ko) ====
@@ -59,6 +59,13 @@
/**
* @brief Device information exported to userspace.
+ *
+ * New fields must be appended to the structure. Each new field or set of
+ * fields should be paired with a bit in dv_fields_present. When libdevinfo
+ * reads a structure from hw.bus.devices that is larger than sizeof(ou_device)
+ * it will use these bits to determine which fields the current kernel
+ * provides. This allows never versions of libdevinfo to operate with older
+ * kernels.
*/
struct u_device {
uintptr_t dv_handle;
@@ -72,7 +79,30 @@
uint32_t dv_devflags; /**< @brief API Flags for device */
uint16_t dv_flags; /**< @brief flags for dev date */
device_state_t dv_state; /**< @brief State of attachment */
- /* XXX more driver info? */
+ uint64_t dv_fields; /**< @brief Further fields */
+#define DV_FIELD_INTR_PARENT 0x1
+#define DV_FIELDS (DV_FIELD_INTR_PARENT)
+ uintptr_t dv_intr_parent; /**< @brief Interrupt-parent */
+};
+
+/**
+ * @brief Old, static set of device information exported to userspace.
+ *
+ * This definition exists to portably provide size information to
+ * consumers of hw.bus.devices.
+ */
+struct ou_device {
+ uintptr_t dv_handle;
+ uintptr_t dv_parent;
+
+ char dv_name[32]; /**< @brief Name of device in tree. */
+ char dv_desc[32]; /**< @brief Driver description */
+ char dv_drivername[32]; /**< @brief Driver name */
+ char dv_pnpinfo[128]; /**< @brief Plug and play info */
+ char dv_location[128]; /**< @brief Where is the device? */
+ uint32_t dv_devflags; /**< @brief API Flags for device */
+ uint16_t dv_flags; /**< @brief flags for dev date */
+ device_state_t dv_state; /**< @brief State of attachment */
};
#ifdef _KERNEL
@@ -437,6 +467,8 @@
driver_t *device_get_driver(device_t dev);
u_int32_t device_get_flags(device_t dev);
device_t device_get_parent(device_t dev);
+device_t device_get_intr_parent(device_t dev);
+void device_set_intr_parent(device_t dev, device_t intr_parent);
int device_get_children(device_t dev, device_t **listp, int *countp);
void *device_get_ivars(device_t dev);
void device_set_ivars(device_t dev, void *ivars);
==== //depot/projects/ctsrd/beribsd/src/usr.sbin/devinfo/devinfo.c#3 (text+ko) ====
@@ -36,9 +36,11 @@
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "devinfo.h"
+static int iflag;
static int rflag;
static int vflag;
@@ -113,6 +115,9 @@
ia->indent = 0;
if (devinfo_foreach_rman_resource(rman,
print_device_matching_resource, ia) != 0) {
+ /* XXX: Resources should have types... */
+ if(iflag && !rflag && strncmp("Interrupt", rman->dm_desc, 9) != 0)
+ goto skip;
/* there are, print header */
for (i = 0; i < indent; i++)
@@ -124,12 +129,13 @@
devinfo_foreach_rman_resource(rman,
print_device_matching_resource, ia);
}
+skip:
ia->indent = indent;
return(0);
}
/*
- * Print information about a device.
+ * Print information about a device and its children.
*/
int
print_device(struct devinfo_dev *dev, void *arg)
@@ -147,7 +153,7 @@
if (vflag && *dev->dd_location)
printf(" at %s", dev->dd_location);
printf("\n");
- if (rflag) {
+ if (iflag || rflag) {
ia.indent = indent + 4;
ia.arg = dev;
devinfo_foreach_rman(print_device_rman_resources,
@@ -155,8 +161,12 @@
}
}
- return(devinfo_foreach_device_child(dev, print_device,
- (void *)((char *)arg + 2)));
+ if (iflag)
+ return(devinfo_foreach_device_intr_child(dev, print_device,
+ (void *)((char *)arg + 2)));
+ else
+ return(devinfo_foreach_device_child(dev, print_device,
+ (void *)((char *)arg + 2)));
}
/*
@@ -197,8 +207,11 @@
int c, uflag;
uflag = 0;
- while ((c = getopt(argc, argv, "ruv")) != -1) {
+ while ((c = getopt(argc, argv, "iruv")) != -1) {
switch(c) {
+ case 'i':
+ iflag++;
+ break;
case 'r':
rflag++;
break;
@@ -210,7 +223,7 @@
break;
default:
fprintf(stderr, "%s\n%s\n",
- "usage: devinfo [-rv]",
+ "usage: devinfo [-irv]",
" devinfo -u");
exit(1);
}
@@ -227,7 +240,11 @@
devinfo_foreach_rman(print_rman, NULL);
} else {
/* print device hierarchy */
- devinfo_foreach_device_child(root, print_device, (void *)0);
+ if (iflag)
+ devinfo_foreach_device_intr_child(root, print_device,
+ NULL);
+ else
+ devinfo_foreach_device_child(root, print_device, NULL);
}
return(0);
}
More information about the p4-projects
mailing list