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, DMA requests (which rightfully should be a part of the 38 * ISA code but it's easier to do it here for now), I/O port addresses, 39 * and I/O memory address space. 40 */ 41 42 #include <sys/cdefs.h> 43 __FBSDID("$FreeBSD: releng/12.2/sys/arm/arm/nexus.c 320198 2017-06-21 18:25:35Z zbb $"); 44 45 #include <sys/kobj.h> 46 #include <sys/systm.h> 47 #include <sys/bus.h> 48 #include "device_if.h" 49 #include "bus_if.h" 50 #include <sys/malloc.h> 51 #include <sys/module.h> 52 #ifdef LOSCFG_DRIVERS_HDF_USB 53 #include "hdf_usb.h" 54 #endif 55 56 struct devclass_res { 57 TAILQ_ENTRY(devclass_res) link; 58 struct resource_list nx_resources; 59 char* devclass_name; 60 }; 61 TAILQ_HEAD(devclass_res_list, devclass_res); 62 static struct devclass_res_list devclass_resources; 63 64 static int nexus_probe(device_t); 65 static int nexus_attach(device_t); 66 static int nexus_print_child(device_t, device_t); 67 static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, 68 rman_res_t, rman_res_t, rman_res_t, u_int); 69 70 static device_method_t nexus_methods[] = { 71 /* Device interface */ 72 DEVMETHOD(device_probe, nexus_probe), 73 DEVMETHOD(device_attach, nexus_attach), 74 /* Bus interface */ 75 DEVMETHOD(bus_print_child, nexus_print_child), 76 DEVMETHOD(bus_add_child, bus_generic_add_child), 77 DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), 78 79 { 0, 0 } 80 }; 81 82 static devclass_t nexus_devclass; 83 static driver_t nexus_driver = { 84 "nexus", 85 nexus_methods, 86 1 /* no softc */ 87 }; 88 EARLY_DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0, 89 BUS_PASS_BUS + BUS_PASS_ORDER_EARLY); 90 91 static struct resource_list *get_resource_list(const char *devclass_name) 92 { 93 struct devclass_res *dr = NULL; 94 if (devclass_name == NULL) { 95 return (NULL); 96 } 97 TAILQ_FOREACH(dr, &devclass_resources, link) { 98 if (!strcmp(dr->devclass_name, devclass_name)) { 99 break; 100 } 101 } 102 if (dr == NULL) { 103 dr = malloc(sizeof(struct devclass_res) + strlen(devclass_name) + 1); 104 if (dr == NULL) { 105 return (NULL); 106 } 107 dr->devclass_name = (char *)(dr + 1); 108 (void)strcpy_s(dr->devclass_name, strlen(devclass_name) + 1, devclass_name); 109 resource_list_init(&dr->nx_resources); 110 TAILQ_INSERT_TAIL(&devclass_resources, dr, link); 111 } 112 return (&dr->nx_resources); 113 } 114 115 static void add_resource(const char *devclass_name, int type, int unit, rman_res_t start, rman_res_t end, 116 rman_res_t count) 117 { 118 struct resource_list *res_list = get_resource_list(devclass_name); 119 if (res_list == NULL) { 120 return; 121 } 122 resource_list_add(res_list, type, unit, start, end, count); 123 } 124 125 int 126 nexus_init(void) 127 { 128 TAILQ_INIT(&devclass_resources); 129 #ifdef LOSCFG_DRIVERS_HDF_USB 130 UsbResourceInit(nexus, add_resource); 131 #endif 132 machine_resource_init(add_resource); 133 134 return driver_module_handler(NULL, MOD_LOAD, &nexus_root_driver_mod); 135 } 136 137 static int 138 nexus_probe(device_t dev) 139 { 140 device_quiet(dev); /* suppress attach message for neatness */ 141 142 return (BUS_PROBE_DEFAULT); 143 } 144 145 static int 146 nexus_attach(device_t dev) 147 { 148 /* 149 * First, deal with the children we know about already 150 */ 151 bus_generic_probe(dev); 152 bus_generic_attach(dev); 153 154 return (0); 155 } 156 157 static int 158 nexus_print_child(device_t bus, device_t child) 159 { 160 int retval = 0; 161 162 retval += bus_print_child_header(bus, child); 163 retval += printf("\n"); 164 165 return (retval); 166 } 167 168 /* 169 * Allocate a resource on behalf of child. NB: child is usually going to be a 170 * child of one of our descendants, not a direct child of nexus0. 171 * (Exceptions include footbridge.) 172 */ 173 static struct resource * 174 nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, 175 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 176 { 177 devclass_t dc = device_get_devclass(child); 178 struct resource_list *res_list = NULL; 179 if (dc == NULL || rid == NULL) { 180 return (NULL); 181 } 182 res_list = get_resource_list(devclass_get_name(dc)); 183 if (res_list == NULL) { 184 return (NULL); 185 } 186 struct resource_list_entry *rle = resource_list_find(res_list, type, *rid); 187 if (rle == NULL) { 188 return(NULL); 189 } 190 return (rle->res); 191 } 192