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