Skip to contentSkip to conversation

struct page to 36 (or 64) bit bus address?

DISCUSSION Johannes Erdfelt 8 participants 15 messages Aug 9, 2001 – Aug 12, 2001

lore
Share & tools
lore
#0 lore raw

I have a 64 bit PCI card which I'd like to do 64 bit DMA with. I have a struct page, but I don't see an easy way of determining what the bus address for that page is.

Is there a way to do it at all?

JE

#1 lore raw
Quoted 5 lines

I have a 64 bit PCI card which I'd like to do 64 bit DMA with. I have a struct page, but I don't see an easy way of determining what the bus address for that page is.

Is there a way to do it at all?

Yes but its not the right way to do it (bttv does it for example). You want to be using the pci or kiovec apis (Documentation/DMA-mapping.txt)

Thats important because it may well be an iommu that handles the mapping to make the stuff visible - not the cpu

#2 lore raw
In reply to Johannes Erdfelt
Quoted 11 lines · Alan Cox
Quoted 5 lines

I have a 64 bit PCI card which I'd like to do 64 bit DMA with. I have a struct page, but I don't see an easy way of determining what the bus address for that page is.

Is there a way to do it at all?

Yes but its not the right way to do it (bttv does it for example). You want to be using the pci or kiovec apis (Documentation/DMA-mapping.txt)

Thats important because it may well be an iommu that handles the mapping to make the stuff visible - not the cpu

Unfortunately the PCI DMA API on i386 will only return 32 bit addresses, which kinda defeats the purpose of what I'm doing.

Obviously the more portable way across architectures is using the PCI DMA API but when will the implementation be fixed so I can use it to exploit the full potential of this device?

I'll take a look at the BTTV for a short term solution.

JE

#3 lore raw
Quoted 2 lines

Unfortunately the PCI DMA API on i386 will only return 32 bit addresses, which kinda defeats the purpose of what I'm doing.

For the short term

Quoted 3 lines

Obviously the more portable way across architectures is using the PCI DMA API but when will the implementation be fixed so I can use it to exploit the full potential of this device?

2.5 I believe, ping the peacefrog and ask <[email protected]>

#4 lore raw
Quoted 5 lines · Alan Cox
Quoted 3 lines

Obviously the more portable way across architectures is using the PCI DMA API but when will the implementation be fixed so I can use it to exploit the full potential of this device?

2.5 I believe, ping the peacefrog and ask <[email protected]>

That's the current plan. There may be a 2.4.x backport, but no promises. It all depends upon how straightforward the changes are.

Note, if you use the "bttv method" (ie. virt_to_bus) your driver will then fail to compile on several platforms.

Later,
David S. Miller
[email protected]

#5 lore raw
Quoted 7 lines · David S. Miller

I'm using the patch below (pulled out of Jens Axboe's bio patches, i386 only).

Are you sure you aren't missing anything in this patch? For example, one can't use the patch you've provided for 64-bit DMA unless the dma_addr_t type is made larger.

The dma_addr_high_t was dumped along with pci_map_page_high etc, on your request in fact :-). So all that is there currently is highmem capable 32-bit DMA stuff.

Signature · 1 line
Jens Axboe
#6 lore raw
In reply to Johannes Erdfelt
Quoted 11 lines · David S. Miller
Quoted 5 lines · Alan Cox
Quoted 3 lines

Obviously the more portable way across architectures is using the PCI DMA API but when will the implementation be fixed so I can use it to exploit the full potential of this device?

2.5 I believe, ping the peacefrog and ask <[email protected]>

That's the current plan. There may be a 2.4.x backport, but no promises. It all depends upon how straightforward the changes are.

It's not a big deal. It's just less efficient which isn't the end of the world.

Quoted 2 lines

Note, if you use the "bttv method" (ie. virt_to_bus) your driver will then fail to compile on several platforms.

So noted. I already have a PCI DMA API version, but I wanted to code up a "i have an i386 and gigs of memory" version as well.

JE

#7 lore raw
In reply to Johannes Erdfelt
Quoted 5 lines
Quoted 2 lines

Note, if you use the "bttv method" (ie. virt_to_bus) your driver will then fail to compile on several platforms.

So noted. I already have a PCI DMA API version, but I wanted to code up a "i have an i386 and gigs of memory" version as well.

Forgot about virt_to_bus() then, it doesn't work for highmem.

