aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/extres
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2017-12-26 16:38:04 +0000
committerKyle Evans <kevans@FreeBSD.org>2017-12-26 16:38:04 +0000
commit198ca831a1c2d5ab9e9880681d561827cb3b9d24 (patch)
treea2b5506dae7dd911d2cfa1a3aa2c8eac16f830f9 /sys/dev/extres
parentfa5867cbd657319aba3179335da50b7d90a555f7 (diff)
downloadsrc-198ca831a1c2d5ab9e9880681d561827cb3b9d24.tar.gz
src-198ca831a1c2d5ab9e9880681d561827cb3b9d24.zip
extres/syscon: Commit missing bits from r327106
r327106 introduced kobj to syscon so it can be subclassed and fit in with the rest of the syscon framework. The diff for syscon.c was misapplied in a clean tree prior to commit, so bring it back to what was included in the review and tested. The entire file has basically been rewritten from what was present prior to the kobj work. Pointy hat to: me
Notes
Notes: svn path=/head/; revision=327215
Diffstat (limited to 'sys/dev/extres')
-rw-r--r--sys/dev/extres/syscon/syscon.c272
1 files changed, 171 insertions, 101 deletions
diff --git a/sys/dev/extres/syscon/syscon.c b/sys/dev/extres/syscon/syscon.c
index 8bb3e14b700a..8c2d76649524 100644
--- a/sys/dev/extres/syscon/syscon.c
+++ b/sys/dev/extres/syscon/syscon.c
@@ -33,153 +33,223 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/lock.h>
#include <sys/module.h>
#include <sys/rman.h>
+#include <sys/sx.h>
+#include <sys/queue.h>
#include <machine/bus.h>
+#ifdef FDT
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#endif
#include "syscon_if.h"
+#include "syscon.h"
+
+/*
+ * Syscon interface details
+ */
+typedef TAILQ_HEAD(syscon_list, syscon) syscon_list_t;
+
+/*
+ * Declarations
+ */
+static int syscon_method_init(struct syscon *syscon);
+static int syscon_method_uninit(struct syscon *syscon);
-#define SYSCON_LOCK(_sc) mtx_lock(&(_sc)->mtx)
-#define SYSCON_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
-#define SYSCON_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
- device_get_nameunit((_sc)->dev), "syscon", MTX_DEF)
-#define SYSCON_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx);
-#define SYSCON_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED);
-#define SYSCON_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED);
-
-struct syscon_softc {
- device_t dev;
- struct resource *mem_res;
- struct mtx mtx;
+MALLOC_DEFINE(M_SYSCON, "syscon", "Syscon driver");
+
+static syscon_list_t syscon_list = TAILQ_HEAD_INITIALIZER(syscon_list);
+static struct sx syscon_topo_lock;
+SX_SYSINIT(syscon_topology, &syscon_topo_lock, "Syscon topology lock");
+
+/*
+ * Syscon methods.
+ */
+static syscon_method_t syscon_methods[] = {
+ SYSCONMETHOD(syscon_init, syscon_method_init),
+ SYSCONMETHOD(syscon_uninit, syscon_method_uninit),
+
+ SYSCONMETHOD_END
};
+DEFINE_CLASS_0(syscon, syscon_class, syscon_methods, 0);
+
+#define SYSCON_TOPO_SLOCK() sx_slock(&syscon_topo_lock)
+#define SYSCON_TOPO_XLOCK() sx_xlock(&syscon_topo_lock)
+#define SYSCON_TOPO_UNLOCK() sx_unlock(&syscon_topo_lock)
+#define SYSCON_TOPO_ASSERT() sx_assert(&syscon_topo_lock, SA_LOCKED)
+#define SYSCON_TOPO_XASSERT() sx_assert(&syscon_topo_lock, SA_XLOCKED)
-static struct ofw_compat_data compat_data[] = {
- {"syscon", 1},
- {NULL, 0}
+/*
+ * Default syscon methods for base class.
+ */
+static int
+syscon_method_init(struct syscon *syscon)
+{
+
+ return (0);
};
-static uint32_t
-syscon_read_4(device_t dev, device_t consumer, bus_size_t offset)
+static int
+syscon_method_uninit(struct syscon *syscon)
{
- struct syscon_softc *sc;
- uint32_t val;
- sc = device_get_softc(dev);
+ return (0);
+};
- SYSCON_LOCK(sc);
- val = bus_read_4(sc->mem_res, offset);
- SYSCON_UNLOCK(sc);
- return (val);
-}
+void *
+syscon_get_softc(struct syscon *syscon)
+{
-static void
-syscon_write_4(device_t dev, device_t consumer, bus_size_t offset, uint32_t val)
+ return (syscon->softc);
+};
+
+/*
+ * Create and initialize syscon object, but do not register it.
+ */
+struct syscon *
+syscon_create(device_t pdev, syscon_class_t syscon_class)
{
- struct syscon_softc *sc;
+ struct syscon *syscon;
+
+ /* Create object and initialize it. */
+ syscon = malloc(sizeof(struct syscon), M_SYSCON,
+ M_WAITOK | M_ZERO);
+ kobj_init((kobj_t)syscon, (kobj_class_t)syscon_class);
- sc = device_get_softc(dev);
+ /* Allocate softc if required. */
+ if (syscon_class->size > 0)
+ syscon->softc = malloc(syscon_class->size, M_SYSCON,
+ M_WAITOK | M_ZERO);
- SYSCON_LOCK(sc);
- bus_write_4(sc->mem_res, offset, val);
- SYSCON_UNLOCK(sc);
+ /* Rest of init. */
+ syscon->pdev = pdev;
+ return (syscon);
}
-static void
-syscon_modify_4(device_t dev, device_t consumer, bus_size_t offset,
- uint32_t clear_bits, uint32_t set_bits)
+/* Register syscon object. */
+struct syscon *
+syscon_register(struct syscon *syscon)
{
- struct syscon_softc *sc;
- uint32_t val;
-
- sc = device_get_softc(dev);
+ int rv;
+
+#ifdef FDT
+ if (syscon->ofw_node <= 0)
+ syscon->ofw_node = ofw_bus_get_node(syscon->pdev);
+ if (syscon->ofw_node <= 0)
+ return (NULL);
+#endif
+
+ rv = SYSCON_INIT(syscon);
+ if (rv != 0) {
+ printf("SYSCON_INIT failed: %d\n", rv);
+ return (NULL);
+ }
- SYSCON_LOCK(sc);
- val = bus_read_4(sc->mem_res, offset);
- val &= ~clear_bits;
- val |= set_bits;
- bus_write_4(sc->mem_res, offset, val);
- SYSCON_UNLOCK(sc);
+#ifdef FDT
+ OF_device_register_xref(OF_xref_from_node(syscon->ofw_node),
+ syscon->pdev);
+#endif
+ SYSCON_TOPO_XLOCK();
+ TAILQ_INSERT_TAIL(&syscon_list, syscon, syscon_link);
+ SYSCON_TOPO_UNLOCK();
+ return (syscon);
}
-static int
-syscon_probe(device_t dev)
+int
+syscon_unregister(struct syscon *syscon)
{
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
- if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
- return (ENXIO);
-
- device_set_desc(dev, "syscon");
- return (BUS_PROBE_GENERIC);
+ SYSCON_TOPO_XLOCK();
+ TAILQ_REMOVE(&syscon_list, syscon, syscon_link);
+ SYSCON_TOPO_UNLOCK();
+#ifdef FDT
+ OF_device_register_xref(OF_xref_from_node(syscon->ofw_node), NULL);
+#endif
+ return (SYSCON_UNINIT(syscon));
}
-static int
-syscon_attach(device_t dev)
+/**
+ * Provider methods
+ */
+#ifdef FDT
+static struct syscon *
+syscon_find_by_ofw_node(phandle_t node)
{
- struct syscon_softc *sc;
- int rid;
- phandle_t node;
-
- sc = device_get_softc(dev);
- sc->dev = dev;
- node = ofw_bus_get_node(sc->dev);
+ struct syscon *entry;
- SYSCON_LOCK_INIT(sc);
+ SYSCON_TOPO_ASSERT();
- rid = 0;
- sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
- RF_ACTIVE);
- if (sc->mem_res == NULL) {
- device_printf(dev, "Cannot allocate memory resource\n");
- return (ENXIO);
+ TAILQ_FOREACH(entry, &syscon_list, syscon_link) {
+ if (entry->ofw_node == node)
+ return (entry);
}
- OF_device_register_xref(OF_xref_from_node(node), dev);
+ return (NULL);
+}
- return (0);
+struct syscon *
+syscon_create_ofw_node(device_t pdev, syscon_class_t syscon_class,
+ phandle_t node)
+{
+ struct syscon *syscon;
+
+ syscon = syscon_create(pdev, syscon_class);
+ if (syscon == NULL)
+ return (NULL);
+ syscon->ofw_node = node;
+ if (syscon_register(syscon) == NULL)
+ return (NULL);
+ return (syscon);
}
-static int
-syscon_detach(device_t dev)
+phandle_t
+syscon_get_ofw_node(struct syscon *syscon)
{
- struct syscon_softc *sc;
- sc = device_get_softc(dev);
+ return (syscon->ofw_node);
+}
- OF_device_register_xref(OF_xref_from_device(dev), NULL);
+int
+syscon_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name,
+ struct syscon **syscon)
+{
+ pcell_t *cells;
+ int ncells;
+
+ if (cnode <= 0)
+ cnode = ofw_bus_get_node(cdev);
+ if (cnode <= 0) {
+ device_printf(cdev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t),
+ (void **)&cells);
+ if (ncells < 1)
+ return (ENXIO);
- SYSCON_LOCK_DESTROY(sc);
- if (sc->mem_res != NULL)
- bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+ /* Translate to syscon node. */
+ SYSCON_TOPO_SLOCK();
+ *syscon = syscon_find_by_ofw_node(OF_node_from_xref(cells[0]));
+ if (*syscon == NULL) {
+ SYSCON_TOPO_UNLOCK();
+ device_printf(cdev, "Failed to find syscon node\n");
+ OF_prop_free(cells);
+ return (ENODEV);
+ }
+ SYSCON_TOPO_UNLOCK();
+ OF_prop_free(cells);
return (0);
}
-
-static device_method_t syscon_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, syscon_probe),
- DEVMETHOD(device_attach, syscon_attach),
- DEVMETHOD(device_detach, syscon_detach),
-
- /* Syscon interface */
- DEVMETHOD(syscon_read_4, syscon_read_4),
- DEVMETHOD(syscon_write_4, syscon_write_4),
- DEVMETHOD(syscon_modify_4, syscon_modify_4),
-
- DEVMETHOD_END
-};
-
-DEFINE_CLASS_0(syscon, syscon_driver, syscon_methods,
- sizeof(struct syscon_softc));
-static devclass_t syscon_devclass;
-EARLY_DRIVER_MODULE(syscon, simplebus, syscon_driver, syscon_devclass, 0, 0,
- BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
-MODULE_VERSION(syscon, 1);
+#endif