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