Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Apr 2013 20:09:23 GMT
From:      Brooks Davis <brooks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 227289 for review
Message-ID:  <201304012009.r31K9NA6027721@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@227289?ac=10

Change 227289 by brooks@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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304012009.r31K9NA6027721>