bttv devel versions (0.8.x -> http://bytesex.org/bttv/) use the pci dma mapping interface. It can handle DMA highmem pages too, but that requires a patched kernel as the current 2.4.x simply has no interfaces to do that. I'm using the patch below (pulled out of Jens Axboe's bio patches, i386 only).

Gerd

---------------------------- cut here ------------------------

include/asm-i386/page.h renamed from include/asm-i386/page.h.high +2 -0
@@ -116,6 +116,8 @@
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define page_to_phys(page)	(((page) - mem_map) * PAGE_SIZE)
+#define page_to_bus(page)	page_to_phys((page))
 
 
 #endif /* __KERNEL__ */
include/asm-i386/pci.h renamed from include/asm-i386/pci.h.high +52 -0

76 lines not on this page · raw message

include/asm-i386/scatterlist.h renamed from include/asm-i386/scatterlist.h.high +23 -0
@@ -8,6 +8,29 @@
     unsigned int length;
 };
 
+/*
+ * new style scatter gather list -- move to this completely?
+ */
+#define HAVE_SG_LIST 1
+struct sg_list {
+	/*
+	 * input
+	 */
+	struct page *page;	/* page to do I/O to */
+	unsigned int length;	/* length of I/O */
+	unsigned int offset;	/* offset into page */
+
+	/*
+	 * original page, if bounced
+	 */
+	struct page *bounce_page;
+
+	/*
+	 * output
+	 */
+	dma_addr_t dma_address;	/* mapped address */
+};
+
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
 #endif /* !(_I386_SCATTERLIST_H) */
#8 lore raw

I'm using the patch below (pulled out of Jens Axboe's bio patches, i386 only).

Are you sure you aren't missing anything in this patch? For example, one can't use the patch you've provided for 64-bit DMA unless the dma_addr_t type is made larger.

Later,
David S. Miller
[email protected]

#9 lore raw
Quoted 7 lines · David S. Miller

I'm using the patch below (pulled out of Jens Axboe's bio patches, i386 only).

Are you sure you aren't missing anything in this patch? For example, one can't use the patch you've provided for 64-bit DMA unless the dma_addr_t type is made larger.

It only allows to use the full 32 bit address range for DMA. Without the patch I'm limited to direct mapped memory (i.e. < ~900MB on i386). With the patch highmem below 4GB can be used too.

Jens's bio patches don't have support for 64-bit DMA (at least not the version I've used to build that patch). Because the bt848/878 chips are 32-bit devices only I havn't even tried to fix that...

Gerd

Signature · 1 line
Damn lot people confuse usability and eye-candy.
#10 lore raw

Write Combining (Write Coalescing) on memory mapped I/O on IA64.

Hi,

I have a PCI adapter which does a lot of PIO (sort of network adapter using host CPU to send data). On IA32 architechtures we could enable Write Combining to get large burst on the PCI bus, but on IA64 I get at max 8 byte stores (ld8, st8) at a time.

The driver for this adapter also exports the memory to user-space (with mmap()) and when doing this I do (inside the mmap function) :

int ssci_mmap(struct file *file, struct vm_area_struct *vma) {
.....
#ifdef __ia64__
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
#endif
map_page_range(file, vma, vm_start,physaddr,

		      contlen, vma->vm_page_prot);

remap_page_range(vma->vm_start,

		       phys_addr,
		       vma->vm_end - vma->vm_start,
		       vma->vm_page_prot))

....
}

This way we get Write Combining on IA64, but only for userspace mappings. Kernel space clients use ioremap() and don't get Write Combining (ioremap on IA64 use the uncacheable region directly).

To solve this I've tried to make my own __ia64_ioremap() (created arch/ia64/mm/ioremap.c) wich has a 'flags' input paramenter so that I can set the _PAGE_MA_WC attribute. I've taken a look on how other architechtures does this (e.g i386 or s390), and made it nearly identical, but it doesn't seem to work. The mapping gets set up, but if I try to read or write something to this address I get a "Unable to handle kernel paging request at virtual address 0xa00000000015c000" which is the address I'm accessing.

I've attached the patch I made. Please let me know if this is doable on IA64 at all. Feedback greatly appreciated.

Thanks,

