device_pager.c revision 12662
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 191541Srgrimes * 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 3912662Sdg * $Id: device_pager.c,v 1.15 1995/12/03 18:59:55 bde Exp $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes#include <sys/param.h> 431541Srgrimes#include <sys/systm.h> 441541Srgrimes#include <sys/conf.h> 451541Srgrimes#include <sys/mman.h> 461541Srgrimes#include <sys/malloc.h> 473311Sphk#include <sys/proc.h> 4812662Sdg#include <sys/queue.h> 491541Srgrimes 501541Srgrimes#include <vm/vm.h> 5112662Sdg#include <vm/vm_param.h> 5212662Sdg#include <vm/vm_prot.h> 531541Srgrimes#include <vm/vm_kern.h> 5412662Sdg#include <vm/vm_object.h> 551541Srgrimes#include <vm/vm_page.h> 569507Sdg#include <vm/vm_pager.h> 571541Srgrimes#include <vm/device_pager.h> 581541Srgrimes 599507Sdgstruct pagerlst dev_pager_object_list; /* list of device pager objects */ 609507SdgTAILQ_HEAD(, vm_page) dev_pager_fakelist; /* list of available vm_page_t's */ 611541Srgrimes 625455Sdgstatic vm_page_t dev_pager_getfake __P((vm_offset_t)); 635455Sdgstatic void dev_pager_putfake __P((vm_page_t)); 641541Srgrimes 659507Sdgstatic int dev_pager_alloc_lock, dev_pager_alloc_lock_want; 669507Sdg 671541Srgrimesstruct pagerops devicepagerops = { 681541Srgrimes dev_pager_init, 691541Srgrimes dev_pager_alloc, 701541Srgrimes dev_pager_dealloc, 719507Sdg dev_pager_getpages, 729507Sdg dev_pager_putpages, 739507Sdg dev_pager_haspage, 749507Sdg NULL 751541Srgrimes}; 761541Srgrimes 779507Sdgvoid 781541Srgrimesdev_pager_init() 791541Srgrimes{ 809507Sdg TAILQ_INIT(&dev_pager_object_list); 811541Srgrimes TAILQ_INIT(&dev_pager_fakelist); 821541Srgrimes} 831541Srgrimes 849507Sdgvm_object_t 851541Srgrimesdev_pager_alloc(handle, size, prot, foff) 868416Sdg void *handle; 871541Srgrimes vm_size_t size; 881541Srgrimes vm_prot_t prot; 891541Srgrimes vm_offset_t foff; 901541Srgrimes{ 911541Srgrimes dev_t dev; 9212591Sbde d_mmap_t *mapfunc; 931541Srgrimes vm_object_t object; 941549Srgrimes unsigned int npages, off; 951541Srgrimes 961541Srgrimes /* 971541Srgrimes * Make sure this device can be mapped. 981541Srgrimes */ 995455Sdg dev = (dev_t) (u_long) handle; 1001541Srgrimes mapfunc = cdevsw[major(dev)].d_mmap; 10112610Sbde if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) { 10212610Sbde printf("obsolete map function %p\n", (void *)mapfunc); 1035455Sdg return (NULL); 10412610Sbde } 1051541Srgrimes 1061541Srgrimes /* 1071541Srgrimes * Offset should be page aligned. 1081541Srgrimes */ 1095455Sdg if (foff & (PAGE_SIZE - 1)) 1105455Sdg return (NULL); 1111541Srgrimes 1121541Srgrimes /* 1135455Sdg * Check that the specified range of the device allows the desired 1145455Sdg * protection. 1158876Srgrimes * 1161541Srgrimes * XXX assumes VM_PROT_* == PROT_* 1171541Srgrimes */ 1181541Srgrimes npages = atop(round_page(size)); 1191541Srgrimes for (off = foff; npages--; off += PAGE_SIZE) 1205455Sdg if ((*mapfunc) (dev, off, (int) prot) == -1) 1215455Sdg return (NULL); 1221541Srgrimes 1231541Srgrimes /* 1249507Sdg * Lock to prevent object creation race contion. 1259507Sdg */ 1269507Sdg while (dev_pager_alloc_lock) { 1279507Sdg dev_pager_alloc_lock_want++; 1289507Sdg tsleep(&dev_pager_alloc_lock, PVM, "dvpall", 0); 1299507Sdg dev_pager_alloc_lock_want--; 1309507Sdg } 1319507Sdg dev_pager_alloc_lock = 1; 1329507Sdg 1339507Sdg /* 1341541Srgrimes * Look up pager, creating as necessary. 1351541Srgrimes */ 1369507Sdg object = vm_pager_object_lookup(&dev_pager_object_list, handle); 1379507Sdg if (object == NULL) { 1381541Srgrimes /* 1391541Srgrimes * Allocate object and associate it with the pager. 1401541Srgrimes */ 1419507Sdg object = vm_object_allocate(OBJT_DEVICE, foff + size); 1429507Sdg object->handle = handle; 1439507Sdg TAILQ_INIT(&object->un_pager.devp.devp_pglist); 1449507Sdg TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list); 1451541Srgrimes } else { 1461541Srgrimes /* 1476585Sdg * Gain a reference to the object. 1481541Srgrimes */ 1499507Sdg vm_object_reference(object); 1508585Sdg if (foff + size > object->size) 1518585Sdg object->size = foff + size; 1521541Srgrimes } 1539507Sdg 1549507Sdg dev_pager_alloc_lock = 0; 1559507Sdg if (dev_pager_alloc_lock_want) 1569507Sdg wakeup(&dev_pager_alloc_lock); 1579507Sdg 1589507Sdg return (object); 1591541Srgrimes} 1601541Srgrimes 1619507Sdgvoid 1629507Sdgdev_pager_dealloc(object) 1639507Sdg vm_object_t object; 1641541Srgrimes{ 1651541Srgrimes vm_page_t m; 1661541Srgrimes 1679507Sdg TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list); 1681541Srgrimes /* 1691541Srgrimes * Free up our fake pages. 1701541Srgrimes */ 1719507Sdg while ((m = object->un_pager.devp.devp_pglist.tqh_first) != 0) { 1729507Sdg TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m, pageq); 1731541Srgrimes dev_pager_putfake(m); 1741541Srgrimes } 1751541Srgrimes} 1761541Srgrimes 1779507Sdgint 1789507Sdgdev_pager_getpages(object, m, count, reqpage) 1799507Sdg vm_object_t object; 1809507Sdg vm_page_t *m; 1819507Sdg int count; 1829507Sdg int reqpage; 1831541Srgrimes{ 1841541Srgrimes vm_offset_t offset, paddr; 1851541Srgrimes vm_page_t page; 1861541Srgrimes dev_t dev; 1879507Sdg int i, s; 18812591Sbde d_mmap_t *mapfunc; 18912591Sbde int prot; 1901541Srgrimes 1919507Sdg dev = (dev_t) (u_long) object->handle; 1929507Sdg offset = m[reqpage]->offset + object->paging_offset; 1931541Srgrimes prot = PROT_READ; /* XXX should pass in? */ 1941541Srgrimes mapfunc = cdevsw[major(dev)].d_mmap; 1951549Srgrimes 19612610Sbde if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) 1971541Srgrimes panic("dev_pager_getpage: no map function"); 1981549Srgrimes 1995455Sdg paddr = pmap_phys_address((*mapfunc) ((dev_t) dev, (int) offset, prot)); 2001541Srgrimes#ifdef DIAGNOSTIC 2011541Srgrimes if (paddr == -1) 2021541Srgrimes panic("dev_pager_getpage: map function returns error"); 2031541Srgrimes#endif 2041541Srgrimes /* 2059507Sdg * Replace the passed in reqpage page with our own fake page and free up the 2069507Sdg * all of the original pages. 2071541Srgrimes */ 2081541Srgrimes page = dev_pager_getfake(paddr); 2099507Sdg TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq); 2109507Sdg for (i = 0; i < count; i++) { 2119507Sdg PAGE_WAKEUP(m[i]); 2129507Sdg vm_page_free(m[i]); 2139507Sdg } 2141549Srgrimes s = splhigh(); 2151541Srgrimes vm_page_insert(page, object, offset); 2161549Srgrimes splx(s); 2171541Srgrimes 2185455Sdg return (VM_PAGER_OK); 2191541Srgrimes} 2201541Srgrimes 2219507Sdgint 2229507Sdgdev_pager_putpages(object, m, count, sync, rtvals) 2239507Sdg vm_object_t object; 2249507Sdg vm_page_t *m; 2259507Sdg int count; 2261541Srgrimes boolean_t sync; 2279507Sdg int *rtvals; 2281541Srgrimes{ 2291541Srgrimes panic("dev_pager_putpage called"); 2301541Srgrimes} 2311541Srgrimes 2329507Sdgboolean_t 2339507Sdgdev_pager_haspage(object, offset, before, after) 2349507Sdg vm_object_t object; 2351541Srgrimes vm_offset_t offset; 2369507Sdg int *before; 2379507Sdg int *after; 2381541Srgrimes{ 2399507Sdg if (before != NULL) 2409507Sdg *before = 0; 2419507Sdg if (after != NULL) 2429507Sdg *after = 0; 2435455Sdg return (TRUE); 2441541Srgrimes} 2451541Srgrimes 2461541Srgrimesstatic vm_page_t 2471541Srgrimesdev_pager_getfake(paddr) 2481541Srgrimes vm_offset_t paddr; 2491541Srgrimes{ 2501541Srgrimes vm_page_t m; 2511541Srgrimes int i; 2521541Srgrimes 2531541Srgrimes if (dev_pager_fakelist.tqh_first == NULL) { 2545455Sdg m = (vm_page_t) malloc(PAGE_SIZE * 2, M_VMPGDATA, M_WAITOK); 2555455Sdg for (i = (PAGE_SIZE * 2) / sizeof(*m); i > 0; i--) { 2561541Srgrimes TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq); 2571541Srgrimes m++; 2581541Srgrimes } 2591541Srgrimes } 2601541Srgrimes m = dev_pager_fakelist.tqh_first; 2611541Srgrimes TAILQ_REMOVE(&dev_pager_fakelist, m, pageq); 2621549Srgrimes 2635455Sdg m->flags = PG_BUSY | PG_FICTITIOUS; 2649507Sdg m->valid = VM_PAGE_BITS_ALL; 2655455Sdg m->dirty = 0; 2665455Sdg m->busy = 0; 2675455Sdg m->bmapped = 0; 2681549Srgrimes 2691549Srgrimes m->wire_count = 1; 2701541Srgrimes m->phys_addr = paddr; 2711549Srgrimes 2725455Sdg return (m); 2731541Srgrimes} 2741541Srgrimes 2751541Srgrimesstatic void 2761541Srgrimesdev_pager_putfake(m) 2771541Srgrimes vm_page_t m; 2781541Srgrimes{ 2791541Srgrimes if (!(m->flags & PG_FICTITIOUS)) 2801541Srgrimes panic("dev_pager_putfake: bad page"); 2811541Srgrimes TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq); 2821541Srgrimes} 283