Subject: Re: bus_dmamem question
To: None <tech-kern@netbsd.org>
From: Hans Petter Selasky <hselasky@c2i.net>
List: tech-kern
Date: 02/26/2006 21:58:21
Hi,
I managed to get it working, after some hard debugging.
On Sunday 19 February 2006 19:32, Hans Petter Selasky wrote:
> 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;
> }
Should be:
u_int32_t
usb_vtophys(void *ptr, u_int32_t size)
{
struct usb_dma *arg = (void *)(((u_int8_t *)ptr) + size);
#if 1
return arg->map->dm_segs[0].ds_addr;
#else
return arg->seg.ds_addr;
#endif
}
> 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;
> }
Should be:
void
usb_free_mem(void *ptr, u_int32_t size)
{
struct usb_dma *arg = (void *)(((u_int8_t *)ptr) + size);
struct usb_dma temp = *arg; /* make a copy ! */
bus_dmamap_unload(temp.tag, temp.map);
bus_dmamap_destroy(temp.tag, temp.map);
bus_dmamem_unmap(temp.tag, ptr, size);
bus_dmamem_free(temp.tag, &temp.seg, temp.seg_count);
return;
}
--HPS