1/*-
2 * Copyright 1998 Massachusetts Institute of Technology
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all
9 * supporting documentation, and that the name of M.I.T. not be used
10 * in advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.  M.I.T. makes
12 * no representations about the suitability of this software for any
13 * purpose.  It is provided "as is" without express or implied
14 * warranty.
15 *
16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31/*
32 * This code implements a `root nexus' for Arm Architecture
33 * machines.  The function of the root nexus is to serve as an
34 * attachment point for both processors and buses, and to manage
35 * resources which are common to all of them.  In particular,
36 * this code implements the core resource managers for interrupt
37 * requests and I/O memory address space.
38 */
39
40#include <sys/cdefs.h>
41#include <sys/kobj.h>
42#include <sys/systm.h>
43#include <sys/bus.h>
44#include "device_if.h"
45#include "bus_if.h"
46#include <sys/malloc.h>
47#include <sys/module.h>
48#ifdef LOSCFG_DRIVERS_HDF_USB
49#include "hdf_usb.h"
50#endif
51
52struct devclass_res {
53	TAILQ_ENTRY(devclass_res) link;
54	struct resource_list    nx_resources;
55	char* devclass_name;
56};
57TAILQ_HEAD(devclass_res_list, devclass_res);
58static struct devclass_res_list devclass_resources;
59
60static	int nexus_probe(device_t);
61static	int nexus_attach(device_t);
62static	int nexus_print_child(device_t, device_t);
63static	struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
64    rman_res_t, rman_res_t, rman_res_t, u_int);
65
66static device_method_t nexus_methods[] = {
67	/* Device interface */
68	DEVMETHOD(device_probe,		nexus_probe),
69	DEVMETHOD(device_attach,	nexus_attach),
70	/* Bus interface */
71	DEVMETHOD(bus_print_child,	nexus_print_child),
72	DEVMETHOD(bus_add_child,	bus_generic_add_child),
73	DEVMETHOD(bus_alloc_resource,	nexus_alloc_resource),
74
75	{ 0, 0 }
76};
77
78static devclass_t nexus_devclass;
79static driver_t nexus_driver = {
80	"nexus",
81	nexus_methods,
82	1			/* no softc */
83};
84EARLY_DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0,
85    BUS_PASS_BUS + BUS_PASS_ORDER_EARLY);
86
87static struct resource_list *get_resource_list(const char *devclass_name)
88{
89	struct devclass_res *dr = NULL;
90	if (devclass_name == NULL) {
91		return (NULL);
92	}
93	TAILQ_FOREACH(dr, &devclass_resources, link) {
94		if (!strcmp(dr->devclass_name, devclass_name)) {
95			break;
96		}
97	}
98	if (dr == NULL) {
99		dr = malloc(sizeof(struct devclass_res) + strlen(devclass_name) + 1);
100		if (dr == NULL) {
101			return (NULL);
102		}
103		dr->devclass_name = (char *)(dr + 1);
104		(void)strcpy_s(dr->devclass_name, strlen(devclass_name) + 1, devclass_name);
105		resource_list_init(&dr->nx_resources);
106		TAILQ_INSERT_TAIL(&devclass_resources, dr, link);
107	}
108	return (&dr->nx_resources);
109}
110
111static void add_resource(const char *devclass_name, int type, int unit, rman_res_t start, rman_res_t end,
112	rman_res_t count)
113{
114	struct resource_list *res_list = get_resource_list(devclass_name);
115	if (res_list == NULL) {
116		return;
117	}
118	resource_list_add(res_list, type, unit, start, end, count);
119}
120
121int
122nexus_init(void)
123{
124	TAILQ_INIT(&devclass_resources);
125#ifdef LOSCFG_DRIVERS_HDF_USB
126	UsbResourceInit(nexus, add_resource);
127#endif
128	machine_resource_init(add_resource);
129
130	return driver_module_handler(NULL, MOD_LOAD, &nexus_root_driver_mod);
131}
132
133static int
134nexus_probe(device_t dev)
135{
136	device_quiet(dev);	/* suppress attach message for neatness */
137
138	return (BUS_PROBE_DEFAULT);
139}
140
141static int
142nexus_attach(device_t dev)
143{
144	/*
145	 * First, deal with the children we know about already
146	 */
147	bus_generic_probe(dev);
148	bus_generic_attach(dev);
149
150	return (0);
151}
152
153static int
154nexus_print_child(device_t bus, device_t child)
155{
156	int retval = 0;
157
158	retval += bus_print_child_header(bus, child);
159	retval += printf("\n");
160
161	return (retval);
162}
163
164/*
165 * Allocate a resource on behalf of child.  NB: child is usually going to be a
166 * child of one of our descendants, not a direct child of nexus0.
167 * (Exceptions include footbridge.)
168 */
169static struct resource *
170nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
171    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
172{
173	devclass_t dc = device_get_devclass(child);
174	struct resource_list *res_list = NULL;
175	if (dc == NULL || rid == NULL) {
176		return (NULL);
177	}
178	res_list = get_resource_list(devclass_get_name(dc));
179	if (res_list == NULL) {
180		return (NULL);
181	}
182	struct resource_list_entry *rle = resource_list_find(res_list, type, *rid);
183	if (rle == NULL) {
184		return(NULL);
185	}
186	return (rle->res);
187}
188