1 1.16 mlelstv /* $NetBSD: viomb.c,v 1.17 2023/03/25 11:04:34 mlelstv Exp $ */ 2 1.1 hannken 3 1.1 hannken /* 4 1.1 hannken * Copyright (c) 2010 Minoura Makoto. 5 1.1 hannken * All rights reserved. 6 1.1 hannken * 7 1.1 hannken * Redistribution and use in source and binary forms, with or without 8 1.1 hannken * modification, are permitted provided that the following conditions 9 1.1 hannken * are met: 10 1.1 hannken * 1. Redistributions of source code must retain the above copyright 11 1.1 hannken * notice, this list of conditions and the following disclaimer. 12 1.1 hannken * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 hannken * notice, this list of conditions and the following disclaimer in the 14 1.1 hannken * documentation and/or other materials provided with the distribution. 15 1.1 hannken * 16 1.1 hannken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 hannken * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 hannken * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 hannken * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 hannken * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 hannken * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 hannken * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 hannken * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 hannken * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 hannken * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 hannken */ 27 1.1 hannken 28 1.1 hannken #include <sys/cdefs.h> 29 1.16 mlelstv __KERNEL_RCSID(0, "$NetBSD: viomb.c,v 1.17 2023/03/25 11:04:34 mlelstv Exp $"); 30 1.1 hannken 31 1.1 hannken #include <sys/param.h> 32 1.1 hannken #include <sys/systm.h> 33 1.1 hannken #include <sys/kernel.h> 34 1.1 hannken #include <sys/bus.h> 35 1.1 hannken #include <sys/condvar.h> 36 1.1 hannken #include <sys/device.h> 37 1.1 hannken #include <sys/kthread.h> 38 1.1 hannken #include <sys/mutex.h> 39 1.1 hannken #include <sys/sysctl.h> 40 1.1 hannken #include <uvm/uvm_page.h> 41 1.7 pgoyette #include <sys/module.h> 42 1.1 hannken 43 1.1 hannken #include <dev/pci/virtioreg.h> 44 1.1 hannken #include <dev/pci/virtiovar.h> 45 1.1 hannken 46 1.7 pgoyette #include "ioconf.h" 47 1.7 pgoyette 48 1.1 hannken /* Configuration registers */ 49 1.1 hannken #define VIRTIO_BALLOON_CONFIG_NUM_PAGES 0 /* 32bit */ 50 1.1 hannken #define VIRTIO_BALLOON_CONFIG_ACTUAL 4 /* 32bit */ 51 1.1 hannken 52 1.1 hannken /* Feature bits */ 53 1.1 hannken #define VIRTIO_BALLOON_F_MUST_TELL_HOST (1<<0) 54 1.1 hannken #define VIRTIO_BALLOON_F_STATS_VQ (1<<1) 55 1.1 hannken 56 1.13 uwe #define VIRTIO_BALLOON_FLAG_BITS \ 57 1.13 uwe VIRTIO_COMMON_FLAG_BITS \ 58 1.13 uwe "b\x01" "STATS_VQ\0" \ 59 1.13 uwe "b\x00" "MUST_TELL_HOST\0" 60 1.5 christos 61 1.1 hannken #define PGS_PER_REQ (256) /* 1MB, 4KB/page */ 62 1.12 reinoud #define VQ_INFLATE 0 63 1.12 reinoud #define VQ_DEFLATE 1 64 1.12 reinoud 65 1.1 hannken 66 1.1 hannken CTASSERT((PAGE_SIZE) == (VIRTIO_PAGE_SIZE)); /* XXX */ 67 1.1 hannken 68 1.1 hannken struct balloon_req { 69 1.1 hannken bus_dmamap_t bl_dmamap; 70 1.1 hannken struct pglist bl_pglist; 71 1.1 hannken int bl_nentries; 72 1.1 hannken uint32_t bl_pages[PGS_PER_REQ]; 73 1.1 hannken }; 74 1.1 hannken 75 1.1 hannken struct viomb_softc { 76 1.1 hannken device_t sc_dev; 77 1.1 hannken 78 1.1 hannken struct virtio_softc *sc_virtio; 79 1.1 hannken struct virtqueue sc_vq[2]; 80 1.1 hannken 81 1.1 hannken unsigned int sc_npages; 82 1.1 hannken unsigned int sc_actual; 83 1.1 hannken int sc_inflight; 84 1.1 hannken struct balloon_req sc_req; 85 1.1 hannken struct pglist sc_balloon_pages; 86 1.1 hannken 87 1.1 hannken int sc_inflate_done; 88 1.1 hannken int sc_deflate_done; 89 1.1 hannken 90 1.1 hannken kcondvar_t sc_wait; 91 1.1 hannken kmutex_t sc_waitlock; 92 1.1 hannken }; 93 1.1 hannken 94 1.1 hannken static int balloon_initialized = 0; /* multiple balloon is not allowed */ 95 1.1 hannken 96 1.1 hannken static int viomb_match(device_t, cfdata_t, void *); 97 1.1 hannken static void viomb_attach(device_t, device_t, void *); 98 1.1 hannken static void viomb_read_config(struct viomb_softc *); 99 1.1 hannken static int viomb_config_change(struct virtio_softc *); 100 1.1 hannken static int inflate(struct viomb_softc *); 101 1.1 hannken static int inflateq_done(struct virtqueue *); 102 1.1 hannken static int inflate_done(struct viomb_softc *); 103 1.1 hannken static int deflate(struct viomb_softc *); 104 1.1 hannken static int deflateq_done(struct virtqueue *); 105 1.1 hannken static int deflate_done(struct viomb_softc *); 106 1.1 hannken static void viomb_thread(void *); 107 1.1 hannken 108 1.1 hannken CFATTACH_DECL_NEW(viomb, sizeof(struct viomb_softc), 109 1.1 hannken viomb_match, viomb_attach, NULL, NULL); 110 1.1 hannken 111 1.1 hannken static int 112 1.1 hannken viomb_match(device_t parent, cfdata_t match, void *aux) 113 1.1 hannken { 114 1.8 jdolecek struct virtio_attach_args *va = aux; 115 1.1 hannken 116 1.12 reinoud if (va->sc_childdevid == VIRTIO_DEVICE_ID_BALLOON) 117 1.1 hannken return 1; 118 1.1 hannken 119 1.1 hannken return 0; 120 1.1 hannken } 121 1.1 hannken 122 1.1 hannken static void 123 1.1 hannken viomb_attach(device_t parent, device_t self, void *aux) 124 1.1 hannken { 125 1.1 hannken struct viomb_softc *sc = device_private(self); 126 1.1 hannken struct virtio_softc *vsc = device_private(parent); 127 1.1 hannken const struct sysctlnode *node; 128 1.12 reinoud uint64_t features; 129 1.1 hannken 130 1.8 jdolecek if (virtio_child(vsc) != NULL) { 131 1.1 hannken aprint_normal(": child already attached for %s; " 132 1.6 msaitoh "something wrong...\n", device_xname(parent)); 133 1.1 hannken return; 134 1.1 hannken } 135 1.8 jdolecek 136 1.1 hannken if (balloon_initialized++) { 137 1.1 hannken aprint_normal(": balloon already exists; something wrong...\n"); 138 1.12 reinoud return; 139 1.12 reinoud } 140 1.12 reinoud 141 1.12 reinoud /* fail on non-4K page size archs */ 142 1.12 reinoud if (VIRTIO_PAGE_SIZE != PAGE_SIZE){ 143 1.12 reinoud aprint_normal("non-4K page size arch found, needs %d, got %d\n", 144 1.12 reinoud VIRTIO_PAGE_SIZE, PAGE_SIZE); 145 1.12 reinoud return; 146 1.1 hannken } 147 1.1 hannken 148 1.1 hannken sc->sc_dev = self; 149 1.1 hannken sc->sc_virtio = vsc; 150 1.1 hannken 151 1.14 yamaguch virtio_child_attach_start(vsc, self, IPL_VM, 152 1.12 reinoud VIRTIO_BALLOON_F_MUST_TELL_HOST, VIRTIO_BALLOON_FLAG_BITS); 153 1.12 reinoud 154 1.12 reinoud features = virtio_features(vsc); 155 1.12 reinoud if (features == 0) 156 1.1 hannken goto err_none; 157 1.1 hannken 158 1.1 hannken viomb_read_config(sc); 159 1.1 hannken sc->sc_inflight = 0; 160 1.1 hannken TAILQ_INIT(&sc->sc_balloon_pages); 161 1.1 hannken 162 1.12 reinoud sc->sc_inflate_done = sc->sc_deflate_done = 0; 163 1.12 reinoud mutex_init(&sc->sc_waitlock, MUTEX_DEFAULT, IPL_VM); /* spin */ 164 1.12 reinoud cv_init(&sc->sc_wait, "balloon"); 165 1.12 reinoud 166 1.15 yamaguch virtio_init_vq_vqdone(vsc, &sc->sc_vq[VQ_INFLATE], VQ_INFLATE, 167 1.15 yamaguch inflateq_done); 168 1.15 yamaguch virtio_init_vq_vqdone(vsc, &sc->sc_vq[VQ_DEFLATE], VQ_DEFLATE, 169 1.15 yamaguch deflateq_done); 170 1.15 yamaguch 171 1.15 yamaguch if (virtio_alloc_vq(vsc, &sc->sc_vq[VQ_INFLATE], 172 1.12 reinoud sizeof(uint32_t)*PGS_PER_REQ, 1, 173 1.12 reinoud "inflate") != 0) 174 1.12 reinoud goto err_mutex; 175 1.15 yamaguch if (virtio_alloc_vq(vsc, &sc->sc_vq[VQ_DEFLATE], 176 1.12 reinoud sizeof(uint32_t)*PGS_PER_REQ, 1, 177 1.12 reinoud "deflate") != 0) 178 1.12 reinoud goto err_vq0; 179 1.12 reinoud 180 1.8 jdolecek if (bus_dmamap_create(virtio_dmat(vsc), sizeof(uint32_t)*PGS_PER_REQ, 181 1.1 hannken 1, sizeof(uint32_t)*PGS_PER_REQ, 0, 182 1.1 hannken BUS_DMA_NOWAIT, &sc->sc_req.bl_dmamap)) { 183 1.1 hannken aprint_error_dev(sc->sc_dev, "dmamap creation failed.\n"); 184 1.1 hannken goto err_vq; 185 1.1 hannken } 186 1.8 jdolecek if (bus_dmamap_load(virtio_dmat(vsc), sc->sc_req.bl_dmamap, 187 1.1 hannken &sc->sc_req.bl_pages[0], 188 1.1 hannken sizeof(uint32_t) * PGS_PER_REQ, 189 1.1 hannken NULL, BUS_DMA_NOWAIT)) { 190 1.1 hannken aprint_error_dev(sc->sc_dev, "dmamap load failed.\n"); 191 1.1 hannken goto err_dmamap; 192 1.1 hannken } 193 1.1 hannken 194 1.14 yamaguch if (virtio_child_attach_finish(vsc, sc->sc_vq, __arraycount(sc->sc_vq), 195 1.17 mlelstv viomb_config_change, VIRTIO_F_INTR_MPSAFE) != 0) 196 1.12 reinoud goto err_out; 197 1.8 jdolecek 198 1.1 hannken if (kthread_create(PRI_IDLE, KTHREAD_MPSAFE, NULL, 199 1.1 hannken viomb_thread, sc, NULL, "viomb")) { 200 1.1 hannken aprint_error_dev(sc->sc_dev, "cannot create kthread.\n"); 201 1.12 reinoud goto err_out; 202 1.1 hannken } 203 1.1 hannken 204 1.1 hannken sysctl_createv(NULL, 0, NULL, &node, 0, CTLTYPE_NODE, 205 1.1 hannken "viomb", SYSCTL_DESCR("VirtIO Balloon status"), 206 1.1 hannken NULL, 0, NULL, 0, 207 1.1 hannken CTL_HW, CTL_CREATE, CTL_EOL); 208 1.1 hannken sysctl_createv(NULL, 0, NULL, NULL, 0, CTLTYPE_INT, 209 1.1 hannken "npages", SYSCTL_DESCR("VirtIO Balloon npages value"), 210 1.1 hannken NULL, 0, &sc->sc_npages, 0, 211 1.1 hannken CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); 212 1.1 hannken sysctl_createv(NULL, 0, NULL, NULL, 0, CTLTYPE_INT, 213 1.1 hannken "actual", SYSCTL_DESCR("VirtIO Balloon actual value"), 214 1.1 hannken NULL, 0, &sc->sc_actual, 0, 215 1.1 hannken CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); 216 1.1 hannken return; 217 1.1 hannken 218 1.12 reinoud err_out: 219 1.12 reinoud err_dmamap: 220 1.12 reinoud bus_dmamap_destroy(virtio_dmat(vsc), sc->sc_req.bl_dmamap); 221 1.12 reinoud err_vq: 222 1.12 reinoud virtio_free_vq(vsc, &sc->sc_vq[VQ_DEFLATE]); 223 1.12 reinoud err_vq0: 224 1.12 reinoud virtio_free_vq(vsc, &sc->sc_vq[VQ_INFLATE]); 225 1.1 hannken err_mutex: 226 1.1 hannken cv_destroy(&sc->sc_wait); 227 1.1 hannken mutex_destroy(&sc->sc_waitlock); 228 1.1 hannken err_none: 229 1.8 jdolecek virtio_child_attach_failed(vsc); 230 1.1 hannken return; 231 1.1 hannken } 232 1.1 hannken 233 1.1 hannken static void 234 1.1 hannken viomb_read_config(struct viomb_softc *sc) 235 1.1 hannken { 236 1.12 reinoud /* these values are explicitly specified as little-endian */ 237 1.12 reinoud sc->sc_npages = virtio_read_device_config_le_4(sc->sc_virtio, 238 1.12 reinoud VIRTIO_BALLOON_CONFIG_NUM_PAGES); 239 1.1 hannken 240 1.12 reinoud sc->sc_actual = virtio_read_device_config_le_4(sc->sc_virtio, 241 1.12 reinoud VIRTIO_BALLOON_CONFIG_ACTUAL); 242 1.1 hannken } 243 1.1 hannken 244 1.1 hannken /* 245 1.1 hannken * Config change callback: wakeup the kthread. 246 1.1 hannken */ 247 1.1 hannken static int 248 1.1 hannken viomb_config_change(struct virtio_softc *vsc) 249 1.1 hannken { 250 1.8 jdolecek struct viomb_softc *sc = device_private(virtio_child(vsc)); 251 1.1 hannken unsigned int old; 252 1.1 hannken 253 1.1 hannken old = sc->sc_npages; 254 1.1 hannken viomb_read_config(sc); 255 1.1 hannken mutex_enter(&sc->sc_waitlock); 256 1.1 hannken cv_signal(&sc->sc_wait); 257 1.1 hannken mutex_exit(&sc->sc_waitlock); 258 1.1 hannken if (sc->sc_npages > old) 259 1.1 hannken printf("%s: inflating balloon from %u to %u.\n", 260 1.1 hannken device_xname(sc->sc_dev), old, sc->sc_npages); 261 1.1 hannken else if (sc->sc_npages < old) 262 1.1 hannken printf("%s: deflating balloon from %u to %u.\n", 263 1.1 hannken device_xname(sc->sc_dev), old, sc->sc_npages); 264 1.1 hannken 265 1.1 hannken return 1; 266 1.1 hannken } 267 1.1 hannken 268 1.1 hannken /* 269 1.1 hannken * Inflate: consume some amount of physical memory. 270 1.1 hannken */ 271 1.1 hannken static int 272 1.1 hannken inflate(struct viomb_softc *sc) 273 1.1 hannken { 274 1.1 hannken struct virtio_softc *vsc = sc->sc_virtio; 275 1.1 hannken int i, slot; 276 1.1 hannken uint64_t nvpages, nhpages; 277 1.1 hannken struct balloon_req *b; 278 1.1 hannken struct vm_page *p; 279 1.12 reinoud struct virtqueue *vq = &sc->sc_vq[VQ_INFLATE]; 280 1.1 hannken 281 1.1 hannken if (sc->sc_inflight) 282 1.1 hannken return 0; 283 1.1 hannken nvpages = sc->sc_npages - sc->sc_actual; 284 1.1 hannken if (nvpages > PGS_PER_REQ) 285 1.1 hannken nvpages = PGS_PER_REQ; 286 1.1 hannken nhpages = nvpages * VIRTIO_PAGE_SIZE / PAGE_SIZE; 287 1.1 hannken 288 1.1 hannken b = &sc->sc_req; 289 1.16 mlelstv if (uvm_pglistalloc(nhpages*PAGE_SIZE, 0, UINT32_MAX*(paddr_t)PAGE_SIZE, 290 1.16 mlelstv 0, 0, &b->bl_pglist, nhpages, 0)) { 291 1.1 hannken printf("%s: %" PRIu64 " pages of physical memory " 292 1.1 hannken "could not be allocated, retrying...\n", 293 1.1 hannken device_xname(sc->sc_dev), nhpages); 294 1.1 hannken return 1; /* sleep longer */ 295 1.1 hannken } 296 1.1 hannken 297 1.1 hannken b->bl_nentries = nvpages; 298 1.1 hannken i = 0; 299 1.1 hannken TAILQ_FOREACH(p, &b->bl_pglist, pageq.queue) { 300 1.12 reinoud b->bl_pages[i++] = 301 1.12 reinoud htole32(VM_PAGE_TO_PHYS(p) / VIRTIO_PAGE_SIZE); 302 1.1 hannken } 303 1.1 hannken KASSERT(i == nvpages); 304 1.1 hannken 305 1.1 hannken if (virtio_enqueue_prep(vsc, vq, &slot) != 0) { 306 1.1 hannken printf("%s: inflate enqueue failed.\n", 307 1.1 hannken device_xname(sc->sc_dev)); 308 1.1 hannken uvm_pglistfree(&b->bl_pglist); 309 1.1 hannken return 0; 310 1.1 hannken } 311 1.1 hannken if (virtio_enqueue_reserve(vsc, vq, slot, 1)) { 312 1.1 hannken printf("%s: inflate enqueue failed.\n", 313 1.1 hannken device_xname(sc->sc_dev)); 314 1.1 hannken uvm_pglistfree(&b->bl_pglist); 315 1.1 hannken return 0; 316 1.1 hannken } 317 1.8 jdolecek bus_dmamap_sync(virtio_dmat(vsc), b->bl_dmamap, 0, 318 1.6 msaitoh sizeof(uint32_t)*nvpages, BUS_DMASYNC_PREWRITE); 319 1.1 hannken virtio_enqueue(vsc, vq, slot, b->bl_dmamap, true); 320 1.1 hannken virtio_enqueue_commit(vsc, vq, slot, true); 321 1.1 hannken sc->sc_inflight += nvpages; 322 1.1 hannken 323 1.1 hannken return 0; 324 1.1 hannken } 325 1.1 hannken 326 1.1 hannken static int 327 1.1 hannken inflateq_done(struct virtqueue *vq) 328 1.1 hannken { 329 1.1 hannken struct virtio_softc *vsc = vq->vq_owner; 330 1.8 jdolecek struct viomb_softc *sc = device_private(virtio_child(vsc)); 331 1.1 hannken 332 1.1 hannken mutex_enter(&sc->sc_waitlock); 333 1.1 hannken sc->sc_inflate_done = 1; 334 1.1 hannken cv_signal(&sc->sc_wait); 335 1.1 hannken mutex_exit(&sc->sc_waitlock); 336 1.1 hannken 337 1.1 hannken return 1; 338 1.1 hannken } 339 1.1 hannken 340 1.1 hannken static int 341 1.1 hannken inflate_done(struct viomb_softc *sc) 342 1.1 hannken { 343 1.1 hannken struct virtio_softc *vsc = sc->sc_virtio; 344 1.12 reinoud struct virtqueue *vq = &sc->sc_vq[VQ_INFLATE]; 345 1.1 hannken struct balloon_req *b; 346 1.1 hannken int r, slot; 347 1.1 hannken uint64_t nvpages; 348 1.1 hannken struct vm_page *p; 349 1.1 hannken 350 1.1 hannken r = virtio_dequeue(vsc, vq, &slot, NULL); 351 1.1 hannken if (r != 0) { 352 1.1 hannken printf("%s: inflate dequeue failed, errno %d.\n", 353 1.1 hannken device_xname(sc->sc_dev), r); 354 1.1 hannken return 1; 355 1.1 hannken } 356 1.1 hannken virtio_dequeue_commit(vsc, vq, slot); 357 1.1 hannken 358 1.1 hannken b = &sc->sc_req; 359 1.1 hannken nvpages = b->bl_nentries; 360 1.8 jdolecek bus_dmamap_sync(virtio_dmat(vsc), b->bl_dmamap, 361 1.11 reinoud 0, 362 1.1 hannken sizeof(uint32_t)*nvpages, 363 1.1 hannken BUS_DMASYNC_POSTWRITE); 364 1.1 hannken while (!TAILQ_EMPTY(&b->bl_pglist)) { 365 1.1 hannken p = TAILQ_FIRST(&b->bl_pglist); 366 1.1 hannken TAILQ_REMOVE(&b->bl_pglist, p, pageq.queue); 367 1.1 hannken TAILQ_INSERT_TAIL(&sc->sc_balloon_pages, p, pageq.queue); 368 1.1 hannken } 369 1.1 hannken 370 1.1 hannken sc->sc_inflight -= nvpages; 371 1.12 reinoud virtio_write_device_config_le_4(vsc, 372 1.12 reinoud VIRTIO_BALLOON_CONFIG_ACTUAL, 373 1.12 reinoud sc->sc_actual + nvpages); 374 1.1 hannken viomb_read_config(sc); 375 1.1 hannken 376 1.1 hannken return 1; 377 1.1 hannken } 378 1.1 hannken 379 1.1 hannken /* 380 1.1 hannken * Deflate: free previously allocated memory. 381 1.1 hannken */ 382 1.1 hannken static int 383 1.1 hannken deflate(struct viomb_softc *sc) 384 1.1 hannken { 385 1.1 hannken struct virtio_softc *vsc = sc->sc_virtio; 386 1.1 hannken int i, slot; 387 1.1 hannken uint64_t nvpages, nhpages; 388 1.1 hannken struct balloon_req *b; 389 1.1 hannken struct vm_page *p; 390 1.12 reinoud struct virtqueue *vq = &sc->sc_vq[VQ_DEFLATE]; 391 1.1 hannken 392 1.1 hannken nvpages = (sc->sc_actual + sc->sc_inflight) - sc->sc_npages; 393 1.1 hannken if (nvpages > PGS_PER_REQ) 394 1.1 hannken nvpages = PGS_PER_REQ; 395 1.1 hannken nhpages = nvpages * VIRTIO_PAGE_SIZE / PAGE_SIZE; 396 1.1 hannken 397 1.1 hannken b = &sc->sc_req; 398 1.1 hannken 399 1.1 hannken b->bl_nentries = nvpages; 400 1.1 hannken TAILQ_INIT(&b->bl_pglist); 401 1.1 hannken for (i = 0; i < nhpages; i++) { 402 1.1 hannken p = TAILQ_FIRST(&sc->sc_balloon_pages); 403 1.4 ozaki if (p == NULL) 404 1.4 ozaki break; 405 1.1 hannken TAILQ_REMOVE(&sc->sc_balloon_pages, p, pageq.queue); 406 1.1 hannken TAILQ_INSERT_TAIL(&b->bl_pglist, p, pageq.queue); 407 1.12 reinoud b->bl_pages[i] = 408 1.12 reinoud htole32(VM_PAGE_TO_PHYS(p) / VIRTIO_PAGE_SIZE); 409 1.1 hannken } 410 1.1 hannken 411 1.1 hannken if (virtio_enqueue_prep(vsc, vq, &slot) != 0) { 412 1.1 hannken printf("%s: deflate enqueue failed.\n", 413 1.1 hannken device_xname(sc->sc_dev)); 414 1.1 hannken TAILQ_FOREACH_REVERSE(p, &b->bl_pglist, pglist, pageq.queue) { 415 1.1 hannken TAILQ_REMOVE(&b->bl_pglist, p, pageq.queue); 416 1.6 msaitoh TAILQ_INSERT_HEAD(&sc->sc_balloon_pages, p, 417 1.6 msaitoh pageq.queue); 418 1.1 hannken } 419 1.1 hannken return 0; 420 1.1 hannken } 421 1.1 hannken if (virtio_enqueue_reserve(vsc, vq, slot, 1) != 0) { 422 1.1 hannken printf("%s: deflate enqueue failed.\n", 423 1.1 hannken device_xname(sc->sc_dev)); 424 1.1 hannken TAILQ_FOREACH_REVERSE(p, &b->bl_pglist, pglist, pageq.queue) { 425 1.1 hannken TAILQ_REMOVE(&b->bl_pglist, p, pageq.queue); 426 1.6 msaitoh TAILQ_INSERT_HEAD(&sc->sc_balloon_pages, p, 427 1.6 msaitoh pageq.queue); 428 1.1 hannken } 429 1.1 hannken return 0; 430 1.1 hannken } 431 1.8 jdolecek bus_dmamap_sync(virtio_dmat(vsc), b->bl_dmamap, 0, 432 1.6 msaitoh sizeof(uint32_t)*nvpages, BUS_DMASYNC_PREWRITE); 433 1.1 hannken virtio_enqueue(vsc, vq, slot, b->bl_dmamap, true); 434 1.1 hannken virtio_enqueue_commit(vsc, vq, slot, true); 435 1.1 hannken sc->sc_inflight -= nvpages; 436 1.1 hannken 437 1.8 jdolecek if (!(virtio_features(vsc) & VIRTIO_BALLOON_F_MUST_TELL_HOST)) 438 1.1 hannken uvm_pglistfree(&b->bl_pglist); 439 1.1 hannken 440 1.1 hannken return 0; 441 1.1 hannken } 442 1.1 hannken 443 1.1 hannken static int 444 1.1 hannken deflateq_done(struct virtqueue *vq) 445 1.1 hannken { 446 1.1 hannken struct virtio_softc *vsc = vq->vq_owner; 447 1.8 jdolecek struct viomb_softc *sc = device_private(virtio_child(vsc)); 448 1.1 hannken 449 1.1 hannken mutex_enter(&sc->sc_waitlock); 450 1.1 hannken sc->sc_deflate_done = 1; 451 1.1 hannken cv_signal(&sc->sc_wait); 452 1.1 hannken mutex_exit(&sc->sc_waitlock); 453 1.1 hannken 454 1.1 hannken return 1; 455 1.1 hannken } 456 1.1 hannken 457 1.1 hannken static int 458 1.1 hannken deflate_done(struct viomb_softc *sc) 459 1.1 hannken { 460 1.1 hannken struct virtio_softc *vsc = sc->sc_virtio; 461 1.12 reinoud struct virtqueue *vq = &sc->sc_vq[VQ_DEFLATE]; 462 1.1 hannken struct balloon_req *b; 463 1.1 hannken int r, slot; 464 1.2 christos uint64_t nvpages; 465 1.1 hannken 466 1.1 hannken r = virtio_dequeue(vsc, vq, &slot, NULL); 467 1.1 hannken if (r != 0) { 468 1.1 hannken printf("%s: deflate dequeue failed, errno %d\n", 469 1.1 hannken device_xname(sc->sc_dev), r); 470 1.1 hannken return 1; 471 1.1 hannken } 472 1.1 hannken virtio_dequeue_commit(vsc, vq, slot); 473 1.1 hannken 474 1.1 hannken b = &sc->sc_req; 475 1.1 hannken nvpages = b->bl_nentries; 476 1.8 jdolecek bus_dmamap_sync(virtio_dmat(vsc), b->bl_dmamap, 477 1.11 reinoud 0, 478 1.1 hannken sizeof(uint32_t)*nvpages, 479 1.1 hannken BUS_DMASYNC_POSTWRITE); 480 1.1 hannken 481 1.8 jdolecek if (virtio_features(vsc) & VIRTIO_BALLOON_F_MUST_TELL_HOST) 482 1.1 hannken uvm_pglistfree(&b->bl_pglist); 483 1.1 hannken 484 1.1 hannken sc->sc_inflight += nvpages; 485 1.12 reinoud virtio_write_device_config_le_4(vsc, 486 1.12 reinoud VIRTIO_BALLOON_CONFIG_ACTUAL, 487 1.12 reinoud sc->sc_actual - nvpages); 488 1.1 hannken viomb_read_config(sc); 489 1.1 hannken 490 1.1 hannken return 1; 491 1.1 hannken } 492 1.1 hannken 493 1.1 hannken /* 494 1.1 hannken * Kthread: sleeps, eventually inflate and deflate. 495 1.1 hannken */ 496 1.1 hannken static void 497 1.1 hannken viomb_thread(void *arg) 498 1.1 hannken { 499 1.1 hannken struct viomb_softc *sc = arg; 500 1.1 hannken int sleeptime, r; 501 1.1 hannken 502 1.1 hannken for ( ; ; ) { 503 1.1 hannken sleeptime = 30000; 504 1.1 hannken if (sc->sc_npages > sc->sc_actual + sc->sc_inflight) { 505 1.1 hannken if (sc->sc_inflight == 0) { 506 1.1 hannken r = inflate(sc); 507 1.1 hannken if (r != 0) 508 1.1 hannken sleeptime = 10000; 509 1.1 hannken else 510 1.16 mlelstv sleeptime = 100; 511 1.1 hannken } else 512 1.16 mlelstv sleeptime = 20; 513 1.1 hannken } else if (sc->sc_npages < sc->sc_actual + sc->sc_inflight) { 514 1.1 hannken if (sc->sc_inflight == 0) 515 1.1 hannken r = deflate(sc); 516 1.1 hannken sleeptime = 100; 517 1.1 hannken } 518 1.1 hannken 519 1.1 hannken again: 520 1.1 hannken mutex_enter(&sc->sc_waitlock); 521 1.1 hannken if (sc->sc_inflate_done) { 522 1.1 hannken sc->sc_inflate_done = 0; 523 1.1 hannken mutex_exit(&sc->sc_waitlock); 524 1.1 hannken inflate_done(sc); 525 1.1 hannken goto again; 526 1.1 hannken } 527 1.1 hannken if (sc->sc_deflate_done) { 528 1.1 hannken sc->sc_deflate_done = 0; 529 1.1 hannken mutex_exit(&sc->sc_waitlock); 530 1.1 hannken deflate_done(sc); 531 1.1 hannken goto again; 532 1.1 hannken } 533 1.1 hannken cv_timedwait(&sc->sc_wait, &sc->sc_waitlock, 534 1.1 hannken mstohz(sleeptime)); 535 1.1 hannken mutex_exit(&sc->sc_waitlock); 536 1.1 hannken } 537 1.1 hannken } 538 1.7 pgoyette 539 1.7 pgoyette MODULE(MODULE_CLASS_DRIVER, viomb, "virtio"); 540 1.7 pgoyette 541 1.7 pgoyette #ifdef _MODULE 542 1.7 pgoyette #include "ioconf.c" 543 1.7 pgoyette #endif 544 1.7 pgoyette 545 1.7 pgoyette static int 546 1.7 pgoyette viomb_modcmd(modcmd_t cmd, void *opaque) 547 1.7 pgoyette { 548 1.7 pgoyette int error = 0; 549 1.7 pgoyette 550 1.7 pgoyette #ifdef _MODULE 551 1.7 pgoyette switch (cmd) { 552 1.7 pgoyette case MODULE_CMD_INIT: 553 1.7 pgoyette error = config_init_component(cfdriver_ioconf_viomb, 554 1.7 pgoyette cfattach_ioconf_viomb, cfdata_ioconf_viomb); 555 1.7 pgoyette break; 556 1.7 pgoyette case MODULE_CMD_FINI: 557 1.7 pgoyette error = config_fini_component(cfdriver_ioconf_viomb, 558 1.7 pgoyette cfattach_ioconf_viomb, cfdata_ioconf_viomb); 559 1.7 pgoyette break; 560 1.7 pgoyette default: 561 1.7 pgoyette error = ENOTTY; 562 1.7 pgoyette break; 563 1.7 pgoyette } 564 1.7 pgoyette #endif 565 1.7 pgoyette 566 1.7 pgoyette return error; 567 1.7 pgoyette } 568