1 /*- 2 * Copyright (c) 2022 Colin Percival 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/bus.h> 29 #include <sys/kernel.h> 30 #include <sys/limits.h> 31 #include <sys/malloc.h> 32 #include <sys/module.h> 33 #include <sys/rman.h> 34 35 #include <machine/bus.h> 36 #include <machine/resource.h> 37 38 #include <dev/virtio/mmio/virtio_mmio.h> 39 40 /* Parse <size>@<baseaddr>:<irq>[:<id>] and add a child. */ 41 static void 42 parsearg(driver_t *driver, device_t parent, char * arg) 43 { 44 device_t child; 45 char * p; 46 unsigned long sz; 47 unsigned long baseaddr; 48 unsigned long irq; 49 unsigned long id; 50 51 /* <size> */ 52 sz = strtoul(arg, &p, 0); 53 if ((sz == 0) || (sz == ULONG_MAX)) 54 goto bad; 55 switch (*p) { 56 case 'E': case 'e': 57 sz <<= 10; 58 /* FALLTHROUGH */ 59 case 'P': case 'p': 60 sz <<= 10; 61 /* FALLTHROUGH */ 62 case 'T': case 't': 63 sz <<= 10; 64 /* FALLTHROUGH */ 65 case 'G': case 'g': 66 sz <<= 10; 67 /* FALLTHROUGH */ 68 case 'M': case 'm': 69 sz <<= 10; 70 /* FALLTHROUGH */ 71 case 'K': case 'k': 72 sz <<= 10; 73 p++; 74 break; 75 } 76 77 /* @<baseaddr> */ 78 if (*p++ != '@') 79 goto bad; 80 baseaddr = strtoul(p, &p, 0); 81 if ((baseaddr == 0) || (baseaddr == ULONG_MAX)) 82 goto bad; 83 84 /* :<irq> */ 85 if (*p++ != ':') 86 goto bad; 87 irq = strtoul(p, &p, 0); 88 if ((irq == 0) || (irq == ULONG_MAX)) 89 goto bad; 90 91 /* Optionally, :<id> */ 92 if (*p) { 93 if (*p++ != ':') 94 goto bad; 95 id = strtoul(p, &p, 0); 96 if ((id == 0) || (id == ULONG_MAX)) 97 goto bad; 98 } else { 99 id = 0; 100 } 101 102 /* Should have reached the end of the string. */ 103 if (*p) 104 goto bad; 105 106 /* Create the child and assign its resources. */ 107 child = BUS_ADD_CHILD(parent, 0, driver->name, id ? id : -1); 108 bus_set_resource(child, SYS_RES_MEMORY, 0, baseaddr, sz); 109 bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 110 device_set_driver(child, driver); 111 112 return; 113 114 bad: 115 printf("Error parsing virtio_mmio parameter: %s\n", arg); 116 } 117 118 static void 119 vtmmio_cmdline_identify(driver_t *driver, device_t parent) 120 { 121 size_t n; 122 char name[] = "virtio_mmio.device_XXXX"; 123 char * val; 124 125 /* First variable just has its own name. */ 126 if ((val = kern_getenv("virtio_mmio.device")) == NULL) 127 return; 128 parsearg(driver, parent, val); 129 freeenv(val); 130 131 /* The rest have _%zu suffixes. */ 132 for (n = 1; n <= 9999; n++) { 133 sprintf(name, "virtio_mmio.device_%zu", n); 134 if ((val = kern_getenv(name)) == NULL) 135 return; 136 parsearg(driver, parent, val); 137 freeenv(val); 138 } 139 } 140 141 static device_method_t vtmmio_cmdline_methods[] = { 142 /* Device interface. */ 143 DEVMETHOD(device_identify, vtmmio_cmdline_identify), 144 DEVMETHOD(device_probe, vtmmio_probe), 145 146 DEVMETHOD_END 147 }; 148 DEFINE_CLASS_1(virtio_mmio, vtmmio_cmdline_driver, vtmmio_cmdline_methods, 149 sizeof(struct vtmmio_softc), vtmmio_driver); 150 DRIVER_MODULE(vtmmio_cmdline, nexus, vtmmio_cmdline_driver, 0, 0); 151