Signature · 4 lines
  Steffen Persvold               Systems Engineer
  Email : mailto:[email protected]     Scali AS (http://www.scali.com)
  Tlf   : (+47) 22 62 89 50      Olaf Helsets vei 6
  Fax   : (+47) 22 62 89 51      N-0621 Oslo, Norway
arch/ia64/mm/Makefile renamed from arch/ia64/mm/Makefile.~1~ +1 -1
@@ -9,6 +9,6 @@
 
 O_TARGET := mm.o
 
-obj-y	 := init.o fault.o tlb.o extable.o
+obj-y	 := init.o fault.o ioremap.o tlb.o extable.o
 
 include $(TOPDIR)/Rules.make
arch/ia64/mm/ioremap.c renamed from arch/ia64/mm/ioremap.c.~1~ +148 -0

148 lines not on this page · raw message

arch/ia64/kernel/ia64_ksyms.c renamed from arch/ia64/kernel/ia64_ksyms.c.~1~ +2 -0
@@ -39,6 +39,8 @@
 EXPORT_SYMBOL(ip_fast_csum);
 
 #include <asm/io.h>
+EXPORT_SYMBOL(__ia64_ioremap);
+EXPORT_SYMBOL(__ia64_iounmap);
 EXPORT_SYMBOL(__ia64_memcpy_fromio);
 EXPORT_SYMBOL(__ia64_memcpy_toio);
 EXPORT_SYMBOL(__ia64_memset_c_io);
include/asm-ia64/io.h renamed from include/asm-ia64/io.h.~1~ +3 -0
@@ -386,6 +386,9 @@
 
 #define ioremap_nocache(o,s)	ioremap(o,s)
 
+extern void * __ia64_ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+extern void __ia64_iounmap(void *addr);
+
 # ifdef __KERNEL__
 
 /*
#11 lore raw
In reply to Johannes Erdfelt
Quoted 7 lines · Gerd Knorr
Quoted 5 lines
Quoted 2 lines

Note, if you use the "bttv method" (ie. virt_to_bus) your driver will then fail to compile on several platforms.

So noted. I already have a PCI DMA API version, but I wanted to code up a "i have an i386 and gigs of memory" version as well.

Forgot about virt_to_bus() then, it doesn't work for highmem.

I knew that already :)

The thing about 64 bit PCI cards is that there is no such thing as highmem, so we don't need to worry about mapping it and using bounce buffers. The device just DMA's. That's why I originally asked.

I took a look at the code in the 2.4.7 version of bttv.c and it wasn't readily obvious what Alan was referring to. I'll spend some more time tomorrow looking into it.

JE

#12 lore raw
In reply to Johannes Erdfelt
Quoted 2 lines · Johannes Erdfelt

It's not a big deal. It's just less efficient which isn't the end of the world.

It's not only less efficient, your machine is going to crash as soon as you ask the iommu to map some giga of ram with the current state of drivers (the API says that if you get null out of the map call you should fallback, but no driver checks for this null retval and so in turn they're all prone to crash, not going to be fixed in 2.4 I guess). So try to reduce as much as possible the number of simultaneous pci mappings and it will probably not crash.

Andrea

#13 lore raw
In reply to Johannes Erdfelt
Quoted 3 lines · Andrea Arcangeli

... (the API says that if you get null out of the map call you should fallback, but no driver checks for this null retval and so in turn they're all prone to crash, not going to be fixed in 2.4 I guess).

That strikes me as a pretty basic programming error. Why on Earth is it not considered a problem urgently needing a fix?

#14 lore raw

From: Sandy Harris <[email protected]>
Date: Sat, 11 Aug 2001 12:13:09 -0400

Quoted 3 lines · Andrea Arcangeli

... (the API says that if you get null out of the map call you should fallback, but no driver checks for this null retval and so in turn they're all prone to crash, not going to be fixed in 2.4 I guess).

That strikes me as a pretty basic programming error. Why on Earth is it not considered a problem urgently needing a fix?

Andrea has told a white lie, the "API says" that the interfaces may not fail ever. That is why there is no failure return value defined for the PCI DMA interfaces currently. The DMA-mapping.txt file (which is the definition of the API) makes no mention of a failure case for these interfaces.

Andrea has mentioned how we would _like_ the interface to behave. :-)

There have been a few threads on this issue. One of the core reasons the situation is unlikely to change in 2.4.x is that the scsi layer in it's current form makes the logic required for recovering from a DMA mapping failure aweful at best.

Later,
David S. Miller
[email protected]