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
parsearg(driver_t * driver,device_t parent,char * arg)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
vtmmio_cmdline_identify(driver_t * driver,device_t parent)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