Date: Sat, 28 Jan 2017 13:25:06 +0000 (UTC) From: Robert Watson <rwatson@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r312922 - head/sys/dev/altera/avgen Message-ID: <201701281325.v0SDP6Yf090172@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rwatson Date: Sat Jan 28 13:25:06 2017 New Revision: 312922 URL: https://svnweb.freebsd.org/changeset/base/312922 Log: Merge enhancements to the ALTERA Avalon bus generic device attachment driver to support exposing a GEOM device, which can be used to mount Avalon-attached ROMs, reserved areas of DRAM, etc, as a filesystem: commit 9deb1e60eaaaf7a3687e48c58af5efd756f32ec6 Author: Robert N. M. Watson <robert.watson@cl.cam.ac.uk> Date: Sat Mar 5 20:33:12 2016 +0000 Use format strings with make_dev(9) in avgen(4). commit 0bf2176c23e7425bfa042c08a24f8a25fe6d8885 Author: Robert N. M. Watson <robert.watson@cl.cam.ac.uk> Date: Tue Mar 1 10:23:23 2016 +0000 Implement a new "geomio" configuration argument to altera_avgen(4), the generic I/O device we attach to various BERI peripherals. The new option requests that, instead of exposing the underlying device via a special device node in /dev, it instead be exposed via geom(4), allowing it to be used with filesystems. The current implementation does not allow a device to be exposed both for file/mmap and geom, so one of the two models must be selected when configuring it via FDT or device.hints. A typical use of the new option will be: sri-cambridge,geomio = "rw"; MFC after: 1 week Sponsored by: DARPA, AFRL Modified: head/sys/dev/altera/avgen/altera_avgen.c head/sys/dev/altera/avgen/altera_avgen.h head/sys/dev/altera/avgen/altera_avgen_fdt.c head/sys/dev/altera/avgen/altera_avgen_nexus.c Modified: head/sys/dev/altera/avgen/altera_avgen.c ============================================================================== --- head/sys/dev/altera/avgen/altera_avgen.c Sat Jan 28 13:09:18 2017 (r312921) +++ head/sys/dev/altera/avgen/altera_avgen.c Sat Jan 28 13:25:06 2017 (r312922) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2013 Robert N. M. Watson + * Copyright (c) 2012-2013, 2016 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/bio.h> #include <sys/bus.h> #include <sys/condvar.h> #include <sys/conf.h> @@ -45,6 +46,8 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/uio.h> +#include <geom/geom_disk.h> + #include <machine/bus.h> #include <machine/resource.h> @@ -65,14 +68,19 @@ static d_mmap_t altera_avgen_mmap; static d_read_t altera_avgen_read; static d_write_t altera_avgen_write; +#define ALTERA_AVGEN_DEVNAME "altera_avgen" +#define ALTERA_AVGEN_DEVNAME_FMT (ALTERA_AVGEN_DEVNAME "%d") + static struct cdevsw avg_cdevsw = { .d_version = D_VERSION, .d_mmap = altera_avgen_mmap, .d_read = altera_avgen_read, .d_write = altera_avgen_write, - .d_name = "altera_avgen", + .d_name = ALTERA_AVGEN_DEVNAME, }; +#define ALTERA_AVGEN_SECTORSIZE 512 /* Not configurable at this time. */ + static int altera_avgen_read(struct cdev *dev, struct uio *uio, int flag) { @@ -227,11 +235,103 @@ altera_avgen_mmap(struct cdev *dev, vm_o return (0); } +/* + * NB: We serialise block reads and writes in case the OS is generating + * concurrent I/O against the same block, in which case we want one I/O (or + * another) to win. This is not sufficient to provide atomicity for the + * sector in the presence of a fail stop -- however, we're just writing this + * to non-persistent DRAM .. right? + */ +static void +altera_avgen_disk_strategy(struct bio *bp) +{ + struct altera_avgen_softc *sc; + void *data; + long bcount; + daddr_t pblkno; + + sc = bp->bio_disk->d_drv1; + data = bp->bio_data; + bcount = bp->bio_bcount; + pblkno = bp->bio_pblkno; + + /* + * Serialize block reads / writes. + */ + mtx_lock(&sc->avg_disk_mtx); + switch (bp->bio_cmd) { + case BIO_READ: + if (!(sc->avg_flags & ALTERA_AVALON_FLAG_GEOM_READ)) { + biofinish(bp, NULL, EIO); + break; + } + switch (sc->avg_width) { + case 1: + bus_read_region_1(sc->avg_res, + bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE, + (uint8_t *)data, bcount); + break; + + case 2: + bus_read_region_2(sc->avg_res, + bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE, + (uint16_t *)data, bcount / 2); + break; + + case 4: + bus_read_region_4(sc->avg_res, + bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE, + (uint32_t *)data, bcount / 4); + break; + + default: + panic("%s: unexpected width %u", __func__, + sc->avg_width); + } + break; + + case BIO_WRITE: + if (!(sc->avg_flags & ALTERA_AVALON_FLAG_GEOM_WRITE)) { + biofinish(bp, NULL, EROFS); + break; + } + switch (sc->avg_width) { + case 1: + bus_write_region_1(sc->avg_res, + bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE, + (uint8_t *)data, bcount); + break; + + case 2: + bus_write_region_2(sc->avg_res, + bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE, + (uint16_t *)data, bcount / 2); + break; + + case 4: + bus_write_region_4(sc->avg_res, + bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE, + (uint32_t *)data, bcount / 4); + break; + + default: + panic("%s: unexpected width %u", __func__, + sc->avg_width); + } + break; + + default: + panic("%s: unsupported I/O operation %d", __func__, + bp->bio_cmd); + } + mtx_unlock(&sc->avg_disk_mtx); + biofinish(bp, NULL, 0); +} static int altera_avgen_process_options(struct altera_avgen_softc *sc, - const char *str_fileio, const char *str_mmapio, const char *str_devname, - int devunit) + const char *str_fileio, const char *str_geomio, const char *str_mmapio, + const char *str_devname, int devunit) { const char *cp; device_t dev = sc->avg_dev; @@ -239,12 +339,30 @@ altera_avgen_process_options(struct alte /* * Check for valid combinations of options. */ - if (str_fileio == NULL && str_mmapio == NULL) { + if (str_fileio == NULL && str_geomio == NULL && str_mmapio == NULL) { + device_printf(dev, + "at least one of %s, %s, or %s must be specified\n", + ALTERA_AVALON_STR_FILEIO, ALTERA_AVALON_STR_GEOMIO, + ALTERA_AVALON_STR_MMAPIO); + return (ENXIO); + } + + /* + * Validity check: a device can either be a GEOM device (in which case + * we use GEOM to register the device node), or a special device -- + * but not both as that causes a collision in /dev. + */ + if (str_geomio != NULL && (str_fileio != NULL || str_mmapio != NULL)) { device_printf(dev, - "at least one of %s or %s must be specified\n", - ALTERA_AVALON_STR_FILEIO, ALTERA_AVALON_STR_MMAPIO); + "at most one of %s and (%s or %s) may be specified\n", + ALTERA_AVALON_STR_GEOMIO, ALTERA_AVALON_STR_FILEIO, + ALTERA_AVALON_STR_MMAPIO); return (ENXIO); } + + /* + * Ensure that a unit is specified if a name is also specified. + */ if (str_devname == NULL && devunit != -1) { device_printf(dev, "%s requires %s be specified\n", ALTERA_AVALON_STR_DEVUNIT, ALTERA_AVALON_STR_DEVNAME); @@ -288,6 +406,25 @@ altera_avgen_process_options(struct alte } } } + if (str_geomio != NULL) { + for (cp = str_geomio; *cp != '\0'; cp++){ + switch (*cp) { + case ALTERA_AVALON_CHAR_READ: + sc->avg_flags |= ALTERA_AVALON_FLAG_GEOM_READ; + break; + + case ALTERA_AVALON_CHAR_WRITE: + sc->avg_flags |= ALTERA_AVALON_FLAG_GEOM_WRITE; + break; + + default: + device_printf(dev, + "invalid %s character %c\n", + ALTERA_AVALON_STR_GEOMIO, *cp); + return (ENXIO); + } + } + } if (str_mmapio != NULL) { for (cp = str_mmapio; *cp != '\0'; cp++) { switch (*cp) { @@ -317,13 +454,14 @@ altera_avgen_process_options(struct alte int altera_avgen_attach(struct altera_avgen_softc *sc, const char *str_fileio, - const char *str_mmapio, const char *str_devname, int devunit) + const char *str_geomio, const char *str_mmapio, const char *str_devname, + int devunit) { device_t dev = sc->avg_dev; int error; - error = altera_avgen_process_options(sc, str_fileio, str_mmapio, - str_devname, devunit); + error = altera_avgen_process_options(sc, str_fileio, str_geomio, + str_mmapio, str_devname, devunit); if (error) return (error); @@ -339,23 +477,59 @@ altera_avgen_attach(struct altera_avgen_ } } - /* Device node allocation. */ - if (str_devname == NULL) { - str_devname = "altera_avgen%d"; + /* + * If a GEOM permission is requested, then create the device via GEOM. + * Otherwise, create a special device. We checked during options + * processing that both weren't requested a once. + */ + if (str_devname != NULL) { + sc->avg_name = strdup(str_devname, M_TEMP); devunit = sc->avg_unit; + } else + sc->avg_name = strdup(ALTERA_AVGEN_DEVNAME, M_TEMP); + if (sc->avg_flags & (ALTERA_AVALON_FLAG_GEOM_READ | + ALTERA_AVALON_FLAG_GEOM_WRITE)) { + mtx_init(&sc->avg_disk_mtx, "altera_avgen_disk", NULL, + MTX_DEF); + sc->avg_disk = disk_alloc(); + sc->avg_disk->d_drv1 = sc; + sc->avg_disk->d_strategy = altera_avgen_disk_strategy; + if (devunit == -1) + devunit = 0; + sc->avg_disk->d_name = sc->avg_name; + sc->avg_disk->d_unit = devunit; + + /* + * NB: As avg_res is a multiple of PAGE_SIZE, it is also a + * multiple of ALTERA_AVGEN_SECTORSIZE. + */ + sc->avg_disk->d_sectorsize = ALTERA_AVGEN_SECTORSIZE; + sc->avg_disk->d_mediasize = rman_get_size(sc->avg_res); + sc->avg_disk->d_maxsize = ALTERA_AVGEN_SECTORSIZE; + disk_create(sc->avg_disk, DISK_VERSION); + } else { + /* Device node allocation. */ + if (str_devname == NULL) { + str_devname = ALTERA_AVGEN_DEVNAME_FMT; + devunit = sc->avg_unit; + } + if (devunit != -1) + sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, + UID_ROOT, GID_WHEEL, S_IRUSR | S_IWUSR, "%s%d", + str_devname, devunit); + else + sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, + UID_ROOT, GID_WHEEL, S_IRUSR | S_IWUSR, + "%s", str_devname); + if (sc->avg_cdev == NULL) { + device_printf(sc->avg_dev, "%s: make_dev failed\n", + __func__); + return (ENXIO); + } + + /* XXXRW: Slight race between make_dev(9) and here. */ + sc->avg_cdev->si_drv1 = sc; } - if (devunit != -1) - sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, UID_ROOT, - GID_WHEEL, S_IRUSR | S_IWUSR, str_devname, devunit); - else - sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, UID_ROOT, - GID_WHEEL, S_IRUSR | S_IWUSR, str_devname); - if (sc->avg_cdev == NULL) { - device_printf(sc->avg_dev, "%s: make_dev failed\n", __func__); - return (ENXIO); - } - /* XXXRW: Slight race between make_dev(9) and here. */ - sc->avg_cdev->si_drv1 = sc; return (0); } @@ -363,5 +537,15 @@ void altera_avgen_detach(struct altera_avgen_softc *sc) { - destroy_dev(sc->avg_cdev); + KASSERT((sc->avg_disk != NULL) || (sc->avg_cdev != NULL), + ("%s: neither GEOM nor special device", __func__)); + + if (sc->avg_disk != NULL) { + disk_gone(sc->avg_disk); + disk_destroy(sc->avg_disk); + free(sc->avg_name, M_TEMP); + mtx_destroy(&sc->avg_disk_mtx); + } else { + destroy_dev(sc->avg_cdev); + } } Modified: head/sys/dev/altera/avgen/altera_avgen.h ============================================================================== --- head/sys/dev/altera/avgen/altera_avgen.h Sat Jan 28 13:09:18 2017 (r312921) +++ head/sys/dev/altera/avgen/altera_avgen.h Sat Jan 28 13:25:06 2017 (r312922) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012 Robert N. M. Watson + * Copyright (c) 2012, 2016 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of @@ -39,6 +39,7 @@ struct altera_avgen_softc { */ device_t avg_dev; int avg_unit; + char *avg_name; /* * The device node and memory-mapped I/O region. @@ -52,6 +53,13 @@ struct altera_avgen_softc { */ u_int avg_flags; u_int avg_width; + u_int avg_sectorsize; + + /* + * disk(9) state, if required for this device. + */ + struct disk *avg_disk; + struct mtx avg_disk_mtx; }; /* @@ -63,6 +71,8 @@ struct altera_avgen_softc { #define ALTERA_AVALON_FLAG_MMAP_READ 0x04 #define ALTERA_AVALON_FLAG_MMAP_WRITE 0x08 #define ALTERA_AVALON_FLAG_MMAP_EXEC 0x10 +#define ALTERA_AVALON_FLAG_GEOM_READ 0x20 +#define ALTERA_AVALON_FLAG_GEOM_WRITE 0x40 #define ALTERA_AVALON_CHAR_READ 'r' #define ALTERA_AVALON_CHAR_WRITE 'w' @@ -70,6 +80,7 @@ struct altera_avgen_softc { #define ALTERA_AVALON_STR_WIDTH "width" #define ALTERA_AVALON_STR_FILEIO "fileio" +#define ALTERA_AVALON_STR_GEOMIO "geomio" #define ALTERA_AVALON_STR_MMAPIO "mmapio" #define ALTERA_AVALON_STR_DEVNAME "devname" #define ALTERA_AVALON_STR_DEVUNIT "devunit" @@ -78,8 +89,8 @@ struct altera_avgen_softc { * Driver setup routines from the bus attachment/teardown. */ int altera_avgen_attach(struct altera_avgen_softc *sc, - const char *str_fileio, const char *str_mmapio, - const char *str_devname, int devunit); + const char *str_fileio, const char *str_geomio, + const char *str_mmapio, const char *str_devname, int devunit); void altera_avgen_detach(struct altera_avgen_softc *sc); extern devclass_t altera_avgen_devclass; Modified: head/sys/dev/altera/avgen/altera_avgen_fdt.c ============================================================================== --- head/sys/dev/altera/avgen/altera_avgen_fdt.c Sat Jan 28 13:09:18 2017 (r312921) +++ head/sys/dev/altera/avgen/altera_avgen_fdt.c Sat Jan 28 13:25:06 2017 (r312922) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2013 Robert N. M. Watson + * Copyright (c) 2012-2013, 2016 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of @@ -75,7 +75,7 @@ static int altera_avgen_fdt_attach(device_t dev) { struct altera_avgen_softc *sc; - char *str_fileio, *str_mmapio; + char *str_fileio, *str_geomio, *str_mmapio; char *str_devname; phandle_t node; pcell_t cell; @@ -90,6 +90,7 @@ altera_avgen_fdt_attach(device_t dev) * expose the device via /dev. */ str_fileio = NULL; + str_geomio = NULL; str_mmapio = NULL; str_devname = NULL; devunit = -1; @@ -99,6 +100,8 @@ altera_avgen_fdt_attach(device_t dev) sc->avg_width = cell; (void)OF_getprop_alloc(node, "sri-cambridge,fileio", sizeof(char), (void **)&str_fileio); + (void)OF_getprop_alloc(node, "sri-cambridge,geomio", sizeof(char), + (void **)&str_geomio); (void)OF_getprop_alloc(node, "sri-cambridge,mmapio", sizeof(char), (void **)&str_mmapio); (void)OF_getprop_alloc(node, "sri-cambridge,devname", sizeof(char), @@ -114,13 +117,15 @@ altera_avgen_fdt_attach(device_t dev) device_printf(dev, "couldn't map memory\n"); return (ENXIO); } - error = altera_avgen_attach(sc, str_fileio, str_mmapio, str_devname, - devunit); + error = altera_avgen_attach(sc, str_fileio, str_geomio, str_mmapio, + str_devname, devunit); if (error != 0) bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res); if (str_fileio != NULL) OF_prop_free(str_fileio); + if (str_geomio != NULL) + OF_prop_free(str_geomio); if (str_mmapio != NULL) OF_prop_free(str_mmapio); if (str_devname != NULL) Modified: head/sys/dev/altera/avgen/altera_avgen_nexus.c ============================================================================== --- head/sys/dev/altera/avgen/altera_avgen_nexus.c Sat Jan 28 13:09:18 2017 (r312921) +++ head/sys/dev/altera/avgen/altera_avgen_nexus.c Sat Jan 28 13:25:06 2017 (r312922) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2013 Robert N. M. Watson + * Copyright (c) 2012-2013, 2016 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of @@ -64,7 +64,7 @@ static int altera_avgen_nexus_attach(device_t dev) { struct altera_avgen_softc *sc; - const char *str_fileio, *str_mmapio; + const char *str_fileio, *str_geomio, *str_mmapio; const char *str_devname; int devunit, error; @@ -77,6 +77,7 @@ altera_avgen_nexus_attach(device_t dev) * on the device, and whether it is cached. */ str_fileio = NULL; + str_geomio = NULL; str_mmapio = NULL; str_devname = NULL; devunit = -1; @@ -90,6 +91,8 @@ altera_avgen_nexus_attach(device_t dev) (void)resource_string_value(device_get_name(dev), device_get_unit(dev), ALTERA_AVALON_STR_FILEIO, &str_fileio); (void)resource_string_value(device_get_name(dev), + device_get_unit(dev), ALTERA_AVALON_STR_GEOMIO, &str_geomio); + (void)resource_string_value(device_get_name(dev), device_get_unit(dev), ALTERA_AVALON_STR_MMAPIO, &str_mmapio); (void)resource_string_value(device_get_name(dev), device_get_unit(dev), ALTERA_AVALON_STR_DEVNAME, &str_devname); @@ -104,8 +107,8 @@ altera_avgen_nexus_attach(device_t dev) device_printf(dev, "couldn't map memory\n"); return (ENXIO); } - error = altera_avgen_attach(sc, str_fileio, str_mmapio, str_devname, - devunit); + error = altera_avgen_attach(sc, str_fileio, str_geomio, str_mmapio, + str_devname, devunit); if (error != 0) bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201701281325.v0SDP6Yf090172>