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 52 struct devclass_res { 53 TAILQ_ENTRY(devclass_res) link; 54 struct resource_list nx_resources; 55 char* devclass_name; 56 }; 57 TAILQ_HEAD(devclass_res_list, devclass_res); 58 static struct devclass_res_list devclass_resources; 59 60 static int nexus_probe(device_t); 61 static int nexus_attach(device_t); 62 static int nexus_print_child(device_t, device_t); 63 static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, 64 rman_res_t, rman_res_t, rman_res_t, u_int); 65 66 static 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 78 static devclass_t nexus_devclass; 79 static driver_t nexus_driver = { 80 "nexus", 81 nexus_methods, 82 1 /* no softc */ 83 }; 84 EARLY_DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0, 85 BUS_PASS_BUS + BUS_PASS_ORDER_EARLY); 86 87 static 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 111 static 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 121 int 122 nexus_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 133 static int 134 nexus_probe(device_t dev) 135 { 136 device_quiet(dev); /* suppress attach message for neatness */ 137 138 return (BUS_PROBE_DEFAULT); 139 } 140 141 static int 142 nexus_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 153 static int 154 nexus_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 */ 169 static struct resource * 170 nexus_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