From: Andy P. <at...@us...> - 2002-04-10 18:36:13
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/ia64/mm In directory usw-pr-cvs1:/tmp/cvs-serv12040/ia64/mm Modified Files: extable.c fault.c init.c tlb.c Log Message: synch 2.4.15 commit 36 Index: extable.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/ia64/mm/extable.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- extable.c 14 Jan 2001 19:50:52 -0000 1.1.1.1 +++ extable.c 10 Apr 2002 14:27:22 -0000 1.2 @@ -1,13 +1,14 @@ /* * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <da...@hp...> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <da...@hp...> */ #include <linux/config.h> -#include <linux/module.h> + #include <asm/uaccess.h> +#include <asm/module.h> extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; @@ -15,54 +16,66 @@ static inline const struct exception_table_entry * search_one_table (const struct exception_table_entry *first, const struct exception_table_entry *last, - signed long value) + unsigned long ip, unsigned long gp) { - /* Abort early if the search value is out of range. */ - if (value != (signed int)value) - return 0; - while (first <= last) { const struct exception_table_entry *mid; long diff; - /* - * We know that first and last are both kernel virtual - * pointers (region 7) so first+last will cause an - * overflow. We fix that by calling __va() on the - * result, which will ensure that the top two bits get - * set again. - */ - mid = (void *) __va((((__u64) first + (__u64) last)/2/sizeof(*mid))*sizeof(*mid)); - diff = mid->addr - value; + + mid = &first[(last - first)/2]; + diff = (mid->addr + gp) - ip; if (diff == 0) return mid; else if (diff < 0) - first = mid+1; + first = mid + 1; else - last = mid-1; + last = mid - 1; } return 0; } -register unsigned long gp __asm__("gp"); +#ifndef CONFIG_MODULES +register unsigned long main_gp __asm__("gp"); +#endif -const struct exception_table_entry * +struct exception_fixup search_exception_table (unsigned long addr) { -#ifndef CONFIG_MODULE + const struct exception_table_entry *entry; + struct exception_fixup fix = { 0 }; + +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ - return search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); + entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr, main_gp); + if (entry) + fix.cont = entry->cont + main_gp; + return fix; #else - struct exception_table_entry *ret; - /* The kernel is the last "module" -- no need to treat it special. */ + struct archdata *archdata; struct module *mp; + /* The kernel is the last "module" -- no need to treat it special. */ for (mp = module_list; mp ; mp = mp->next) { if (!mp->ex_table_start) continue; - ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); - if (ret) - return ret; + archdata = (struct archdata *) mp->archdata_start; + entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, + addr, (unsigned long) archdata->gp); + if (entry) { + fix.cont = entry->cont + (unsigned long) archdata->gp; + return fix; + } } - return 0; #endif + return fix; +} + +void +handle_exception (struct pt_regs *regs, struct exception_fixup fix) +{ + regs->r8 = -EFAULT; + if (fix.cont & 4) + regs->r9 = 0; + regs->cr_iip = (long) fix.cont & ~0xf; + ia64_psr(regs)->ri = fix.cont & 0x3; /* set continuation slot number */ } Index: fault.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/ia64/mm/fault.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- fault.c 14 Jan 2001 19:50:53 -0000 1.1.1.1 +++ fault.c 10 Apr 2002 14:27:22 -0000 1.2 @@ -1,8 +1,8 @@ /* * MMU fault handling support. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <da...@hp...> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <da...@hp...> */ #include <linux/sched.h> #include <linux/kernel.h> @@ -16,7 +16,7 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> -extern void die_if_kernel (char *, struct pt_regs *, long); +extern void die (char *, struct pt_regs *, long); /* * This routine is analogous to expand_stack() but instead grows the @@ -46,21 +46,20 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { - struct mm_struct *mm = current->mm; - const struct exception_table_entry *fix; + int signal = SIGSEGV, code = SEGV_MAPERR; struct vm_area_struct *vma, *prev_vma; + struct mm_struct *mm = current->mm; + struct exception_fixup fix; struct siginfo si; - int signal = SIGSEGV; unsigned long mask; /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. + * If we're in an interrupt or have no user context, we must not take the fault.. */ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma_prev(mm, address, &prev_vma); if (!vma) @@ -71,6 +70,8 @@ goto check_expansion; good_area: + code = SEGV_ACCERR; + /* OK, we've got a good vm_area for this memory area. Check the access permissions: */ # define VM_READ_BIT 0 @@ -89,12 +90,13 @@ if ((vma->vm_flags & mask) != mask) goto bad_area; + survive: /* * If for any reason at all we couldn't handle the fault, make * sure we exit gracefully rather than endlessly redo the * fault. */ - switch (handle_mm_fault(mm, vma, address, mask) != 0) { + switch (handle_mm_fault(mm, vma, address, mask)) { case 1: ++current->min_flt; break; @@ -112,7 +114,7 @@ default: goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; check_expansion: @@ -135,7 +137,7 @@ goto good_area; bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (isr & IA64_ISR_SP) { /* * This fault was due to a speculative load set the "ed" bit in the psr to @@ -147,7 +149,7 @@ if (user_mode(regs)) { si.si_signo = signal; si.si_errno = 0; - si.si_code = SI_KERNEL; + si.si_code = code; si.si_addr = (void *) address; force_sig_info(signal, &si, current); return; @@ -163,29 +165,40 @@ return; } +#ifdef GAS_HAS_LOCAL_TAGS + fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); +#else fix = search_exception_table(regs->cr_iip); - if (fix) { - regs->r8 = -EFAULT; - if (fix->skip & 1) { - regs->r9 = 0; - } - regs->cr_iip += ((long) fix->skip) & ~15; - regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ +#endif + if (fix.cont) { + handle_exception(regs, fix); return; } /* - * Oops. The kernel tried to access some bad page. We'll have - * to terminate things with extreme prejudice. + * Oops. The kernel tried to access some bad page. We'll have to terminate things + * with extreme prejudice. */ - printk(KERN_ALERT "Unable to handle kernel paging request at " - "virtual address %016lx\n", address); - die_if_kernel("Oops", regs, isr); + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request at " + "virtual address %016lx\n", address); + die("Oops", regs, isr); + bust_spinlocks(0); do_exit(SIGKILL); return; out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); + if (current->pid == 1) { + current->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); Index: init.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/ia64/mm/init.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- init.c 14 Jan 2001 19:50:55 -0000 1.1.1.1 +++ init.c 10 Apr 2002 14:27:22 -0000 1.2 @@ -1,8 +1,8 @@ /* * Initialize MMU support. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <da...@hp...> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <da...@hp...> */ #include <linux/config.h> #include <linux/kernel.h> @@ -23,116 +23,36 @@ #include <asm/pgalloc.h> #include <asm/sal.h> #include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; /* References to section boundaries: */ extern char _stext, _etext, _edata, __init_begin, __init_end; -/* - * These are allocated in head.S so that we get proper page alignment. - * If you change the size of these then change head.S as well. - */ -extern char empty_bad_page[PAGE_SIZE]; -extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; -extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; - extern void ia64_tlb_init (void); -static unsigned long totalram_pages; - -/* - * Fill in empty_bad_pmd_table with entries pointing to - * empty_bad_pte_table and return the address of this PMD table. - */ -static pmd_t * -get_bad_pmd_table (void) -{ - pmd_t v; - int i; - - pmd_set(&v, empty_bad_pte_table); - - for (i = 0; i < PTRS_PER_PMD; ++i) - empty_bad_pmd_table[i] = v; - - return empty_bad_pmd_table; -} - -/* - * Fill in empty_bad_pte_table with PTEs pointing to empty_bad_page - * and return the address of this PTE table. - */ -static pte_t * -get_bad_pte_table (void) -{ - pte_t v; - int i; - - set_pte(&v, pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED))); - - for (i = 0; i < PTRS_PER_PTE; ++i) - empty_bad_pte_table[i] = v; +unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; - return empty_bad_pte_table; -} - -void -__handle_bad_pgd (pgd_t *pgd) -{ - pgd_ERROR(*pgd); - pgd_set(pgd, get_bad_pmd_table()); -} - -void -__handle_bad_pmd (pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set(pmd, get_bad_pte_table()); -} - -/* - * Allocate and initialize an L3 directory page and set - * the L2 directory entry PMD to the newly allocated page. - */ -pte_t* -get_pte_slow (pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - /* everything A-OK */ - clear_page(pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long) pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} +static unsigned long totalram_pages; int do_check_pgt_cache (int low, int high) { int freed = 0; - if (pgtable_cache_size > high) { - do { - if (pgd_quicklist) - free_page((unsigned long)get_pgd_fast()), ++freed; - if (pmd_quicklist) - free_page((unsigned long)get_pmd_fast()), ++freed; - if (pte_quicklist) - free_page((unsigned long)get_pte_fast()), ++freed; - } while (pgtable_cache_size > low); - } - return freed; + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed; + if (pmd_quicklist) + free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed; + if (pte_quicklist) + free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed; + } while (pgtable_cache_size > low); + } + return freed; } /* @@ -188,21 +108,21 @@ { /* * EFI uses 4KB pages while the kernel can use 4KB or bigger. - * Thus EFI and the kernel may have different page sizes. It is - * therefore possible to have the initrd share the same page as - * the end of the kernel (given current setup). + * Thus EFI and the kernel may have different page sizes. It is + * therefore possible to have the initrd share the same page as + * the end of the kernel (given current setup). * * To avoid freeing/using the wrong page (kernel sized) we: - * - align up the beginning of initrd - * - keep the end untouched + * - align up the beginning of initrd + * - align down the end of initrd * * | | * |=============| a000 * | | * | | * | | 9000 - * |/////////////| - * |/////////////| + * |/////////////| + * |/////////////| * |=============| 8000 * |///INITRD////| * |/////////////| @@ -211,18 +131,21 @@ * |KKKKKKKKKKKKK| * |=============| 6000 * |KKKKKKKKKKKKK| - * |KKKKKKKKKKKKK| + * |KKKKKKKKKKKKK| * K=kernel using 8KB pages - * + * * In this example, we must free page 8000 ONLY. So we must align up * initrd_start and keep initrd_end as is. */ start = PAGE_ALIGN(start); + end = end & PAGE_MASK; if (start < end) printk ("Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { + if (!VALID_PAGE(virt_to_page(start))) + continue; clear_bit(PG_reserved, &virt_to_page(start)->flags); set_page_count(virt_to_page(start), 1); free_page(start); @@ -244,13 +167,40 @@ } void -show_mem (void) +show_mem(void) { int i, total = 0, reserved = 0; int shared = 0, cached = 0; printk("Mem-info:\n"); show_free_areas(); + +#ifdef CONFIG_DISCONTIGMEM + { + pg_data_t *pgdat = pgdat_list; + + printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + do { + printk("Node ID: %d\n", pgdat->node_id); + for(i = 0; i < pgdat->node_size; i++) { + if (PageReserved(pgdat->node_mem_map+i)) + reserved++; + else if (PageSwapCache(pgdat->node_mem_map+i)) + cached++; + else if (page_count(pgdat->node_mem_map + i)) + shared += page_count(pgdat->node_mem_map + i) - 1; + } + printk("\t%d pages of RAM\n", pgdat->node_size); + printk("\t%d reserved pages\n", reserved); + printk("\t%d pages shared\n", shared); + printk("\t%d pages swap cached\n", cached); + pgdat = pgdat->node_next; + } while (pgdat); + printk("Total of %ld pages in page table cache\n", pgtable_cache_size); + show_buffers(); + printk("%d free buffer pages\n", nr_free_buffer_pages()); + } +#else /* !CONFIG_DISCONTIGMEM */ printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); i = max_mapnr; while (i-- > 0) { @@ -268,6 +218,7 @@ printk("%d pages swap cached\n", cached); printk("%ld pages in page table cache\n", pgtable_cache_size); show_buffers(); +#endif /* !CONFIG_DISCONTIGMEM */ } /* @@ -286,52 +237,58 @@ page_address(page)); pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - panic("Out of memory."); - return 0; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - panic("Out of memory."); - return 0; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return 0; + + spin_lock(&init_mm.page_table_lock); + { + pmd = pmd_alloc(&init_mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(&init_mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) { + pte_ERROR(*pte); + goto out; + } + flush_page_to_ram(page); + set_pte(pte, mk_pte(page, PAGE_GATE)); } - flush_page_to_ram(page); - set_pte(pte, mk_pte(page, PAGE_GATE)); + out: spin_unlock(&init_mm.page_table_lock); /* no need for flush_tlb */ return page; } void __init -ia64_rid_init (void) +ia64_mmu_init (void *my_cpu_data) { unsigned long flags, rid, pta, impl_va_bits; + extern void __init tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 #else # define VHPT_ENABLE_BIT 1 #endif - /* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */ + /* + * Set up the kernel identity mapping for regions 6 and 5. The mapping for region + * 7 is setup up in _start(). + */ ia64_clear_ic(flags); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET); - ia64_set_rr(PAGE_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2)); rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); + /* ensure rr6 is up-to-date before inserting the PERCPU_ADDR translation: */ + ia64_srlz_d(); + + ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, + pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT); + __restore_flags(flags); + ia64_srlz_i(); /* * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped @@ -356,7 +313,7 @@ # define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) # define POW2(n) (1ULL << (n)) - impl_va_bits = ffz(~my_cpu_data.unimpl_va_mask); + impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); if (impl_va_bits < 51 || impl_va_bits > 61) panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); @@ -374,6 +331,8 @@ * enabled. */ ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); + + ia64_tlb_init(); } /* @@ -390,7 +349,7 @@ memset(zones_size, 0, sizeof(zones_size)); - max_dma = (PAGE_ALIGN(MAX_DMA_ADDRESS) >> PAGE_SHIFT); + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; if (max_low_pfn < max_dma) zones_size[ZONE_DMA] = max_low_pfn; else { @@ -428,6 +387,7 @@ { extern char __start_gate_section[]; long reserved_pages, codesize, datasize, initsize; + unsigned long num_pgt_pages; #ifdef CONFIG_PCI /* @@ -460,6 +420,19 @@ (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10), max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); + + /* + * Allow for enough (cached) page table pages so that we can map the entire memory + * at least once. Each task also needs a couple of page tables pages, so add in a + * fudge factor for that (don't use "threads-max" here; that would be wrong!). + * Don't allow the cache to be more than 10% of total memory, though. + */ +# define NUM_TASKS 500 /* typical number of tasks */ + num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS; + if (num_pgt_pages > nr_free_pages() / 10) + num_pgt_pages = nr_free_pages() / 10; + if (num_pgt_pages > pgt_cache_water[1]) + pgt_cache_water[1] = num_pgt_pages; /* install the gate page in the global page table: */ put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); Index: tlb.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/ia64/mm/tlb.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- tlb.c 14 Jan 2001 19:50:55 -0000 1.1.1.1 +++ tlb.c 10 Apr 2002 14:27:22 -0000 1.2 @@ -1,11 +1,11 @@ /* * TLB support routines. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <da...@hp...> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <da...@hp...> * - * 08/02/00 A. Mallick <asi...@in...> - * Modified RID allocation for SMP + * 08/02/00 A. Mallick <asi...@in...> + * Modified RID allocation for SMP * Goutham Rao <gou...@in...> * IPI based ptc implementation and A-step IPI implementation. */ @@ -41,88 +41,6 @@ }; /* - * Seralize usage of ptc.g - */ -spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see <asm/pgtable.h> */ - -#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) - -#include <linux/irq.h> - -unsigned long flush_end, flush_start, flush_nbits, flush_rid; -atomic_t flush_cpu_count; - -/* - * flush_tlb_no_ptcg is called with ptcg_lock locked - */ -static inline void -flush_tlb_no_ptcg (unsigned long start, unsigned long end, unsigned long nbits) -{ - extern void smp_send_flush_tlb (void); - unsigned long saved_tpr = 0; - unsigned long flags; - - /* - * Some times this is called with interrupts disabled and causes - * dead-lock; to avoid this we enable interrupt and raise the TPR - * to enable ONLY IPI. - */ - __save_flags(flags); - if (!(flags & IA64_PSR_I)) { - saved_tpr = ia64_get_tpr(); - ia64_srlz_d(); - ia64_set_tpr(IPI_IRQ - 16); - ia64_srlz_d(); - local_irq_enable(); - } - - spin_lock(&ptcg_lock); - flush_rid = ia64_get_rr(start); - ia64_srlz_d(); - flush_start = start; - flush_end = end; - flush_nbits = nbits; - atomic_set(&flush_cpu_count, smp_num_cpus - 1); - smp_send_flush_tlb(); - /* - * Purge local TLB entries. ALAT invalidation is done in ia64_leave_kernel. - */ - do { - asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - - ia64_srlz_i(); /* srlz.i implies srlz.d */ - - /* - * Wait for other CPUs to finish purging entries. - */ -#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) - { - unsigned long start = ia64_get_itc(); - while (atomic_read(&flush_cpu_count) > 0) { - if ((ia64_get_itc() - start) > 40000UL) { - atomic_set(&flush_cpu_count, smp_num_cpus - 1); - smp_send_flush_tlb(); - start = ia64_get_itc(); - } - } - } -#else - while (atomic_read(&flush_cpu_count)) { - /* Nothing */ - } -#endif - if (!(flags & IA64_PSR_I)) { - local_irq_disable(); - ia64_set_tpr(saved_tpr); - ia64_srlz_d(); - } -} - -#endif /* CONFIG_SMP && !CONFIG_ITANIUM_PTCG */ - -/* * Acquire the ia64_ctx.lock before calling this function! */ void @@ -148,7 +66,7 @@ if (tsk_context == ia64_ctx.next) { if (++ia64_ctx.next >= ia64_ctx.limit) { /* empty range: reset the range limit and start over */ - if (ia64_ctx.next > max_ctx) + if (ia64_ctx.next > max_ctx) ia64_ctx.next = 300; ia64_ctx.limit = max_ctx + 1; goto repeat; @@ -161,16 +79,36 @@ flush_tlb_all(); } +static inline void +ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) +{ + static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; + + /* HW requires global serialization of ptc.ga. */ + spin_lock(&ptcg_lock); + { + do { + /* + * Flush ALAT entries also. + */ + asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) + : "memory"); + start += (1UL << nbits); + } while (start < end); + } + spin_unlock(&ptcg_lock); +} + void __flush_tlb_all (void) { unsigned long i, j, flags, count0, count1, stride0, stride1, addr; - addr = my_cpu_data.ptce_base; - count0 = my_cpu_data.ptce_count[0]; - count1 = my_cpu_data.ptce_count[1]; - stride0 = my_cpu_data.ptce_stride[0]; - stride1 = my_cpu_data.ptce_stride[1]; + addr = local_cpu_data->ptce_base; + count0 = local_cpu_data->ptce_count[0]; + count1 = local_cpu_data->ptce_count[1]; + stride0 = local_cpu_data->ptce_stride[0]; + stride1 = local_cpu_data->ptce_stride[1]; local_irq_save(flags); for (i = 0; i < count0; ++i) { @@ -221,23 +159,15 @@ } start &= ~((1UL << nbits) - 1); -#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) - flush_tlb_no_ptcg(start, end, nbits); -#else - spin_lock(&ptcg_lock); - do { # ifdef CONFIG_SMP - /* - * Flush ALAT entries also. - */ - asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory"); + platform_global_tlb_purge(start, end, nbits); # else + do { asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); -# endif start += (1UL << nbits); } while (start < end); -#endif /* CONFIG_SMP && !defined(CONFIG_ITANIUM_PTCG) */ - spin_unlock(&ptcg_lock); +# endif + ia64_insn_group_barrier(); ia64_srlz_i(); /* srlz.i implies srlz.d */ ia64_insn_group_barrier(); @@ -249,11 +179,11 @@ ia64_ptce_info_t ptce_info; ia64_get_ptce(&ptce_info); - my_cpu_data.ptce_base = ptce_info.base; - my_cpu_data.ptce_count[0] = ptce_info.count[0]; - my_cpu_data.ptce_count[1] = ptce_info.count[1]; - my_cpu_data.ptce_stride[0] = ptce_info.stride[0]; - my_cpu_data.ptce_stride[1] = ptce_info.stride[1]; + local_cpu_data->ptce_base = ptce_info.base; + local_cpu_data->ptce_count[0] = ptce_info.count[0]; + local_cpu_data->ptce_count[1] = ptce_info.count[1]; + local_cpu_data->ptce_stride[0] = ptce_info.stride[0]; + local_cpu_data->ptce_stride[1] = ptce_info.stride[1]; __flush_tlb_all(); /* nuke left overs from bootstrapping... */ } |