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>