1df3af4c9SAaron LI /*-
2df3af4c9SAaron LI * SPDX-License-Identifier: BSD-3-Clause
3df3af4c9SAaron LI *
4df3af4c9SAaron LI * Copyright (c) 2021 The DragonFly Project. All rights reserved.
5df3af4c9SAaron LI *
6df3af4c9SAaron LI * This code is derived from software contributed to The DragonFly Project
7df3af4c9SAaron LI * by Aaron LI <aly@aaronly.me>
8df3af4c9SAaron LI *
9df3af4c9SAaron LI * Redistribution and use in source and binary forms, with or without
10df3af4c9SAaron LI * modification, are permitted provided that the following conditions
11df3af4c9SAaron LI * are met:
12df3af4c9SAaron LI *
13df3af4c9SAaron LI * 1. Redistributions of source code must retain the above copyright
14df3af4c9SAaron LI * notice, this list of conditions and the following disclaimer.
15df3af4c9SAaron LI * 2. Redistributions in binary form must reproduce the above copyright
16df3af4c9SAaron LI * notice, this list of conditions and the following disclaimer in
17df3af4c9SAaron LI * the documentation and/or other materials provided with the
18df3af4c9SAaron LI * distribution.
19df3af4c9SAaron LI * 3. Neither the name of The DragonFly Project nor the names of its
20df3af4c9SAaron LI * contributors may be used to endorse or promote products derived
21df3af4c9SAaron LI * from this software without specific, prior written permission.
22df3af4c9SAaron LI *
23df3af4c9SAaron LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24df3af4c9SAaron LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25df3af4c9SAaron LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26df3af4c9SAaron LI * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27df3af4c9SAaron LI * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28df3af4c9SAaron LI * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29df3af4c9SAaron LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30df3af4c9SAaron LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31df3af4c9SAaron LI * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32df3af4c9SAaron LI * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33df3af4c9SAaron LI * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df3af4c9SAaron LI * SUCH DAMAGE.
35df3af4c9SAaron LI */
36df3af4c9SAaron LI
37df3af4c9SAaron LI #include <sys/param.h>
38df3af4c9SAaron LI #include <sys/systm.h>
39df3af4c9SAaron LI #include <sys/kernel.h>
40df3af4c9SAaron LI #include <sys/mman.h>
41df3af4c9SAaron LI
42002185e5SAaron LI #include "nvmm.h"
43df3af4c9SAaron LI #include "nvmm_os.h"
44002185e5SAaron LI #include "nvmm_internal.h"
45df3af4c9SAaron LI
46df3af4c9SAaron LI MALLOC_DEFINE(M_NVMM, "nvmm", "NVMM data");
47df3af4c9SAaron LI
48df3af4c9SAaron LI /*
49df3af4c9SAaron LI * NVMM expects VM functions to return 0 on success, but DragonFly's VM
50df3af4c9SAaron LI * functions return KERN_SUCCESS. Although it's also defined to be 0,
51df3af4c9SAaron LI * assert it to be future-proofing.
52df3af4c9SAaron LI */
53df3af4c9SAaron LI CTASSERT(KERN_SUCCESS == 0);
54df3af4c9SAaron LI
55df3af4c9SAaron LI os_vmspace_t *
os_vmspace_create(vaddr_t vmin,vaddr_t vmax)56df3af4c9SAaron LI os_vmspace_create(vaddr_t vmin, vaddr_t vmax)
57df3af4c9SAaron LI {
58*24f14bf4SAaron LI struct vmspace *vm;
59*24f14bf4SAaron LI
60*24f14bf4SAaron LI vm = vmspace_alloc(vmin, vmax);
61*24f14bf4SAaron LI
62*24f14bf4SAaron LI /*
63*24f14bf4SAaron LI * Set PMAP_MULTI on the backing pmap for the machine. Only
64*24f14bf4SAaron LI * pmap changes to the backing pmap for the machine affect the
65*24f14bf4SAaron LI * guest. Changes to the host's pmap do not affect the guest's
66*24f14bf4SAaron LI * backing pmap.
67*24f14bf4SAaron LI */
68*24f14bf4SAaron LI pmap_maybethreaded(&vm->vm_pmap);
69*24f14bf4SAaron LI
70*24f14bf4SAaron LI return vm;
71df3af4c9SAaron LI }
72df3af4c9SAaron LI
73df3af4c9SAaron LI void
os_vmspace_destroy(os_vmspace_t * vm)74df3af4c9SAaron LI os_vmspace_destroy(os_vmspace_t *vm)
75df3af4c9SAaron LI {
76df3af4c9SAaron LI pmap_del_all_cpus(vm);
77df3af4c9SAaron LI vmspace_rel(vm);
78df3af4c9SAaron LI }
79df3af4c9SAaron LI
80df3af4c9SAaron LI int
os_vmspace_fault(os_vmspace_t * vm,vaddr_t va,vm_prot_t prot)81df3af4c9SAaron LI os_vmspace_fault(os_vmspace_t *vm, vaddr_t va, vm_prot_t prot)
82df3af4c9SAaron LI {
83df3af4c9SAaron LI int fault_flags;
84df3af4c9SAaron LI
85df3af4c9SAaron LI if (prot & VM_PROT_WRITE)
86df3af4c9SAaron LI fault_flags = VM_FAULT_DIRTY;
87df3af4c9SAaron LI else
88df3af4c9SAaron LI fault_flags = VM_FAULT_NORMAL;
89df3af4c9SAaron LI
90df3af4c9SAaron LI return vm_fault(&vm->vm_map, trunc_page(va), prot, fault_flags);
91df3af4c9SAaron LI }
92df3af4c9SAaron LI
93df3af4c9SAaron LI os_vmobj_t *
os_vmobj_create(voff_t size)94df3af4c9SAaron LI os_vmobj_create(voff_t size)
95df3af4c9SAaron LI {
96df3af4c9SAaron LI struct vm_object *object;
97df3af4c9SAaron LI
98df3af4c9SAaron LI object = default_pager_alloc(NULL, size, VM_PROT_DEFAULT, 0);
99df3af4c9SAaron LI vm_object_set_flag(object, OBJ_NOSPLIT);
100df3af4c9SAaron LI
101df3af4c9SAaron LI return object;
102df3af4c9SAaron LI }
103df3af4c9SAaron LI
104df3af4c9SAaron LI void
os_vmobj_ref(os_vmobj_t * vmobj)105df3af4c9SAaron LI os_vmobj_ref(os_vmobj_t *vmobj)
106df3af4c9SAaron LI {
107df3af4c9SAaron LI vm_object_hold(vmobj);
108df3af4c9SAaron LI vm_object_reference_locked(vmobj);
109df3af4c9SAaron LI vm_object_drop(vmobj);
110df3af4c9SAaron LI }
111df3af4c9SAaron LI
112df3af4c9SAaron LI void
os_vmobj_rel(os_vmobj_t * vmobj)113df3af4c9SAaron LI os_vmobj_rel(os_vmobj_t *vmobj)
114df3af4c9SAaron LI {
115df3af4c9SAaron LI vm_object_deallocate(vmobj);
116df3af4c9SAaron LI }
117df3af4c9SAaron LI
118df3af4c9SAaron 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)119df3af4c9SAaron LI os_vmobj_map(struct vm_map *map, vaddr_t *addr, vsize_t size, os_vmobj_t *vmobj,
120df3af4c9SAaron LI voff_t offset, bool wired, bool fixed, bool shared, int prot, int maxprot)
121df3af4c9SAaron LI {
122df3af4c9SAaron LI vm_prot_t vmprot, vmmaxprot;
123df3af4c9SAaron LI vm_inherit_t inherit;
124df3af4c9SAaron LI vm_offset_t start = *addr;
125df3af4c9SAaron LI int rv = KERN_SUCCESS;
126df3af4c9SAaron LI int count;
127df3af4c9SAaron LI
128df3af4c9SAaron LI /* Convert prot. */
129df3af4c9SAaron LI vmprot = 0;
130df3af4c9SAaron LI if (prot & PROT_READ)
131df3af4c9SAaron LI vmprot |= VM_PROT_READ;
132df3af4c9SAaron LI if (prot & PROT_WRITE)
133df3af4c9SAaron LI vmprot |= VM_PROT_WRITE;
134df3af4c9SAaron LI if (prot & PROT_EXEC)
135df3af4c9SAaron LI vmprot |= VM_PROT_EXECUTE;
136df3af4c9SAaron LI
137df3af4c9SAaron LI /* Convert maxprot. */
138df3af4c9SAaron LI vmmaxprot = 0;
139df3af4c9SAaron LI if (maxprot & PROT_READ)
140df3af4c9SAaron LI vmmaxprot |= VM_PROT_READ;
141df3af4c9SAaron LI if (maxprot & PROT_WRITE)
142df3af4c9SAaron LI vmmaxprot |= VM_PROT_WRITE;
143df3af4c9SAaron LI if (maxprot & PROT_EXEC)
144df3af4c9SAaron LI vmmaxprot |= VM_PROT_EXECUTE;
145df3af4c9SAaron LI
146df3af4c9SAaron LI count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
147df3af4c9SAaron LI vm_map_lock(map);
148df3af4c9SAaron LI
149df3af4c9SAaron LI if (fixed) {
150df3af4c9SAaron LI /*
151df3af4c9SAaron LI * Remove any existing entries in the range, so the new
152df3af4c9SAaron LI * mapping can be created at the requested address.
153df3af4c9SAaron LI */
154df3af4c9SAaron LI rv = vm_map_delete(map, start, start + size, &count);
155df3af4c9SAaron LI } else {
156df3af4c9SAaron LI if (vm_map_findspace(map, start, size, 1, 0, &start))
157df3af4c9SAaron LI rv = KERN_NO_SPACE;
158df3af4c9SAaron LI }
159df3af4c9SAaron LI if (rv != KERN_SUCCESS) {
160df3af4c9SAaron LI vm_map_unlock(map);
161df3af4c9SAaron LI vm_map_entry_release(count);
162df3af4c9SAaron LI return rv;
163df3af4c9SAaron LI }
164df3af4c9SAaron LI
165df3af4c9SAaron LI /* Get a reference to the object. */
166df3af4c9SAaron LI os_vmobj_ref(vmobj);
167df3af4c9SAaron LI
168df3af4c9SAaron LI /*
169df3af4c9SAaron LI * Map the object. This consumes the reference on success only. On
170df3af4c9SAaron LI * failure we must drop the reference manually.
171df3af4c9SAaron LI */
172df3af4c9SAaron LI vm_object_hold(vmobj);
173df3af4c9SAaron LI rv = vm_map_insert(map, &count, vmobj, NULL, offset, NULL,
174df3af4c9SAaron LI start, start + size, VM_MAPTYPE_NORMAL, VM_SUBSYS_NVMM,
175df3af4c9SAaron LI vmprot, vmmaxprot, 0);
176df3af4c9SAaron LI vm_object_drop(vmobj);
177df3af4c9SAaron LI vm_map_unlock(map);
178df3af4c9SAaron LI vm_map_entry_release(count);
179df3af4c9SAaron LI if (rv != KERN_SUCCESS) {
180df3af4c9SAaron LI /* Drop the ref. */
181df3af4c9SAaron LI os_vmobj_rel(vmobj);
182df3af4c9SAaron LI return rv;
183df3af4c9SAaron LI }
184df3af4c9SAaron LI
185df3af4c9SAaron LI inherit = shared ? VM_INHERIT_SHARE : VM_INHERIT_NONE;
186df3af4c9SAaron LI rv = vm_map_inherit(map, start, start + size, inherit);
187df3af4c9SAaron LI if (rv != KERN_SUCCESS) {
188df3af4c9SAaron LI os_vmobj_unmap(map, start, start + size, false);
189df3af4c9SAaron LI return rv;
190df3af4c9SAaron LI }
191df3af4c9SAaron LI
192df3af4c9SAaron LI if (wired) {
193949c56f8SMatthew Dillon rv = vm_map_kernel_wiring(map, start, start + size, 0);
194df3af4c9SAaron LI if (rv != KERN_SUCCESS) {
195df3af4c9SAaron LI os_vmobj_unmap(map, start, start + size, false);
196df3af4c9SAaron LI return rv;
197df3af4c9SAaron LI }
198df3af4c9SAaron LI }
199df3af4c9SAaron LI
200df3af4c9SAaron LI *addr = start;
201df3af4c9SAaron LI return 0;
202df3af4c9SAaron LI }
203df3af4c9SAaron LI
204df3af4c9SAaron LI void
os_vmobj_unmap(struct vm_map * map,vaddr_t start,vaddr_t end,bool wired)205df3af4c9SAaron LI os_vmobj_unmap(struct vm_map *map, vaddr_t start, vaddr_t end, bool wired)
206df3af4c9SAaron LI {
207df3af4c9SAaron LI if (wired) {
208df3af4c9SAaron LI /* Unwire kernel mappings before removing. */
209949c56f8SMatthew Dillon vm_map_kernel_wiring(map, start, end, KM_PAGEABLE);
210df3af4c9SAaron LI }
211df3af4c9SAaron LI vm_map_remove(map, start, end);
212df3af4c9SAaron LI }
213df3af4c9SAaron LI
214df3af4c9SAaron LI void *
os_pagemem_zalloc(size_t size)215df3af4c9SAaron LI os_pagemem_zalloc(size_t size)
216df3af4c9SAaron LI {
217df3af4c9SAaron LI void *ret;
218df3af4c9SAaron LI
219df3af4c9SAaron LI /* NOTE: kmem_alloc() may return 0 ! */
220df3af4c9SAaron LI ret = (void *)kmem_alloc(kernel_map, roundup(size, PAGE_SIZE),
221df3af4c9SAaron LI VM_SUBSYS_NVMM);
222df3af4c9SAaron LI
223df3af4c9SAaron LI OS_ASSERT((uintptr_t)ret % PAGE_SIZE == 0);
224df3af4c9SAaron LI
225df3af4c9SAaron LI return ret;
226df3af4c9SAaron LI }
227df3af4c9SAaron LI
228df3af4c9SAaron LI void
os_pagemem_free(void * ptr,size_t size)229df3af4c9SAaron LI os_pagemem_free(void *ptr, size_t size)
230df3af4c9SAaron LI {
231df3af4c9SAaron LI kmem_free(kernel_map, (vaddr_t)ptr, roundup(size, PAGE_SIZE));
232df3af4c9SAaron LI }
233df3af4c9SAaron LI
234df3af4c9SAaron LI paddr_t
os_pa_zalloc(void)235df3af4c9SAaron LI os_pa_zalloc(void)
236df3af4c9SAaron LI {
237df3af4c9SAaron LI struct vm_page *pg;
238df3af4c9SAaron LI
239df3af4c9SAaron LI pg = vm_page_alloczwq(0,
240df3af4c9SAaron LI VM_ALLOC_SYSTEM | VM_ALLOC_ZERO | VM_ALLOC_RETRY);
241df3af4c9SAaron LI
242df3af4c9SAaron LI return VM_PAGE_TO_PHYS(pg);
243df3af4c9SAaron LI }
244df3af4c9SAaron LI
245df3af4c9SAaron LI void
os_pa_free(paddr_t pa)246df3af4c9SAaron LI os_pa_free(paddr_t pa)
247df3af4c9SAaron LI {
248df3af4c9SAaron LI vm_page_freezwq(PHYS_TO_VM_PAGE(pa));
249df3af4c9SAaron LI }
250df3af4c9SAaron LI
251df3af4c9SAaron LI int
os_contigpa_zalloc(paddr_t * pa,vaddr_t * va,size_t npages)252df3af4c9SAaron LI os_contigpa_zalloc(paddr_t *pa, vaddr_t *va, size_t npages)
253df3af4c9SAaron LI {
254df3af4c9SAaron LI void *addr;
255df3af4c9SAaron LI
256df3af4c9SAaron LI addr = contigmalloc(npages * PAGE_SIZE, M_NVMM, M_WAITOK | M_ZERO,
257df3af4c9SAaron LI 0, ~0UL, PAGE_SIZE, 0);
258df3af4c9SAaron LI if (addr == NULL)
259df3af4c9SAaron LI return ENOMEM;
260df3af4c9SAaron LI
261df3af4c9SAaron LI *va = (vaddr_t)addr;
262df3af4c9SAaron LI *pa = vtophys(addr);
263df3af4c9SAaron LI return 0;
264df3af4c9SAaron LI }
265df3af4c9SAaron LI
266df3af4c9SAaron LI void
os_contigpa_free(paddr_t pa __unused,vaddr_t va,size_t npages)267df3af4c9SAaron LI os_contigpa_free(paddr_t pa __unused, vaddr_t va, size_t npages)
268df3af4c9SAaron LI {
269df3af4c9SAaron LI contigfree((void *)va, npages * PAGE_SIZE, M_NVMM);
270df3af4c9SAaron LI }
271002185e5SAaron LI
272002185e5SAaron LI /* -------------------------------------------------------------------------- */
273002185e5SAaron LI
274002185e5SAaron LI #include <sys/conf.h>
275002185e5SAaron LI #include <sys/devfs.h>
276002185e5SAaron LI #include <sys/device.h>
277002185e5SAaron LI #include <sys/fcntl.h>
278002185e5SAaron LI #include <sys/module.h>
279002185e5SAaron LI
280002185e5SAaron LI static d_open_t dfbsd_nvmm_open;
281002185e5SAaron LI static d_ioctl_t dfbsd_nvmm_ioctl;
282002185e5SAaron LI static d_priv_dtor_t dfbsd_nvmm_dtor;
283002185e5SAaron LI
284002185e5SAaron LI static struct dev_ops nvmm_ops = {
285002185e5SAaron LI { "nvmm", 0, D_MPSAFE },
286002185e5SAaron LI .d_open = dfbsd_nvmm_open,
287002185e5SAaron LI .d_ioctl = dfbsd_nvmm_ioctl,
288002185e5SAaron LI };
289002185e5SAaron LI
290002185e5SAaron LI static int
dfbsd_nvmm_open(struct dev_open_args * ap)291002185e5SAaron LI dfbsd_nvmm_open(struct dev_open_args *ap)
292002185e5SAaron LI {
293002185e5SAaron LI int flags = ap->a_oflags;
294002185e5SAaron LI struct nvmm_owner *owner;
295002185e5SAaron LI struct file *fp;
296002185e5SAaron LI int error;
297002185e5SAaron LI
298002185e5SAaron LI if (__predict_false(nvmm_impl == NULL))
299002185e5SAaron LI return ENXIO;
300002185e5SAaron LI if (!(flags & O_CLOEXEC))
301002185e5SAaron LI return EINVAL;
302002185e5SAaron LI
303002185e5SAaron LI if (OFLAGS(flags) & O_WRONLY) {
304002185e5SAaron LI owner = &nvmm_root_owner;
305002185e5SAaron LI } else {
306002185e5SAaron LI owner = os_mem_alloc(sizeof(*owner));
307002185e5SAaron LI owner->pid = curthread->td_proc->p_pid;
308002185e5SAaron LI }
309002185e5SAaron LI
310002185e5SAaron LI fp = ap->a_fpp ? *ap->a_fpp : NULL;
311002185e5SAaron LI error = devfs_set_cdevpriv(fp, owner, dfbsd_nvmm_dtor);
312002185e5SAaron LI if (error) {
313002185e5SAaron LI dfbsd_nvmm_dtor(owner);
314002185e5SAaron LI return error;
315002185e5SAaron LI }
316002185e5SAaron LI
317002185e5SAaron LI return 0;
318002185e5SAaron LI }
319002185e5SAaron LI
320002185e5SAaron LI static void
dfbsd_nvmm_dtor(void * arg)321002185e5SAaron LI dfbsd_nvmm_dtor(void *arg)
322002185e5SAaron LI {
323002185e5SAaron LI struct nvmm_owner *owner = arg;
324002185e5SAaron LI
325002185e5SAaron LI OS_ASSERT(owner != NULL);
326002185e5SAaron LI nvmm_kill_machines(owner);
327002185e5SAaron LI if (owner != &nvmm_root_owner) {
328002185e5SAaron LI os_mem_free(owner, sizeof(*owner));
329002185e5SAaron LI }
330002185e5SAaron LI }
331002185e5SAaron LI
332002185e5SAaron LI static int
dfbsd_nvmm_ioctl(struct dev_ioctl_args * ap)333002185e5SAaron LI dfbsd_nvmm_ioctl(struct dev_ioctl_args *ap)
334002185e5SAaron LI {
335002185e5SAaron LI unsigned long cmd = ap->a_cmd;
336002185e5SAaron LI void *data = ap->a_data;
337002185e5SAaron LI struct file *fp = ap->a_fp;
338002185e5SAaron LI struct nvmm_owner *owner = NULL;
339002185e5SAaron LI
340002185e5SAaron LI devfs_get_cdevpriv(fp, (void **)&owner);
341002185e5SAaron LI OS_ASSERT(owner != NULL);
342002185e5SAaron LI
343002185e5SAaron LI return nvmm_ioctl(owner, cmd, data);
344002185e5SAaron LI }
345002185e5SAaron LI
346002185e5SAaron LI /* -------------------------------------------------------------------------- */
347002185e5SAaron LI
348002185e5SAaron LI static int
nvmm_attach(void)349002185e5SAaron LI nvmm_attach(void)
350002185e5SAaron LI {
351002185e5SAaron LI int error;
352002185e5SAaron LI
353002185e5SAaron LI error = nvmm_init();
354002185e5SAaron LI if (error)
355002185e5SAaron LI panic("%s: impossible", __func__);
356002185e5SAaron LI os_printf("nvmm: attached, using backend %s\n", nvmm_impl->name);
357002185e5SAaron LI
358002185e5SAaron LI return 0;
359002185e5SAaron LI }
360002185e5SAaron LI
361002185e5SAaron LI static int
nvmm_detach(void)362002185e5SAaron LI nvmm_detach(void)
363002185e5SAaron LI {
364002185e5SAaron LI if (os_atomic_load_uint(&nmachines) > 0)
365002185e5SAaron LI return EBUSY;
366002185e5SAaron LI
367002185e5SAaron LI nvmm_fini();
368002185e5SAaron LI return 0;
369002185e5SAaron LI }
370002185e5SAaron LI
371002185e5SAaron LI static int
nvmm_modevent(module_t mod __unused,int type,void * data __unused)372002185e5SAaron LI nvmm_modevent(module_t mod __unused, int type, void *data __unused)
373002185e5SAaron LI {
374002185e5SAaron LI static cdev_t dev = NULL;
375002185e5SAaron LI int error;
376002185e5SAaron LI
377002185e5SAaron LI switch (type) {
378002185e5SAaron LI case MOD_LOAD:
379002185e5SAaron LI if (nvmm_ident() == NULL) {
380002185e5SAaron LI os_printf("nvmm: cpu not supported\n");
381002185e5SAaron LI return ENOTSUP;
382002185e5SAaron LI }
383002185e5SAaron LI error = nvmm_attach();
384002185e5SAaron LI if (error)
385002185e5SAaron LI return error;
386002185e5SAaron LI
387002185e5SAaron LI dev = make_dev(&nvmm_ops, 0, UID_ROOT, GID_NVMM, 0640, "nvmm");
388002185e5SAaron LI if (dev == NULL) {
389002185e5SAaron LI os_printf("nvmm: unable to create device\n");
390002185e5SAaron LI error = ENOMEM;
391002185e5SAaron LI }
392002185e5SAaron LI break;
393002185e5SAaron LI
394002185e5SAaron LI case MOD_UNLOAD:
395002185e5SAaron LI if (dev == NULL)
396002185e5SAaron LI return 0;
397002185e5SAaron LI error = nvmm_detach();
398002185e5SAaron LI if (error == 0)
399002185e5SAaron LI destroy_dev(dev);
400002185e5SAaron LI break;
401002185e5SAaron LI
402002185e5SAaron LI case MOD_SHUTDOWN:
403002185e5SAaron LI error = 0;
404002185e5SAaron LI break;
405002185e5SAaron LI
406002185e5SAaron LI default:
407002185e5SAaron LI error = EOPNOTSUPP;
408002185e5SAaron LI break;
409002185e5SAaron LI }
410002185e5SAaron LI
411002185e5SAaron LI return error;
412002185e5SAaron LI }
413002185e5SAaron LI
414002185e5SAaron LI static moduledata_t nvmm_moddata = {
415002185e5SAaron LI .name = "nvmm",
416002185e5SAaron LI .evhand = nvmm_modevent,
417002185e5SAaron LI .priv = NULL,
418002185e5SAaron LI };
419002185e5SAaron LI
420002185e5SAaron LI DECLARE_MODULE(nvmm, nvmm_moddata, SI_SUB_PSEUDO, SI_ORDER_ANY);
421002185e5SAaron LI MODULE_VERSION(nvmm, NVMM_KERN_VERSION);
422