Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tile: support CONFIG_PREEMPT

This change adds support for CONFIG_PREEMPT (full kernel preemption).
In addition to the core support, this change includes a number
of places where we fix up uses of smp_processor_id() and per-cpu
variables. I also eliminate the PAGE_HOME_HERE and PAGE_HOME_UNKNOWN
values for page homing, as it turns out they weren't being used.

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>

+98 -45
+2
arch/tile/Kconfig
··· 301 301 302 302 source "mm/Kconfig" 303 303 304 + source "kernel/Kconfig.preempt" 305 + 304 306 config CMDLINE_BOOL 305 307 bool "Built-in kernel command line" 306 308 default n
-8
arch/tile/include/asm/homecache.h
··· 44 44 */ 45 45 #define PAGE_HOME_INCOHERENT -3 46 46 47 - #if CHIP_HAS_CBOX_HOME_MAP() 48 47 /* Home for the page is distributed via hash-for-home. */ 49 48 #define PAGE_HOME_HASH -4 50 - #endif 51 - 52 - /* Homing is unknown or unspecified. Not valid for page_home(). */ 53 - #define PAGE_HOME_UNKNOWN -5 54 - 55 - /* Home on the current cpu. Not valid for page_home(). */ 56 - #define PAGE_HOME_HERE -6 57 49 58 50 /* Support wrapper to use instead of explicit hv_flush_remote(). */ 59 51 extern void flush_remote(unsigned long cache_pfn, unsigned long cache_length,
+18 -3
arch/tile/include/asm/irqflags.h
··· 124 124 DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); 125 125 #define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR) 126 126 127 + #ifdef CONFIG_DEBUG_PREEMPT 128 + /* Due to inclusion issues, we can't rely on <linux/smp.h> here. */ 129 + extern unsigned int debug_smp_processor_id(void); 130 + # define smp_processor_id() debug_smp_processor_id() 131 + #endif 132 + 127 133 /* Disable interrupts. */ 128 134 #define arch_local_irq_disable() \ 129 135 interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS) ··· 138 132 #define arch_local_irq_disable_all() \ 139 133 interrupt_mask_set_mask(-1ULL) 140 134 135 + /* 136 + * Read the set of maskable interrupts. 137 + * We avoid the preemption warning here via __this_cpu_ptr since even 138 + * if irqs are already enabled, it's harmless to read the wrong cpu's 139 + * enabled mask. 140 + */ 141 + #define arch_local_irqs_enabled() \ 142 + (*__this_cpu_ptr(&interrupts_enabled_mask)) 143 + 141 144 /* Re-enable all maskable interrupts. */ 142 145 #define arch_local_irq_enable() \ 143 - interrupt_mask_reset_mask(__get_cpu_var(interrupts_enabled_mask)) 146 + interrupt_mask_reset_mask(arch_local_irqs_enabled()) 144 147 145 148 /* Disable or enable interrupts based on flag argument. */ 146 149 #define arch_local_irq_restore(disabled) do { \ ··· 176 161 177 162 /* Prevent the given interrupt from being enabled next time we enable irqs. */ 178 163 #define arch_local_irq_mask(interrupt) \ 179 - (__get_cpu_var(interrupts_enabled_mask) &= ~(1ULL << (interrupt))) 164 + this_cpu_and(interrupts_enabled_mask, ~(1ULL << (interrupt))) 180 165 181 166 /* Prevent the given interrupt from being enabled immediately. */ 182 167 #define arch_local_irq_mask_now(interrupt) do { \ ··· 186 171 187 172 /* Allow the given interrupt to be enabled next time we enable irqs. */ 188 173 #define arch_local_irq_unmask(interrupt) \ 189 - (__get_cpu_var(interrupts_enabled_mask) |= (1ULL << (interrupt))) 174 + this_cpu_or(interrupts_enabled_mask, (1ULL << (interrupt))) 190 175 191 176 /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */ 192 177 #define arch_local_irq_unmask_now(interrupt) do { \
+2
arch/tile/kernel/asm-offsets.c
··· 58 58 offsetof(struct thread_info, status)); 59 59 DEFINE(THREAD_INFO_HOMECACHE_CPU_OFFSET, 60 60 offsetof(struct thread_info, homecache_cpu)); 61 + DEFINE(THREAD_INFO_PREEMPT_COUNT_OFFSET, 62 + offsetof(struct thread_info, preempt_count)); 61 63 DEFINE(THREAD_INFO_STEP_STATE_OFFSET, 62 64 offsetof(struct thread_info, step_state)); 63 65 #ifdef __tilegx__
+9 -9
arch/tile/kernel/hardwall.c
··· 272 272 struct hardwall_info *r = info; 273 273 struct hardwall_type *hwt = r->type; 274 274 275 - int cpu = smp_processor_id(); 276 - int x = cpu % smp_width; 277 - int y = cpu / smp_width; 275 + int cpu = smp_processor_id(); /* on_each_cpu disables preemption */ 276 + int x = cpu_x(cpu); 277 + int y = cpu_y(cpu); 278 278 int bits = 0; 279 279 if (x == r->ulhc_x) 280 280 bits |= W_PROTECT; ··· 317 317 on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1); 318 318 } 319 319 320 + /* Entered from INT_xDN_FIREWALL interrupt vector with irqs disabled. */ 320 321 void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) 321 322 { 322 323 struct hardwall_info *rect; ··· 326 325 struct siginfo info; 327 326 int cpu = smp_processor_id(); 328 327 int found_processes; 329 - unsigned long flags; 330 328 struct pt_regs *old_regs = set_irq_regs(regs); 331 329 332 330 irq_enter(); ··· 346 346 BUG_ON(hwt->disabled); 347 347 348 348 /* This tile trapped a network access; find the rectangle. */ 349 - spin_lock_irqsave(&hwt->lock, flags); 349 + spin_lock(&hwt->lock); 350 350 list_for_each_entry(rect, &hwt->list, list) { 351 351 if (cpumask_test_cpu(cpu, &rect->cpumask)) 352 352 break; ··· 401 401 pr_notice("hardwall: no associated processes!\n"); 402 402 403 403 done: 404 - spin_unlock_irqrestore(&hwt->lock, flags); 404 + spin_unlock(&hwt->lock); 405 405 406 406 /* 407 407 * We have to disable firewall interrupts now, or else when we ··· 661 661 return -EINVAL; 662 662 663 663 printk(KERN_DEBUG "Pid %d (%s) deactivated for %s hardwall: cpu %d\n", 664 - task->pid, task->comm, hwt->name, smp_processor_id()); 664 + task->pid, task->comm, hwt->name, raw_smp_processor_id()); 665 665 return 0; 666 666 } 667 667 ··· 803 803 /* Reset UDN coordinates to their standard value */ 804 804 { 805 805 unsigned int cpu = smp_processor_id(); 806 - unsigned int x = cpu % smp_width; 807 - unsigned int y = cpu / smp_width; 806 + unsigned int x = cpu_x(cpu); 807 + unsigned int y = cpu_y(cpu); 808 808 __insn_mtspr(SPR_UDN_TILE_COORD, (x << 18) | (y << 7)); 809 809 } 810 810
+20 -7
arch/tile/kernel/intvec_32.S
··· 28 28 #include <arch/interrupts.h> 29 29 #include <arch/spr_def.h> 30 30 31 - #ifdef CONFIG_PREEMPT 32 - # error "No support for kernel preemption currently" 33 - #endif 34 - 35 31 #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) 36 32 37 33 #define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) ··· 808 812 } 809 813 lw r29, r29 810 814 andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ 815 + bzt r29, .Lresume_userspace 816 + 817 + #ifdef CONFIG_PREEMPT 818 + /* Returning to kernel space. Check if we need preemption. */ 819 + GET_THREAD_INFO(r29) 820 + addli r28, r29, THREAD_INFO_FLAGS_OFFSET 811 821 { 812 - bzt r29, .Lresume_userspace 813 - PTREGS_PTR(r29, PTREGS_OFFSET_PC) 822 + lw r28, r28 823 + addli r29, r29, THREAD_INFO_PREEMPT_COUNT_OFFSET 814 824 } 825 + { 826 + andi r28, r28, _TIF_NEED_RESCHED 827 + lw r29, r29 828 + } 829 + bzt r28, 1f 830 + bnz r29, 1f 831 + jal preempt_schedule_irq 832 + FEEDBACK_REENTER(interrupt_return) 833 + 1: 834 + #endif 815 835 816 836 /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ 817 837 { 818 - lw r28, r29 838 + PTREGS_PTR(r29, PTREGS_OFFSET_PC) 819 839 moveli r27, lo16(_cpu_idle_nap) 820 840 } 821 841 { 842 + lw r28, r29 822 843 auli r27, r27, ha16(_cpu_idle_nap) 823 844 } 824 845 {
+24 -6
arch/tile/kernel/intvec_64.S
··· 30 30 #include <arch/interrupts.h> 31 31 #include <arch/spr_def.h> 32 32 33 - #ifdef CONFIG_PREEMPT 34 - # error "No support for kernel preemption currently" 35 - #endif 36 - 37 33 #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) 38 34 39 35 #define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) ··· 816 820 andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ 817 821 { 818 822 beqzt r29, .Lresume_userspace 819 - PTREGS_PTR(r29, PTREGS_OFFSET_PC) 823 + move r29, sp 820 824 } 821 825 826 + #ifdef CONFIG_PREEMPT 827 + /* Returning to kernel space. Check if we need preemption. */ 828 + EXTRACT_THREAD_INFO(r29) 829 + addli r28, r29, THREAD_INFO_FLAGS_OFFSET 830 + { 831 + ld r28, r28 832 + addli r29, r29, THREAD_INFO_PREEMPT_COUNT_OFFSET 833 + } 834 + { 835 + andi r28, r28, _TIF_NEED_RESCHED 836 + ld4s r29, r29 837 + } 838 + beqzt r28, 1f 839 + bnez r29, 1f 840 + jal preempt_schedule_irq 841 + FEEDBACK_REENTER(interrupt_return) 842 + 1: 843 + #endif 844 + 822 845 /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ 823 - moveli r27, hw2_last(_cpu_idle_nap) 846 + { 847 + moveli r27, hw2_last(_cpu_idle_nap) 848 + PTREGS_PTR(r29, PTREGS_OFFSET_PC) 849 + } 824 850 { 825 851 ld r28, r29 826 852 shl16insli r27, r27, hw1(_cpu_idle_nap)
+1
arch/tile/kernel/irq.c
··· 74 74 /* 75 75 * The interrupt handling path, implemented in terms of HV interrupt 76 76 * emulation on TILE64 and TILEPro, and IPI hardware on TILE-Gx. 77 + * Entered with interrupts disabled. 77 78 */ 78 79 void tile_dev_intr(struct pt_regs *regs, int intnum) 79 80 {
+1 -1
arch/tile/kernel/smp.c
··· 100 100 /* Handler to stop the current cpu. */ 101 101 static void smp_stop_cpu_interrupt(void) 102 102 { 103 - set_cpu_online(smp_processor_id(), 0); 104 103 arch_local_irq_disable_all(); 104 + set_cpu_online(smp_processor_id(), 0); 105 105 for (;;) 106 106 asm("nap; nop"); 107 107 }
+5 -3
arch/tile/kernel/smpboot.c
··· 142 142 */ 143 143 static void __cpuinit start_secondary(void) 144 144 { 145 - int cpuid = smp_processor_id(); 145 + int cpuid; 146 + 147 + preempt_disable(); 148 + 149 + cpuid = smp_processor_id(); 146 150 147 151 /* Set our thread pointer appropriately. */ 148 152 set_my_cpu_offset(__per_cpu_offset[cpuid]); 149 - 150 - preempt_disable(); 151 153 152 154 /* 153 155 * In large machines even this will slow us down, since we
+2 -2
arch/tile/kernel/stack.c
··· 194 194 */ 195 195 static void validate_stack(struct pt_regs *regs) 196 196 { 197 - int cpu = smp_processor_id(); 197 + int cpu = raw_smp_processor_id(); 198 198 unsigned long ksp0 = get_current_ksp0(); 199 199 unsigned long ksp0_base = ksp0 - THREAD_SIZE; 200 200 unsigned long sp = stack_pointer; ··· 392 392 pr_err("Starting stack dump of tid %d, pid %d (%s)" 393 393 " on cpu %d at cycle %lld\n", 394 394 kbt->task->pid, kbt->task->tgid, kbt->task->comm, 395 - smp_processor_id(), get_cycles()); 395 + raw_smp_processor_id(), get_cycles()); 396 396 } 397 397 kbt->verbose = 1; 398 398 i = 0;
+3 -1
arch/tile/kernel/sys.c
··· 38 38 SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, 39 39 unsigned long, flags) 40 40 { 41 + /* DCACHE is not particularly effective if not bound to one cpu. */ 41 42 if (flags & DCACHE) 42 - homecache_evict(cpumask_of(smp_processor_id())); 43 + homecache_evict(cpumask_of(raw_smp_processor_id())); 44 + 43 45 if (flags & ICACHE) 44 46 flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(current->mm), 45 47 0, 0, 0, NULL, NULL, 0);
+8 -4
arch/tile/lib/memcpy_tile64.c
··· 65 65 pmd_t *pmdp; 66 66 pte_t *ptep; 67 67 int type0, type1; 68 - int cpu = get_cpu(); 68 + int cpu = smp_processor_id(); 69 69 70 70 /* 71 71 * Disable interrupts so that we don't recurse into memcpy() ··· 126 126 kmap_atomic_idx_pop(); 127 127 sim_allow_multiple_caching(0); 128 128 local_irq_restore(flags); 129 - put_cpu(); 130 129 } 131 130 132 131 /* ··· 136 137 static unsigned long fast_copy(void *dest, const void *source, int len, 137 138 memcpy_t func) 138 139 { 140 + int cpu = get_cpu(); 141 + unsigned long retval; 142 + 139 143 /* 140 144 * Check if it's big enough to bother with. We may end up doing a 141 145 * small copy via TLB manipulation if we're near a page boundary, ··· 160 158 !hv_pte_get_readable(src_pte) || 161 159 hv_pte_get_mode(src_pte) != HV_PTE_MODE_CACHE_TILE_L3) 162 160 break; 163 - if (get_remote_cache_cpu(src_pte) == smp_processor_id()) 161 + if (get_remote_cache_cpu(src_pte) == cpu) 164 162 break; 165 163 src_page = pfn_to_page(pte_pfn(src_pte)); 166 164 get_page(src_page); ··· 237 235 len -= copy_size; 238 236 } 239 237 240 - return func(dest, source, len); 238 + retval = func(dest, source, len); 239 + put_cpu(); 240 + return retval; 241 241 } 242 242 243 243 void *memcpy(void *to, const void *from, __kernel_size_t n)
+3 -1
arch/tile/mm/homecache.c
··· 172 172 173 173 static void homecache_finv_page_va(void* va, int home) 174 174 { 175 - if (home == smp_processor_id()) { 175 + int cpu = get_cpu(); 176 + if (home == cpu) { 176 177 finv_buffer_local(va, PAGE_SIZE); 177 178 } else if (home == PAGE_HOME_HASH) { 178 179 finv_buffer_remote(va, PAGE_SIZE, 1); ··· 181 180 BUG_ON(home < 0 || home >= NR_CPUS); 182 181 finv_buffer_remote(va, PAGE_SIZE, 0); 183 182 } 183 + put_cpu(); 184 184 } 185 185 186 186 void homecache_finv_map_page(struct page *page, int home)