Page MenuHomeFreeBSD

D21478.diff
No OneTemporary

D21478.diff

Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -961,6 +961,11 @@
# Flattened device tree options
FDT opt_platform.h
FDT_DTB_STATIC opt_platform.h
+# Open Firmware
+# Enable automatic ordering by device dependency.
+OFWBUS_AUTODEP opt_ofw.h
+# Quirk to allow to auto-ordered attach of generic devices.
+OFWBUS_AUTODEP_BUS_PASS_OVERRIDE opt_ofw.h
# OFED Infiniband stack
OFED opt_ofed.h
Index: sys/dev/ofw/ofw_bus_subr.h
===================================================================
--- sys/dev/ofw/ofw_bus_subr.h
+++ sys/dev/ofw/ofw_bus_subr.h
@@ -34,12 +34,14 @@
#define _DEV_OFW_OFW_BUS_SUBR_H_
#include <sys/bus.h>
+#include <sys/linker_set.h>
#ifdef INTRNG
#include <sys/intr.h>
#endif
#include <dev/ofw/openfirm.h>
#include "ofw_bus_if.h"
+#include "opt_ofw.h"
#define ORIP_NOINT -1
#define ORIR_NOTFOUND 0xffffffff
@@ -64,6 +66,27 @@
pcell_t cells[];
};
#endif
+
+#ifdef OFWBUS_AUTODEP
+struct ofwbus_static_req_props {
+ char *ofwbus_srp_prop;
+ char *ofwbus_srp_propcells;
+ int ofwbus_srp_flags;
+#define OFWBUS_REQ_FIND_ATTPARENT 1 /* Traverse parents up to that
+ having "compatible" prop. */
+#define OFWBUS_REQ_FIND_PROP 2 /* Search for prop with link. */
+};
+
+SET_DECLARE(ofwbus_static_req_props_set, struct ofwbus_static_req_props);
+#define OFWBUS_STATIC_REQ_PROP(r) DATA_SET(ofwbus_static_req_props_set, r)
+
+#ifdef OFWBUS_AUTODEP_BUS_PASS_OVERRIDE
+#undef BUS_PASS_TIMER
+#define BUS_PASS_TIMER BUS_PASS_DEFAULT
+#undef BUS_PASS_ORDER_MIDDLE
+#define BUS_PASS_ORDER_MIDDLE 0
+#endif /* OFWBUS_AUTODEP_BUS_PASS_OVERRIDE */
+#endif /* OFWBUS_AUTODEP */
#define FDTCOMPAT_PNP_DESCR "Z:compat;P:#;"
#define FDTCOMPAT_PNP_INFO(t, busname) \
Index: sys/dev/ofw/ofwbus.c
===================================================================
--- sys/dev/ofw/ofwbus.c
+++ sys/dev/ofw/ofwbus.c
@@ -39,6 +39,7 @@
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/pcpu.h>
@@ -58,6 +59,8 @@
#include <machine/bus.h>
#include <machine/resource.h>
+#include "opt_ofw.h"
+
/*
* The ofwbus (which is a pseudo-bus actually) iterates over the nodes that
* hang from the Open Firmware root node and adds them as devices to this bus
@@ -70,6 +73,9 @@
struct simplebus_softc simplebus_sc;
struct rman sc_intr_rman;
struct rman sc_mem_rman;
+#ifdef OFWBUS_AUTODEP
+ TAILQ_HEAD(, ofwbus_dep_entry) sc_dep_head;
+#endif /* OFWBUS_AUTODEP */
};
#ifndef __aarch64__
@@ -97,6 +103,16 @@
DEVMETHOD_END
};
+#ifdef OFWBUS_AUTODEP
+struct ofwbus_dep_entry {
+ TAILQ_ENTRY(ofwbus_dep_entry) entries;
+ phandle_t pnode;
+ phandle_t node;
+ phandle_t rnode;
+ int flags;
+};
+#endif /* OFWBUS_AUTODEP */
+
DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods,
sizeof(struct ofwbus_softc), simplebus_driver);
static devclass_t ofwbus_devclass;
@@ -131,28 +147,184 @@
return (BUS_PROBE_NOWILDCARD);
}
+#ifdef OFWBUS_AUTODEP
static int
+__topmost_req(struct ofwbus_softc *sc, phandle_t node, phandle_t *cur_top_node,
+ int cur_top)
+{
+ struct ofwbus_dep_entry *np;
+ int i;
+
+ i = 0;
+ TAILQ_FOREACH(np, &sc->sc_dep_head, entries) {
+ if (node == np->node) {
+ *cur_top_node = np->node;
+ return (i);
+ }
+ i ++;
+ /*
+ * if current position more than cur_top, left cur_top_node
+ * untouched.
+ */
+ if (i >= cur_top)
+ return (cur_top);
+ }
+
+ return (i);
+}
+
+static int
+ofwbus_device_require(struct ofwbus_softc *sc, phandle_t pnode, phandle_t node,
+ phandle_t rnode, int flags)
+{
+ struct ofwbus_dep_entry *n1, *np;
+ phandle_t requiring;
+ int top;
+
+ requiring = 0;
+ top = INT_MAX;
+ n1 = malloc(sizeof(struct ofwbus_dep_entry), M_TEMP, M_WAITOK);
+ n1->pnode = pnode;
+ n1->node = node;
+ n1->rnode = rnode;
+ n1->flags = flags;
+
+ /* 0 mean default requirement of device by bus. */
+ if (rnode != 0) {
+ TAILQ_INSERT_TAIL(&sc->sc_dep_head, n1, entries);
+ return (0);
+ }
+ /* Find device that require me. */
+ TAILQ_FOREACH(np, &sc->sc_dep_head, entries)
+ if (node == np->rnode) {
+ top = __topmost_req(sc, np->node, &requiring, top);
+ }
+ /* Requiring node not found, insert at tail. */
+ if (requiring == 0) {
+ TAILQ_INSERT_TAIL(&sc->sc_dep_head, n1, entries);
+ return (0);
+ }
+ /* Now find top record of requiring device. */
+ TAILQ_FOREACH(np, &sc->sc_dep_head, entries)
+ if (requiring == np->node) {
+ TAILQ_INSERT_BEFORE(np, n1, entries);
+ break;
+ }
+ return (0);
+}
+
+static int
+ofwbus_reg_std_prop_req(struct ofwbus_softc *sc, phandle_t pnode, phandle_t
+ node, char *prop, char *propcells, int flags)
+{
+ phandle_t p, xref;
+ pcell_t *cells;
+ int i, ncells, ret, total;
+
+ ret = 0;
+ if (flags & OFWBUS_REQ_FIND_PROP) {
+ if (OF_searchencprop(node, prop, &p, sizeof(p)) != -1) {
+ p = OF_node_from_xref(p);
+ if (p == 0)
+ return (ENXIO);
+ ret = ofwbus_device_require(sc, pnode, node, p, flags);
+ }
+ return (ret);
+ }
+
+ ret = ofw_bus_parse_xref_list_get_length(node, prop, propcells, &total);
+ if (ret)
+ return (ret);
+ for (i = 0; i < total; i++) {
+ ret = ofw_bus_parse_xref_list_alloc(node, prop, propcells, i,
+ &xref, &ncells, &cells);
+ if (flags & OFWBUS_REQ_FIND_ATTPARENT) {
+ for (p = OF_node_from_xref(xref); p; p = OF_parent(p)) {
+ if (OF_hasprop(p, "compatible")) {
+ ofwbus_device_require(sc, pnode, node,
+ p, flags);
+ break;
+ }
+ }
+ } else {
+ ofwbus_device_require(sc, pnode, node,
+ OF_node_from_xref(xref), flags);
+ }
+ OF_prop_free(cells);
+ }
+
+ return (ret);
+}
+
+static int
+ofwbus_device_standard_requirement(struct ofwbus_softc *sc, phandle_t pnode,
+ phandle_t node)
+{
+ struct ofwbus_static_req_props **spr;
+ phandle_t n;
+ int ret;
+
+ if (OF_hasprop(node, "interrupts")) {
+ n = ofw_bus_find_iparent(node);
+ ofwbus_device_require(sc, pnode, node, OF_node_from_xref(n), 0);
+ }
+#define OFW_STD_REQ_PROCESS(name, flags) \
+ if (OF_hasprop(node, name "s")) { \
+ ret = ofwbus_reg_std_prop_req(sc, pnode, node, \
+ name "s", "#" name "-cells", (flags)); \
+ }
+ OFW_STD_REQ_PROCESS("clock", 0);
+ OFW_STD_REQ_PROCESS("power-domain", 0);
+ OFW_STD_REQ_PROCESS("reset", 0);
+ OFW_STD_REQ_PROCESS("phy", OFWBUS_REQ_FIND_ATTPARENT);
+ OFW_STD_REQ_PROCESS("dma", 0);
+ OFW_STD_REQ_PROCESS("gpio", 0);
+#undef OFW_STD_REQ_PROCESS
+
+ ret = ofwbus_reg_std_prop_req(sc, pnode, node, "freebsd,phandle", NULL,
+ OFWBUS_REQ_FIND_PROP);
+ if (ret)
+ return (ret);
+
+ SET_FOREACH(spr, ofwbus_static_req_props_set) {
+ ret = ofwbus_reg_std_prop_req(sc, pnode, node,
+ (*spr)->ofwbus_srp_prop, (*spr)->ofwbus_srp_propcells,
+ (*spr)->ofwbus_srp_flags);
+ if (ret)
+ return (ret);
+ }
+ return (0);
+}
+#endif /* OFWBUS_AUTODEP */
+
+static int
ofwbus_attach(device_t dev)
{
struct ofwbus_softc *sc;
- phandle_t node;
+ phandle_t node, pnode;
struct ofw_bus_devinfo obd;
+#ifdef OFWBUS_AUTODEP
+ struct ofwbus_dep_entry *np;
+#endif /* OFWBUS_AUTODEP */
sc = device_get_softc(dev);
+#ifdef OFWBUS_AUTODEP
+ TAILQ_INIT(&sc->sc_dep_head);
+#endif /* OFWBUS_AUTODEP */
- node = OF_peer(0);
+ pnode = OF_peer(0);
/*
* If no Open Firmware, bail early
*/
- if (node == -1)
+ if (pnode == -1)
return (ENXIO);
/*
* ofwbus bus starts on unamed node in FDT, so we cannot make
* ofw_bus_devinfo from it. Pass node to simplebus_init directly.
*/
- simplebus_init(dev, node);
+ simplebus_init(dev, pnode);
sc->sc_intr_rman.rm_type = RMAN_ARRAY;
sc->sc_intr_rman.rm_descr = "Interrupts";
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
@@ -171,12 +343,35 @@
/*
* Now walk the OFW tree and attach top-level devices.
*/
- for (node = OF_child(node); node > 0; node = OF_peer(node)) {
+#ifndef OFWBUS_AUTODEP
+ for (node = OF_child(pnode); node > 0; node = OF_peer(node)) {
if (ofw_bus_gen_setup_devinfo(&obd, node) != 0)
continue;
simplebus_add_device(dev, node, 0, NULL, -1, NULL);
}
- return (bus_generic_attach(dev));
+#else
+ for (node = OF_child(pnode); node > 0; node = OF_peer(node)) {
+ if (ofw_bus_gen_setup_devinfo(&obd, node) != 0)
+ continue;
+ ofwbus_device_require(sc, pnode, node, 0, 1);
+ ofwbus_device_standard_requirement(sc, pnode, node);
+ }
+
+ TAILQ_FOREACH(np, &sc->sc_dep_head, entries) {
+ if (ofw_bus_find_child_device_by_phandle(dev, np->node) == NULL)
+ {
+ simplebus_add_device(dev, np->node, 0, NULL, -1, NULL);
+ }
+ }
+
+ while (!TAILQ_EMPTY(&sc->sc_dep_head)) {
+ np = TAILQ_FIRST(&sc->sc_dep_head);
+ TAILQ_REMOVE(&sc->sc_dep_head, np, entries);
+ free(np, M_TEMP);
+ }
+ TAILQ_INIT(&sc->sc_dep_head);
+#endif
+ return (0);
}
static struct resource *

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 18, 4:18 AM (20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29878694
Default Alt Text
D21478.diff (8 KB)

Event Timeline