Status on ioremap patch
Subsystems (7)
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Steffen Persvold
Steffen> So, how about that patch guys ? Any chance you'll put it Steffen> into the mainstream IA64 kernel ???
I haven't looked at it yet, but am planning to do so as part of the 2.4.10 patch.
--david
Quoted 9 lines · David Mosberger
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines · Steffen Persvold
Steffen> So, how about that patch guys ? Any chance you'll put it Steffen> into the mainstream IA64 kernel ???
I haven't looked at it yet, but am planning to do so as part of the 2.4.10 patch.
I just discovered that several files in arch/ia64/kernel (more specifically acpi.c, efi.c and iosapic.c) calls ioremap with 0 as size argument. This is ok with the current ioremap implementation which always uses region 6 and therefore in theory doesn't need a size since it's mapped all the time. However with my patch you will get a NULL pointer in return if you specify size as 0. Because of this I've modified my original patch to accept 0 as size argument and return the region 6 address when this is the case. This means that we cannot get rid of region 6 yet since some of the source files seem to depend on it.
Attached is my new version of the patch. (Please note that the old ioremap() methods in asm/io.h is just disabled with '#if 0')
Regards,
Signature · 4 lines
Steffen Persvold | Scali Computer AS | Try out the world's best mailto:[email protected] | http://www.scali.com | performing MPI implementation: Tel: (+47) 2262 8950 | Olaf Helsets vei 6 | - ScaMPI 1.12.2 - Fax: (+47) 2262 8951 | N0621 Oslo, NORWAY | >300MBytes/s and <4uS latency
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~ +162 -0
162 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~ +28 -0
@@ -32,6 +32,7 @@#include <asm/machvec.h> #include <asm/page.h> #include <asm/system.h> +#include <asm/pgtable.h> /* * Change virtual addresses to physical addresses and vv.
@@ -372,7 +373,15 @@* accept both, thus the casts. * * On ia-64, we access the physical I/O memory space through the uncached kernel region. +* +* Which is not a good idea if we want speed on large PIO operations. This is now changed +* to map dynamically so that we can use the page table attributes to decide the caching. */ + +extern void *__ia64_ioremap (unsigned long offset,unsigned long size,unsigned long flags); +extern void __ia64_iounmap (void *addr); + +#if 0 static inline void *ioremap (unsigned long offset,unsigned long size) {
@@ -385,6 +394,25 @@ }#define ioremap_nocache (o,s) ioremap(o,s) +#else +static inline void * +ioremap (unsigned long offset,unsigned long size) +{ +return __ia64_ioremap (offset, size, _PAGE_MA_WC); +} + +static inline void * +ioremap_nocache (unsigned long offset,unsigned long size) +{ +return __ia64_ioremap (offset, size, _PAGE_MA_UC); +} + +static inline void +iounmap (void *addr) +{ +__ia64_iounmap (addr); +} +#endif # ifdef __KERNEL__
include/asm-ia64/pgtable.h renamed from include/asm-ia64/pgtable.h.~1~ +1 -6
@@ -125,7 +125,6 @@# ifndef __ASSEMBLY__#include <asm/bitops.h> -#include <asm/mmu_context.h> #include <asm/processor.h> /*
@@ -329,11 +328,7 @@/* The offset in the 1-level directory is given by the 3 region bits (61..63) and the seven level-1 bits (33-39). */ -static inline pgd_t * -pgd_offset (struct mm_struct *mm,unsigned long address) -{ -return mm->pgd +pgd_index (address); -} +#define pgd_offset (mm, address) ((mm)->pgd+pgd_index(address))/* In the kernel's mapped region we have a full 43 bit space available and completely ignore the region number (since we know its in region number 5). */
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
"Steffen" = Steffen Persvold <[email protected]> writes:
Quoted 2 lines · Steffen> David Mosberger wrote:
Quoted 2 lines
I haven't looked at it yet, but am planning to do so as part of
the 2.4.10 patch.
Steffen> I just discovered that several files in arch/ia64/kernel Steffen> (more specifically acpi.c, efi.c and iosapic.c) calls ioremap Steffen> with 0 as size argument. This is ok with the current ioremap Steffen> implementation which always uses region 6 and therefore in Steffen> theory doesn't need a size since it's mapped all the Steffen> time.
This is really borked, it should be changed whether we change the ioremap() implementation or not. ioremap() really should be treated identically on all architectures from the users perspective.
Cheers
Jes
Quoted 9 lines · David Mosberger
Steffen,
I looked at your patch and have a comment and a suggestion. First, I do not think it's safe to define
ioremap()as a way to install write-cached mappings. There are plenty of drivers left that useioremap()instead ofioremap_nocache()and we can't change the semantics ofioremap()underneath them.
Quoted 9 lines
Second, it seems to me it would be cleaner to extend
remap_page_range()to allow remapping into the kernel mapped segment (region 5 in the case of ia64 linux). This should work as is, except that in the kernel case, you need to usepgd_offset_k(). I think you could hackmm/memory.cto check whether "from" is in the range fromVMALLOC_STARTtoVMALLOC_ENDand, if so, usepgd_offset_k()instead ofpgd_offset(). Can you try this and let me know if it works for your needs?
I've had some time to look at it, and I decided to do what you said. I also changed ioremap on all platforms that implements it so that they use remap_page_range()). I've tested the patch on IA64 and i386.
I've attached the patch (I didn't post it on the lkml even though it affects more that the IA64 platform), it's against a vanilla 2.4.17 tree.
Please take a look and tell me what you think.
Regards,
Signature · 4 lines
Steffen Persvold | Scalable Linux Systems | Try out the world's best mailto:[email protected] | http://www.scali.com | performing MPI implementation: Tel: (+47) 2262 8950 | Olaf Helsets vei 6 | - ScaMPI 1.12.2 - Fax: (+47) 2262 8951 | N0621 Oslo, NORWAY | >300MBytes/s and <4uS latencyy
mm/memory.c renamed from mm/memory.c.orig +28 -10
@@ -791,6 +791,9 @@* maps a range of physical memory into the requested pages. the old * mappings are removed. any references to nonexistent pages results * in null mappings (currently treated as "copy-on-access") +* +* For physical (or I/O) memory mapped into the kernel virtual space, +* the old mappings will not be removed. */ static inline void remap_pte_range (pte_t * pte,unsigned long address,unsigned long size,unsigned long phys_addr,pgprot_t prot)
@@ -802,14 +805,22 @@if (end >PMD_SIZE ) end =PMD_SIZE ; do { - struct page *page; - pte_t oldpage; - oldpage = ptep_get_and_clear(pte); - - page = virt_to_page(__va(phys_addr)); - if ((!VALID_PAGE(page)) || PageReserved(page)) - set_pte(pte, mk_pte_phys(phys_addr, prot)); - forget_pte(oldpage); + if (address > VMALLOC_START && address < VMALLOC_END) { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, mk_pte_phys(phys_addr, prot)); + } else { + struct page *page; + pte_t oldpage; + oldpage = ptep_get_and_clear(pte); + + page = virt_to_page(__va(phys_addr)); + if ((!VALID_PAGE(page)) || PageReserved(page)) + set_pte(pte, mk_pte_phys(phys_addr, prot)); + forget_pte(oldpage); + } address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++;
@@ -844,10 +855,17 @@pgd_t * dir;unsigned long beg = from;unsigned long end = from + size; -struct mm_struct *mm = current->mm; +struct mm_struct *mm; phys_addr -= from; - dir =pgd_offset (mm, from); +/* Check if we're going to map into the kernel virtual addresses (ioremap) */ +if (from >VMALLOC_START && end <VMALLOC_END ) { + mm = &init_mm; + dir =pgd_offset_k (from); + }else { + mm = current->mm; + dir =pgd_offset (mm, from); + }flush_cache_range (mm, beg, end);if (from >= end)BUG ();
arch/i386/mm/ioremap.c renamed from arch/i386/mm/ioremap.c.orig +3 -79
100 lines not on this page · raw message
arch/mips/mm/ioremap.c renamed from arch/mips/mm/ioremap.c.orig +3 -83
107 lines not on this page · raw message
arch/mips/kernel/mips_ksyms.c renamed from arch/mips/kernel/mips_ksyms.c.orig +3 -0
@@ -106,6 +106,9 @@*/ EXPORT_SYMBOL (mips_io_port_base); +EXPORT_SYMBOL (__ioremap); +EXPORT_SYMBOL (iounmap); +/* * Architecture specific stuff. */
arch/arm/mm/ioremap.c renamed from arch/arm/mm/ioremap.c.orig +3 -83
104 lines not on this page · raw message
arch/sh/mm/ioremap.c renamed from arch/sh/mm/ioremap.c.orig +4 -81
103 lines not on this page · raw message
arch/ia64/kernel/ia64_ksyms.c renamed from arch/ia64/kernel/ia64_ksyms.c.orig +2 -0
@@ -43,6 +43,8 @@EXPORT_SYMBOL (ip_fast_csum);#include <asm/io.h> +EXPORT_SYMBOL (__ioremap); +EXPORT_SYMBOL (iounmap);EXPORT_SYMBOL (__ia64_memcpy_fromio);EXPORT_SYMBOL (__ia64_memcpy_toio);EXPORT_SYMBOL (__ia64_memset_c_io);
arch/ia64/mm/ioremap.c renamed from arch/ia64/mm/ioremap.c.orig +70 -0
70 lines not on this page · raw message
arch/s390/mm/ioremap.c renamed from arch/s390/mm/ioremap.c.orig +3 -80
101 lines not on this page · raw message
arch/cris/mm/ioremap.c renamed from arch/cris/mm/ioremap.c.orig +4 -81
103 lines not on this page · raw message
arch/s390x/mm/ioremap.c renamed from arch/s390x/mm/ioremap.c.orig +2 -79
99 lines not on this page · raw message
include/asm-ia64/io.h renamed from include/asm-ia64/io.h.orig +10 -5
@@ -37,6 +37,7 @@#include <asm/machvec.h> #include <asm/page.h> #include <asm/system.h> +#include <asm/pgtable.h> /* * Change virtual addresses to physical addresses and vv.
@@ -378,19 +379,23 @@* accept both, thus the casts. * * On ia-64, we access the physical I/O memory space through the uncached kernel region. +* +* Which is not a good idea if we want speed on large PIO operations. It is now possible +* to map dynamically so that we can use the page table attributes to decide the caching. +* ioremap_wrcomb() does this and uses Write Coalescing attribute. */ + +extern void *__ioremap (unsigned long offset,unsigned long size,unsigned long flags); +extern void iounmap (void *addr); +static inline void *ioremap (unsigned long offset,unsigned long size) {return (void *) (__IA64_UNCACHED_OFFSET | (offset)); } -static inline void -iounmap (void *addr) -{ -} -#define ioremap_nocache (o,s) ioremap(o,s) +#define ioremap_wrcomb (o,s) __ioremap(o,s,_PAGE_MA_WC)# ifdef __KERNEL__
include/asm-ia64/pgtable.h renamed from include/asm-ia64/pgtable.h.orig +1 -6
@@ -125,7 +125,6 @@# ifndef __ASSEMBLY__#include <asm/bitops.h> -#include <asm/mmu_context.h> #include <asm/processor.h> /*
@@ -329,11 +328,7 @@/* The offset in the 1-level directory is given by the 3 region bits (61..63) and the seven level-1 bits (33-39). */ -static inline pgd_t * -pgd_offset (struct mm_struct *mm,unsigned long address) -{ -return mm->pgd +pgd_index (address); -} +#define pgd_offset (mm, address) ((mm)->pgd+pgd_index(address))/* In the kernel's mapped region we have a full 43 bit space available and completely ignore the region number (since we know its in region number 5). */
mm/memory.c line 796
Quoted 9 lines · Steffen Persvold
mm/memory.c renamed from mm/memory.c.orig +3
-0@@ -791,6 +791,9 @@* maps a range of physical memory into the requested pages. the old * mappings are removed. any references to nonexistent pages results * in null mappings (currently treated as "copy-on-access") +* +* For physical (or I/O) memory mapped into the kernel virtual space, +* the old mappings will not be removed.
That comment worries me. If you have multiple mappings for the same page then you may have problems on hardware that uses virtually indexed caches. Two virtual addresses could map to the same physical page but index to different cache lines, destroying cache coherency. How do you prevent that?
Quoted 19 lines · Keith Owens
mm/memory.c Sat Jan 5 13:13:26 2002 line 796
Quoted 9 lines · Steffen Persvold
mm/memory.c Sat Jan 5 13:13:26 2002 renamed from mm/memory.c.orig Fri Dec 21 18:42:05 2001 +3
-0@@ -791,6 +791,9 @@ * maps a range of physical memory into the requested pages. the old * mappings are removed. any references to nonexistent pages results * in null mappings (currently treated as "copy-on-access") + * + * For physical (or I/O) memory mapped into the kernel virtual space, + * the old mappings will not be removed.That comment worries me. If you have multiple mappings for the same page then you may have problems on hardware that uses virtually indexed caches. Two virtual addresses could map to the same physical page but index to different cache lines, destroying cache coherency. How do you prevent that?
Well, actually multiple mappings in kernel space is denied :
+ if (address > VMALLOC_START && address < VMALLOC_END) {
+ if (!pte_none(*pte)) {
+ printk("remap_area_pte: page already exists\n");
+ BUG();
+ }
+ set_pte(pte, mk_pte_phys(phys_addr, prot));
+ } else {
+ struct page *page; + pte_t oldpage; + oldpage = ptep_get_and_clear(pte);
+
+ page = virt_to_page(__va(phys_addr));
+ if ((!VALID_PAGE(page)) || PageReserved(page))
+ set_pte(pte, mk_pte_phys(phys_addr, prot));
+ forget_pte(oldpage);
+ }
Regards,
Signature · 4 lines
Steffen Persvold | Scalable Linux Systems | Try out the world's best mailto:[email protected] | http://www.scali.com | performing MPI implementation: Tel: (+47) 2262 8950 | Olaf Helsets vei 6 | - ScaMPI 1.12.2 - Fax: (+47) 2262 8951 | N0621 Oslo, NORWAY | >300MBytes/s and <4uS latency
Quoted 29 lines · Steffen Persvold
Quoted 19 lines · Keith Owens
mm/memory.c Sat Jan 5 13:13:26 2002 line 796
Quoted 9 lines · Steffen Persvold
mm/memory.c Sat Jan 5 13:13:26 2002 renamed from mm/memory.c.orig Fri Dec 21 18:42:05 2001 +3
-0@@ -791,6 +791,9 @@ * maps a range of physical memory into the requested pages. the old * mappings are removed. any references to nonexistent pages results * in null mappings (currently treated as "copy-on-access") + * + * For physical (or I/O) memory mapped into the kernel virtual space, + * the old mappings will not be removed.That comment worries me. If you have multiple mappings for the same page then you may have problems on hardware that uses virtually indexed caches. Two virtual addresses could map to the same physical page but index to different cache lines, destroying cache coherency. How do you prevent that?
Well, actually multiple mappings in kernel space is denied :
(quoted diff) +6
-0+ if (address > VMALLOC_START && address < VMALLOC_END) { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, mk_pte_phys(phys_addr, prot));
Review
Quoted 10 lines
(quoted diff) +10
-0+ } else { + struct page *page; + pte_t oldpage; + oldpage = ptep_get_and_clear(pte); + + page = virt_to_page(__va(phys_addr)); + if ((!VALID_PAGE(page)) || PageReserved(page)) + set_pte(pte, mk_pte_phys(phys_addr, prot)); + forget_pte(oldpage); + }
What about one mapping in kernel space and one in user space, or two mappings in user space? As long as you have more than one mapping to the same physical page you must handle virtual cache aliasing.
Quoted 43 lines · Keith Owens
Quoted 29 lines · Steffen Persvold
Quoted 19 lines · Keith Owens
mm/memory.c Sat Jan 5 13:13:26 2002 line 796
Quoted 9 lines · Steffen Persvold
mm/memory.c Sat Jan 5 13:13:26 2002 renamed from mm/memory.c.orig Fri Dec 21 18:42:05 2001 +3
-0@@ -791,6 +791,9 @@ * maps a range of physical memory into the requested pages. the old * mappings are removed. any references to nonexistent pages results * in null mappings (currently treated as "copy-on-access") + * + * For physical (or I/O) memory mapped into the kernel virtual space, + * the old mappings will not be removed.That comment worries me. If you have multiple mappings for the same page then you may have problems on hardware that uses virtually indexed caches. Two virtual addresses could map to the same physical page but index to different cache lines, destroying cache coherency. How do you prevent that?
Well, actually multiple mappings in kernel space is denied :
(quoted diff) +6
-0+ if (address > VMALLOC_START && address < VMALLOC_END) { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, mk_pte_phys(phys_addr, prot));Review
Quoted 10 lines
(quoted diff) +10
-0+ } else { + struct page *page; + pte_t oldpage; + oldpage = ptep_get_and_clear(pte); + + page = virt_to_page(__va(phys_addr)); + if ((!VALID_PAGE(page)) || PageReserved(page)) + set_pte(pte, mk_pte_phys(phys_addr, prot)); + forget_pte(oldpage); + }
Quoted 4 lines
What about one mapping in kernel space and one in user space, or two mappings in user space? As long as you have more than one mapping to the same physical page you must handle virtual cache aliasing.
If you do two mappings from userspace (via mmap() and from there remap_page_range()), the "else" case would be true because then the addess isn't a kernel virtual address and the old mapping would be forgotten. The case where ioremap() is called first and then remap_page_range() is called later (via mmap() function) will also work fine. The two cases I can think of where the BUG() case wold trigger, are when remap_page_range() is called first and then ioremap() is called, or when ioremap() is called twice. None of these two cases is something that I would consider "legal" and this would also happen with the old (similar) ioremap() implementation.
Do you think I should drop the if/else statements and just always treat it as it was two mappings from userspace (currently the "else" case) ?
Regards,
Signature · 4 lines
Steffen Persvold | Scalable Linux Systems | Try out the world's best mailto:[email protected] | http://www.scali.com | performing MPI implementation: Tel: (+47) 2262 8950 | Olaf Helsets vei 6 | - ScaMPI 1.12.2 - Fax: (+47) 2262 8951 | N0621 Oslo, NORWAY | >300MBytes/s and <4uS latency
Quoted 21 lines · Steffen Persvold
Quoted 9 lines · David Mosberger
Steffen,
I looked at your patch and have a comment and a suggestion. First, I do not think it's safe to define
ioremap()as a way to install write-cached mappings. There are plenty of drivers left that useioremap()instead ofioremap_nocache()and we can't change the semantics ofioremap()underneath them.Quoted 9 lines
Second, it seems to me it would be cleaner to extend
remap_page_range()to allow remapping into the kernel mapped segment (region 5 in the case of ia64 linux). This should work as is, except that in the kernel case, you need to usepgd_offset_k(). I think you could hackmm/memory.cto check whether "from" is in the range fromVMALLOC_STARTtoVMALLOC_ENDand, if so, usepgd_offset_k()instead ofpgd_offset(). Can you try this and let me know if it works for your needs?
Quoted 9 lines
I've had some time to look at it, and I decided to do what you said. I also changed ioremap on all platforms that implements it so that they use
remap_page_range()). I've tested the patch on IA64 and i386.I've attached the patch (I didn't post it on the lkml even though it affects more that the IA64 platform), it's against a vanilla 2.4.17 tree.
Please take a look and tell me what you think.
So, what about this patch (posted earlier) David ? Have you seen the comments from Keith ?
Regards,
Signature · 4 lines
Steffen Persvold | Scalable Linux Systems | Try out the world's best mailto:[email protected] | http://www.scali.com | performing MPI implementation: Tel: (+47) 2262 8950 | Olaf Helsets vei 6 | - ScaMPI 1.12.2 - Fax: (+47) 2262 8951 | N0621 Oslo, NORWAY | >300MBytes/s and <4uS latency
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Steffen Persvold
Steffen> So, what about this patch (posted earlier) David ? Have you Steffen> seen the comments from Keith ?
Keith's concerns are legitimate and to some degree apply even for ia64. On ia64, we need to be careful to avoid mapping the same physical page with different memory attributes. If more and more drivers are starting to use write-combine mappings, we need to solve this problem properly. I don't have a solution off hand (I suspect we'll have to keep track of which i/o regions are mapped how) and don't have time to work on it now. I'd recommend to maintain a separate patch for now, until a proper solution is ready (which will have to take non-ia64 platforms into consideration, of course).
--david
PS: I apologize for not being as responsive yet as I'd like to be.
I'm done with the book (well, 99.999% as my wife put it...) and ready to attack my backlog of kernel work (and other things, such as user-level unwind support). I just had a spell of bad luck this week, which didn't help. Hopefully, over the next one or two weeks, things will start to go back to normal.