device_pager.c revision 98630
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
3950477Speter * $FreeBSD: head/sys/vm/device_pager.c 98630 2002-06-22 18:36:51Z alc $
401541Srgrimes */
411541Srgrimes
421541Srgrimes#include <sys/param.h>
431541Srgrimes#include <sys/systm.h>
441541Srgrimes#include <sys/conf.h>
4576166Smarkm#include <sys/lock.h>
4679224Sdillon#include <sys/proc.h>
4776166Smarkm#include <sys/mutex.h>
481541Srgrimes#include <sys/mman.h>
4975675Salfred#include <sys/sx.h>
501541Srgrimes
511541Srgrimes#include <vm/vm.h>
5212662Sdg#include <vm/vm_object.h>
531541Srgrimes#include <vm/vm_page.h>
549507Sdg#include <vm/vm_pager.h>
5592748Sjeff#include <vm/uma.h>
561541Srgrimes
5792727Salfredstatic void dev_pager_init(void);
5892727Salfredstatic vm_object_t dev_pager_alloc(void *, vm_ooffset_t, vm_prot_t,
5992727Salfred		vm_ooffset_t);
6092727Salfredstatic void dev_pager_dealloc(vm_object_t);
6192727Salfredstatic int dev_pager_getpages(vm_object_t, vm_page_t *, int, int);
6292727Salfredstatic void dev_pager_putpages(vm_object_t, vm_page_t *, int,
6392727Salfred		boolean_t, int *);
6492727Salfredstatic boolean_t dev_pager_haspage(vm_object_t, vm_pindex_t, int *,
6592727Salfred		int *);
661541Srgrimes
6712820Sphk/* list of device pager objects */
6812820Sphkstatic struct pagerlst dev_pager_object_list;
6975675Salfred/* protect against object creation */
7075675Salfredstatic struct sx dev_pager_sx;
7175675Salfred/* protect list manipulation */
7275675Salfredstatic struct mtx dev_pager_mtx;
7312820Sphk
7475675Salfred
7592748Sjeffstatic uma_zone_t fakepg_zone;
7612820Sphk
7792727Salfredstatic vm_page_t dev_pager_getfake(vm_offset_t);
7892727Salfredstatic void dev_pager_putfake(vm_page_t);
791541Srgrimes
801541Srgrimesstruct pagerops devicepagerops = {
811541Srgrimes	dev_pager_init,
821541Srgrimes	dev_pager_alloc,
831541Srgrimes	dev_pager_dealloc,
849507Sdg	dev_pager_getpages,
859507Sdg	dev_pager_putpages,
869507Sdg	dev_pager_haspage,
879507Sdg	NULL
881541Srgrimes};
891541Srgrimes
9012820Sphkstatic void
911541Srgrimesdev_pager_init()
921541Srgrimes{
939507Sdg	TAILQ_INIT(&dev_pager_object_list);
9475675Salfred	sx_init(&dev_pager_sx, "dev_pager create");
9593818Sjhb	mtx_init(&dev_pager_mtx, "dev_pager list", NULL, MTX_DEF);
9692748Sjeff	fakepg_zone = uma_zcreate("DP fakepg", sizeof(struct vm_page),
9792748Sjeff	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
981541Srgrimes}
991541Srgrimes
10098630Salc/*
10198630Salc * MPSAFE
10298630Salc */
10312820Sphkstatic vm_object_t
10440286Sdgdev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff)
1051541Srgrimes{
1061541Srgrimes	dev_t dev;
10712591Sbde	d_mmap_t *mapfunc;
1081541Srgrimes	vm_object_t object;
10941004Sdfr	unsigned int npages;
11041004Sdfr	vm_offset_t off;
1111541Srgrimes
1121541Srgrimes	/*
11398630Salc	 * Offset should be page aligned.
11498630Salc	 */
11598630Salc	if (foff & PAGE_MASK)
11698630Salc		return (NULL);
11798630Salc
11898630Salc	size = round_page(size);
11998630Salc
12098630Salc	/*
1211541Srgrimes	 * Make sure this device can be mapped.
1221541Srgrimes	 */
12347111Sbde	dev = handle;
12498630Salc	mtx_lock(&Giant);
12546676Sphk	mapfunc = devsw(dev)->d_mmap;
12612610Sbde	if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) {
12712610Sbde		printf("obsolete map function %p\n", (void *)mapfunc);
12898630Salc		mtx_unlock(&Giant);
1295455Sdg		return (NULL);
13012610Sbde	}
1311541Srgrimes
1321541Srgrimes	/*
1335455Sdg	 * Check that the specified range of the device allows the desired
1345455Sdg	 * protection.
1358876Srgrimes	 *
1361541Srgrimes	 * XXX assumes VM_PROT_* == PROT_*
1371541Srgrimes	 */
13840286Sdg	npages = OFF_TO_IDX(size);
1391541Srgrimes	for (off = foff; npages--; off += PAGE_SIZE)
14098630Salc		if ((*mapfunc)(dev, off, (int) prot) == -1) {
14198630Salc			mtx_unlock(&Giant);
1425455Sdg			return (NULL);
14398630Salc		}
1441541Srgrimes
1451541Srgrimes	/*
14658634Scharnier	 * Lock to prevent object creation race condition.
1479507Sdg	 */
14875675Salfred	sx_xlock(&dev_pager_sx);
1499507Sdg
1509507Sdg	/*
1511541Srgrimes	 * Look up pager, creating as necessary.
1521541Srgrimes	 */
1539507Sdg	object = vm_pager_object_lookup(&dev_pager_object_list, handle);
1549507Sdg	if (object == NULL) {
1551541Srgrimes		/*
1561541Srgrimes		 * Allocate object and associate it with the pager.
1571541Srgrimes		 */
15812767Sdyson		object = vm_object_allocate(OBJT_DEVICE,
15940286Sdg			OFF_TO_IDX(foff + size));
1609507Sdg		object->handle = handle;
1619507Sdg		TAILQ_INIT(&object->un_pager.devp.devp_pglist);
16275675Salfred		mtx_lock(&dev_pager_mtx);
1639507Sdg		TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list);
16475675Salfred		mtx_unlock(&dev_pager_mtx);
1651541Srgrimes	} else {
1661541Srgrimes		/*
1676585Sdg		 * Gain a reference to the object.
1681541Srgrimes		 */
1699507Sdg		vm_object_reference(object);
17040286Sdg		if (OFF_TO_IDX(foff + size) > object->size)
17140286Sdg			object->size = OFF_TO_IDX(foff + size);
1721541Srgrimes	}
1739507Sdg
17475675Salfred	sx_xunlock(&dev_pager_sx);
17598630Salc	mtx_unlock(&Giant);
1769507Sdg	return (object);
1771541Srgrimes}
1781541Srgrimes
17912820Sphkstatic void
1809507Sdgdev_pager_dealloc(object)
1819507Sdg	vm_object_t object;
1821541Srgrimes{
1831541Srgrimes	vm_page_t m;
1841541Srgrimes
18575675Salfred	mtx_lock(&dev_pager_mtx);
1869507Sdg	TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list);
18775675Salfred	mtx_unlock(&dev_pager_mtx);
1881541Srgrimes	/*
1891541Srgrimes	 * Free up our fake pages.
1901541Srgrimes	 */
19115809Sdyson	while ((m = TAILQ_FIRST(&object->un_pager.devp.devp_pglist)) != 0) {
1929507Sdg		TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m, pageq);
1931541Srgrimes		dev_pager_putfake(m);
1941541Srgrimes	}
1951541Srgrimes}
1961541Srgrimes
19712820Sphkstatic int
1989507Sdgdev_pager_getpages(object, m, count, reqpage)
1999507Sdg	vm_object_t object;
2009507Sdg	vm_page_t *m;
2019507Sdg	int count;
2029507Sdg	int reqpage;
2031541Srgrimes{
20412767Sdyson	vm_offset_t offset;
20512767Sdyson	vm_offset_t paddr;
2061541Srgrimes	vm_page_t page;
2071541Srgrimes	dev_t dev;
20877087Sjhb	int i;
20912591Sbde	d_mmap_t *mapfunc;
21012591Sbde	int prot;
2111541Srgrimes
21277087Sjhb	mtx_assert(&Giant, MA_OWNED);
21347111Sbde	dev = object->handle;
21442957Sdillon	offset = m[reqpage]->pindex;
2151541Srgrimes	prot = PROT_READ;	/* XXX should pass in? */
21646676Sphk	mapfunc = devsw(dev)->d_mmap;
2171549Srgrimes
21812610Sbde	if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop)
2191541Srgrimes		panic("dev_pager_getpage: no map function");
2201549Srgrimes
22147028Sphk	paddr = pmap_phys_address((*mapfunc) (dev, (vm_offset_t) offset << PAGE_SHIFT, prot));
22242408Seivind	KASSERT(paddr != -1,("dev_pager_getpage: map function returns error"));
2231541Srgrimes	/*
2249507Sdg	 * Replace the passed in reqpage page with our own fake page and free up the
2259507Sdg	 * all of the original pages.
2261541Srgrimes	 */
2271541Srgrimes	page = dev_pager_getfake(paddr);
2289507Sdg	TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq);
2299507Sdg	for (i = 0; i < count; i++) {
2309507Sdg		vm_page_free(m[i]);
2319507Sdg	}
2321541Srgrimes	vm_page_insert(page, object, offset);
2331541Srgrimes
2345455Sdg	return (VM_PAGER_OK);
2351541Srgrimes}
2361541Srgrimes
23743129Sdillonstatic void
2389507Sdgdev_pager_putpages(object, m, count, sync, rtvals)
2399507Sdg	vm_object_t object;
2409507Sdg	vm_page_t *m;
2419507Sdg	int count;
2421541Srgrimes	boolean_t sync;
2439507Sdg	int *rtvals;
2441541Srgrimes{
2451541Srgrimes	panic("dev_pager_putpage called");
2461541Srgrimes}
2471541Srgrimes
24812820Sphkstatic boolean_t
24912767Sdysondev_pager_haspage(object, pindex, before, after)
2509507Sdg	vm_object_t object;
25112767Sdyson	vm_pindex_t pindex;
2529507Sdg	int *before;
2539507Sdg	int *after;
2541541Srgrimes{
2559507Sdg	if (before != NULL)
2569507Sdg		*before = 0;
2579507Sdg	if (after != NULL)
2589507Sdg		*after = 0;
2595455Sdg	return (TRUE);
2601541Srgrimes}
2611541Srgrimes
2621541Srgrimesstatic vm_page_t
2631541Srgrimesdev_pager_getfake(paddr)
2641541Srgrimes	vm_offset_t paddr;
2651541Srgrimes{
2661541Srgrimes	vm_page_t m;
2671541Srgrimes
26892748Sjeff	m = uma_zalloc(fakepg_zone, M_WAITOK);
2691549Srgrimes
2705455Sdg	m->flags = PG_BUSY | PG_FICTITIOUS;
2719507Sdg	m->valid = VM_PAGE_BITS_ALL;
2725455Sdg	m->dirty = 0;
2735455Sdg	m->busy = 0;
27413490Sdyson	m->queue = PQ_NONE;
27540557Sdg	m->object = NULL;
2761549Srgrimes
2771549Srgrimes	m->wire_count = 1;
27814430Sdyson	m->hold_count = 0;
2791541Srgrimes	m->phys_addr = paddr;
2801549Srgrimes
2815455Sdg	return (m);
2821541Srgrimes}
2831541Srgrimes
2841541Srgrimesstatic void
2851541Srgrimesdev_pager_putfake(m)
2861541Srgrimes	vm_page_t m;
2871541Srgrimes{
2881541Srgrimes	if (!(m->flags & PG_FICTITIOUS))
2891541Srgrimes		panic("dev_pager_putfake: bad page");
29092748Sjeff	uma_zfree(fakepg_zone, m);
2911541Srgrimes}
292