device_pager.c revision 116226
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1990 University of Utah. 31541Srgrimes * Copyright (c) 1991, 1993 41541Srgrimes * The Regents of the University of California. All rights reserved. 51541Srgrimes * 61541Srgrimes * This code is derived from software contributed to Berkeley by 71541Srgrimes * the Systems Programming Group of the University of Utah Computer 81541Srgrimes * Science Department. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 3. All advertising materials mentioning features or use of this software 1958705Scharnier * must display the following acknowledgement: 201541Srgrimes * This product includes software developed by the University of 211541Srgrimes * California, Berkeley and its contributors. 221541Srgrimes * 4. Neither the name of the University nor the names of its contributors 231541Srgrimes * may be used to endorse or promote products derived from this software 241541Srgrimes * without specific prior written permission. 251541Srgrimes * 261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361541Srgrimes * SUCH DAMAGE. 371541Srgrimes * 381549Srgrimes * @(#)device_pager.c 8.1 (Berkeley) 6/11/93 391541Srgrimes */ 401541Srgrimes 41116226Sobrien#include <sys/cdefs.h> 42116226Sobrien__FBSDID("$FreeBSD: head/sys/vm/device_pager.c 116226 2003-06-11 23:50:51Z obrien $"); 43116226Sobrien 441541Srgrimes#include <sys/param.h> 451541Srgrimes#include <sys/systm.h> 461541Srgrimes#include <sys/conf.h> 4776166Smarkm#include <sys/lock.h> 4879224Sdillon#include <sys/proc.h> 4976166Smarkm#include <sys/mutex.h> 501541Srgrimes#include <sys/mman.h> 5175675Salfred#include <sys/sx.h> 521541Srgrimes 531541Srgrimes#include <vm/vm.h> 5412662Sdg#include <vm/vm_object.h> 551541Srgrimes#include <vm/vm_page.h> 569507Sdg#include <vm/vm_pager.h> 5792748Sjeff#include <vm/uma.h> 581541Srgrimes 5992727Salfredstatic void dev_pager_init(void); 6092727Salfredstatic vm_object_t dev_pager_alloc(void *, vm_ooffset_t, vm_prot_t, 6192727Salfred vm_ooffset_t); 6292727Salfredstatic void dev_pager_dealloc(vm_object_t); 6392727Salfredstatic int dev_pager_getpages(vm_object_t, vm_page_t *, int, int); 6492727Salfredstatic void dev_pager_putpages(vm_object_t, vm_page_t *, int, 6592727Salfred boolean_t, int *); 6692727Salfredstatic boolean_t dev_pager_haspage(vm_object_t, vm_pindex_t, int *, 6792727Salfred int *); 681541Srgrimes 6912820Sphk/* list of device pager objects */ 7012820Sphkstatic struct pagerlst dev_pager_object_list; 7175675Salfred/* protect against object creation */ 7275675Salfredstatic struct sx dev_pager_sx; 7375675Salfred/* protect list manipulation */ 7475675Salfredstatic struct mtx dev_pager_mtx; 7512820Sphk 7675675Salfred 7792748Sjeffstatic uma_zone_t fakepg_zone; 7812820Sphk 79112569Sjakestatic vm_page_t dev_pager_getfake(vm_paddr_t); 8092727Salfredstatic void dev_pager_putfake(vm_page_t); 811541Srgrimes 821541Srgrimesstruct pagerops devicepagerops = { 831541Srgrimes dev_pager_init, 841541Srgrimes dev_pager_alloc, 851541Srgrimes dev_pager_dealloc, 869507Sdg dev_pager_getpages, 879507Sdg dev_pager_putpages, 889507Sdg dev_pager_haspage, 899507Sdg NULL 901541Srgrimes}; 911541Srgrimes 9212820Sphkstatic void 931541Srgrimesdev_pager_init() 941541Srgrimes{ 959507Sdg TAILQ_INIT(&dev_pager_object_list); 9675675Salfred sx_init(&dev_pager_sx, "dev_pager create"); 9793818Sjhb mtx_init(&dev_pager_mtx, "dev_pager list", NULL, MTX_DEF); 9892748Sjeff fakepg_zone = uma_zcreate("DP fakepg", sizeof(struct vm_page), 9992748Sjeff NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); 1001541Srgrimes} 1011541Srgrimes 10298630Salc/* 10398630Salc * MPSAFE 10498630Salc */ 10512820Sphkstatic vm_object_t 10640286Sdgdev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff) 1071541Srgrimes{ 1081541Srgrimes dev_t dev; 10912591Sbde d_mmap_t *mapfunc; 1101541Srgrimes vm_object_t object; 11141004Sdfr unsigned int npages; 112112569Sjake vm_paddr_t paddr; 113112569Sjake vm_offset_t off; 1141541Srgrimes 1151541Srgrimes /* 11698630Salc * Offset should be page aligned. 11798630Salc */ 11898630Salc if (foff & PAGE_MASK) 11998630Salc return (NULL); 12098630Salc 12198630Salc size = round_page(size); 12298630Salc 12398630Salc /* 1241541Srgrimes * Make sure this device can be mapped. 1251541Srgrimes */ 12647111Sbde dev = handle; 12798630Salc mtx_lock(&Giant); 12846676Sphk mapfunc = devsw(dev)->d_mmap; 12912610Sbde if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) { 13012610Sbde printf("obsolete map function %p\n", (void *)mapfunc); 13198630Salc mtx_unlock(&Giant); 1325455Sdg return (NULL); 13312610Sbde } 1341541Srgrimes 1351541Srgrimes /* 1365455Sdg * Check that the specified range of the device allows the desired 1375455Sdg * protection. 1388876Srgrimes * 1391541Srgrimes * XXX assumes VM_PROT_* == PROT_* 1401541Srgrimes */ 14140286Sdg npages = OFF_TO_IDX(size); 1421541Srgrimes for (off = foff; npages--; off += PAGE_SIZE) 143111462Smux if ((*mapfunc)(dev, off, &paddr, (int)prot) != 0) { 14498630Salc mtx_unlock(&Giant); 1455455Sdg return (NULL); 14698630Salc } 1471541Srgrimes 1481541Srgrimes /* 14958634Scharnier * Lock to prevent object creation race condition. 1509507Sdg */ 15175675Salfred sx_xlock(&dev_pager_sx); 1529507Sdg 1539507Sdg /* 1541541Srgrimes * Look up pager, creating as necessary. 1551541Srgrimes */ 1569507Sdg object = vm_pager_object_lookup(&dev_pager_object_list, handle); 1579507Sdg if (object == NULL) { 1581541Srgrimes /* 1591541Srgrimes * Allocate object and associate it with the pager. 1601541Srgrimes */ 16112767Sdyson object = vm_object_allocate(OBJT_DEVICE, 16240286Sdg OFF_TO_IDX(foff + size)); 1639507Sdg object->handle = handle; 1649507Sdg TAILQ_INIT(&object->un_pager.devp.devp_pglist); 16575675Salfred mtx_lock(&dev_pager_mtx); 1669507Sdg TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list); 16775675Salfred mtx_unlock(&dev_pager_mtx); 1681541Srgrimes } else { 1691541Srgrimes /* 1706585Sdg * Gain a reference to the object. 1711541Srgrimes */ 1729507Sdg vm_object_reference(object); 17340286Sdg if (OFF_TO_IDX(foff + size) > object->size) 17440286Sdg object->size = OFF_TO_IDX(foff + size); 1751541Srgrimes } 1769507Sdg 17775675Salfred sx_xunlock(&dev_pager_sx); 17898630Salc mtx_unlock(&Giant); 1799507Sdg return (object); 1801541Srgrimes} 1811541Srgrimes 18212820Sphkstatic void 1839507Sdgdev_pager_dealloc(object) 1849507Sdg vm_object_t object; 1851541Srgrimes{ 1861541Srgrimes vm_page_t m; 1871541Srgrimes 18875675Salfred mtx_lock(&dev_pager_mtx); 1899507Sdg TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list); 19075675Salfred mtx_unlock(&dev_pager_mtx); 1911541Srgrimes /* 1921541Srgrimes * Free up our fake pages. 1931541Srgrimes */ 19415809Sdyson while ((m = TAILQ_FIRST(&object->un_pager.devp.devp_pglist)) != 0) { 1959507Sdg TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m, pageq); 1961541Srgrimes dev_pager_putfake(m); 1971541Srgrimes } 1981541Srgrimes} 1991541Srgrimes 20012820Sphkstatic int 2019507Sdgdev_pager_getpages(object, m, count, reqpage) 2029507Sdg vm_object_t object; 2039507Sdg vm_page_t *m; 2049507Sdg int count; 2059507Sdg int reqpage; 2061541Srgrimes{ 20798824Siedowse vm_pindex_t offset; 208112569Sjake vm_paddr_t paddr; 2091541Srgrimes vm_page_t page; 2101541Srgrimes dev_t dev; 211111462Smux int i, ret; 21212591Sbde d_mmap_t *mapfunc; 21312591Sbde int prot; 2141541Srgrimes 21577087Sjhb mtx_assert(&Giant, MA_OWNED); 21647111Sbde dev = object->handle; 21742957Sdillon offset = m[reqpage]->pindex; 2181541Srgrimes prot = PROT_READ; /* XXX should pass in? */ 21946676Sphk mapfunc = devsw(dev)->d_mmap; 2201549Srgrimes 22112610Sbde if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) 2221541Srgrimes panic("dev_pager_getpage: no map function"); 2231549Srgrimes 224111462Smux ret = (*mapfunc)(dev, (vm_offset_t)offset << PAGE_SHIFT, &paddr, prot); 225111462Smux KASSERT(ret == 0, ("dev_pager_getpage: map function returns error")); 2261541Srgrimes /* 227111462Smux * Replace the passed in reqpage page with our own fake page and 228111462Smux * free up the all of the original pages. 2291541Srgrimes */ 2301541Srgrimes page = dev_pager_getfake(paddr); 2319507Sdg TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq); 23299849Salc vm_page_lock_queues(); 23399849Salc for (i = 0; i < count; i++) 2349507Sdg vm_page_free(m[i]); 23599849Salc vm_page_unlock_queues(); 2361541Srgrimes vm_page_insert(page, object, offset); 2371541Srgrimes 2385455Sdg return (VM_PAGER_OK); 2391541Srgrimes} 2401541Srgrimes 24143129Sdillonstatic void 2429507Sdgdev_pager_putpages(object, m, count, sync, rtvals) 2439507Sdg vm_object_t object; 2449507Sdg vm_page_t *m; 2459507Sdg int count; 2461541Srgrimes boolean_t sync; 2479507Sdg int *rtvals; 2481541Srgrimes{ 2491541Srgrimes panic("dev_pager_putpage called"); 2501541Srgrimes} 2511541Srgrimes 25212820Sphkstatic boolean_t 25312767Sdysondev_pager_haspage(object, pindex, before, after) 2549507Sdg vm_object_t object; 25512767Sdyson vm_pindex_t pindex; 2569507Sdg int *before; 2579507Sdg int *after; 2581541Srgrimes{ 2599507Sdg if (before != NULL) 2609507Sdg *before = 0; 2619507Sdg if (after != NULL) 2629507Sdg *after = 0; 2635455Sdg return (TRUE); 2641541Srgrimes} 2651541Srgrimes 2661541Srgrimesstatic vm_page_t 2671541Srgrimesdev_pager_getfake(paddr) 268112569Sjake vm_paddr_t paddr; 2691541Srgrimes{ 2701541Srgrimes vm_page_t m; 2711541Srgrimes 272111119Simp m = uma_zalloc(fakepg_zone, M_WAITOK); 2731549Srgrimes 2745455Sdg m->flags = PG_BUSY | PG_FICTITIOUS; 2759507Sdg m->valid = VM_PAGE_BITS_ALL; 2765455Sdg m->dirty = 0; 2775455Sdg m->busy = 0; 27813490Sdyson m->queue = PQ_NONE; 27940557Sdg m->object = NULL; 2801549Srgrimes 2811549Srgrimes m->wire_count = 1; 28214430Sdyson m->hold_count = 0; 2831541Srgrimes m->phys_addr = paddr; 2841549Srgrimes 2855455Sdg return (m); 2861541Srgrimes} 2871541Srgrimes 2881541Srgrimesstatic void 2891541Srgrimesdev_pager_putfake(m) 2901541Srgrimes vm_page_t m; 2911541Srgrimes{ 2921541Srgrimes if (!(m->flags & PG_FICTITIOUS)) 2931541Srgrimes panic("dev_pager_putfake: bad page"); 29492748Sjeff uma_zfree(fakepg_zone, m); 2951541Srgrimes} 296