Subject: bus_dmamem question
To: None <tech-kern@netbsd.org>
From: Hans Petter Selasky <hselasky@c2i.net>
List: tech-kern
Date: 02/19/2006 19:32:38
Hi,

Can someone here help get the following BUS-DMA code right? Currently 
"usb_alloc_mem()" works, but "usb_free_mem()" will cause a "uvm_fault()":

uvm_fault(0xc07b08a0, 0xcb6bd000, 0, 1) -> 0xe
kernel: page fault trap, code=0
Stopped in pid 1257.1 (modload) at      0xcbbf146c:     movl    0(%ebx),%eax


struct usb_dma {
    bus_dma_tag_t     tag;
    bus_dmamap_t      map;
    bus_dma_segment_t seg;
    int               seg_count;
} __packed;

void *
usb_alloc_mem(bus_dma_tag_t dma_tag, u_int32_t size, u_int8_t align_power)
{
    caddr_t ptr = NULL;
    struct usb_dma temp;

    bzero(&temp, sizeof(temp));

    temp.tag = dma_tag;
    temp.seg_count = 1;

    size += sizeof(struct usb_dma);

    if(bus_dmamem_alloc(temp.tag, size, (1 << align_power), 0,
                        &temp.seg, 1,
                        &temp.seg_count, BUS_DMA_NOWAIT))
    {
        goto done_4;
    }

    if(bus_dmamem_map(temp.tag, &temp.seg, temp.seg_count, size,
                      &ptr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT))
    {
        goto done_3;
    }

    if(bus_dmamap_create(temp.tag, size, 1, size,
                         0, BUS_DMA_NOWAIT, &temp.map))
    {
        goto done_2;
    }

    if(bus_dmamap_load(temp.tag, temp.map, ptr, size, NULL, 
                       BUS_DMA_NOWAIT))
    {
        goto done_1;
    }

    size -= sizeof(temp);

    bcopy(&temp, ((u_int8_t *)ptr) + size, sizeof(temp));
 
    return ptr;

 done_1:
    bus_dmamap_destroy(temp.tag, temp.map);

 done_2:
    bus_dmamem_unmap(temp.tag, ptr, size);

 done_3:
    bus_dmamem_free(temp.tag, &temp.seg, temp.seg_count);

 done_4:
    return NULL;
}

u_int32_t
usb_vtophys(void *ptr, u_int32_t size)
{
    struct usb_dma *arg = (void *)(((u_int8_t *)ptr) + size);
    return arg->seg.ds_addr;
}

void
usb_free_mem(void *ptr, u_int32_t size)
{
    struct usb_dma *arg = (void *)(((u_int8_t *)ptr) + size);

    bus_dmamap_unload(arg->tag, arg->map);
    bus_dmamap_destroy(arg->tag, arg->map);
    bus_dmamem_unmap(arg->tag, ptr, size);
    bus_dmamem_free(arg->tag, &arg->seg, arg->seg_count);

    return;
}

--HPS