From 2411151738fdce2a546116d694e126462ada5730 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Thu, 2 Nov 2006 09:54:18 +0000 Subject: [PATCH] * Add patches from linux-mips.org's 2.6.18-stable branch: - bugfix/copy-user-highpage.patch, needed for cache alias handling on mips/mipsel/hppa. - bugfix/mips/syscall-wiring.patch, fixes TLS register access, and n32 rt_sigqueueinfo. - bugfix/mips/sb1-flush-cache-data-page.patch, missing cache flush on SB-1. - bugfix/mips/trylock.patch, fix trylock implementation for R1x000 and R3xxx. - bugfix/mips/smp-cpu-bringup.patch, correct initialization of non-contiguous CPU topology. - bugfix/mips/header-exports.patch, clean up userland exports of kernel headers. - bugfix/mips/sb1-interrupt-handler.patch, fix broken interrupt routing on SB-1. - bugfix/mips/cache-alias.patch, fixes #387498 for mips/mipsel. - bugfix/mips/ip22-zilog-console.patch, fix long delays seen with SGI ip22 serial console. - bugfix/mips/signal-handling.patch, fixes a signal handling race condition shown with gdb. - bugfix/mips/sb1-duart-tts.patch, replaces mips-sb1-duart-tts.patch, use standard Linux names for SB-1 consoles. - bugfix/mips/wait-race.patch, correct behaviour of the idle loop. - bugfix/mips/sgi-ioc3.patch, checksumming fix for IOC3 network driver. - features/mips/qemu-kernel.patch, support for the mips/mipsel machine emulated by Qemu. - features/mips/backtrace.patch, reimplementation of stack analysis and backtrace printing, useful for in-kernel debugging. - bugfix/mips/dec-scsi.patch, replaces mips-dec-scsi.patch, fixes DSP SCSI driver for DECstations. - bugfix/mips/dec-serial.patch, replaces mips-dec-serial.patch, fix serial console handling on DECstations. svn path=/dists/trunk/linux-2.6/; revision=7681 --- debian/changelog | 35 + .../patches/bugfix/copy-user-highpage.patch | 70 ++ debian/patches/bugfix/mips/cache-alias.patch | 675 ++++++++++++++++++ debian/patches/bugfix/mips/dec-scsi.patch | 32 + debian/patches/bugfix/mips/dec-serial.patch | 197 +++++ .../patches/bugfix/mips/header-exports.patch | 73 ++ .../bugfix/mips/ip22-zilog-console.patch | 22 + .../patches/bugfix/mips/sb1-duart-tts.patch | 24 + .../mips/sb1-flush-cache-data-page.patch | 67 ++ .../bugfix/mips/sb1-interrupt-handler.patch | 76 ++ debian/patches/bugfix/mips/sgi-ioc3.patch | 164 +++++ .../patches/bugfix/mips/signal-handling.patch | 78 ++ .../patches/bugfix/mips/smp-cpu-bringup.patch | 85 +++ .../patches/bugfix/mips/syscall-wiring.patch | 54 ++ debian/patches/bugfix/mips/trylock.patch | 61 ++ debian/patches/bugfix/mips/wait-race.patch | 118 +++ debian/patches/features/mips/backtrace.patch | 401 +++++++++++ .../patches/features/mips/qemu-kernel.patch | 231 ++++++ debian/patches/series/4 | 16 + debian/patches/series/4-extra | 4 + 20 files changed, 2483 insertions(+) create mode 100644 debian/patches/bugfix/copy-user-highpage.patch create mode 100644 debian/patches/bugfix/mips/cache-alias.patch create mode 100644 debian/patches/bugfix/mips/dec-scsi.patch create mode 100644 debian/patches/bugfix/mips/dec-serial.patch create mode 100644 debian/patches/bugfix/mips/header-exports.patch create mode 100644 debian/patches/bugfix/mips/ip22-zilog-console.patch create mode 100644 debian/patches/bugfix/mips/sb1-duart-tts.patch create mode 100644 debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch create mode 100644 debian/patches/bugfix/mips/sb1-interrupt-handler.patch create mode 100644 debian/patches/bugfix/mips/sgi-ioc3.patch create mode 100644 debian/patches/bugfix/mips/signal-handling.patch create mode 100644 debian/patches/bugfix/mips/smp-cpu-bringup.patch create mode 100644 debian/patches/bugfix/mips/syscall-wiring.patch create mode 100644 debian/patches/bugfix/mips/trylock.patch create mode 100644 debian/patches/bugfix/mips/wait-race.patch create mode 100644 debian/patches/features/mips/backtrace.patch create mode 100644 debian/patches/features/mips/qemu-kernel.patch diff --git a/debian/changelog b/debian/changelog index c231fcb60..da3329578 100644 --- a/debian/changelog +++ b/debian/changelog @@ -54,6 +54,41 @@ linux-2.6 (2.6.18-4) UNRELEASED; urgency=low * Bump ABI to 2. * Update vserver patch to 2.0.2.2-rc4. + [ Thiemo Seufer ] + * Add patches from linux-mips.org's 2.6.18-stable branch: + - bugfix/copy-user-highpage.patch, needed for cache alias handling + on mips/mipsel/hppa. + - bugfix/mips/syscall-wiring.patch, fixes TLS register access, and + n32 rt_sigqueueinfo. + - bugfix/mips/sb1-flush-cache-data-page.patch, missing cache flush + on SB-1. + - bugfix/mips/trylock.patch, fix trylock implementation for R1x000 + and R3xxx. + - bugfix/mips/smp-cpu-bringup.patch, correct initialization of + non-contiguous CPU topology. + - bugfix/mips/header-exports.patch, clean up userland exports of + kernel headers. + - bugfix/mips/sb1-interrupt-handler.patch, fix broken interrupt + routing on SB-1. + - bugfix/mips/cache-alias.patch, fixes #387498 for mips/mipsel. + - bugfix/mips/ip22-zilog-console.patch, fix long delays seen with + SGI ip22 serial console. + - bugfix/mips/signal-handling.patch, fixes a signal handling race + condition shown with gdb. + - bugfix/mips/sb1-duart-tts.patch, replaces mips-sb1-duart-tts.patch, + use standard Linux names for SB-1 consoles. + - bugfix/mips/wait-race.patch, correct behaviour of the idle loop. + - bugfix/mips/sgi-ioc3.patch, checksumming fix for IOC3 network + driver. + - features/mips/qemu-kernel.patch, support for the mips/mipsel + machine emulated by Qemu. + - features/mips/backtrace.patch, reimplementation of stack analysis + and backtrace printing, useful for in-kernel debugging. + - bugfix/mips/dec-scsi.patch, replaces mips-dec-scsi.patch, fixes DSP + SCSI driver for DECstations. + - bugfix/mips/dec-serial.patch, replaces mips-dec-serial.patch, fix + serial console handling on DECstations. + -- Frederik Schüler Wed, 1 Nov 2006 23:44:06 +0100 linux-2.6 (2.6.18-3) unstable; urgency=low diff --git a/debian/patches/bugfix/copy-user-highpage.patch b/debian/patches/bugfix/copy-user-highpage.patch new file mode 100644 index 000000000..41c854bcf --- /dev/null +++ b/debian/patches/bugfix/copy-user-highpage.patch @@ -0,0 +1,70 @@ +# Arch-specific copy_user_highpage, from linux-mips.org 2.6.18-stable, +# also in kernel.org mainline, needed for cache alias fix. + + +--- a/include/linux/highmem.h ++++ b/include/linux/highmem.h +@@ -89,7 +89,10 @@ static inline void memclear_highpage_flu + kunmap_atomic(kaddr, KM_USER0); + } + +-static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr) ++#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE ++ ++static inline void copy_user_highpage(struct page *to, struct page *from, ++ unsigned long vaddr, struct vm_area_struct *vma) + { + char *vfrom, *vto; + +@@ -102,6 +105,8 @@ static inline void copy_user_highpage(st + smp_wmb(); + } + ++#endif ++ + static inline void copy_highpage(struct page *to, struct page *from) + { + char *vfrom, *vto; +diff --git a/mm/memory.c b/mm/memory.c +index 109e986..2e4ee87 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1407,7 +1407,7 @@ static inline pte_t maybe_mkwrite(pte_t + return pte; + } + +-static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va) ++static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va, struct vm_area_struct *vma) + { + /* + * If the source page was a PFN mapping, we don't have +@@ -1429,9 +1429,9 @@ static inline void cow_user_page(struct + memset(kaddr, 0, PAGE_SIZE); + kunmap_atomic(kaddr, KM_USER0); + return; +- ++ + } +- copy_user_highpage(dst, src, va); ++ copy_user_highpage(dst, src, va, vma); + } + + /* +@@ -1531,7 +1531,7 @@ gotten: + new_page = alloc_page_vma(GFP_HIGHUSER, vma, address); + if (!new_page) + goto oom; +- cow_user_page(new_page, old_page, address); ++ cow_user_page(new_page, old_page, address, vma); + } + + /* +@@ -2135,7 +2135,7 @@ retry: + page = alloc_page_vma(GFP_HIGHUSER, vma, address); + if (!page) + goto oom; +- copy_user_highpage(page, new_page, address); ++ copy_user_highpage(page, new_page, address, vma); + page_cache_release(new_page); + new_page = page; + anon = 1; diff --git a/debian/patches/bugfix/mips/cache-alias.patch b/debian/patches/bugfix/mips/cache-alias.patch new file mode 100644 index 000000000..ed2e44c06 --- /dev/null +++ b/debian/patches/bugfix/mips/cache-alias.patch @@ -0,0 +1,675 @@ +# Fix cache alias handling for mips (see #387498), from linux-mips.org +# 2.6.18-stable, also in kernel.org mainline. + + +diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c +index bb041a2..e1f35ef 100644 +--- a/arch/mips/mm/c-r3k.c ++++ b/arch/mips/mm/c-r3k.c +@@ -335,7 +335,7 @@ void __init r3k_cache_init(void) + flush_cache_mm = r3k_flush_cache_mm; + flush_cache_range = r3k_flush_cache_range; + flush_cache_page = r3k_flush_cache_page; +- flush_icache_page = r3k_flush_icache_page; ++ __flush_icache_page = r3k_flush_icache_page; + flush_icache_range = r3k_flush_icache_range; + + flush_cache_sigtramp = r3k_flush_cache_sigtramp; +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index 069803f..2d729f6 100644 +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -475,7 +475,7 @@ static inline void local_r4k_flush_cache + } + } + if (exec) { +- if (cpu_has_vtag_icache) { ++ if (cpu_has_vtag_icache && mm == current->active_mm) { + int cpu = smp_processor_id(); + + if (cpu_context(cpu, mm) != 0) +@@ -599,7 +599,7 @@ static inline void local_r4k_flush_icach + * We're not sure of the virtual address(es) involved here, so + * we have to flush the entire I-cache. + */ +- if (cpu_has_vtag_icache) { ++ if (cpu_has_vtag_icache && vma->vm_mm == current->active_mm) { + int cpu = smp_processor_id(); + + if (cpu_context(cpu, vma->vm_mm) != 0) +@@ -1291,7 +1291,7 @@ void __init r4k_cache_init(void) + __flush_cache_all = r4k___flush_cache_all; + flush_cache_mm = r4k_flush_cache_mm; + flush_cache_page = r4k_flush_cache_page; +- flush_icache_page = r4k_flush_icache_page; ++ __flush_icache_page = r4k_flush_icache_page; + flush_cache_range = r4k_flush_cache_range; + + flush_cache_sigtramp = r4k_flush_cache_sigtramp; +diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c +index 2d71efb..16bad7c 100644 +--- a/arch/mips/mm/c-sb1.c ++++ b/arch/mips/mm/c-sb1.c +@@ -155,6 +155,26 @@ static inline void __sb1_flush_icache_al + } + + /* ++ * Invalidate a range of the icache. The addresses are virtual, and ++ * the cache is virtually indexed and tagged. However, we don't ++ * necessarily have the right ASID context, so use index ops instead ++ * of hit ops. ++ */ ++static inline void __sb1_flush_icache_range(unsigned long start, ++ unsigned long end) ++{ ++ start &= ~(icache_line_size - 1); ++ end = (end + icache_line_size - 1) & ~(icache_line_size - 1); ++ ++ while (start != end) { ++ cache_set_op(Index_Invalidate_I, start & icache_index_mask); ++ start += icache_line_size; ++ } ++ mispredict(); ++ sync(); ++} ++ ++/* + * Flush the icache for a given physical page. Need to writeback the + * dcache first, then invalidate the icache. If the page isn't + * executable, nothing is required. +@@ -173,8 +193,11 @@ #endif + /* + * Bumping the ASID is probably cheaper than the flush ... + */ +- if (cpu_context(cpu, vma->vm_mm) != 0) +- drop_mmu_context(vma->vm_mm, cpu); ++ if (vma->vm_mm == current->active_mm) { ++ if (cpu_context(cpu, vma->vm_mm) != 0) ++ drop_mmu_context(vma->vm_mm, cpu); ++ } else ++ __sb1_flush_icache_range(addr, addr + PAGE_SIZE); + } + + #ifdef CONFIG_SMP +@@ -210,26 +233,6 @@ void sb1_flush_cache_page(struct vm_area + __attribute__((alias("local_sb1_flush_cache_page"))); + #endif + +-/* +- * Invalidate a range of the icache. The addresses are virtual, and +- * the cache is virtually indexed and tagged. However, we don't +- * necessarily have the right ASID context, so use index ops instead +- * of hit ops. +- */ +-static inline void __sb1_flush_icache_range(unsigned long start, +- unsigned long end) +-{ +- start &= ~(icache_line_size - 1); +- end = (end + icache_line_size - 1) & ~(icache_line_size - 1); +- +- while (start != end) { +- cache_set_op(Index_Invalidate_I, start & icache_index_mask); +- start += icache_line_size; +- } +- mispredict(); +- sync(); +-} +- + + /* + * Invalidate all caches on this CPU +@@ -326,9 +329,12 @@ #endif + * If there's a context, bump the ASID (cheaper than a flush, + * since we don't know VAs!) + */ +- if (cpu_context(cpu, vma->vm_mm) != 0) { +- drop_mmu_context(vma->vm_mm, cpu); +- } ++ if (vma->vm_mm == current->active_mm) { ++ if (cpu_context(cpu, vma->vm_mm) != 0) ++ drop_mmu_context(vma->vm_mm, cpu); ++ } else ++ __sb1_flush_icache_range(start, start + PAGE_SIZE); ++ + } + + #ifdef CONFIG_SMP +@@ -520,7 +526,7 @@ #endif + + /* These routines are for Icache coherence with the Dcache */ + flush_icache_range = sb1_flush_icache_range; +- flush_icache_page = sb1_flush_icache_page; ++ __flush_icache_page = sb1_flush_icache_page; + flush_icache_all = __sb1_flush_icache_all; /* local only */ + + /* This implies an Icache flush too, so can't be nop'ed */ +diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c +index ddd3a2d..40c8b02 100644 +--- a/arch/mips/mm/cache.c ++++ b/arch/mips/mm/cache.c +@@ -25,7 +25,7 @@ void (*flush_cache_range)(struct vm_area + void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, + unsigned long pfn); + void (*flush_icache_range)(unsigned long start, unsigned long end); +-void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page); ++void (*__flush_icache_page)(struct vm_area_struct *vma, struct page *page); + + /* MIPS specific cache operations */ + void (*flush_cache_sigtramp)(unsigned long addr); +@@ -70,6 +70,8 @@ void __flush_dcache_page(struct page *pa + struct address_space *mapping = page_mapping(page); + unsigned long addr; + ++ if (PageHighMem(page)) ++ return; + if (mapping && !mapping_mapped(mapping)) { + SetPageDcacheDirty(page); + return; +@@ -91,16 +93,16 @@ void __update_cache(struct vm_area_struc + { + struct page *page; + unsigned long pfn, addr; ++ int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; + + pfn = pte_pfn(pte); +- if (pfn_valid(pfn) && (page = pfn_to_page(pfn), page_mapping(page)) && +- Page_dcache_dirty(page)) { +- if (pages_do_alias((unsigned long)page_address(page), +- address & PAGE_MASK)) { +- addr = (unsigned long) page_address(page); ++ if (unlikely(!pfn_valid(pfn))) ++ return; ++ page = pfn_to_page(pfn); ++ if (page_mapping(page) && Page_dcache_dirty(page)) { ++ addr = (unsigned long) page_address(page); ++ if (exec || pages_do_alias(addr, address & PAGE_MASK)) + flush_data_cache_page(addr); +- } +- + ClearPageDcacheDirty(page); + } + } +diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c +index e3a6172..a4f8c45 100644 +--- a/arch/mips/mm/fault.c ++++ b/arch/mips/mm/fault.c +@@ -89,7 +89,7 @@ good_area: + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { +- if (!(vma->vm_flags & (VM_READ | VM_EXEC))) ++ if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) + goto bad_area; + } + +diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c +index c52497b..a681f57 100644 +--- a/arch/mips/mm/init.c ++++ b/arch/mips/mm/init.c +@@ -30,11 +30,39 @@ #include + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include ++ ++/* CP0 hazard avoidance. */ ++#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ ++ "nop; nop; nop; nop; nop; nop;\n\t" \ ++ ".set reorder\n\t") ++ ++/* Atomicity and interruptability */ ++#ifdef CONFIG_MIPS_MT_SMTC ++ ++#include ++ ++#define ENTER_CRITICAL(flags) \ ++ { \ ++ unsigned int mvpflags; \ ++ local_irq_save(flags);\ ++ mvpflags = dvpe() ++#define EXIT_CRITICAL(flags) \ ++ evpe(mvpflags); \ ++ local_irq_restore(flags); \ ++ } ++#else ++ ++#define ENTER_CRITICAL(flags) local_irq_save(flags) ++#define EXIT_CRITICAL(flags) local_irq_restore(flags) ++ ++#endif /* CONFIG_MIPS_MT_SMTC */ + + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +@@ -80,13 +108,184 @@ unsigned long setup_zero_pages(void) + return 1UL << order; + } + +-#ifdef CONFIG_HIGHMEM +-pte_t *kmap_pte; +-pgprot_t kmap_prot; ++/* ++ * These are almost like kmap_atomic / kunmap_atmic except they take an ++ * additional address argument as the hint. ++ */ + + #define kmap_get_fixmap_pte(vaddr) \ + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) + ++#ifdef CONFIG_MIPS_MT_SMTC ++static pte_t *kmap_coherent_pte; ++static void __init kmap_coherent_init(void) ++{ ++ unsigned long vaddr; ++ ++ /* cache the first coherent kmap pte */ ++ vaddr = __fix_to_virt(FIX_CMAP_BEGIN); ++ kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); ++} ++#else ++static inline void kmap_coherent_init(void) {} ++#endif ++ ++static inline void *kmap_coherent(struct page *page, unsigned long addr) ++{ ++ enum fixed_addresses idx; ++ unsigned long vaddr, flags, entrylo; ++ unsigned long old_ctx; ++ pte_t pte; ++ int tlbidx; ++ ++ inc_preempt_count(); ++ idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1); ++#ifdef CONFIG_MIPS_MT_SMTC ++ idx += FIX_N_COLOURS * smp_processor_id(); ++#endif ++ vaddr = __fix_to_virt(FIX_CMAP_END - idx); ++ pte = mk_pte(page, PAGE_KERNEL); ++#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) ++ entrylo = pte.pte_high; ++#else ++ entrylo = pte_val(pte) >> 6; ++#endif ++ ++ ENTER_CRITICAL(flags); ++ old_ctx = read_c0_entryhi(); ++ write_c0_entryhi(vaddr & (PAGE_MASK << 1)); ++ write_c0_entrylo0(entrylo); ++ write_c0_entrylo1(entrylo); ++#ifdef CONFIG_MIPS_MT_SMTC ++ set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); ++ /* preload TLB instead of local_flush_tlb_one() */ ++ mtc0_tlbw_hazard(); ++ tlb_probe(); ++ BARRIER; ++ tlbidx = read_c0_index(); ++ mtc0_tlbw_hazard(); ++ if (tlbidx < 0) ++ tlb_write_random(); ++ else ++ tlb_write_indexed(); ++#else ++ tlbidx = read_c0_wired(); ++ write_c0_wired(tlbidx + 1); ++ write_c0_index(tlbidx); ++ mtc0_tlbw_hazard(); ++ tlb_write_indexed(); ++#endif ++ tlbw_use_hazard(); ++ write_c0_entryhi(old_ctx); ++ EXIT_CRITICAL(flags); ++ ++ return (void*) vaddr; ++} ++ ++#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) ++ ++static inline void kunmap_coherent(struct page *page) ++{ ++#ifndef CONFIG_MIPS_MT_SMTC ++ unsigned int wired; ++ unsigned long flags, old_ctx; ++ ++ ENTER_CRITICAL(flags); ++ old_ctx = read_c0_entryhi(); ++ wired = read_c0_wired() - 1; ++ write_c0_wired(wired); ++ write_c0_index(wired); ++ write_c0_entryhi(UNIQUE_ENTRYHI(wired)); ++ write_c0_entrylo0(0); ++ write_c0_entrylo1(0); ++ mtc0_tlbw_hazard(); ++ tlb_write_indexed(); ++ tlbw_use_hazard(); ++ write_c0_entryhi(old_ctx); ++ EXIT_CRITICAL(flags); ++#endif ++ dec_preempt_count(); ++ preempt_check_resched(); ++} ++ ++void copy_user_highpage(struct page *to, struct page *from, ++ unsigned long vaddr, struct vm_area_struct *vma) ++{ ++ void *vfrom, *vto; ++ ++ vto = kmap_atomic(to, KM_USER1); ++ if (cpu_has_dc_aliases) { ++ vfrom = kmap_coherent(from, vaddr); ++ copy_page(vto, vfrom); ++ kunmap_coherent(from); ++ } else { ++ vfrom = kmap_atomic(from, KM_USER0); ++ copy_page(vto, vfrom); ++ kunmap_atomic(vfrom, KM_USER0); ++ } ++ if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) || ++ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) ++ flush_data_cache_page((unsigned long)vto); ++ kunmap_atomic(vto, KM_USER1); ++ /* Make sure this page is cleared on other CPU's too before using it */ ++ smp_wmb(); ++} ++ ++EXPORT_SYMBOL(copy_user_highpage); ++ ++void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, ++ struct page *to) ++{ ++ if (cpu_has_dc_aliases) { ++ struct page *from = virt_to_page(vfrom); ++ vfrom = kmap_coherent(from, vaddr); ++ copy_page(vto, vfrom); ++ kunmap_coherent(from); ++ } else ++ copy_page(vto, vfrom); ++ if (!cpu_has_ic_fills_f_dc || ++ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) ++ flush_data_cache_page((unsigned long)vto); ++} ++ ++EXPORT_SYMBOL(copy_user_page); ++ ++void copy_to_user_page(struct vm_area_struct *vma, ++ struct page *page, unsigned long vaddr, void *dst, const void *src, ++ unsigned long len) ++{ ++ if (cpu_has_dc_aliases) { ++ void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); ++ memcpy(vto, src, len); ++ kunmap_coherent(page); ++ } else ++ memcpy(dst, src, len); ++ if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ++ flush_cache_page(vma, vaddr, page_to_pfn(page)); ++} ++ ++EXPORT_SYMBOL(copy_to_user_page); ++ ++void copy_from_user_page(struct vm_area_struct *vma, ++ struct page *page, unsigned long vaddr, void *dst, const void *src, ++ unsigned long len) ++{ ++ if (cpu_has_dc_aliases) { ++ void *vfrom = ++ kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); ++ memcpy(dst, vfrom, len); ++ kunmap_coherent(page); ++ } else ++ memcpy(dst, src, len); ++} ++ ++EXPORT_SYMBOL(copy_from_user_page); ++ ++ ++#ifdef CONFIG_HIGHMEM ++pte_t *kmap_pte; ++pgprot_t kmap_prot; ++ + static void __init kmap_init(void) + { + unsigned long kmap_vstart; +@@ -97,11 +296,12 @@ static void __init kmap_init(void) + + kmap_prot = PAGE_KERNEL; + } ++#endif /* CONFIG_HIGHMEM */ + +-#ifdef CONFIG_32BIT + void __init fixrange_init(unsigned long start, unsigned long end, + pgd_t *pgd_base) + { ++#if defined(CONFIG_HIGHMEM) || defined(CONFIG_MIPS_MT_SMTC) + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; +@@ -122,7 +322,7 @@ void __init fixrange_init(unsigned long + for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { + if (pmd_none(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); +- set_pmd(pmd, __pmd(pte)); ++ set_pmd(pmd, __pmd((unsigned long)pte)); + if (pte != pte_offset_kernel(pmd, 0)) + BUG(); + } +@@ -132,9 +332,8 @@ void __init fixrange_init(unsigned long + } + j = 0; + } ++#endif + } +-#endif /* CONFIG_32BIT */ +-#endif /* CONFIG_HIGHMEM */ + + #ifndef CONFIG_NEED_MULTIPLE_NODES + extern void pagetable_init(void); +@@ -175,6 +374,7 @@ #endif + #ifdef CONFIG_HIGHMEM + kmap_init(); + #endif ++ kmap_coherent_init(); + + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = max_low_pfn; +diff --git a/arch/mips/mm/pgtable-32.c b/arch/mips/mm/pgtable-32.c +index 4bdaa05..4a61e62 100644 +--- a/arch/mips/mm/pgtable-32.c ++++ b/arch/mips/mm/pgtable-32.c +@@ -31,9 +31,10 @@ void pgd_init(unsigned long page) + + void __init pagetable_init(void) + { +-#ifdef CONFIG_HIGHMEM + unsigned long vaddr; +- pgd_t *pgd, *pgd_base; ++ pgd_t *pgd_base; ++#ifdef CONFIG_HIGHMEM ++ pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; +@@ -44,7 +45,6 @@ #endif + pgd_init((unsigned long)swapper_pg_dir + + sizeof(pgd_t) * USER_PTRS_PER_PGD); + +-#ifdef CONFIG_HIGHMEM + pgd_base = swapper_pg_dir; + + /* +@@ -53,6 +53,7 @@ #ifdef CONFIG_HIGHMEM + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; + fixrange_init(vaddr, 0, pgd_base); + ++#ifdef CONFIG_HIGHMEM + /* + * Permanent kmaps: + */ +diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c +index 44b5e97..8d600d3 100644 +--- a/arch/mips/mm/pgtable-64.c ++++ b/arch/mips/mm/pgtable-64.c +@@ -8,6 +8,7 @@ + */ + #include + #include ++#include + #include + + void pgd_init(unsigned long page) +@@ -52,7 +53,17 @@ void pmd_init(unsigned long addr, unsign + + void __init pagetable_init(void) + { ++ unsigned long vaddr; ++ pgd_t *pgd_base; ++ + /* Initialize the entire pgd. */ + pgd_init((unsigned long)swapper_pg_dir); + pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); ++ ++ pgd_base = swapper_pg_dir; ++ /* ++ * Fixed mappings: ++ */ ++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; ++ fixrange_init(vaddr, 0, pgd_base); + } +diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h +index 47bc8f6..d10517c 100644 +--- a/include/asm-mips/cacheflush.h ++++ b/include/asm-mips/cacheflush.h +@@ -21,7 +21,6 @@ #include + * - flush_cache_range(vma, start, end) flushes a range of pages + * - flush_icache_range(start, end) flush a range of instructions + * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache +- * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache + * + * MIPS specific flush operations: + * +@@ -39,7 +38,7 @@ extern void __flush_dcache_page(struct p + + static inline void flush_dcache_page(struct page *page) + { +- if (cpu_has_dc_aliases) ++ if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) + __flush_dcache_page(page); + + } +@@ -47,30 +46,24 @@ static inline void flush_dcache_page(str + #define flush_dcache_mmap_lock(mapping) do { } while (0) + #define flush_dcache_mmap_unlock(mapping) do { } while (0) + +-extern void (*flush_icache_page)(struct vm_area_struct *vma, ++extern void (*__flush_icache_page)(struct vm_area_struct *vma, + struct page *page); ++static inline void flush_icache_page(struct vm_area_struct *vma, ++ struct page *page) ++{ ++} ++ + extern void (*flush_icache_range)(unsigned long start, unsigned long end); + #define flush_cache_vmap(start, end) flush_cache_all() + #define flush_cache_vunmap(start, end) flush_cache_all() + +-static inline void copy_to_user_page(struct vm_area_struct *vma, ++extern void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, +- unsigned long len) +-{ +- if (cpu_has_dc_aliases) +- flush_cache_page(vma, vaddr, page_to_pfn(page)); +- memcpy(dst, src, len); +- flush_icache_page(vma, page); +-} ++ unsigned long len); + +-static inline void copy_from_user_page(struct vm_area_struct *vma, ++extern void copy_from_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, +- unsigned long len) +-{ +- if (cpu_has_dc_aliases) +- flush_cache_page(vma, vaddr, page_to_pfn(page)); +- memcpy(dst, src, len); +-} ++ unsigned long len); + + extern void (*flush_cache_sigtramp)(unsigned long addr); + extern void (*flush_icache_all)(void); +diff --git a/include/asm-mips/fixmap.h b/include/asm-mips/fixmap.h +index 6959bdb..02c8a13 100644 +--- a/include/asm-mips/fixmap.h ++++ b/include/asm-mips/fixmap.h +@@ -45,8 +45,16 @@ #endif + * fix-mapped? + */ + enum fixed_addresses { ++#define FIX_N_COLOURS 8 ++ FIX_CMAP_BEGIN, ++#ifdef CONFIG_MIPS_MT_SMTC ++ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS), ++#else ++ FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS, ++#endif + #ifdef CONFIG_HIGHMEM +- FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ ++ /* reserved pte's for temporary kernel mappings */ ++ FIX_KMAP_BEGIN = FIX_CMAP_END + 1, + FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, + #endif + __end_of_fixed_addresses +diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h +index 219d359..67bea9e 100644 +--- a/include/asm-mips/page.h ++++ b/include/asm-mips/page.h +@@ -53,19 +53,17 @@ static inline void clear_user_page(void + extern void (*flush_data_cache_page)(unsigned long addr); + + clear_page(addr); +- if (pages_do_alias((unsigned long) addr, vaddr)) ++ if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK)) + flush_data_cache_page((unsigned long)addr); + } + +-static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, +- struct page *to) +-{ +- extern void (*flush_data_cache_page)(unsigned long addr); ++extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, ++ struct page *to); ++struct vm_area_struct; ++extern void copy_user_highpage(struct page *to, struct page *from, ++ unsigned long vaddr, struct vm_area_struct *vma); + +- copy_page(vto, vfrom); +- if (pages_do_alias((unsigned long)vto, vaddr)) +- flush_data_cache_page((unsigned long)vto); +-} ++#define __HAVE_ARCH_COPY_USER_HIGHPAGE + + /* + * These are used to make use of C type-checking.. +@@ -74,15 +72,17 @@ #ifdef CONFIG_64BIT_PHYS_ADDR + #ifdef CONFIG_CPU_MIPS32 + typedef struct { unsigned long pte_low, pte_high; } pte_t; + #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) ++ #define __pte(x) ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; }) + #else + typedef struct { unsigned long long pte; } pte_t; + #define pte_val(x) ((x).pte) ++ #define __pte(x) ((pte_t) { (x) } ) + #endif + #else + typedef struct { unsigned long pte; } pte_t; + #define pte_val(x) ((x).pte) +-#endif + #define __pte(x) ((pte_t) { (x) } ) ++#endif + + /* + * For 3-level pagetables we defines these ourselves, for 2-level the diff --git a/debian/patches/bugfix/mips/dec-scsi.patch b/debian/patches/bugfix/mips/dec-scsi.patch new file mode 100644 index 000000000..59291bde5 --- /dev/null +++ b/debian/patches/bugfix/mips/dec-scsi.patch @@ -0,0 +1,32 @@ +# Upstream status: in linux-mips tree; someone needs to figure out how to +# integrate this into the Linux tree... + +From: Maciej W. Rozycki + +--- a/drivers/scsi/NCR53C9x.h 2006-03-05 20:35:04.000000000 +0100 ++++ b/drivers/scsi/NCR53C9x.h 2006-03-05 19:51:16.000000000 +0100 +@@ -145,12 +145,7 @@ + + #ifndef MULTIPLE_PAD_SIZES + +-#ifdef CONFIG_CPU_HAS_WB +-#include +-#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0) +-#else +-#define esp_write(__reg, __val) ((__reg) = (__val)) +-#endif ++#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0) + #define esp_read(__reg) (__reg) + + struct ESP_regs { +--- a/drivers/scsi/dec_esp.c ++++ b/drivers/scsi/dec_esp.c +@@ -230,7 +230,7 @@ static int dec_esp_detect(struct scsi_ho + mem_start = get_tc_base_addr(slot); + + /* Store base addr into esp struct */ +- esp->slot = CPHYSADDR(mem_start); ++ esp->slot = mem_start; + + esp->dregs = 0; + esp->eregs = (void *)CKSEG1ADDR(mem_start + diff --git a/debian/patches/bugfix/mips/dec-serial.patch b/debian/patches/bugfix/mips/dec-serial.patch new file mode 100644 index 000000000..0c52e4eb4 --- /dev/null +++ b/debian/patches/bugfix/mips/dec-serial.patch @@ -0,0 +1,197 @@ +# Upstream status: won't go into Linus' tree like this but is in the +# linux-mips tree. The drivers/char serial drivers need to be converted to +# real serial drivers in drivers/serial + +# Author: Martin Michlmayr , mostly taken from the +# linux-mips tree, with some updates by Maciej W. Rozycki. + + +--- b/drivers/char/Kconfig~ 2006-05-25 12:51:58.000000000 +0200 ++++ b/drivers/char/Kconfig 2006-05-25 12:53:03.000000000 +0200 +@@ -362,6 +362,41 @@ + bool "Console on BCM1xxx DUART" + depends on SIBYTE_SB1250_DUART + ++config SERIAL_DEC ++ bool "DECstation serial support" ++ depends on MACH_DECSTATION ++ default y ++ help ++ This selects whether you want to be asked about drivers for ++ DECstation serial ports. ++ ++ Note that the answer to this question won't directly affect the ++ kernel: saying N will just cause the configurator to skip all ++ the questions about DECstation serial ports. ++ ++ If unsure, say Y. ++ ++config SERIAL_DEC_CONSOLE ++ bool "Support for console on a DECstation serial port" ++ depends on SERIAL_DEC ++ default y ++ help ++ If you say Y here, it will be possible to use a serial port as the ++ system console (the system console is the device which receives all ++ kernel messages and warnings and which allows logins in single user ++ mode). Note that the firmware uses ttyS0 as the serial console on ++ the Maxine and ttyS2 on the others. ++ ++ If unsure, say Y. ++ ++config ZS ++ bool "Z85C30 Serial Support" ++ depends on SERIAL_DEC ++ default y ++ help ++ Documentation on the Zilog 85C350 serial communications controller ++ is downloadable at . ++ + config QTRONIX_KEYBOARD + bool "Enable Qtronix 990P Keyboard Support" + depends on IT8712 +--- b/drivers/char/Makefile~ 2006-05-25 12:51:52.000000000 +0200 ++++ b/drivers/char/Makefile 2006-05-25 12:52:27.000000000 +0200 +@@ -50,6 +50,7 @@ + obj-$(CONFIG_VIOTAPE) += viotape.o + obj-$(CONFIG_HVCS) += hvcs.o + obj-$(CONFIG_SGI_MBCS) += mbcs.o ++obj-$(CONFIG_SERIAL_DEC) += decserial.o + + obj-$(CONFIG_PRINTER) += lp.o + obj-$(CONFIG_TIPAR) += tipar.o +--- a/drivers/char/decserial.c ++++ b/drivers/char/decserial.c +@@ -14,86 +14,84 @@ + * device. Added support for PROM console in drivers/char/tty_io.c + * instead. Although it may work to enable more than one + * console device I strongly recommend to use only one. ++ * ++ * Copyright (C) 2004 Maciej W. Rozycki + */ + ++#include + #include +-#include +- +-#ifdef CONFIG_ZS +-extern int zs_init(void); +-#endif + +-#ifdef CONFIG_DZ +-extern int dz_init(void); +-#endif ++#include ++#include + +-#ifdef CONFIG_SERIAL_CONSOLE ++extern int register_zs_hook(unsigned int channel, ++ struct dec_serial_hook *hook); ++extern int unregister_zs_hook(unsigned int channel); + ++int register_dec_serial_hook(unsigned int channel, ++ struct dec_serial_hook *hook) ++{ + #ifdef CONFIG_ZS +-extern void zs_serial_console_init(void); +-#endif +- +-#ifdef CONFIG_DZ +-extern void dz_serial_console_init(void); ++ if (IOASIC) ++ return register_zs_hook(channel, hook); + #endif ++ return 0; ++} + ++int unregister_dec_serial_hook(unsigned int channel) ++{ ++#ifdef CONFIG_ZS ++ if (IOASIC) ++ return unregister_zs_hook(channel); + #endif ++ return 0; ++} + +-/* rs_init - starts up the serial interface - +- handle normal case of starting up the serial interface */ + +-#ifdef CONFIG_SERIAL ++extern int zs_init(void); ++extern int dz_init(void); + ++/* ++ * rs_init - starts up the serial interface - ++ * handle normal case of starting up the serial interface ++ */ + int __init rs_init(void) + { +- +-#if defined(CONFIG_ZS) && defined(CONFIG_DZ) +- if (IOASIC) +- return zs_init(); +- else +- return dz_init(); +-#else +- + #ifdef CONFIG_ZS +- return zs_init(); ++ if (IOASIC) ++ return zs_init(); + #endif +- + #ifdef CONFIG_DZ +- return dz_init(); +-#endif +- ++ if (!IOASIC) ++ return dz_init(); + #endif ++ return -ENXIO; + } + + __initcall(rs_init); + +-#endif + +-#ifdef CONFIG_SERIAL_CONSOLE ++#ifdef CONFIG_SERIAL_DEC_CONSOLE + +-/* serial_console_init handles the special case of starting +- * up the console on the serial port ++extern void zs_serial_console_init(void); ++extern void dz_serial_console_init(void); ++ ++/* ++ * dec_serial_console_init handles the special case of starting ++ * up the console on the serial port + */ +-static int __init decserial_console_init(void) ++static int __init dec_serial_console_init(void) + { +-#if defined(CONFIG_ZS) && defined(CONFIG_DZ) +- if (IOASIC) +- zs_serial_console_init(); +- else +- dz_serial_console_init(); +-#else +- + #ifdef CONFIG_ZS +- zs_serial_console_init(); ++ if (IOASIC) ++ zs_serial_console_init(); + #endif +- + #ifdef CONFIG_DZ +- dz_serial_console_init(); +-#endif +- ++ if (!IOASIC) ++ dz_serial_console_init(); + #endif + return 0; + } +-console_initcall(decserial_console_init); ++console_initcall(dec_serial_console_init); + + #endif diff --git a/debian/patches/bugfix/mips/header-exports.patch b/debian/patches/bugfix/mips/header-exports.patch new file mode 100644 index 000000000..ef2e93023 --- /dev/null +++ b/debian/patches/bugfix/mips/header-exports.patch @@ -0,0 +1,73 @@ +# Cleanups for kernel header exports, from linux-mips.org 2.6.18-stable, +# scheduled for mainline. + + +diff --git a/include/asm-mips/Kbuild b/include/asm-mips/Kbuild +index c68e168..7897f05 100644 +--- a/include/asm-mips/Kbuild ++++ b/include/asm-mips/Kbuild +@@ -1 +1,3 @@ + include include/asm-generic/Kbuild.asm ++ ++header-y += cachectl.h sgidefs.h sysmips.h +diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h +index 4113316..4fb0fc4 100644 +--- a/include/asm-mips/ptrace.h ++++ b/include/asm-mips/ptrace.h +@@ -10,8 +10,6 @@ #ifndef _ASM_PTRACE_H + #define _ASM_PTRACE_H + + +-#include +- + /* 0 - 31 are integer registers, 32 - 63 are fp registers. */ + #define FPR_BASE 32 + #define PC 64 +@@ -73,6 +71,7 @@ #define PTRACE_GET_THREAD_AREA_3264 0xc4 + #ifdef __KERNEL__ + + #include ++#include + + /* + * Does the process account for user or for system time? +diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h +index 98aa737..b80de8e 100644 +--- a/include/asm-mips/timex.h ++++ b/include/asm-mips/timex.h +@@ -8,6 +8,8 @@ + #ifndef _ASM_TIMEX_H + #define _ASM_TIMEX_H + ++#ifdef __KERNEL__ ++ + #include + + /* +@@ -51,4 +53,6 @@ static inline cycles_t get_cycles (void) + return read_c0_count(); + } + ++#endif /* __KERNEL__ */ ++ + #endif /* _ASM_TIMEX_H */ +diff --git a/include/asm-mips/user.h b/include/asm-mips/user.h +index 89bf8b4..61f2a09 100644 +--- a/include/asm-mips/user.h ++++ b/include/asm-mips/user.h +@@ -8,6 +8,8 @@ + #ifndef _ASM_USER_H + #define _ASM_USER_H + ++#ifdef __KERNEL__ ++ + #include + #include + +@@ -55,4 +57,6 @@ #define HOST_TEXT_START_ADDR (u.start_co + #define HOST_DATA_START_ADDR (u.start_data) + #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + ++#endif /* __KERNEL__ */ ++ + #endif /* _ASM_USER_H */ diff --git a/debian/patches/bugfix/mips/ip22-zilog-console.patch b/debian/patches/bugfix/mips/ip22-zilog-console.patch new file mode 100644 index 000000000..9dbdb8c72 --- /dev/null +++ b/debian/patches/bugfix/mips/ip22-zilog-console.patch @@ -0,0 +1,22 @@ +# Upstream status: in linux-mips tree; someone needs to figure out how to +# integrate this into the Linux tree... + +--- a/drivers/serial/ip22zilog.c ++++ b/drivers/serial/ip22zilog.c +@@ -865,6 +865,7 @@ ip22zilog_set_termios(struct uart_port * + up->cflag = termios->c_cflag; + + ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); ++ uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&up->port.lock, flags); + } +@@ -1026,6 +1027,8 @@ ip22serial_console_termios(struct consol + } + + con->cflag = cflag | CS8; /* 8N1 */ ++ ++ uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud); + } + + static int __init ip22zilog_console_setup(struct console *con, char *options) diff --git a/debian/patches/bugfix/mips/sb1-duart-tts.patch b/debian/patches/bugfix/mips/sb1-duart-tts.patch new file mode 100644 index 000000000..8f3f76507 --- /dev/null +++ b/debian/patches/bugfix/mips/sb1-duart-tts.patch @@ -0,0 +1,24 @@ +Patch: change the name of the sb1250 DUART from duart to ttyS +Needed for debian-installer +Status: the sb1250_duart.c driver needs a completely re-write... + +--- a/drivers/char/sb1250_duart.c~ 2006-09-05 15:04:15.015419723 +0200 ++++ b/drivers/char/sb1250_duart.c 2006-09-05 15:04:24.442152073 +0200 +@@ -762,7 +762,7 @@ + return -ENOMEM; + + sb1250_duart_driver->owner = THIS_MODULE; +- sb1250_duart_driver->name = "duart"; ++ sb1250_duart_driver->name = "ttyS"; + sb1250_duart_driver->major = TTY_MAJOR; + sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE; + sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL; +@@ -891,7 +891,7 @@ #endif + } + + static struct console sb1250_ser_cons = { +- .name = "duart", ++ .name = "ttyS", + .write = ser_console_write, + .device = ser_console_device, + .setup = ser_console_setup, diff --git a/debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch b/debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch new file mode 100644 index 000000000..a033b72cb --- /dev/null +++ b/debian/patches/bugfix/mips/sb1-flush-cache-data-page.patch @@ -0,0 +1,67 @@ +# Add missing cache flush, fixes hang on boot from PIO-driven devices, +# proposed patch at linux-mips.org. +# +# Signed-off-by: Thiemo Seufer + +diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c +index 16bad7c..acae51c 100644 +--- a/arch/mips/mm/c-sb1.c ++++ b/arch/mips/mm/c-sb1.c +@@ -19,6 +19,7 @@ + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + #include ++#include + + #include + #include +@@ -233,6 +234,25 @@ void sb1_flush_cache_page(struct vm_area + __attribute__((alias("local_sb1_flush_cache_page"))); + #endif + ++#ifdef CONFIG_SMP ++static void sb1_flush_cache_data_page_ipi(void *info) ++{ ++ unsigned long start = (unsigned long)info; ++ ++ __sb1_writeback_inv_dcache_range(start, start + PAGE_SIZE); ++} ++ ++static void sb1_flush_cache_data_page(unsigned long addr) ++{ ++ if (in_atomic()) ++ __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE); ++ else ++ on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1); ++} ++#else ++void sb1_flush_cache_data_page(unsigned long) ++ __attribute__((alias("local_sb1_flush_cache_data_page"))); ++#endif + + /* + * Invalidate all caches on this CPU +@@ -504,7 +524,6 @@ static __init void probe_cache_sizes(voi + void sb1_cache_init(void) + { + extern char except_vec2_sb1; +- extern char handle_vec2_sb1; + + /* Special cache error handler for SB1 */ + set_uncached_handler (0x100, &except_vec2_sb1, 0x80); +@@ -534,7 +553,7 @@ #endif + + flush_cache_sigtramp = sb1_flush_cache_sigtramp; + local_flush_data_cache_page = (void *) sb1_nop; +- flush_data_cache_page = (void *) sb1_nop; ++ flush_data_cache_page = sb1_flush_cache_data_page; + + /* Full flush */ + __flush_cache_all = sb1___flush_cache_all; +@@ -558,5 +577,5 @@ #endif + : + : "memory"); + +- flush_cache_all(); ++ local_sb1___flush_cache_all(); + } diff --git a/debian/patches/bugfix/mips/sb1-interrupt-handler.patch b/debian/patches/bugfix/mips/sb1-interrupt-handler.patch new file mode 100644 index 000000000..ef5c40ae4 --- /dev/null +++ b/debian/patches/bugfix/mips/sb1-interrupt-handler.patch @@ -0,0 +1,76 @@ +# Fix broken interrupt routing for sb1, from linux-mips.org +# 2.6.18-stable, also in kernel.org mainline. + + +diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c +index ed325f0..a0222fa 100644 +--- a/arch/mips/sibyte/bcm1480/irq.c ++++ b/arch/mips/sibyte/bcm1480/irq.c +@@ -469,21 +469,6 @@ void bcm1480_kgdb_interrupt(struct pt_re + + #endif /* CONFIG_KGDB */ + +-static inline int dclz(unsigned long long x) +-{ +- int lz; +- +- __asm__ ( +- " .set push \n" +- " .set mips64 \n" +- " dclz %0, %1 \n" +- " .set pop \n" +- : "=r" (lz) +- : "r" (x)); +- +- return lz; +-} +- + extern void bcm1480_timer_interrupt(struct pt_regs *regs); + extern void bcm1480_mailbox_interrupt(struct pt_regs *regs); + extern void bcm1480_kgdb_interrupt(struct pt_regs *regs); +@@ -536,9 +521,9 @@ #endif + + if (mask_h) { + if (mask_h ^ 1) +- do_IRQ(63 - dclz(mask_h), regs); ++ do_IRQ(fls64(mask_h) - 1, regs); + else +- do_IRQ(127 - dclz(mask_l), regs); ++ do_IRQ(63 + fls64(mask_l), regs); + } + } + } +diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c +index 1de71ad..a451b4c 100644 +--- a/arch/mips/sibyte/sb1250/irq.c ++++ b/arch/mips/sibyte/sb1250/irq.c +@@ -419,21 +419,6 @@ static void sb1250_kgdb_interrupt(struct + + #endif /* CONFIG_KGDB */ + +-static inline int dclz(unsigned long long x) +-{ +- int lz; +- +- __asm__ ( +- " .set push \n" +- " .set mips64 \n" +- " dclz %0, %1 \n" +- " .set pop \n" +- : "=r" (lz) +- : "r" (x)); +- +- return lz; +-} +- + extern void sb1250_timer_interrupt(struct pt_regs *regs); + extern void sb1250_mailbox_interrupt(struct pt_regs *regs); + extern void sb1250_kgdb_interrupt(struct pt_regs *regs); +@@ -490,6 +475,6 @@ #endif + mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(), + R_IMR_INTERRUPT_STATUS_BASE))); + if (mask) +- do_IRQ(63 - dclz(mask), regs); ++ do_IRQ(fls64(mask) - 1, regs); + } + } diff --git a/debian/patches/bugfix/mips/sgi-ioc3.patch b/debian/patches/bugfix/mips/sgi-ioc3.patch new file mode 100644 index 000000000..b1c3ce388 --- /dev/null +++ b/debian/patches/bugfix/mips/sgi-ioc3.patch @@ -0,0 +1,164 @@ +# ioc3 driver checksumming fix, from linux-mips.org 2.6.18-stable, +# scheduled for kernel.org mainline. + + +diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig +index a2bd811..778fbae 100644 +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -467,25 +471,6 @@ config SGI_IOC3_ETH + the Ethernet-HOWTO, available from + . + +-config SGI_IOC3_ETH_HW_RX_CSUM +- bool "Receive hardware checksums" +- depends on SGI_IOC3_ETH && INET +- default y +- help +- The SGI IOC3 network adapter supports TCP and UDP checksums in +- hardware to offload processing of these checksums from the CPU. At +- the moment only acceleration of IPv4 is supported. This option +- enables offloading for checksums on receive. If unsure, say Y. +- +-config SGI_IOC3_ETH_HW_TX_CSUM +- bool "Transmit hardware checksums" +- depends on SGI_IOC3_ETH && INET +- default y +- help +- The SGI IOC3 network adapter supports TCP and UDP checksums in +- hardware to offload processing of these checksums from the CPU. At +- the moment only acceleration of IPv4 is supported. This option +- enables offloading for checksums on transmit. If unsure, say Y. + + config MIPS_SIM_NET + tristate "MIPS simulator Network device (EXPERIMENTAL)" +diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c +index 68d8af7..9837213 100644 +--- a/drivers/net/ioc3-eth.c ++++ b/drivers/net/ioc3-eth.c +@@ -5,7 +5,7 @@ + * + * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. + * +- * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle ++ * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle + * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. + * + * References: +@@ -62,12 +62,7 @@ #include + #include + #include + #include +-#include +-#include +-#include +-#include + #include +-#include + #include + + /* +@@ -95,6 +90,9 @@ struct ioc3_private { + u32 emcr, ehar_h, ehar_l; + spinlock_t ioc3_lock; + struct mii_if_info mii; ++ unsigned long flags; ++#define IOC3_FLAG_RX_CHECKSUMS 1 ++ + struct pci_dev *pdev; + + /* Members used by autonegotiation */ +@@ -522,8 +520,6 @@ static struct net_device_stats *ioc3_get + return &ip->stats; + } + +-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM +- + static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) + { + struct ethhdr *eh = eth_hdr(skb); +@@ -591,7 +587,6 @@ static void ioc3_tcpudp_checksum(struct + if (csum == 0xffff) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } +-#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */ + + static inline void ioc3_rx(struct ioc3_private *ip) + { +@@ -626,9 +621,9 @@ static inline void ioc3_rx(struct ioc3_p + goto next; + } + +-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM +- ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len); +-#endif ++ if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) ++ ioc3_tcpudp_checksum(skb, ++ w0 & ERXBUF_IPCKSUM_MASK, len); + + netif_rx(skb); + +@@ -1289,9 +1284,7 @@ #endif + dev->set_multicast_list = ioc3_set_multicast_list; + dev->set_mac_address = ioc3_set_mac_address; + dev->ethtool_ops = &ioc3_ethtool_ops; +-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM + dev->features = NETIF_F_IP_CSUM; +-#endif + + sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); + sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); +@@ -1378,7 +1371,6 @@ static int ioc3_start_xmit(struct sk_buf + uint32_t w0 = 0; + int produce; + +-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM + /* + * IOC3 has a fairly simple minded checksumming hardware which simply + * adds up the 1's complement checksum for the entire packet and +@@ -1426,7 +1418,6 @@ #ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM + + w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); + } +-#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */ + + spin_lock_irq(&ip->ioc3_lock); + +@@ -1580,12 +1571,37 @@ static u32 ioc3_get_link(struct net_devi + return rc; + } + ++static u32 ioc3_get_rx_csum(struct net_device *dev) ++{ ++ struct ioc3_private *ip = netdev_priv(dev); ++ ++ return ip->flags & IOC3_FLAG_RX_CHECKSUMS; ++} ++ ++static int ioc3_set_rx_csum(struct net_device *dev, u32 data) ++{ ++ struct ioc3_private *ip = netdev_priv(dev); ++ ++ spin_lock_bh(&ip->ioc3_lock); ++ if (data) ++ ip->flags |= IOC3_FLAG_RX_CHECKSUMS; ++ else ++ ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; ++ spin_unlock_bh(&ip->ioc3_lock); ++ ++ return 0; ++} ++ + static struct ethtool_ops ioc3_ethtool_ops = { + .get_drvinfo = ioc3_get_drvinfo, + .get_settings = ioc3_get_settings, + .set_settings = ioc3_set_settings, + .nway_reset = ioc3_nway_reset, + .get_link = ioc3_get_link, ++ .get_rx_csum = ioc3_get_rx_csum, ++ .set_rx_csum = ioc3_set_rx_csum, ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = ethtool_op_set_tx_csum + }; + + static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/debian/patches/bugfix/mips/signal-handling.patch b/debian/patches/bugfix/mips/signal-handling.patch new file mode 100644 index 000000000..35c89a70d --- /dev/null +++ b/debian/patches/bugfix/mips/signal-handling.patch @@ -0,0 +1,78 @@ +# Fix signal handling, from linux-mips.org 2.6.18-stable, scheduled for +# kernel.org mainline. + + +diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c +index 6b4d9be..b9d358e 100644 +--- a/arch/mips/kernel/signal.c ++++ b/arch/mips/kernel/signal.c +@@ -424,15 +424,11 @@ void do_signal(struct pt_regs *regs) + if (!user_mode(regs)) + return; + +- if (try_to_freeze()) +- goto no_signal; +- + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + +- + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ +@@ -446,9 +442,10 @@ void do_signal(struct pt_regs *regs) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } ++ ++ return; + } + +-no_signal: + /* + * Who's code doesn't conform to the restartable syscall convention + * dies here!!! The li instruction, a single machine instruction, +@@ -466,6 +463,7 @@ no_signal: + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 4; + } ++ regs->regs[0] = 0; /* Don't deal with this again. */ + } + + /* +diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c +index f32a229..c86a5dd 100644 +--- a/arch/mips/kernel/signal32.c ++++ b/arch/mips/kernel/signal32.c +@@ -815,9 +815,6 @@ void do_signal32(struct pt_regs *regs) + if (!user_mode(regs)) + return; + +- if (try_to_freeze()) +- goto no_signal; +- + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else +@@ -836,9 +833,10 @@ void do_signal32(struct pt_regs *regs) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } ++ ++ return; + } + +-no_signal: + /* + * Who's code doesn't conform to the restartable syscall convention + * dies here!!! The li instruction, a single machine instruction, +@@ -856,6 +854,7 @@ no_signal: + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 4; + } ++ regs->regs[0] = 0; /* Don't deal with this again. */ + } + + /* diff --git a/debian/patches/bugfix/mips/smp-cpu-bringup.patch b/debian/patches/bugfix/mips/smp-cpu-bringup.patch new file mode 100644 index 000000000..46c623146 --- /dev/null +++ b/debian/patches/bugfix/mips/smp-cpu-bringup.patch @@ -0,0 +1,85 @@ +# Fix bringup of non-contiguous CPU topology, from linux-mips.org +# 2.6.18-stable, scheduled for kernel.org mainline. + + +diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h +index 896550b..d35c617 100644 +--- a/include/asm-mips/irq.h ++++ b/include/asm-mips/irq.h +@@ -76,8 +76,4 @@ extern int setup_irq_smtc(unsigned int i + unsigned long hwmask); + #endif /* CONFIG_MIPS_MT_SMTC */ + +-#ifdef CONFIG_SMP +-#define ARCH_HAS_IRQ_PER_CPU +-#endif +- + #endif /* _ASM_IRQ_H */ +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 330f6ab..96165d7 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -614,6 +610,7 @@ config SGI_IP27 + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_NUMA ++ select SYS_SUPPORTS_SMP + help + This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics + workstations. To compile a Linux kernel that runs on these, say Y +@@ -1649,9 +1648,7 @@ config GENERIC_IRQ_PROBE + default y + + config IRQ_PER_CPU +- depends on SMP + bool +- default y + + # + # - Highmem only makes sense for the 32-bit kernel. +@@ -1691,9 +1688,6 @@ config ARCH_DISCONTIGMEM_ENABLE + + config ARCH_SPARSEMEM_ENABLE + bool +- +-config ARCH_SPARSEMEM_ENABLE +- bool + select SPARSEMEM_STATIC + + config NUMA +@@ -1719,6 +1713,7 @@ source "mm/Kconfig" + config SMP + bool "Multi-Processing support" + depends on SYS_SUPPORTS_SMP ++ select IRQ_PER_CPU + help + This enables support for systems with more than one CPU. If you have + a system with only one CPU, like most personal computers, say N. If +diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c +index 2218958..1af3612 100644 +--- a/arch/mips/kernel/smp.c ++++ b/arch/mips/kernel/smp.c +@@ -467,14 +467,18 @@ static DEFINE_PER_CPU(struct cpu, cpu_de + + static int __init topology_init(void) + { +- int cpu; +- int ret; ++ int i, ret; + +- for_each_present_cpu(cpu) { +- ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu); ++#ifdef CONFIG_NUMA ++ for_each_online_node(i) ++ register_one_node(i); ++#endif /* CONFIG_NUMA */ ++ ++ for_each_present_cpu(i) { ++ ret = register_cpu(&per_cpu(cpu_devices, i), i); + if (ret) + printk(KERN_WARNING "topology_init: register_cpu %d " +- "failed (%d)\n", cpu, ret); ++ "failed (%d)\n", i, ret); + } + + return 0; diff --git a/debian/patches/bugfix/mips/syscall-wiring.patch b/debian/patches/bugfix/mips/syscall-wiring.patch new file mode 100644 index 000000000..1c2024529 --- /dev/null +++ b/debian/patches/bugfix/mips/syscall-wiring.patch @@ -0,0 +1,54 @@ +# Fix syscall wiring for n32 rt_sigqueueinfo, fix implementation of +# sys_set_thread_area. Patch from linux-mips.org 2.6.18-stable, +# scheduled for kernel.org mainline. + + +diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c +index 450ac59..dc500e2 100644 +--- a/arch/mips/kernel/linux32.c ++++ b/arch/mips/kernel/linux32.c +@@ -1296,9 +1296,3 @@ _sys32_clone(nabi_no_regargs struct pt_r + return do_fork(clone_flags, newsp, ®s, 0, + parent_tidptr, child_tidptr); + } +- +-extern asmlinkage void sys_set_thread_area(u32 addr); +-asmlinkage void sys32_set_thread_area(u32 addr) +-{ +- sys_set_thread_area(AA(addr)); +-} +diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c +index 0721314..9951240 100644 +--- a/arch/mips/kernel/syscall.c ++++ b/arch/mips/kernel/syscall.c +@@ -263,7 +263,7 @@ asmlinkage int sys_olduname(struct oldol + return error; + } + +-void sys_set_thread_area(unsigned long addr) ++asmlinkage int sys_set_thread_area(unsigned long addr) + { + struct thread_info *ti = task_thread_info(current); + +@@ -271,6 +271,8 @@ void sys_set_thread_area(unsigned long a + + /* If some future MIPS implementation has this register in hardware, + * we will need to update it here (and in context switches). */ ++ ++ return 0; + } + + asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) +diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S +index 98abbc5..f25c2a2 100644 +--- a/arch/mips/kernel/scall64-n32.S ++++ b/arch/mips/kernel/scall64-n32.S +@@ -247,7 +247,7 @@ EXPORT(sysn32_call_table) + PTR sys_capset + PTR sys32_rt_sigpending /* 6125 */ + PTR compat_sys_rt_sigtimedwait +- PTR sys_rt_sigqueueinfo ++ PTR sys32_rt_sigqueueinfo + PTR sysn32_rt_sigsuspend + PTR sys32_sigaltstack + PTR compat_sys_utime /* 6130 */ diff --git a/debian/patches/bugfix/mips/trylock.patch b/debian/patches/bugfix/mips/trylock.patch new file mode 100644 index 000000000..f5d719e89 --- /dev/null +++ b/debian/patches/bugfix/mips/trylock.patch @@ -0,0 +1,61 @@ +# Fix __raw_read_trylock implementaation for mips/mipsel, from +# linux-mips.org 2.6.18-stable, scheduled for kernel.org mainline. + + +diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h +index 669b8e3..4c1a1b5 100644 +--- a/include/asm-mips/spinlock.h ++++ b/include/asm-mips/spinlock.h +@@ -239,7 +239,51 @@ static inline void __raw_write_unlock(ra + : "memory"); + } + +-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) ++static inline int __raw_read_trylock(raw_rwlock_t *rw) ++{ ++ unsigned int tmp; ++ int ret; ++ ++ if (R10000_LLSC_WAR) { ++ __asm__ __volatile__( ++ " .set noreorder # __raw_read_trylock \n" ++ " li %2, 0 \n" ++ "1: ll %1, %3 \n" ++ " bnez %1, 2f \n" ++ " addu %1, 1 \n" ++ " sc %1, %0 \n" ++ " beqzl %1, 1b \n" ++ " .set reorder \n" ++#ifdef CONFIG_SMP ++ " sync \n" ++#endif ++ " li %2, 1 \n" ++ "2: \n" ++ : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) ++ : "m" (rw->lock) ++ : "memory"); ++ } else { ++ __asm__ __volatile__( ++ " .set noreorder # __raw_read_trylock \n" ++ " li %2, 0 \n" ++ "1: ll %1, %3 \n" ++ " bnez %1, 2f \n" ++ " addu %1, 1 \n" ++ " sc %1, %0 \n" ++ " beqz %1, 1b \n" ++ " .set reorder \n" ++#ifdef CONFIG_SMP ++ " sync \n" ++#endif ++ " li %2, 1 \n" ++ "2: \n" ++ : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) ++ : "m" (rw->lock) ++ : "memory"); ++ } ++ ++ return ret; ++} + + static inline int __raw_write_trylock(raw_rwlock_t *rw) + { diff --git a/debian/patches/bugfix/mips/wait-race.patch b/debian/patches/bugfix/mips/wait-race.patch new file mode 100644 index 000000000..425515ec3 --- /dev/null +++ b/debian/patches/bugfix/mips/wait-race.patch @@ -0,0 +1,118 @@ +# Fix race condition of wait with enabled interrupts, from linux-mips.org +# 2.6.18-stable, also in kernel.org mainline. + + +diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c +index aa2caa6..8485af3 100644 +--- a/arch/mips/kernel/cpu-probe.c ++++ b/arch/mips/kernel/cpu-probe.c +@@ -38,15 +38,40 @@ static void r3081_wait(void) + + static void r39xx_wait(void) + { +- unsigned long cfg = read_c0_conf(); +- write_c0_conf(cfg | TX39_CONF_HALT); ++ local_irq_disable(); ++ if (!need_resched()) ++ write_c0_conf(read_c0_conf() | TX39_CONF_HALT); ++ local_irq_enable(); + } + ++/* ++ * There is a race when WAIT instruction executed with interrupt ++ * enabled. ++ * But it is implementation-dependent wheter the pipelie restarts when ++ * a non-enabled interrupt is requested. ++ */ + static void r4k_wait(void) + { +- __asm__(".set\tmips3\n\t" +- "wait\n\t" +- ".set\tmips0"); ++ __asm__(" .set mips3 \n" ++ " wait \n" ++ " .set mips0 \n"); ++} ++ ++/* ++ * This variant is preferable as it allows testing need_resched and going to ++ * sleep depending on the outcome atomically. Unfortunately the "It is ++ * implementation-dependent whether the pipeline restarts when a non-enabled ++ * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes ++ * using this version a gamble. ++ */ ++static void r4k_wait_irqoff(void) ++{ ++ local_irq_disable(); ++ if (!need_resched()) ++ __asm__(" .set mips3 \n" ++ " wait \n" ++ " .set mips0 \n"); ++ local_irq_enable(); + } + + /* The Au1xxx wait is available only if using 32khz counter or +@@ -56,17 +81,17 @@ int allow_au1k_wait; + static void au1k_wait(void) + { + /* using the wait instruction makes CP0 counter unusable */ +- __asm__(".set mips3\n\t" +- "cache 0x14, 0(%0)\n\t" +- "cache 0x14, 32(%0)\n\t" +- "sync\n\t" +- "nop\n\t" +- "wait\n\t" +- "nop\n\t" +- "nop\n\t" +- "nop\n\t" +- "nop\n\t" +- ".set mips0\n\t" ++ __asm__(" .set mips3 \n" ++ " cache 0x14, 0(%0) \n" ++ " cache 0x14, 32(%0) \n" ++ " sync \n" ++ " nop \n" ++ " wait \n" ++ " nop \n" ++ " nop \n" ++ " nop \n" ++ " nop \n" ++ " .set mips0 \n" + : : "r" (au1k_wait)); + } + +@@ -110,8 +135,6 @@ static inline void check_wait(void) + case CPU_R5000: + case CPU_NEVADA: + case CPU_RM7000: +- case CPU_RM9000: +- case CPU_TX49XX: + case CPU_4KC: + case CPU_4KEC: + case CPU_4KSC: +@@ -125,6 +148,10 @@ static inline void check_wait(void) + cpu_wait = r4k_wait; + printk(" available.\n"); + break; ++ case CPU_TX49XX: ++ cpu_wait = r4k_wait_irqoff; ++ printk(" available.\n"); ++ break; + case CPU_AU1000: + case CPU_AU1100: + case CPU_AU1500: +@@ -136,6 +163,14 @@ static inline void check_wait(void) + } else + printk(" unavailable.\n"); + break; ++ case CPU_RM9000: ++ if ((c->processor_id & 0x00ff) >= 0x40) { ++ cpu_wait = r4k_wait; ++ printk(" available.\n"); ++ } else { ++ printk(" unavailable.\n"); ++ } ++ break; + default: + printk(" unavailable.\n"); + break; diff --git a/debian/patches/features/mips/backtrace.patch b/debian/patches/features/mips/backtrace.patch new file mode 100644 index 000000000..a728ca49d --- /dev/null +++ b/debian/patches/features/mips/backtrace.patch @@ -0,0 +1,401 @@ +# Kernel backtraces for mips/mipsel, from linux-mips.org 2.6.18-stable, +# in kernel.org mainline. + + +diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c +index 7ab67f7..951bf9c 100644 +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -281,62 +281,63 @@ static struct mips_frame_info { + } *schedule_frame, mfinfo[64]; + static int mfinfo_num; + +-static int __init get_frame_info(struct mips_frame_info *info) ++static inline int is_ra_save_ins(union mips_instruction *ip) + { +- int i; +- void *func = info->func; +- union mips_instruction *ip = (union mips_instruction *)func; ++ /* sw / sd $ra, offset($sp) */ ++ return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && ++ ip->i_format.rs == 29 && ++ ip->i_format.rt == 31; ++} ++ ++static inline int is_jal_jalr_jr_ins(union mips_instruction *ip) ++{ ++ if (ip->j_format.opcode == jal_op) ++ return 1; ++ if (ip->r_format.opcode != spec_op) ++ return 0; ++ return ip->r_format.func == jalr_op || ip->r_format.func == jr_op; ++} ++ ++static inline int is_sp_move_ins(union mips_instruction *ip) ++{ ++ /* addiu/daddiu sp,sp,-imm */ ++ if (ip->i_format.rs != 29 || ip->i_format.rt != 29) ++ return 0; ++ if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) ++ return 1; ++ return 0; ++} ++ ++static int get_frame_info(struct mips_frame_info *info) ++{ ++ union mips_instruction *ip = info->func; ++ int i, max_insns = ++ min(128UL, info->func_size / sizeof(union mips_instruction)); ++ + info->pc_offset = -1; + info->frame_size = 0; +- for (i = 0; i < 128; i++, ip++) { +- /* if jal, jalr, jr, stop. */ +- if (ip->j_format.opcode == jal_op || +- (ip->r_format.opcode == spec_op && +- (ip->r_format.func == jalr_op || +- ip->r_format.func == jr_op))) +- break; + +- if (info->func_size && i >= info->func_size / 4) ++ for (i = 0; i < max_insns; i++, ip++) { ++ ++ if (is_jal_jalr_jr_ins(ip)) + break; +- if ( +-#ifdef CONFIG_32BIT +- ip->i_format.opcode == addiu_op && +-#endif +-#ifdef CONFIG_64BIT +- ip->i_format.opcode == daddiu_op && +-#endif +- ip->i_format.rs == 29 && +- ip->i_format.rt == 29) { +- /* addiu/daddiu sp,sp,-imm */ +- if (info->frame_size) +- continue; +- info->frame_size = - ip->i_format.simmediate; ++ if (!info->frame_size) { ++ if (is_sp_move_ins(ip)) ++ info->frame_size = - ip->i_format.simmediate; ++ continue; + } +- +- if ( +-#ifdef CONFIG_32BIT +- ip->i_format.opcode == sw_op && +-#endif +-#ifdef CONFIG_64BIT +- ip->i_format.opcode == sd_op && +-#endif +- ip->i_format.rs == 29 && +- ip->i_format.rt == 31) { +- /* sw / sd $ra, offset($sp) */ +- if (info->pc_offset != -1) +- continue; ++ if (info->pc_offset == -1 && is_ra_save_ins(ip)) { + info->pc_offset = + ip->i_format.simmediate / sizeof(long); ++ break; + } + } +- if (info->pc_offset == -1 || info->frame_size == 0) { +- if (func == schedule) +- printk("Can't analyze prologue code at %p\n", func); +- info->pc_offset = -1; +- info->frame_size = 0; +- } +- +- return 0; ++ if (info->frame_size && info->pc_offset >= 0) /* nested */ ++ return 0; ++ if (info->pc_offset < 0) /* leaf */ ++ return 1; ++ /* prologue seems boggus... */ ++ return -1; + } + + static int __init frame_info_init(void) +@@ -368,7 +369,14 @@ #else + schedule_frame = &mfinfo[0]; + #endif + for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) +- get_frame_info(&mfinfo[i]); ++ get_frame_info(mfinfo + i); ++ ++ /* ++ * Without schedule() frame info, result given by ++ * thread_saved_pc() and get_wchan() are not reliable. ++ */ ++ if (schedule_frame->pc_offset < 0) ++ printk("Can't analyze schedule() prologue at %p\n", schedule); + + mfinfo_num = i; + return 0; +@@ -427,6 +435,8 @@ #ifdef CONFIG_KALLSYMS + if (i < 0) + break; + ++ if (mfinfo[i].pc_offset < 0) ++ break; + pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; + if (!mfinfo[i].frame_size) + break; +@@ -437,3 +447,49 @@ #endif + return pc; + } + ++#ifdef CONFIG_KALLSYMS ++/* used by show_backtrace() */ ++unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, ++ unsigned long pc, unsigned long ra) ++{ ++ unsigned long stack_page; ++ struct mips_frame_info info; ++ char *modname; ++ char namebuf[KSYM_NAME_LEN + 1]; ++ unsigned long size, ofs; ++ int leaf; ++ ++ stack_page = (unsigned long)task_stack_page(task); ++ if (!stack_page) ++ return 0; ++ ++ if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) ++ return 0; ++ if (ofs == 0) ++ return 0; ++ ++ info.func = (void *)(pc - ofs); ++ info.func_size = ofs; /* analyze from start to ofs */ ++ leaf = get_frame_info(&info); ++ if (leaf < 0) ++ return 0; ++ ++ if (*sp < stack_page || ++ *sp + info.frame_size > stack_page + THREAD_SIZE - 32) ++ return 0; ++ ++ if (leaf) ++ /* ++ * For some extreme cases, get_frame_info() can ++ * consider wrongly a nested function as a leaf ++ * one. In that cases avoid to return always the ++ * same value. ++ */ ++ pc = pc != ra ? ra : 0; ++ else ++ pc = ((unsigned long *)(*sp))[info.pc_offset]; ++ ++ *sp += info.frame_size; ++ return __kernel_text_address(pc) ? pc : 0; ++} ++#endif +diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c +index 954a198..e51d8fd 100644 +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -20,6 +20,7 @@ #include + #include + #include + #include ++#include + + #include + #include +@@ -72,28 +73,68 @@ void (*board_nmi_handler_setup)(void); + void (*board_ejtag_handler_setup)(void); + void (*board_bind_eic_interrupt)(int irq, int regset); + +-/* +- * These constant is for searching for possible module text segments. +- * MODULE_RANGE is a guess of how much space is likely to be vmalloced. +- */ +-#define MODULE_RANGE (8*1024*1024) ++ ++static void show_raw_backtrace(unsigned long reg29) ++{ ++ unsigned long *sp = (unsigned long *)reg29; ++ unsigned long addr; ++ ++ printk("Call Trace:"); ++#ifdef CONFIG_KALLSYMS ++ printk("\n"); ++#endif ++ while (!kstack_end(sp)) { ++ addr = *sp++; ++ if (__kernel_text_address(addr)) ++ print_ip_sym(addr); ++ } ++ printk("\n"); ++} ++ ++#ifdef CONFIG_KALLSYMS ++static int raw_show_trace; ++static int __init set_raw_show_trace(char *str) ++{ ++ raw_show_trace = 1; ++ return 1; ++} ++__setup("raw_show_trace", set_raw_show_trace); ++ ++extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, ++ unsigned long pc, unsigned long ra); ++ ++static void show_backtrace(struct task_struct *task, struct pt_regs *regs) ++{ ++ unsigned long sp = regs->regs[29]; ++ unsigned long ra = regs->regs[31]; ++ unsigned long pc = regs->cp0_epc; ++ ++ if (raw_show_trace || !__kernel_text_address(pc)) { ++ show_raw_backtrace(sp); ++ return; ++ } ++ printk("Call Trace:\n"); ++ do { ++ print_ip_sym(pc); ++ pc = unwind_stack(task, &sp, pc, ra); ++ ra = 0; ++ } while (pc); ++ printk("\n"); ++} ++#else ++#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]); ++#endif + + /* + * This routine abuses get_user()/put_user() to reference pointers + * with at least a bit of error checking ... + */ +-void show_stack(struct task_struct *task, unsigned long *sp) ++static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) + { + const int field = 2 * sizeof(unsigned long); + long stackdata; + int i; +- +- if (!sp) { +- if (task && task != current) +- sp = (unsigned long *) task->thread.reg29; +- else +- sp = (unsigned long *) &sp; +- } ++ unsigned long *sp = (unsigned long *)regs->regs[29]; + + printk("Stack :"); + i = 0; +@@ -114,32 +155,48 @@ void show_stack(struct task_struct *task + i++; + } + printk("\n"); ++ show_backtrace(task, regs); + } + +-void show_trace(struct task_struct *task, unsigned long *stack) ++static __always_inline void prepare_frametrace(struct pt_regs *regs) + { +- const int field = 2 * sizeof(unsigned long); +- unsigned long addr; +- +- if (!stack) { +- if (task && task != current) +- stack = (unsigned long *) task->thread.reg29; +- else +- stack = (unsigned long *) &stack; +- } +- +- printk("Call Trace:"); +-#ifdef CONFIG_KALLSYMS +- printk("\n"); ++ __asm__ __volatile__( ++ ".set push\n\t" ++ ".set noat\n\t" ++#ifdef CONFIG_64BIT ++ "1: dla $1, 1b\n\t" ++ "sd $1, %0\n\t" ++ "sd $29, %1\n\t" ++ "sd $31, %2\n\t" ++#else ++ "1: la $1, 1b\n\t" ++ "sw $1, %0\n\t" ++ "sw $29, %1\n\t" ++ "sw $31, %2\n\t" + #endif +- while (!kstack_end(stack)) { +- addr = *stack++; +- if (__kernel_text_address(addr)) { +- printk(" [<%0*lx>] ", field, addr); +- print_symbol("%s\n", addr); ++ ".set pop\n\t" ++ : "=m" (regs->cp0_epc), ++ "=m" (regs->regs[29]), "=m" (regs->regs[31]) ++ : : "memory"); ++} ++ ++void show_stack(struct task_struct *task, unsigned long *sp) ++{ ++ struct pt_regs regs; ++ if (sp) { ++ regs.regs[29] = (unsigned long)sp; ++ regs.regs[31] = 0; ++ regs.cp0_epc = 0; ++ } else { ++ if (task && task != current) { ++ regs.regs[29] = task->thread.reg29; ++ regs.regs[31] = 0; ++ regs.cp0_epc = task->thread.reg31; ++ } else { ++ prepare_frametrace(®s); + } + } +- printk("\n"); ++ show_stacktrace(task, ®s); + } + + /* +@@ -147,9 +204,15 @@ #endif + */ + void dump_stack(void) + { +- unsigned long stack; ++ struct pt_regs regs; + +- show_trace(current, &stack); ++ /* ++ * Remove any garbage that may be in regs (specially func ++ * addresses) to avoid show_raw_backtrace() to report them ++ */ ++ memset(®s, 0, sizeof(regs)); ++ prepare_frametrace(®s); ++ show_backtrace(current, ®s); + } + + EXPORT_SYMBOL(dump_stack); +@@ -268,8 +331,7 @@ void show_registers(struct pt_regs *regs + print_modules(); + printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", + current->comm, current->pid, current_thread_info(), current); +- show_stack(current, (long *) regs->regs[29]); +- show_trace(current, (long *) regs->regs[29]); ++ show_stacktrace(current, regs); + show_code((unsigned int *) regs->cp0_epc); + printk("\n"); + } +@@ -292,6 +354,16 @@ #endif /* CONFIG_MIPS_MT_SMTC */ + printk("%s[#%d]:\n", str, ++die_counter); + show_registers(regs); + spin_unlock_irq(&die_lock); ++ ++ if (in_interrupt()) ++ panic("Fatal exception in interrupt"); ++ ++ if (panic_on_oops) { ++ printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); ++ ssleep(5); ++ panic("Fatal exception"); ++ } ++ + do_exit(SIGSEGV); + } + diff --git a/debian/patches/features/mips/qemu-kernel.patch b/debian/patches/features/mips/qemu-kernel.patch new file mode 100644 index 000000000..e31ee11b4 --- /dev/null +++ b/debian/patches/features/mips/qemu-kernel.patch @@ -0,0 +1,231 @@ +# Qemu kernel config for mips/mipsel, from linux-mips.org 2.6.18-stable, +# some initialization bits should eventually happen in qemu BIOS. + + +diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile +index 078cd30..493259c 100644 +--- a/arch/mips/qemu/Makefile ++++ b/arch/mips/qemu/Makefile +@@ -4,4 +4,5 @@ # + + obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o q-reset.o + ++obj-$(CONFIG_VT) += q-vga.o + obj-$(CONFIG_SMP) += q-smp.o +diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c +index 8413943..37c2f73 100644 +--- a/arch/mips/qemu/q-setup.c ++++ b/arch/mips/qemu/q-setup.c +@@ -2,6 +2,7 @@ #include + #include + #include + ++extern void qvga_init(void); + extern void qemu_reboot_setup(void); + + #define QEMU_PORT_BASE 0xb4000000 +@@ -23,5 +24,9 @@ void __init plat_timer_setup(struct irqa + void __init plat_mem_setup(void) + { + set_io_port_base(QEMU_PORT_BASE); ++#ifdef CONFIG_VT ++ qvga_init(); ++#endif ++ + qemu_reboot_setup(); + } +diff --git a/arch/mips/qemu/q-vga.c b/arch/mips/qemu/q-vga.c +new file mode 100644 +index 0000000..e26109a +--- /dev/null ++++ b/arch/mips/qemu/q-vga.c +@@ -0,0 +1,189 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2005 by Ralf Baechle (ralf@linux-mips.org) ++ * ++ * This will eventually go into the qemu firmware. ++ */ ++#include ++#include ++#include ++#include ++#include