Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148322890
D21478.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D21478.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D21478: Automatic dependency tracking for FDT/OFW.
Attached
Detach File
Event Timeline
Log In to Comment