xref: /dragonfly/sys/dev/virtual/nvmm/nvmm_netbsd.c (revision 8a0a54bf)
1df3af4c9SAaron LI /*
2df3af4c9SAaron LI  * Copyright (c) 2021 Maxime Villard, m00nbsd.net
3df3af4c9SAaron LI  * All rights reserved.
4df3af4c9SAaron LI  *
5df3af4c9SAaron LI  * This code is part of the NVMM hypervisor.
6df3af4c9SAaron LI  *
7df3af4c9SAaron LI  * Redistribution and use in source and binary forms, with or without
8df3af4c9SAaron LI  * modification, are permitted provided that the following conditions
9df3af4c9SAaron LI  * are met:
10df3af4c9SAaron LI  * 1. Redistributions of source code must retain the above copyright
11df3af4c9SAaron LI  *    notice, this list of conditions and the following disclaimer.
12df3af4c9SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
13df3af4c9SAaron LI  *    notice, this list of conditions and the following disclaimer in the
14df3af4c9SAaron LI  *    documentation and/or other materials provided with the distribution.
15df3af4c9SAaron LI  *
16df3af4c9SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17df3af4c9SAaron LI  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18df3af4c9SAaron LI  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19df3af4c9SAaron LI  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20df3af4c9SAaron LI  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21df3af4c9SAaron LI  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22df3af4c9SAaron LI  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23df3af4c9SAaron LI  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24df3af4c9SAaron LI  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25df3af4c9SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26df3af4c9SAaron LI  * SUCH DAMAGE.
27df3af4c9SAaron LI  */
28df3af4c9SAaron LI 
29df3af4c9SAaron LI #include <sys/param.h>
30df3af4c9SAaron LI #include <sys/systm.h>
31df3af4c9SAaron LI #include <sys/kernel.h>
32df3af4c9SAaron LI #include <sys/mman.h>
33df3af4c9SAaron LI 
34*8a0a54bfSAaron LI #include "nvmm.h"
35df3af4c9SAaron LI #include "nvmm_os.h"
36*8a0a54bfSAaron LI #include "nvmm_internal.h"
37df3af4c9SAaron LI 
38df3af4c9SAaron LI os_vmspace_t *
os_vmspace_create(vaddr_t vmin,vaddr_t vmax)39df3af4c9SAaron LI os_vmspace_create(vaddr_t vmin, vaddr_t vmax)
40df3af4c9SAaron LI {
41df3af4c9SAaron LI 	return uvmspace_alloc(vmin, vmax, false);
42df3af4c9SAaron LI }
43df3af4c9SAaron LI 
44df3af4c9SAaron LI void
os_vmspace_destroy(os_vmspace_t * vm)45df3af4c9SAaron LI os_vmspace_destroy(os_vmspace_t *vm)
46df3af4c9SAaron LI {
47df3af4c9SAaron LI 	uvmspace_free(vm);
48df3af4c9SAaron LI }
49df3af4c9SAaron LI 
50df3af4c9SAaron LI int
os_vmspace_fault(os_vmspace_t * vm,vaddr_t va,vm_prot_t prot)51df3af4c9SAaron LI os_vmspace_fault(os_vmspace_t *vm, vaddr_t va, vm_prot_t prot)
52df3af4c9SAaron LI {
53df3af4c9SAaron LI 	return uvm_fault(&vm->vm_map, va, prot);
54df3af4c9SAaron LI }
55df3af4c9SAaron LI 
56df3af4c9SAaron LI os_vmobj_t *
os_vmobj_create(voff_t size)57df3af4c9SAaron LI os_vmobj_create(voff_t size)
58df3af4c9SAaron LI {
59df3af4c9SAaron LI 	return uao_create(size, 0);
60df3af4c9SAaron LI }
61df3af4c9SAaron LI 
62df3af4c9SAaron LI void
os_vmobj_ref(os_vmobj_t * vmobj)63df3af4c9SAaron LI os_vmobj_ref(os_vmobj_t *vmobj)
64df3af4c9SAaron LI {
65df3af4c9SAaron LI 	uao_reference(vmobj);
66df3af4c9SAaron LI }
67df3af4c9SAaron LI 
68df3af4c9SAaron LI void
os_vmobj_rel(os_vmobj_t * vmobj)69df3af4c9SAaron LI os_vmobj_rel(os_vmobj_t *vmobj)
70df3af4c9SAaron LI {
71df3af4c9SAaron LI 	uao_detach(vmobj);
72df3af4c9SAaron LI }
73df3af4c9SAaron LI 
74df3af4c9SAaron LI int
os_vmobj_map(struct vm_map * map,vaddr_t * addr,vsize_t size,os_vmobj_t * vmobj,voff_t offset,bool wired,bool fixed,bool shared,int prot,int maxprot)75df3af4c9SAaron LI os_vmobj_map(struct vm_map *map, vaddr_t *addr, vsize_t size, os_vmobj_t *vmobj,
76df3af4c9SAaron LI     voff_t offset, bool wired, bool fixed, bool shared, int prot, int maxprot)
77df3af4c9SAaron LI {
78df3af4c9SAaron LI 	uvm_flag_t uflags, uprot, umaxprot;
79df3af4c9SAaron LI 	int error;
80df3af4c9SAaron LI 
81df3af4c9SAaron LI 	/* Convert prot. */
82df3af4c9SAaron LI 	uprot = 0;
83df3af4c9SAaron LI 	if (prot & PROT_READ)
84df3af4c9SAaron LI 		uprot |= UVM_PROT_R;
85df3af4c9SAaron LI 	if (prot & PROT_WRITE)
86df3af4c9SAaron LI 		uprot |= UVM_PROT_W;
87df3af4c9SAaron LI 	if (prot & PROT_EXEC)
88df3af4c9SAaron LI 		uprot |= UVM_PROT_X;
89df3af4c9SAaron LI 
90df3af4c9SAaron LI 	/* Convert maxprot. */
91df3af4c9SAaron LI 	umaxprot = 0;
92df3af4c9SAaron LI 	if (maxprot & PROT_READ)
93df3af4c9SAaron LI 		umaxprot |= UVM_PROT_R;
94df3af4c9SAaron LI 	if (maxprot & PROT_WRITE)
95df3af4c9SAaron LI 		umaxprot |= UVM_PROT_W;
96df3af4c9SAaron LI 	if (maxprot & PROT_EXEC)
97df3af4c9SAaron LI 		umaxprot |= UVM_PROT_X;
98df3af4c9SAaron LI 
99df3af4c9SAaron LI 	uflags = UVM_MAPFLAG(uprot, umaxprot,
100df3af4c9SAaron LI 	    shared ? UVM_INH_SHARE : UVM_INH_NONE, UVM_ADV_RANDOM,
101df3af4c9SAaron LI 	    fixed ? (UVM_FLAG_FIXED | UVM_FLAG_UNMAP) : 0);
102df3af4c9SAaron LI 
103df3af4c9SAaron LI 	if (!fixed) {
104df3af4c9SAaron LI 		/* Need to provide a hint. */
105df3af4c9SAaron LI 		if (map == os_curproc_map) {
106df3af4c9SAaron LI 			*addr = curproc->p_emul->e_vm_default_addr(curproc,
107df3af4c9SAaron LI 			    (vaddr_t)curproc->p_vmspace->vm_daddr, size,
108df3af4c9SAaron LI 			    curproc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN);
109df3af4c9SAaron LI 		} else {
110df3af4c9SAaron LI 			*addr = 0;
111df3af4c9SAaron LI 		}
112df3af4c9SAaron LI 	}
113df3af4c9SAaron LI 
114df3af4c9SAaron LI 	/* Get a reference to the object. */
115df3af4c9SAaron LI 	os_vmobj_ref(vmobj);
116df3af4c9SAaron LI 
117df3af4c9SAaron LI 	/*
118df3af4c9SAaron LI 	 * Map the object. This consumes the reference on success only. On
119df3af4c9SAaron LI 	 * failure we must drop the reference manually.
120df3af4c9SAaron LI 	 */
121df3af4c9SAaron LI 	error = uvm_map(map, addr, size, vmobj, offset, 0, uflags);
122df3af4c9SAaron LI 	if (error) {
123df3af4c9SAaron LI 		/* Drop the ref. */
124df3af4c9SAaron LI 		os_vmobj_rel(vmobj);
125df3af4c9SAaron LI 		return error;
126df3af4c9SAaron LI 	}
127df3af4c9SAaron LI 
128df3af4c9SAaron LI 	if (wired) {
129df3af4c9SAaron LI 		error = uvm_map_pageable(map, *addr, *addr + size, false, 0);
130df3af4c9SAaron LI 		if (error) {
131df3af4c9SAaron LI 			os_vmobj_unmap(map, *addr, *addr + size, false);
132df3af4c9SAaron LI 			return error;
133df3af4c9SAaron LI 		}
134df3af4c9SAaron LI 	}
135df3af4c9SAaron LI 
136df3af4c9SAaron LI 	return 0;
137df3af4c9SAaron LI }
138df3af4c9SAaron LI 
139df3af4c9SAaron LI void
os_vmobj_unmap(struct vm_map * map,vaddr_t start,vaddr_t end,bool wired __unused)140df3af4c9SAaron LI os_vmobj_unmap(struct vm_map *map, vaddr_t start, vaddr_t end,
141df3af4c9SAaron LI     bool wired __unused)
142df3af4c9SAaron LI {
143df3af4c9SAaron LI 	uvm_unmap(map, start, end);
144df3af4c9SAaron LI }
145df3af4c9SAaron LI 
146df3af4c9SAaron LI void *
os_pagemem_zalloc(size_t size)147df3af4c9SAaron LI os_pagemem_zalloc(size_t size)
148df3af4c9SAaron LI {
149df3af4c9SAaron LI 	void *ret;
150df3af4c9SAaron LI 
151df3af4c9SAaron LI 	ret = (void *)uvm_km_alloc(kernel_map, roundup(size, PAGE_SIZE), 0,
152df3af4c9SAaron LI 	    UVM_KMF_WIRED | UVM_KMF_ZERO);
153df3af4c9SAaron LI 
154df3af4c9SAaron LI 	OS_ASSERT((uintptr_t)ret % PAGE_SIZE == 0);
155df3af4c9SAaron LI 
156df3af4c9SAaron LI 	return ret;
157df3af4c9SAaron LI }
158df3af4c9SAaron LI 
159df3af4c9SAaron LI void
os_pagemem_free(void * ptr,size_t size)160df3af4c9SAaron LI os_pagemem_free(void *ptr, size_t size)
161df3af4c9SAaron LI {
162df3af4c9SAaron LI 	uvm_km_free(kernel_map, (vaddr_t)ptr, roundup(size, PAGE_SIZE),
163df3af4c9SAaron LI 	    UVM_KMF_WIRED);
164df3af4c9SAaron LI }
165df3af4c9SAaron LI 
166df3af4c9SAaron LI paddr_t
os_pa_zalloc(void)167df3af4c9SAaron LI os_pa_zalloc(void)
168df3af4c9SAaron LI {
169df3af4c9SAaron LI 	struct vm_page *pg;
170df3af4c9SAaron LI 
171df3af4c9SAaron LI 	pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
172df3af4c9SAaron LI 
173df3af4c9SAaron LI 	return VM_PAGE_TO_PHYS(pg);
174df3af4c9SAaron LI }
175df3af4c9SAaron LI 
176df3af4c9SAaron LI void
os_pa_free(paddr_t pa)177df3af4c9SAaron LI os_pa_free(paddr_t pa)
178df3af4c9SAaron LI {
179df3af4c9SAaron LI 	uvm_pagefree(PHYS_TO_VM_PAGE(pa));
180df3af4c9SAaron LI }
181df3af4c9SAaron LI 
182df3af4c9SAaron LI int
os_contigpa_zalloc(paddr_t * pa,vaddr_t * va,size_t npages)183df3af4c9SAaron LI os_contigpa_zalloc(paddr_t *pa, vaddr_t *va, size_t npages)
184df3af4c9SAaron LI {
185df3af4c9SAaron LI 	struct pglist pglist;
186df3af4c9SAaron LI 	paddr_t _pa;
187df3af4c9SAaron LI 	vaddr_t _va;
188df3af4c9SAaron LI 	size_t i;
189df3af4c9SAaron LI 	int ret;
190df3af4c9SAaron LI 
191df3af4c9SAaron LI 	ret = uvm_pglistalloc(npages * PAGE_SIZE, 0, ~0UL, PAGE_SIZE, 0,
192df3af4c9SAaron LI 	    &pglist, 1, 0);
193df3af4c9SAaron LI 	if (ret != 0)
194df3af4c9SAaron LI 		return ENOMEM;
195df3af4c9SAaron LI 	_pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist));
196df3af4c9SAaron LI 	_va = uvm_km_alloc(kernel_map, npages * PAGE_SIZE, 0,
197df3af4c9SAaron LI 	    UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
198df3af4c9SAaron LI 	if (_va == 0)
199df3af4c9SAaron LI 		goto error;
200df3af4c9SAaron LI 
201df3af4c9SAaron LI 	for (i = 0; i < npages; i++) {
202df3af4c9SAaron LI 		pmap_kenter_pa(_va + i * PAGE_SIZE, _pa + i * PAGE_SIZE,
203df3af4c9SAaron LI 		    VM_PROT_READ | VM_PROT_WRITE, PMAP_WRITE_BACK);
204df3af4c9SAaron LI 	}
205df3af4c9SAaron LI 	pmap_update(pmap_kernel());
206df3af4c9SAaron LI 
207df3af4c9SAaron LI 	memset((void *)_va, 0, npages * PAGE_SIZE);
208df3af4c9SAaron LI 
209df3af4c9SAaron LI 	*pa = _pa;
210df3af4c9SAaron LI 	*va = _va;
211df3af4c9SAaron LI 	return 0;
212df3af4c9SAaron LI 
213df3af4c9SAaron LI error:
214df3af4c9SAaron LI 	for (i = 0; i < npages; i++) {
215df3af4c9SAaron LI 		uvm_pagefree(PHYS_TO_VM_PAGE(_pa + i * PAGE_SIZE));
216df3af4c9SAaron LI 	}
217df3af4c9SAaron LI 	return ENOMEM;
218df3af4c9SAaron LI }
219df3af4c9SAaron LI 
220df3af4c9SAaron LI void
os_contigpa_free(paddr_t pa,vaddr_t va,size_t npages)221df3af4c9SAaron LI os_contigpa_free(paddr_t pa, vaddr_t va, size_t npages)
222df3af4c9SAaron LI {
223df3af4c9SAaron LI 	size_t i;
224df3af4c9SAaron LI 
225df3af4c9SAaron LI 	pmap_kremove(va, npages * PAGE_SIZE);
226df3af4c9SAaron LI 	pmap_update(pmap_kernel());
227df3af4c9SAaron LI 	uvm_km_free(kernel_map, va, npages * PAGE_SIZE, UVM_KMF_VAONLY);
228df3af4c9SAaron LI 	for (i = 0; i < npages; i++) {
229df3af4c9SAaron LI 		uvm_pagefree(PHYS_TO_VM_PAGE(pa + i * PAGE_SIZE));
230df3af4c9SAaron LI 	}
231df3af4c9SAaron LI }
232*8a0a54bfSAaron LI 
233*8a0a54bfSAaron LI /* -------------------------------------------------------------------------- */
234*8a0a54bfSAaron LI 
235*8a0a54bfSAaron LI #include <sys/conf.h>
236*8a0a54bfSAaron LI #include <sys/device.h>
237*8a0a54bfSAaron LI #include <sys/file.h>
238*8a0a54bfSAaron LI #include <sys/filedesc.h>
239*8a0a54bfSAaron LI #include <sys/module.h>
240*8a0a54bfSAaron LI 
241*8a0a54bfSAaron LI #include "ioconf.h"
242*8a0a54bfSAaron LI 
243*8a0a54bfSAaron LI static dev_type_open(nbsd_nvmm_open);
244*8a0a54bfSAaron LI static int nbsd_nvmm_ioctl(file_t *, u_long, void *);
245*8a0a54bfSAaron LI static int nbsd_nvmm_close(file_t *);
246*8a0a54bfSAaron LI 
247*8a0a54bfSAaron LI const struct cdevsw nvmm_cdevsw = {
248*8a0a54bfSAaron LI 	.d_open = nbsd_nvmm_open,
249*8a0a54bfSAaron LI 	.d_close = noclose,
250*8a0a54bfSAaron LI 	.d_read = noread,
251*8a0a54bfSAaron LI 	.d_write = nowrite,
252*8a0a54bfSAaron LI 	.d_ioctl = noioctl,
253*8a0a54bfSAaron LI 	.d_stop = nostop,
254*8a0a54bfSAaron LI 	.d_tty = notty,
255*8a0a54bfSAaron LI 	.d_poll = nopoll,
256*8a0a54bfSAaron LI 	.d_mmap = nommap,
257*8a0a54bfSAaron LI 	.d_kqfilter = nokqfilter,
258*8a0a54bfSAaron LI 	.d_discard = nodiscard,
259*8a0a54bfSAaron LI 	.d_flag = D_OTHER | D_MPSAFE
260*8a0a54bfSAaron LI };
261*8a0a54bfSAaron LI 
262*8a0a54bfSAaron LI static const struct fileops nvmm_fileops = {
263*8a0a54bfSAaron LI 	.fo_read = fbadop_read,
264*8a0a54bfSAaron LI 	.fo_write = fbadop_write,
265*8a0a54bfSAaron LI 	.fo_ioctl = nbsd_nvmm_ioctl,
266*8a0a54bfSAaron LI 	.fo_fcntl = fnullop_fcntl,
267*8a0a54bfSAaron LI 	.fo_poll = fnullop_poll,
268*8a0a54bfSAaron LI 	.fo_stat = fbadop_stat,
269*8a0a54bfSAaron LI 	.fo_close = nbsd_nvmm_close,
270*8a0a54bfSAaron LI 	.fo_kqfilter = fnullop_kqfilter,
271*8a0a54bfSAaron LI 	.fo_restart = fnullop_restart,
272*8a0a54bfSAaron LI 	.fo_mmap = NULL,
273*8a0a54bfSAaron LI };
274*8a0a54bfSAaron LI 
275*8a0a54bfSAaron LI static int
nbsd_nvmm_open(dev_t dev,int flags,int type,struct lwp * l)276*8a0a54bfSAaron LI nbsd_nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
277*8a0a54bfSAaron LI {
278*8a0a54bfSAaron LI 	struct nvmm_owner *owner;
279*8a0a54bfSAaron LI 	struct file *fp;
280*8a0a54bfSAaron LI 	int error, fd;
281*8a0a54bfSAaron LI 
282*8a0a54bfSAaron LI 	if (__predict_false(nvmm_impl == NULL))
283*8a0a54bfSAaron LI 		return ENXIO;
284*8a0a54bfSAaron LI 	if (minor(dev) != 0)
285*8a0a54bfSAaron LI 		return EXDEV;
286*8a0a54bfSAaron LI 	if (!(flags & O_CLOEXEC))
287*8a0a54bfSAaron LI 		return EINVAL;
288*8a0a54bfSAaron LI 	error = fd_allocfile(&fp, &fd);
289*8a0a54bfSAaron LI 	if (error)
290*8a0a54bfSAaron LI 		return error;
291*8a0a54bfSAaron LI 
292*8a0a54bfSAaron LI 	if (OFLAGS(flags) & O_WRONLY) {
293*8a0a54bfSAaron LI 		owner = &nvmm_root_owner;
294*8a0a54bfSAaron LI 	} else {
295*8a0a54bfSAaron LI 		owner = os_mem_alloc(sizeof(*owner));
296*8a0a54bfSAaron LI 		owner->pid = l->l_proc->p_pid;
297*8a0a54bfSAaron LI 	}
298*8a0a54bfSAaron LI 
299*8a0a54bfSAaron LI 	return fd_clone(fp, fd, flags, &nvmm_fileops, owner);
300*8a0a54bfSAaron LI }
301*8a0a54bfSAaron LI 
302*8a0a54bfSAaron LI static int
nbsd_nvmm_ioctl(file_t * fp,u_long cmd,void * data)303*8a0a54bfSAaron LI nbsd_nvmm_ioctl(file_t *fp, u_long cmd, void *data)
304*8a0a54bfSAaron LI {
305*8a0a54bfSAaron LI 	struct nvmm_owner *owner = fp->f_data;
306*8a0a54bfSAaron LI 
307*8a0a54bfSAaron LI 	OS_ASSERT(owner != NULL);
308*8a0a54bfSAaron LI 
309*8a0a54bfSAaron LI 	return nvmm_ioctl(owner, cmd, data);
310*8a0a54bfSAaron LI }
311*8a0a54bfSAaron LI 
312*8a0a54bfSAaron LI static int
nbsd_nvmm_close(file_t * fp)313*8a0a54bfSAaron LI nbsd_nvmm_close(file_t *fp)
314*8a0a54bfSAaron LI {
315*8a0a54bfSAaron LI 	struct nvmm_owner *owner = fp->f_data;
316*8a0a54bfSAaron LI 
317*8a0a54bfSAaron LI 	OS_ASSERT(owner != NULL);
318*8a0a54bfSAaron LI 	nvmm_kill_machines(owner);
319*8a0a54bfSAaron LI 	if (owner != &nvmm_root_owner) {
320*8a0a54bfSAaron LI 		os_mem_free(owner, sizeof(*owner));
321*8a0a54bfSAaron LI 	}
322*8a0a54bfSAaron LI 	fp->f_data = NULL;
323*8a0a54bfSAaron LI 
324*8a0a54bfSAaron LI 	return 0;
325*8a0a54bfSAaron LI }
326*8a0a54bfSAaron LI 
327*8a0a54bfSAaron LI /* -------------------------------------------------------------------------- */
328*8a0a54bfSAaron LI 
329*8a0a54bfSAaron LI static int nvmm_match(device_t, cfdata_t, void *);
330*8a0a54bfSAaron LI static void nvmm_attach(device_t, device_t, void *);
331*8a0a54bfSAaron LI static int nvmm_detach(device_t, int);
332*8a0a54bfSAaron LI 
333*8a0a54bfSAaron LI extern struct cfdriver nvmm_cd;
334*8a0a54bfSAaron LI 
335*8a0a54bfSAaron LI CFATTACH_DECL_NEW(nvmm, 0, nvmm_match, nvmm_attach, nvmm_detach, NULL);
336*8a0a54bfSAaron LI 
337*8a0a54bfSAaron LI static struct cfdata nvmm_cfdata[] = {
338*8a0a54bfSAaron LI 	{
339*8a0a54bfSAaron LI 		.cf_name = "nvmm",
340*8a0a54bfSAaron LI 		.cf_atname = "nvmm",
341*8a0a54bfSAaron LI 		.cf_unit = 0,
342*8a0a54bfSAaron LI 		.cf_fstate = FSTATE_STAR,
343*8a0a54bfSAaron LI 		.cf_loc = NULL,
344*8a0a54bfSAaron LI 		.cf_flags = 0,
345*8a0a54bfSAaron LI 		.cf_pspec = NULL,
346*8a0a54bfSAaron LI 	},
347*8a0a54bfSAaron LI 	{ NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL }
348*8a0a54bfSAaron LI };
349*8a0a54bfSAaron LI 
350*8a0a54bfSAaron LI static int
nvmm_match(device_t self,cfdata_t cfdata,void * arg)351*8a0a54bfSAaron LI nvmm_match(device_t self, cfdata_t cfdata, void *arg)
352*8a0a54bfSAaron LI {
353*8a0a54bfSAaron LI 	return 1;
354*8a0a54bfSAaron LI }
355*8a0a54bfSAaron LI 
356*8a0a54bfSAaron LI static void
nvmm_attach(device_t parent,device_t self,void * aux)357*8a0a54bfSAaron LI nvmm_attach(device_t parent, device_t self, void *aux)
358*8a0a54bfSAaron LI {
359*8a0a54bfSAaron LI 	int error;
360*8a0a54bfSAaron LI 
361*8a0a54bfSAaron LI 	error = nvmm_init();
362*8a0a54bfSAaron LI 	if (error)
363*8a0a54bfSAaron LI 		panic("%s: impossible", __func__);
364*8a0a54bfSAaron LI 	aprint_normal_dev(self, "attached, using backend %s\n",
365*8a0a54bfSAaron LI 	    nvmm_impl->name);
366*8a0a54bfSAaron LI }
367*8a0a54bfSAaron LI 
368*8a0a54bfSAaron LI static int
nvmm_detach(device_t self,int flags)369*8a0a54bfSAaron LI nvmm_detach(device_t self, int flags)
370*8a0a54bfSAaron LI {
371*8a0a54bfSAaron LI 	if (os_atomic_load_uint(&nmachines) > 0)
372*8a0a54bfSAaron LI 		return EBUSY;
373*8a0a54bfSAaron LI 	nvmm_fini();
374*8a0a54bfSAaron LI 	return 0;
375*8a0a54bfSAaron LI }
376*8a0a54bfSAaron LI 
377*8a0a54bfSAaron LI void
nvmmattach(int nunits)378*8a0a54bfSAaron LI nvmmattach(int nunits)
379*8a0a54bfSAaron LI {
380*8a0a54bfSAaron LI 	/* nothing */
381*8a0a54bfSAaron LI }
382*8a0a54bfSAaron LI 
383*8a0a54bfSAaron LI MODULE(MODULE_CLASS_DRIVER, nvmm, NULL);
384*8a0a54bfSAaron LI 
385*8a0a54bfSAaron LI #if defined(_MODULE)
386*8a0a54bfSAaron LI CFDRIVER_DECL(nvmm, DV_VIRTUAL, NULL);
387*8a0a54bfSAaron LI #endif
388*8a0a54bfSAaron LI 
389*8a0a54bfSAaron LI static int
nvmm_modcmd(modcmd_t cmd,void * arg)390*8a0a54bfSAaron LI nvmm_modcmd(modcmd_t cmd, void *arg)
391*8a0a54bfSAaron LI {
392*8a0a54bfSAaron LI #if defined(_MODULE)
393*8a0a54bfSAaron LI 	devmajor_t bmajor = NODEVMAJOR;
394*8a0a54bfSAaron LI 	devmajor_t cmajor = 345;
395*8a0a54bfSAaron LI #endif
396*8a0a54bfSAaron LI 	int error;
397*8a0a54bfSAaron LI 
398*8a0a54bfSAaron LI 	switch (cmd) {
399*8a0a54bfSAaron LI 	case MODULE_CMD_INIT:
400*8a0a54bfSAaron LI 		if (nvmm_ident() == NULL) {
401*8a0a54bfSAaron LI 			aprint_error("%s: cpu not supported\n",
402*8a0a54bfSAaron LI 			    nvmm_cd.cd_name);
403*8a0a54bfSAaron LI 			return ENOTSUP;
404*8a0a54bfSAaron LI 		}
405*8a0a54bfSAaron LI #if defined(_MODULE)
406*8a0a54bfSAaron LI 		error = config_cfdriver_attach(&nvmm_cd);
407*8a0a54bfSAaron LI 		if (error)
408*8a0a54bfSAaron LI 			return error;
409*8a0a54bfSAaron LI #endif
410*8a0a54bfSAaron LI 		error = config_cfattach_attach(nvmm_cd.cd_name, &nvmm_ca);
411*8a0a54bfSAaron LI 		if (error) {
412*8a0a54bfSAaron LI 			config_cfdriver_detach(&nvmm_cd);
413*8a0a54bfSAaron LI 			aprint_error("%s: config_cfattach_attach failed\n",
414*8a0a54bfSAaron LI 			    nvmm_cd.cd_name);
415*8a0a54bfSAaron LI 			return error;
416*8a0a54bfSAaron LI 		}
417*8a0a54bfSAaron LI 
418*8a0a54bfSAaron LI 		error = config_cfdata_attach(nvmm_cfdata, 1);
419*8a0a54bfSAaron LI 		if (error) {
420*8a0a54bfSAaron LI 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
421*8a0a54bfSAaron LI 			config_cfdriver_detach(&nvmm_cd);
422*8a0a54bfSAaron LI 			aprint_error("%s: unable to register cfdata\n",
423*8a0a54bfSAaron LI 			    nvmm_cd.cd_name);
424*8a0a54bfSAaron LI 			return error;
425*8a0a54bfSAaron LI 		}
426*8a0a54bfSAaron LI 
427*8a0a54bfSAaron LI 		if (config_attach_pseudo(nvmm_cfdata) == NULL) {
428*8a0a54bfSAaron LI 			aprint_error("%s: config_attach_pseudo failed\n",
429*8a0a54bfSAaron LI 			    nvmm_cd.cd_name);
430*8a0a54bfSAaron LI 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
431*8a0a54bfSAaron LI 			config_cfdriver_detach(&nvmm_cd);
432*8a0a54bfSAaron LI 			return ENXIO;
433*8a0a54bfSAaron LI 		}
434*8a0a54bfSAaron LI 
435*8a0a54bfSAaron LI #if defined(_MODULE)
436*8a0a54bfSAaron LI 		/* mknod /dev/nvmm c 345 0 */
437*8a0a54bfSAaron LI 		error = devsw_attach(nvmm_cd.cd_name, NULL, &bmajor,
438*8a0a54bfSAaron LI 			&nvmm_cdevsw, &cmajor);
439*8a0a54bfSAaron LI 		if (error) {
440*8a0a54bfSAaron LI 			aprint_error("%s: unable to register devsw\n",
441*8a0a54bfSAaron LI 			    nvmm_cd.cd_name);
442*8a0a54bfSAaron LI 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
443*8a0a54bfSAaron LI 			config_cfdriver_detach(&nvmm_cd);
444*8a0a54bfSAaron LI 			return error;
445*8a0a54bfSAaron LI 		}
446*8a0a54bfSAaron LI #endif
447*8a0a54bfSAaron LI 		return 0;
448*8a0a54bfSAaron LI 	case MODULE_CMD_FINI:
449*8a0a54bfSAaron LI 		error = config_cfdata_detach(nvmm_cfdata);
450*8a0a54bfSAaron LI 		if (error)
451*8a0a54bfSAaron LI 			return error;
452*8a0a54bfSAaron LI 		error = config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
453*8a0a54bfSAaron LI 		if (error)
454*8a0a54bfSAaron LI 			return error;
455*8a0a54bfSAaron LI #if defined(_MODULE)
456*8a0a54bfSAaron LI 		config_cfdriver_detach(&nvmm_cd);
457*8a0a54bfSAaron LI 		devsw_detach(NULL, &nvmm_cdevsw);
458*8a0a54bfSAaron LI #endif
459*8a0a54bfSAaron LI 		return 0;
460*8a0a54bfSAaron LI 	case MODULE_CMD_AUTOUNLOAD:
461*8a0a54bfSAaron LI 		return EBUSY;
462*8a0a54bfSAaron LI 	default:
463*8a0a54bfSAaron LI 		return ENOTTY;
464*8a0a54bfSAaron LI 	}
465*8a0a54bfSAaron LI }
466