Re: DMA mapping

From: Jakub Jelinek (jakub@redhat.com)
Date: Tue Mar 07 2000 - 04:11:00 EST


On Tue, Mar 07, 2000 at 08:41:53AM +0000, Giuliano Procida wrote:
> Could someone point me at the discussion that lead to current API?

The discussion was held mostly privately among Linux port maintainers, but
parts of it went to lkml, just do a search.

> In
> particular, I'm curious as to why there isn't a
>
> void * pci_map_invert (pci_dev * device, dma_addr_t bus_addr)

It can be fairly slow, its the same as why there is no virt_to_phys for
vmalloced area (both may require looking up some page tables, in
pci_map_invert IO page tables particularly on some machines).
What's so hard in remembering the dma_addr_t the API gives you?
It is not hard to store the consistent mapping dma addresses into device
private structures and for the streaming mappings you can store them e.g.
into the SCp members of Scsi_Cmnd structure etc. It will be definitely
faster.

>
> and why ia64 has a 64-bit dma_addr_t.

We have still not decided on PCI64 DMA support. Following is one proposal,
the other one is just using 64bit dma_addr_t on platforms for which DAC is
useful (sparc64, alpha, mips64, ia64), but still leaving dma_mask default to
0xffffffff. Drivers which support DAC would just set it to ~0ULL.
That one would require some inspection of already converted drivers to make
sure nothing depends on the size of dma_addr_t (e.g. that nobody stores it
into fixed size structure etc.), pci64_* interface would not need that, on
the other side it would be harder to have drivers which will dynamically
choose PCI64 and PCI32:

I don't know whether there might be cards which support more than 32bits but
less than 64bits of the address during a DAC, but I strongly doubt about it,
so we can as well just not look at dma_mask at all and drivers don't have to
check pci_dma_supported() (because otherwise, unless we chose some magic
value (#define PCI_DMA_64BIT (dma_addr_t)0), all drivers would have to cope
with a 64bit dma64_addr_t (either via inlines in asm/pci.h or
pci-dma.c/pci-iommu.c)).
So, IMHO we can simply come with this interface:

#if PLATFORM_USES_64BIT_DMA_ADDRESSES
typedef u64 dma64_addr_t;
extern void *pci64_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr64_t *dma_handle);
extern void pci64_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr64_t dma_handle);
extern dma_addr64_t pci64_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
extern void pci64_unmap_single(struct pci_dev *hwdev, dma_addr64_t dma_addr, size_t size, int direction);
extern int pci64_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
extern void pci64_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction);
extern void pci64_dma_sync_single(struct pci_dev *hwdev, dma_addr64_t dma_handle, size_t size, int direction);
extern void pci64_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
#define pci64_dma_hi32(a) ((a) >> 32)
#define pci64_dma_lo32(a) ((a) & 0xffffffff)
#define pci64_dma_build(hi,lo) ((((dma64_addr_t)(hi)) << 32) | (lo))
#define sg_dma64_address(s) XXXXXXXXX
#define sg_dma64_len(s) YYYYYYYYY
#define PCI64_DMA_BITS 64
#else
typedef u32 dma64_addr_t;
#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p))
#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a))
#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir))
#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir))
#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir))
#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir))
#define pci64_dma_hi32(a) 0
#define pci64_dma_lo32(a) (a)
#define pci64_dma_build(hi,lo) (lo)
#define sg_dma64_address(s) sg_dma_address(s)
#define sg_dma64_len(s) sg_dma_len(s)
#define PCI64_DMA_BITS 32
#endif

Particularly on sparc64:

typedef u64 dma64_addr_t;
extern inline dma64_addr_t __virt_to_bus64(unsigned long addr) { return 0xFFFC000000000000UL | (addr & ~PAGE_OFFSET); }
#define virt_to_bus64(addr) __virt_to_bus64((unsigned long)(addr))
extern void *pci64_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr64_t *dma_handle);
extern void pci64_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr64_t dma_handle);
extern inline dma_addr64_t pci64_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) {
        if (direction == PCI_DMA_NONE)
                BUG();
        return virt_to_bus64(ptr);
}
extern void pci64_unmap_single(struct pci_dev *hwdev, dma_addr64_t dma_addr, size_t size, int direction) {
        if (direction == PCI_DMA_NONE)
                BUG();
        /* Nothing to do */
}
extern int pci64_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) {
        if (direction == PCI_DMA_NONE)
                BUG();
        /* Nothing to do */
}
extern void pci64_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) {
        if (direction == PCI_DMA_NONE)
                BUG();
        /* Nothing to do */
}
extern void pci64_dma_sync_single(struct pci_dev *hwdev, dma_addr64_t dma_handle, size_t size, int direction) {
        if (direction == PCI_DMA_NONE)
                BUG();
        /* Nothing to do */
}
extern void pci64_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) {
        if (direction == PCI_DMA_NONE)
                BUG();
        /* Nothing to do */
}
#define pci64_dma_hi32(a) ((a) >> 32)
#define pci64_dma_lo32(a) ((a) & 0xffffffff)
#define pci64_dma_build(hi,lo) ((((dma64_addr_t)(hi)) << 32) | (lo))
#define sg_dma64_address(s) virt_to_bus64((s)->address)
#define sg_dma64_len(s) ((s)->length)
#define PCI64_DMA_BITS 64

Cheers,
    Jakub
___________________________________________________________________
Jakub Jelinek | jakub@redhat.com | http://sunsite.mff.cuni.cz/~jj
Linux version 2.3.47 on a sparc64 machine (1343.49 BogoMips)
___________________________________________________________________

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Mar 07 2000 - 21:00:22 EST