svn commit: r312922 - head/sys/dev/altera/avgen
Robert Watson
rwatson at FreeBSD.org
Sat Jan 28 13:25:08 UTC 2017
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 at 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 at 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);
More information about the svn-src-head
mailing list