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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to