Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Jun 2009 11:10:39 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        Andrew Gallatin <gallatin@cs.duke.edu>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r193275 - in head/sys: kern sys vm
Message-ID:  <200906021110.40347.jhb@freebsd.org>
In-Reply-To: <4A253627.4090505@cs.duke.edu>
References:  <200906012132.n51LWq2U092924@svn.freebsd.org> <4A253627.4090505@cs.duke.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tuesday 02 June 2009 10:24:39 am Andrew Gallatin wrote:
> John Baldwin wrote:
> > Author: jhb
> > Date: Mon Jun  1 21:32:52 2009
> > New Revision: 193275
> > URL: http://svn.freebsd.org/changeset/base/193275
> > 
> > Log:
> >   Add an extension to the character device interface that allows character
> >   device drivers to use arbitrary VM objects to satisfy individual mmap()
> >   requests.
> 
> Is there an example usage of this?  Was this one of the things that
> Nvidia asked for?

Yes, this is for Nvidia.  I have a bizarr-o test device 
in //depot/user/jhb/pat/modules/patdev/patdev.c.  It exports a single 
anonymous memory object for mappings that use an offset at page 0 and a 
OBJT_SG (new type of VM object) object that maps the local APIC for mappings 
that use an offset at page 1.

It's d_mmap_single() routine looks like this:

static int
pat_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
    vm_object_t *object, int nprot)
{
	struct patdev_softc *sc;
	int error;

	sc = dev->si_drv1;

	error = 0;
	sx_xlock(&sc->lock);
	switch (*offset) {
	case 0:
		/*
		 * The first mmap() attempt with an offset of 0 creates
		 * a new memory object with the requested size.  Subsequent
		 * mmap()'s map the same object.
		 */
		if (sc->mem == NULL) {
			/*
			 * Note that this does not wire any backing
			 * pages.  I could do that later before a DMA
			 * was started by wiring pages (even just
			 * using the userland mapping to do that)
			 * while the DMA was in-progress and unwiring
			 * them later.
			 */
			sc->mem = vm_pager_allocate(OBJT_DEFAULT, NULL, size,
			    VM_PROT_DEFAULT, 0);
			VM_OBJECT_LOCK(sc->mem);
			vm_object_clear_flag(sc->mem, OBJ_ONEMAPPING);
			vm_object_set_flag(sc->mem, OBJ_NOSPLIT);
			vm_object_set_cache_mode(sc->mem,
			    VM_CACHE_WRITE_COMBINING);
			VM_OBJECT_UNLOCK(sc->mem);
		}

		vm_object_reference(sc->mem);
		*object = sc->mem;
		break;
	case PAGE_SIZE:
		/* Map the local APIC. */
		vm_object_reference(sc->sgobj);
		*object = sc->sgobj;
		*offset = 0;
		break;
	default:
		/* Use ENODEV to fallback to d_mmap(). */
		error = EINVAL;
		break;
	}
	sx_xunlock(&sc->lock);
	return (error);
}

The 'sgobj' object is created when the module is loaded:

static int
pat_attach(struct patdev_softc *sc)
{
	vm_offset_t va;
	int rv;

	bzero(sc, sizeof(*sc));
	sx_init(&sc->lock, "patdev");
	sc->cdev = make_dev(&pat_devsw, 0, UID_ROOT, GID_WHEEL, 0640, "pat");
	sc->cdev->si_drv1 = sc;

	/* Create a scatter/gather list that maps the local APIC. */
	sc->sg = sglist_alloc(1, M_WAITOK);
	sglist_append_phys(sc->sg, lapic_paddr, LAPIC_LEN);

	/* Create a VM object that is backed by the scatter/gather list. */
	sc->sgobj = vm_pager_allocate(OBJT_SG, sc->sg, LAPIC_LEN, VM_PROT_READ,
	    0);
	VM_OBJECT_LOCK(sc->sgobj);
	vm_object_set_cache_mode(sc->sgobj, VM_CACHE_UNCACHEABLE);
	VM_OBJECT_UNLOCK(sc->sgobj);
	...
}

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906021110.40347.jhb>