Re: How to DMA on PCI devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi !

> as a person who have written ZERO PCI drivers, let me make a
> guess
> (apologized if wrong)

Actually yes ! You are not wrong (not yet).

> On Thu, Mar 5, 2009 at 1:59 AM, Fernand LONE SANG
> <flone_sa@xxxxxxxxx> wrote:
> >
> > Hello everybody !
> >
> > I have 2 question about how DMA work, especially for
> PCI devices.
> >
> > The first one concerns the device. How can i know if a
> device is DMA-able ? I found a function in the kernel source
> code called 'dma_set_mask'.  I want to know which
> registers of the device this function sets, and how it sets
> it : via Port I/O or MMIO, and where i can find the address
> where it is written ? I browsed the code, but i did not
> managed to see from which register inside a pci device are
> involved.
> 
> as far as i can see, it only set a field value in a
> structure, no
> hardware involved.
> 
> int dma_set_mask(struct device *dev, u64 mask)
> {
>         if (!dev->dma_mask || !dma_supported(dev, mask))
>                 return -EIO;
> 
>         *dev->dma_mask = mask;
> 
>         return 0;
> }
> 
> and from all the possible examples:
> 
> ./drivers/media/video/meye.c:
> 	if (dma_set_mask(&meye.mchip_dev->dev,
> DMA_32BIT_MASK))
> 
> ./drivers/net/b44.c:
> 	err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK);
> 
> ./drivers/net/wireless/b43/dma.c:
> static int b43_dma_set_mask(struct b43_wldev *dev, u64
> mask)
> 		err = ssb_dma_set_mask(dev->dev, mask);
> 	err = b43_dma_set_mask(dev, dmamask);
> 
> ./drivers/net/wireless/b43legacy/dma.c:
> static int b43legacy_dma_set_mask(struct b43legacy_wldev
> *dev, u64 mask)
> 		err = ssb_dma_set_mask(dev->dev, mask);
> 	err = b43legacy_dma_set_mask(dev, dmamask);
> 
> ./drivers/net/wireless/rt2x00/rt2x00pci.c:
> 	if (dma_set_mask(&pci_dev->dev, DMA_32BIT_MASK)) {
> 
> ./drivers/scsi/aic7xxx/aic79xx_osm_pci.c:
> 		    dma_set_mask(dev, DMA_64BIT_MASK) == 0)
> 			 dma_set_mask(dev, DMA_39BIT_MASK) == 0)
> 			dma_set_mask(dev, DMA_32BIT_MASK);
> 		dma_set_mask(dev, DMA_32BIT_MASK);
> 
> ./drivers/scsi/aic7xxx/aic7xxx_osm_pci.c:
> 	    && dma_set_mask(dev, mask_39bit) == 0
> 		if (dma_set_mask(dev, DMA_32BIT_MASK)) {
> 
> ./drivers/scsi/lasi700.c:
> 	dma_set_mask(&dev->dev, DMA_32BIT_MASK);
> 
> ./drivers/scsi/qla2xxx/qla_os.c:
> 	if (!dma_set_mask(&ha->pdev->dev,
> DMA_64BIT_MASK)) {
> 	dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK);
> 
> ./drivers/scsi/sni_53c710.c:
> 	dma_set_mask(&dev->dev, DMA_32BIT_MASK);
> 
> ./drivers/ssb/main.c:
> int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
> 		return dma_set_mask(dev->dev, mask);
> 
> it only have a two value involved.   so again, i don't
> think it is
> hardware specific.

Ok ! You confirm what i was thinking. BTW, it is the first time i go through kernel code source. :)

> >
> > The second question concern the DMA principles
> (precisely DMA Bus Mastering). For the question, let's
> make the supposition that we want to make a transfert from a
> device to RAM. How do i specify the memory address of the
> device from where i need to copy data of a specified length
> to the DMA buffer? How do i know where the data to be
> transfered begin ? In most of the documents describing a
> driver with DMA, they never specify that point.
> >
> 
> copying data to DMA buffer?   after u have done pci_iomap()
> u can just
> memcpy() or memset() to it directly, and followed by
> pci_iounmap().
> these and many other PCI specific API are well covered in
> Documentation/PCI/pci.txt:   How to write Linux PCI
> drivers.
> 
> > If someone can light me on those two points, that
> would help me a lot in my work.
> >
> > Fernand.
> >
> >
> 
> And deeper than that - PCI protocol specific, is really
> beyond driver
> level, u can ignore that.   And after understanding the
> hardware
> independent Linux PCI layer (pci.txt), take one simple
> example (eg,
> drivers/video/vt8623fb.c) and delved into all the hardware
> specific
> portion, and see how these information can be extracted
> from the
> relevant datasheet.
> 
> For example (blanking and syncing in vt8623fb.c etc):
> 
> static int vt8623fb_blank(int blank_mode, struct fb_info
> *info)
> {
>         switch (blank_mode) {
>         case FB_BLANK_UNBLANK:
>                 pr_debug("fb%d: unblank\n",
> info->node);
>                 svga_wcrt_mask(0x36, 0x00, 0x30);
>                 svga_wseq_mask(0x01, 0x00, 0x20);
>                 break;
>         case FB_BLANK_NORMAL:
>                 pr_debug("fb%d: blank\n",
> info->node);
>                 svga_wcrt_mask(0x36, 0x00, 0x30);
>                 svga_wseq_mask(0x01, 0x20, 0x20);
>                 break;
>         case FB_BLANK_HSYNC_SUSPEND:
>                 pr_debug("fb%d: DPMS standby (hsync
> off)\n", info->node);
>                 svga_wcrt_mask(0x36, 0x10, 0x30);
>                 svga_wseq_mask(0x01, 0x20, 0x20);
>                 break;
>         case FB_BLANK_VSYNC_SUSPEND:
>                 pr_debug("fb%d: DPMS suspend (vsync
> off)\n", info->node);
>                 svga_wcrt_mask(0x36, 0x20, 0x30);
>                 svga_wseq_mask(0x01, 0x20, 0x20);
>                 break;
> 
> These are setting the DMA memory to implement some hardware
> feature for eg.
> 

Thank you for the tips & answers. I will check the hardware datasheet for the hardware specific details.

> -- 
> Regards,
> Peter Teoh

Fernand LS


      

--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ



[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux