svn commit: r193275 - in head/sys: kern sys vm

John Baldwin jhb at freebsd.org
Tue Jun 2 15:11:49 UTC 2009


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


More information about the svn-src-head mailing list