diff options
Diffstat (limited to 'arch/x86/kernel')
| -rw-r--r-- | arch/x86/kernel/amd_nb.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/amd.c | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 7 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel.c | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/amd_early.c | 43 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/generic.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/ftrace.c | 83 | ||||
| -rw-r--r-- | arch/x86/kernel/irq.c | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/quirks.c | 37 | ||||
| -rw-r--r-- | arch/x86/kernel/tsc.c | 4 | 
10 files changed, 136 insertions, 68 deletions
| diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 59554dca96ec..dec8de4e1663 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -179,7 +179,7 @@ int amd_get_subcaches(int cpu)  	return (mask >> (4 * cuid)) & 0xf;  } -int amd_set_subcaches(int cpu, int mask) +int amd_set_subcaches(int cpu, unsigned long mask)  {  	static unsigned int reset, ban;  	struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu)); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index d3153e281d72..c67ffa686064 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -767,10 +767,7 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size)  static void cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c)  { -	tlb_flushall_shift = 5; - -	if (c->x86 <= 0x11) -		tlb_flushall_shift = 4; +	tlb_flushall_shift = 6;  }  static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 24b6fd10625a..8e28bf2fc3ef 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -284,8 +284,13 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)  	raw_local_save_flags(eflags);  	BUG_ON(eflags & X86_EFLAGS_AC); -	if (cpu_has(c, X86_FEATURE_SMAP)) +	if (cpu_has(c, X86_FEATURE_SMAP)) { +#ifdef CONFIG_X86_SMAP  		set_in_cr4(X86_CR4_SMAP); +#else +		clear_in_cr4(X86_CR4_SMAP); +#endif +	}  }  /* diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 3db61c644e44..5cd9bfabd645 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -640,21 +640,17 @@ static void intel_tlb_flushall_shift_set(struct cpuinfo_x86 *c)  	case 0x61d: /* six-core 45 nm xeon "Dunnington" */  		tlb_flushall_shift = -1;  		break; +	case 0x63a: /* Ivybridge */ +		tlb_flushall_shift = 2; +		break;  	case 0x61a: /* 45 nm nehalem, "Bloomfield" */  	case 0x61e: /* 45 nm nehalem, "Lynnfield" */  	case 0x625: /* 32 nm nehalem, "Clarkdale" */  	case 0x62c: /* 32 nm nehalem, "Gulftown" */  	case 0x62e: /* 45 nm nehalem-ex, "Beckton" */  	case 0x62f: /* 32 nm Xeon E7 */ -		tlb_flushall_shift = 6; -		break;  	case 0x62a: /* SandyBridge */  	case 0x62d: /* SandyBridge, "Romely-EP" */ -		tlb_flushall_shift = 5; -		break; -	case 0x63a: /* Ivybridge */ -		tlb_flushall_shift = 1; -		break;  	default:  		tlb_flushall_shift = 6;  	} diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index 8384c0fa206f..617a9e284245 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -285,6 +285,15 @@ static void __init collect_cpu_sig_on_bsp(void *arg)  	uci->cpu_sig.sig = cpuid_eax(0x00000001);  } + +static void __init get_bsp_sig(void) +{ +	unsigned int bsp = boot_cpu_data.cpu_index; +	struct ucode_cpu_info *uci = ucode_cpu_info + bsp; + +	if (!uci->cpu_sig.sig) +		smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1); +}  #else  void load_ucode_amd_ap(void)  { @@ -337,31 +346,37 @@ void load_ucode_amd_ap(void)  int __init save_microcode_in_initrd_amd(void)  { +	unsigned long cont;  	enum ucode_state ret;  	u32 eax; -#ifdef CONFIG_X86_32 -	unsigned int bsp = boot_cpu_data.cpu_index; -	struct ucode_cpu_info *uci = ucode_cpu_info + bsp; - -	if (!uci->cpu_sig.sig) -		smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1); +	if (!container) +		return -EINVAL; +#ifdef CONFIG_X86_32 +	get_bsp_sig(); +	cont = (unsigned long)container; +#else  	/* -	 * Take into account the fact that the ramdisk might get relocated -	 * and therefore we need to recompute the container's position in -	 * virtual memory space. +	 * We need the physical address of the container for both bitness since +	 * boot_params.hdr.ramdisk_image is a physical address.  	 */ -	container = (u8 *)(__va((u32)relocated_ramdisk) + -			   ((u32)container - boot_params.hdr.ramdisk_image)); +	cont = __pa(container);  #endif + +	/* +	 * Take into account the fact that the ramdisk might get relocated and +	 * therefore we need to recompute the container's position in virtual +	 * memory space. +	 */ +	if (relocated_ramdisk) +		container = (u8 *)(__va(relocated_ramdisk) + +			     (cont - boot_params.hdr.ramdisk_image)); +  	if (ucode_new_rev)  		pr_info("microcode: updated early to new patch_level=0x%08x\n",  			ucode_new_rev); -	if (!container) -		return -EINVAL; -  	eax   = cpuid_eax(0x00000001);  	eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index ce2d0a2c3e4f..0e25a1bc5ab5 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -683,7 +683,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock)  	}  	/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */ -	count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); +	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);  	__flush_tlb();  	/* Save MTRR state */ @@ -697,7 +697,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock)  static void post_set(void) __releases(set_atomicity_lock)  {  	/* Flush TLBs (no need to flush caches - they are disabled) */ -	count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); +	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);  	__flush_tlb();  	/* Intel (P6) standard MTRRs */ diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index d4bdd253fea7..e6253195a301 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -77,8 +77,7 @@ within(unsigned long addr, unsigned long start, unsigned long end)  	return addr >= start && addr < end;  } -static int -do_ftrace_mod_code(unsigned long ip, const void *new_code) +static unsigned long text_ip_addr(unsigned long ip)  {  	/*  	 * On x86_64, kernel text mappings are mapped read-only with @@ -91,7 +90,7 @@ do_ftrace_mod_code(unsigned long ip, const void *new_code)  	if (within(ip, (unsigned long)_text, (unsigned long)_etext))  		ip = (unsigned long)__va(__pa_symbol(ip)); -	return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE); +	return ip;  }  static const unsigned char *ftrace_nop_replace(void) @@ -123,8 +122,10 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,  	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)  		return -EINVAL; +	ip = text_ip_addr(ip); +  	/* replace the text with the new text */ -	if (do_ftrace_mod_code(ip, new_code)) +	if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))  		return -EPERM;  	sync_core(); @@ -221,37 +222,51 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,  	return -EINVAL;  } -int ftrace_update_ftrace_func(ftrace_func_t func) +static unsigned long ftrace_update_func; + +static int update_ftrace_func(unsigned long ip, void *new)  { -	unsigned long ip = (unsigned long)(&ftrace_call); -	unsigned char old[MCOUNT_INSN_SIZE], *new; +	unsigned char old[MCOUNT_INSN_SIZE];  	int ret; -	memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); -	new = ftrace_call_replace(ip, (unsigned long)func); +	memcpy(old, (void *)ip, MCOUNT_INSN_SIZE); + +	ftrace_update_func = ip; +	/* Make sure the breakpoints see the ftrace_update_func update */ +	smp_wmb();  	/* See comment above by declaration of modifying_ftrace_code */  	atomic_inc(&modifying_ftrace_code);  	ret = ftrace_modify_code(ip, old, new); +	atomic_dec(&modifying_ftrace_code); + +	return ret; +} + +int ftrace_update_ftrace_func(ftrace_func_t func) +{ +	unsigned long ip = (unsigned long)(&ftrace_call); +	unsigned char *new; +	int ret; + +	new = ftrace_call_replace(ip, (unsigned long)func); +	ret = update_ftrace_func(ip, new); +  	/* Also update the regs callback function */  	if (!ret) {  		ip = (unsigned long)(&ftrace_regs_call); -		memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE);  		new = ftrace_call_replace(ip, (unsigned long)func); -		ret = ftrace_modify_code(ip, old, new); +		ret = update_ftrace_func(ip, new);  	} -	atomic_dec(&modifying_ftrace_code); -  	return ret;  }  static int is_ftrace_caller(unsigned long ip)  { -	if (ip == (unsigned long)(&ftrace_call) || -		ip == (unsigned long)(&ftrace_regs_call)) +	if (ip == ftrace_update_func)  		return 1;  	return 0; @@ -677,45 +692,41 @@ int __init ftrace_dyn_arch_init(void *data)  #ifdef CONFIG_DYNAMIC_FTRACE  extern void ftrace_graph_call(void); -static int ftrace_mod_jmp(unsigned long ip, -			  int old_offset, int new_offset) +static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)  { -	unsigned char code[MCOUNT_INSN_SIZE]; +	static union ftrace_code_union calc; -	if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) -		return -EFAULT; +	/* Jmp not a call (ignore the .e8) */ +	calc.e8		= 0xe9; +	calc.offset	= ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr); -	if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) -		return -EINVAL; +	/* +	 * ftrace external locks synchronize the access to the static variable. +	 */ +	return calc.code; +} -	*(int *)(&code[1]) = new_offset; +static int ftrace_mod_jmp(unsigned long ip, void *func) +{ +	unsigned char *new; -	if (do_ftrace_mod_code(ip, &code)) -		return -EPERM; +	new = ftrace_jmp_replace(ip, (unsigned long)func); -	return 0; +	return update_ftrace_func(ip, new);  }  int ftrace_enable_ftrace_graph_caller(void)  {  	unsigned long ip = (unsigned long)(&ftrace_graph_call); -	int old_offset, new_offset; -	old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); -	new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); - -	return ftrace_mod_jmp(ip, old_offset, new_offset); +	return ftrace_mod_jmp(ip, &ftrace_graph_caller);  }  int ftrace_disable_ftrace_graph_caller(void)  {  	unsigned long ip = (unsigned long)(&ftrace_graph_call); -	int old_offset, new_offset; - -	old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); -	new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); -	return ftrace_mod_jmp(ip, old_offset, new_offset); +	return ftrace_mod_jmp(ip, &ftrace_stub);  }  #endif /* !CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index dbb60878b744..d99f31d9a750 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -266,6 +266,14 @@ __visible void smp_trace_x86_platform_ipi(struct pt_regs *regs)  EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);  #ifdef CONFIG_HOTPLUG_CPU + +/* These two declarations are only used in check_irq_vectors_for_cpu_disable() + * below, which is protected by stop_machine().  Putting them on the stack + * results in a stack frame overflow.  Dynamically allocating could result in a + * failure so declare these two cpumasks as global. + */ +static struct cpumask affinity_new, online_new; +  /*   * This cpu is going to be removed and its vectors migrated to the remaining   * online cpus.  Check to see if there are enough vectors in the remaining cpus. @@ -277,7 +285,6 @@ int check_irq_vectors_for_cpu_disable(void)  	unsigned int this_cpu, vector, this_count, count;  	struct irq_desc *desc;  	struct irq_data *data; -	struct cpumask affinity_new, online_new;  	this_cpu = smp_processor_id();  	cpumask_copy(&online_new, cpu_online_mask); diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 04ee1e2e4c02..7c6acd4b8995 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -571,3 +571,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F5,  			quirk_amd_nb_node);  #endif + +#ifdef CONFIG_PCI +/* + * Processor does not ensure DRAM scrub read/write sequence + * is atomic wrt accesses to CC6 save state area. Therefore + * if a concurrent scrub read/write access is to same address + * the entry may appear as if it is not written. This quirk + * applies to Fam16h models 00h-0Fh + * + * See "Revision Guide" for AMD F16h models 00h-0fh, + * document 51810 rev. 3.04, Nov 2013 + */ +static void amd_disable_seq_and_redirect_scrub(struct pci_dev *dev) +{ +	u32 val; + +	/* +	 * Suggested workaround: +	 * set D18F3x58[4:0] = 00h and set D18F3x5C[0] = 0b +	 */ +	pci_read_config_dword(dev, 0x58, &val); +	if (val & 0x1F) { +		val &= ~(0x1F); +		pci_write_config_dword(dev, 0x58, val); +	} + +	pci_read_config_dword(dev, 0x5C, &val); +	if (val & BIT(0)) { +		val &= ~BIT(0); +		pci_write_config_dword(dev, 0x5c, val); +	} +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3, +			amd_disable_seq_and_redirect_scrub); + +#endif diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 19e5adb49a27..acb3b606613e 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -209,7 +209,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)  	 * dance when its actually needed.  	 */ -	preempt_disable(); +	preempt_disable_notrace();  	data = this_cpu_read(cyc2ns.head);  	tail = this_cpu_read(cyc2ns.tail); @@ -229,7 +229,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)  		if (!--data->__count)  			this_cpu_write(cyc2ns.tail, data);  	} -	preempt_enable(); +	preempt_enable_notrace();  	return ns;  } |