Subject: Re: Bus Dma Question
To: Riaz <riazr@cat.co.za>
From: Wayne Knowles <wdk@NetBSD.ORG>
List: tech-kern
Date: 08/25/2000 13:31:26
Hi Riaz,

Recently I needed to do something similar and did a bit of looking at
other device deriver implementations to help me understand bus_dma(9)

You didn't explicitly say what the problem was - I assume what the device
DMA isn't appearing in kernel memory.

On Thu, 24 Aug 2000, Riaz wrote:

> Just before we capture an image we set the first 4 bytes
> to a magic number and check those bytes when an interrupt
> is generated after a capture. If they are the same, we assume
> that the capture failed (may happen after a few minutes).
> I don't know whether the data is cached somewhere.
> 
> (I know that I am transferring a ridiculous amount of data on the PCI bus)
> 
> I tried "bus_dmamap_sync" but isn't that a "nop" on i386?

You should get into the habit of performing a bus_dmamap_sync even if it 
it is a nop operation.  The PCI bus is used on other architectures which
may require special cache ops to guarantee consistency.

> Also what is the need for creating a dmamap anyway?

You need this as the first step to getting a physical address.  AFAIK it
also sets up memory management, MTRR's etc.

> Are the results I obtain to be expected or is there something I could do?

I would strongly suggest you check the return codes when calling bus_dma*

If you read the bus_dmamem_alloc(9) manual you will see you have to load
the map as well using dus_dmamap_load to get the physical memory address.

Take a look at sys/arch/mipsco/obio/if_le.c and
sys/arch/sparc/dev/if_le_obio.c for examples.

> 
> ----------------------------------------------------------------------
> static void
> fg_attach_pci(parent, self, aux)
>      struct device  *parent, *self;
>      void *aux;
> {
>   struct fg_softc        *sc         = (void *) self;
>   struct pci_attach_args *pap        = aux;
>   bus_space_tag_t        memt;
>   bus_space_handle_t     memh;
>   bus_size_t             memsize;
>   bus_dma_segment_t      segs;
>   int rsegs;
>   caddr_t kva;
>  ...
> 
>  pci_mapreg_map(pap, 0x10, PCI_MAPREG_TYPE_MEM, 0,&memt, &memh, NULL,
> &memsize);
>  bus_dmamem_alloc(pap->pa_dmat, TOTAL_DMA, 0,
> 0,&segs,1,&rsegs,BUS_DMA_NOWAIT);
>  bus_dmamem_map(pap->pa_dmat,&segs,rsegs,TOTAL_DMA,&kva,BUS_DMA_NOWAIT);
>  ...
>  sc->VideoPhysMem = segs.ds_addr;
>  sc->VideoMapMem  = kva;
>  ...
> }
> 
> then just before capture:
> ...
> *(int*)(sc->VideoMapMem) = 0xfacecafe;
> ...
> 
> and the card transfers the image into sc->VideoPhysMem
> 
> then interrupt handler (after capture):
> 
> int
> fg_intr(arg)
>      void *arg;
> {...
>   if ( *(int*)(sc->VideoMapMem) == 0xfacecafe)
>   {
>     RawFail = 1;
>   }
>  ...
> }

Regards,
Wayne