diff options
Diffstat (limited to 'arch')
348 files changed, 6480 insertions, 8333 deletions
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index e8c956098424..572b228c44c7 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -17,11 +17,11 @@ #define ATOMIC_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic64_read(v) ACCESS_ONCE((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic64_read(v) READ_ONCE((v)->counter) -#define atomic_set(v,i) ((v)->counter = (i)) -#define atomic64_set(v,i) ((v)->counter = (i)) +#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) +#define atomic64_set(v,i) WRITE_ONCE((v)->counter, (i)) /* * To get proper branch prediction for the main line, we must branch diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 78c0621d5819..2c2ac3f3ff80 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -76,6 +76,10 @@ config STACKTRACE_SUPPORT config HAVE_LATENCYTOP_SUPPORT def_bool y +config HAVE_ARCH_TRANSPARENT_HUGEPAGE + def_bool y + depends on ARC_MMU_V4 + source "init/Kconfig" source "kernel/Kconfig.freezer" @@ -190,6 +194,16 @@ config NR_CPUS range 2 4096 default "4" +config ARC_SMP_HALT_ON_RESET + bool "Enable Halt-on-reset boot mode" + default y if ARC_UBOOT_SUPPORT + help + In SMP configuration cores can be configured as Halt-on-reset + or they could all start at same time. For Halt-on-reset, non + masters are parked until Master kicks them so they can start of + at designated entry point. For other case, all jump to common + entry point and spin wait for Master's signal. + endif #SMP menuconfig ARC_CACHE @@ -278,6 +292,8 @@ choice default ARC_MMU_V2 if ARC_CPU_750D default ARC_MMU_V4 if ARC_CPU_HS +if ISA_ARCOMPACT + config ARC_MMU_V1 bool "MMU v1" help @@ -297,6 +313,8 @@ config ARC_MMU_V3 Variable Page size (1k-16k), var JTLB size 128 x (2 or 4) Shared Address Spaces (SASID) +endif + config ARC_MMU_V4 bool "MMU v4" depends on ISA_ARCV2 @@ -428,6 +446,28 @@ config LINUX_LINK_BASE Linux needs to be scooted a bit. If you don't know what the above means, leave this setting alone. +config HIGHMEM + bool "High Memory Support" + help + With ARC 2G:2G address split, only upper 2G is directly addressable by + kernel. Enable this to potentially allow access to rest of 2G and PAE + in future + +config ARC_HAS_PAE40 + bool "Support for the 40-bit Physical Address Extension" + default n + depends on ISA_ARCV2 + select HIGHMEM + help + Enable access to physical memory beyond 4G, only supported on + ARC cores with 40 bit Physical Addressing support + +config ARCH_PHYS_ADDR_T_64BIT + def_bool ARC_HAS_PAE40 + +config ARCH_DMA_ADDR_T_64BIT + bool + config ARC_CURR_IN_REG bool "Dedicate Register r25 for current_task pointer" default y diff --git a/arch/arc/boot/dts/axc001.dtsi b/arch/arc/boot/dts/axc001.dtsi index a5e2726a067e..420dcfde289f 100644 --- a/arch/arc/boot/dts/axc001.dtsi +++ b/arch/arc/boot/dts/axc001.dtsi @@ -95,6 +95,6 @@ #size-cells = <1>; ranges = <0x00000000 0x80000000 0x40000000>; device_type = "memory"; - reg = <0x00000000 0x20000000>; /* 512MiB */ + reg = <0x80000000 0x20000000>; /* 512MiB */ }; }; diff --git a/arch/arc/boot/dts/axc003.dtsi b/arch/arc/boot/dts/axc003.dtsi index 846481f37eef..f90fadf7f94e 100644 --- a/arch/arc/boot/dts/axc003.dtsi +++ b/arch/arc/boot/dts/axc003.dtsi @@ -98,6 +98,6 @@ #size-cells = <1>; ranges = <0x00000000 0x80000000 0x40000000>; device_type = "memory"; - reg = <0x00000000 0x20000000>; /* 512MiB */ + reg = <0x80000000 0x20000000>; /* 512MiB */ }; }; diff --git a/arch/arc/boot/dts/axc003_idu.dtsi b/arch/arc/boot/dts/axc003_idu.dtsi index 2f0b33257db2..06a9f294a2e6 100644 --- a/arch/arc/boot/dts/axc003_idu.dtsi +++ b/arch/arc/boot/dts/axc003_idu.dtsi @@ -121,6 +121,6 @@ #size-cells = <1>; ranges = <0x00000000 0x80000000 0x40000000>; device_type = "memory"; - reg = <0x00000000 0x20000000>; /* 512MiB */ + reg = <0x80000000 0x20000000>; /* 512MiB */ }; }; diff --git a/arch/arc/boot/dts/nsim_hs.dts b/arch/arc/boot/dts/nsim_hs.dts index 911f069e0540..b0eb0e7fe21d 100644 --- a/arch/arc/boot/dts/nsim_hs.dts +++ b/arch/arc/boot/dts/nsim_hs.dts @@ -11,8 +11,16 @@ / { compatible = "snps,nsim_hs"; + #address-cells = <2>; + #size-cells = <2>; interrupt-parent = <&core_intc>; + memory { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x40000000 /* 1 GB low mem */ + 0x1 0x00000000 0x0 0x40000000>; /* 1 GB highmem */ + }; + chosen { bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; }; @@ -26,8 +34,8 @@ #address-cells = <1>; #size-cells = <1>; - /* child and parent address space 1:1 mapped */ - ranges; + /* only perip space at end of low mem accessible */ + ranges = <0x80000000 0x0 0x80000000 0x80000000>; core_intc: core-interrupt-controller { compatible = "snps,archs-intc"; diff --git a/arch/arc/boot/dts/skeleton.dtsi b/arch/arc/boot/dts/skeleton.dtsi index a870bdd5e404..296d371a335c 100644 --- a/arch/arc/boot/dts/skeleton.dtsi +++ b/arch/arc/boot/dts/skeleton.dtsi @@ -32,6 +32,6 @@ memory { device_type = "memory"; - reg = <0x00000000 0x10000000>; /* 256M */ + reg = <0x80000000 0x10000000>; /* 256M */ }; }; diff --git a/arch/arc/boot/dts/vdk_axc003.dtsi b/arch/arc/boot/dts/vdk_axc003.dtsi index 9393fd902f0d..84226bd48baf 100644 --- a/arch/arc/boot/dts/vdk_axc003.dtsi +++ b/arch/arc/boot/dts/vdk_axc003.dtsi @@ -56,6 +56,6 @@ #size-cells = <1>; ranges = <0x00000000 0x80000000 0x40000000>; device_type = "memory"; - reg = <0x00000000 0x20000000>; /* 512MiB */ + reg = <0x80000000 0x20000000>; /* 512MiB */ }; }; diff --git a/arch/arc/boot/dts/vdk_axc003_idu.dtsi b/arch/arc/boot/dts/vdk_axc003_idu.dtsi index 9bee8ed09eb0..31f0fb5fc91d 100644 --- a/arch/arc/boot/dts/vdk_axc003_idu.dtsi +++ b/arch/arc/boot/dts/vdk_axc003_idu.dtsi @@ -71,6 +71,6 @@ #size-cells = <1>; ranges = <0x00000000 0x80000000 0x40000000>; device_type = "memory"; - reg = <0x00000000 0x20000000>; /* 512MiB */ + reg = <0x80000000 0x20000000>; /* 512MiB */ }; }; diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index 562dac6a7f78..c92c0ef1e9d2 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -89,7 +89,6 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index 83a6d8d5cc58..cfac24e0e7b6 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -95,7 +95,6 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index f1e1c84e0dda..9922a118a15a 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -96,7 +96,6 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index d8023bc8d1ad..7fac7d85ed6a 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -120,7 +120,7 @@ /* gcc builtin sr needs reg param to be long immediate */ #define write_aux_reg(reg_immed, val) \ - __builtin_arc_sr((unsigned int)val, reg_immed) + __builtin_arc_sr((unsigned int)(val), reg_immed) #else @@ -327,8 +327,8 @@ struct bcr_generic { */ struct cpuinfo_arc_mmu { - unsigned int ver:4, pg_sz_k:8, s_pg_sz_m:8, u_dtlb:6, u_itlb:6; - unsigned int num_tlb:16, sets:12, ways:4; + unsigned int ver:4, pg_sz_k:8, s_pg_sz_m:8, pad:10, sasid:1, pae:1; + unsigned int sets:12, ways:4, u_dtlb:8, u_itlb:8; }; struct cpuinfo_arc_cache { diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index c3ecda023e3a..7730d302cadb 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -17,11 +17,11 @@ #include <asm/barrier.h> #include <asm/smp.h> -#define atomic_read(v) ((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) #ifdef CONFIG_ARC_HAS_LLSC -#define atomic_set(v, i) (((v)->counter) = (i)) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) #ifdef CONFIG_ARC_STAR_9000923308 @@ -107,7 +107,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ #ifndef CONFIG_SMP /* violating atomic_xxx API locking protocol in UP for optimization sake */ -#define atomic_set(v, i) (((v)->counter) = (i)) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) #else @@ -125,7 +125,7 @@ static inline void atomic_set(atomic_t *v, int i) unsigned long flags; atomic_ops_lock(flags); - v->counter = i; + WRITE_ONCE(v->counter, i); atomic_ops_unlock(flags); } diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index e23ea6e7633a..abf06e81c929 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -65,6 +65,7 @@ extern int ioc_exists; #if defined(CONFIG_ARC_MMU_V3) || defined(CONFIG_ARC_MMU_V4) #define ARC_REG_IC_PTAG 0x1E #endif +#define ARC_REG_IC_PTAG_HI 0x1F /* Bit val in IC_CTRL */ #define IC_CTRL_CACHE_DISABLE 0x1 @@ -77,6 +78,7 @@ extern int ioc_exists; #define ARC_REG_DC_FLSH 0x4B #define ARC_REG_DC_FLDL 0x4C #define ARC_REG_DC_PTAG 0x5C +#define ARC_REG_DC_PTAG_HI 0x5F /* Bit val in DC_CTRL */ #define DC_CTRL_INV_MODE_FLUSH 0x40 diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h index 0992d3dbcc65..fbe3587c4f36 100644 --- a/arch/arc/include/asm/cacheflush.h +++ b/arch/arc/include/asm/cacheflush.h @@ -31,10 +31,10 @@ void flush_cache_all(void); -void flush_icache_range(unsigned long start, unsigned long end); -void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len); -void __inv_icache_page(unsigned long paddr, unsigned long vaddr); -void __flush_dcache_page(unsigned long paddr, unsigned long vaddr); +void flush_icache_range(unsigned long kstart, unsigned long kend); +void __sync_icache_dcache(phys_addr_t paddr, unsigned long vaddr, int len); +void __inv_icache_page(phys_addr_t paddr, unsigned long vaddr); +void __flush_dcache_page(phys_addr_t paddr, unsigned long vaddr); #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 diff --git a/arch/arc/include/asm/entry-compact.h b/arch/arc/include/asm/entry-compact.h index 415443c2a8c4..1aff3be91075 100644 --- a/arch/arc/include/asm/entry-compact.h +++ b/arch/arc/include/asm/entry-compact.h @@ -110,13 +110,12 @@ .macro FAKE_RET_FROM_EXCPN - ld r9, [sp, PT_status32] - bic r9, r9, (STATUS_U_MASK|STATUS_DE_MASK) - bset r9, r9, STATUS_L_BIT - sr r9, [erstatus] - mov r9, 55f - sr r9, [eret] - + lr r9, [status32] + bclr r9, r9, STATUS_AE_BIT + or r9, r9, (STATUS_E1_MASK|STATUS_E2_MASK) + sr r9, [erstatus] + mov r9, 55f + sr r9, [eret] rtie 55: .endm diff --git a/arch/arc/include/asm/highmem.h b/arch/arc/include/asm/highmem.h new file mode 100644 index 000000000000..b1585c96324a --- /dev/null +++ b/arch/arc/include/asm/highmem.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef CONFIG_HIGHMEM + +#include <uapi/asm/page.h> +#include <asm/kmap_types.h> + +/* start after vmalloc area */ +#define FIXMAP_BASE (PAGE_OFFSET - FIXMAP_SIZE - PKMAP_SIZE) +#define FIXMAP_SIZE PGDIR_SIZE /* only 1 PGD worth */ +#define KM_TYPE_NR ((FIXMAP_SIZE >> PAGE_SHIFT)/NR_CPUS) +#define FIXMAP_ADDR(nr) (FIXMAP_BASE + ((nr) << PAGE_SHIFT)) + +/* start after fixmap area */ +#define PKMAP_BASE (FIXMAP_BASE + FIXMAP_SIZE) +#define PKMAP_SIZE PGDIR_SIZE +#define LAST_PKMAP (PKMAP_SIZE >> PAGE_SHIFT) +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) +#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) + +#define kmap_prot PAGE_KERNEL + + +#include <asm/cacheflush.h> + +extern void *kmap(struct page *page); +extern void *kmap_high(struct page *page); +extern void *kmap_atomic(struct page *page); +extern void __kunmap_atomic(void *kvaddr); +extern void kunmap_high(struct page *page); + +extern void kmap_init(void); + +static inline void flush_cache_kmaps(void) +{ + flush_cache_all(); +} + +static inline void kunmap(struct page *page) +{ + BUG_ON(in_interrupt()); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + + +#endif + +#endif diff --git a/arch/arc/include/asm/hugepage.h b/arch/arc/include/asm/hugepage.h new file mode 100644 index 000000000000..c5094de86403 --- /dev/null +++ b/arch/arc/include/asm/hugepage.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013-15 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +#ifndef _ASM_ARC_HUGEPAGE_H +#define _ASM_ARC_HUGEPAGE_H + +#include <linux/types.h> +#include <asm-generic/pgtable-nopmd.h> + +static inline pte_t pmd_pte(pmd_t pmd) +{ + return __pte(pmd_val(pmd)); +} + +static inline pmd_t pte_pmd(pte_t pte) +{ + return __pmd(pte_val(pte)); +} + +#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) +#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) +#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) +#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) +#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) +#define pmd_mkhuge(pmd) pte_pmd(pte_mkhuge(pmd_pte(pmd))) +#define pmd_mknotpresent(pmd) pte_pmd(pte_mknotpresent(pmd_pte(pmd))) +#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd))) +#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd))) + +#define pmd_write(pmd) pte_write(pmd_pte(pmd)) +#define pmd_young(pmd) pte_young(pmd_pte(pmd)) +#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd)) +#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd)) +#define pmd_special(pmd) pte_special(pmd_pte(pmd)) + +#define mk_pmd(page, prot) pte_pmd(mk_pte(page, prot)) + +#define pmd_trans_huge(pmd) (pmd_val(pmd) & _PAGE_HW_SZ) +#define pmd_trans_splitting(pmd) (pmd_trans_huge(pmd) && pmd_special(pmd)) + +#define pfn_pmd(pfn, prot) (__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) + +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ + /* + * open-coded pte_modify() with additional retaining of HW_SZ bit + * so that pmd_trans_huge() remains true for this PMD + */ + return __pmd((pmd_val(pmd) & (_PAGE_CHG_MASK | _PAGE_HW_SZ)) | pgprot_val(newprot)); +} + +static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp, pmd_t pmd) +{ + *pmdp = pmd; +} + +extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd); + +#define has_transparent_hugepage() 1 + +/* Generic variants assume pgtable_t is struct page *, hence need for these */ +#define __HAVE_ARCH_PGTABLE_DEPOSIT +extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, + pgtable_t pgtable); + +#define __HAVE_ARCH_PGTABLE_WITHDRAW +extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); + +#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE +extern void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); + +#endif diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index bc5103637326..4fd7d62a6e30 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -16,6 +16,7 @@ #ifdef CONFIG_ISA_ARCOMPACT #define TIMER0_IRQ 3 #define TIMER1_IRQ 4 +#define IPI_IRQ (NR_CPU_IRQS-1) /* dummy to enable SMP build for up hardware */ #else #define TIMER0_IRQ 16 #define TIMER1_IRQ 17 diff --git a/arch/arc/include/asm/irqflags-compact.h b/arch/arc/include/asm/irqflags-compact.h index aa805575c320..d8c608174617 100644 --- a/arch/arc/include/asm/irqflags-compact.h +++ b/arch/arc/include/asm/irqflags-compact.h @@ -23,11 +23,13 @@ #define STATUS_E2_BIT 2 /* Int 2 enable */ #define STATUS_A1_BIT 3 /* Int 1 active */ #define STATUS_A2_BIT 4 /* Int 2 active */ +#define STATUS_AE_BIT 5 /* Exception active */ #define STATUS_E1_MASK (1<<STATUS_E1_BIT) #define STATUS_E2_MASK (1<<STATUS_E2_BIT) #define STATUS_A1_MASK (1<<STATUS_A1_BIT) #define STATUS_A2_MASK (1<<STATUS_A2_BIT) +#define STATUS_AE_MASK (1<<STATUS_AE_BIT) #define STATUS_IE_MASK (STATUS_E1_MASK | STATUS_E2_MASK) /* Other Interrupt Handling related Aux regs */ @@ -91,7 +93,19 @@ static inline void arch_local_irq_restore(unsigned long flags) /* * Unconditionally Enable IRQs */ -extern void arch_local_irq_enable(void); +static inline void arch_local_irq_enable(void) +{ + unsigned long temp; + + __asm__ __volatile__( + " lr %0, [status32] \n" + " or %0, %0, %1 \n" + " flag %0 \n" + : "=&r"(temp) + : "n"((STATUS_E1_MASK | STATUS_E2_MASK)) + : "cc", "memory"); +} + /* * Unconditionally Disable IRQs diff --git a/arch/arc/include/asm/kmap_types.h b/arch/arc/include/asm/kmap_types.h new file mode 100644 index 000000000000..f0d7f6acea4e --- /dev/null +++ b/arch/arc/include/asm/kmap_types.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +/* + * We primarily need to define KM_TYPE_NR here but that in turn + * is a function of PGDIR_SIZE etc. + * To avoid circular deps issue, put everything in asm/highmem.h + */ +#endif diff --git a/arch/arc/include/asm/mach_desc.h b/arch/arc/include/asm/mach_desc.h index e8993a2be6c2..6ff657a904b6 100644 --- a/arch/arc/include/asm/mach_desc.h +++ b/arch/arc/include/asm/mach_desc.h @@ -23,11 +23,8 @@ * @dt_compat: Array of device tree 'compatible' strings * (XXX: although only 1st entry is looked at) * @init_early: Very early callback [called from setup_arch()] - * @init_irq: setup external IRQ controllers [called from init_IRQ()] - * @init_smp: for each CPU (e.g. setup IPI) + * @init_cpu_smp: for each CPU as it is coming up (SMP as well as UP) * [(M):init_IRQ(), (o):start_kernel_secondary()] - * @init_time: platform specific clocksource/clockevent registration - * [called from time_init()] * @init_machine: arch initcall level callback (e.g. populate static * platform devices or parse Devicetree) * @init_late: Late initcall level callback @@ -36,13 +33,10 @@ struct machine_desc { const char *name; const char **dt_compat; - void (*init_early)(void); - void (*init_irq)(void); #ifdef CONFIG_SMP - void (*init_smp)(unsigned int); + void (*init_cpu_smp)(unsigned int); #endif - void (*init_time)(void); void (*init_machine)(void); void (*init_late)(void); diff --git a/arch/arc/include/asm/mcip.h b/arch/arc/include/asm/mcip.h index 52c11f0bb0e5..46f4e5351b2a 100644 --- a/arch/arc/include/asm/mcip.h +++ b/arch/arc/include/asm/mcip.h @@ -86,9 +86,6 @@ static inline void __mcip_cmd_data(unsigned int cmd, unsigned int param, __mcip_cmd(cmd, param); } -extern void mcip_init_early_smp(void); -extern void mcip_init_smp(unsigned int cpu); - #endif #endif diff --git a/arch/arc/include/asm/mmu.h b/arch/arc/include/asm/mmu.h index 0f9c3eb5327e..b144d7ca7d20 100644 --- a/arch/arc/include/asm/mmu.h +++ b/arch/arc/include/asm/mmu.h @@ -24,6 +24,7 @@ #if (CONFIG_ARC_MMU_VER < 4) #define ARC_REG_TLBPD0 0x405 #define ARC_REG_TLBPD1 0x406 +#define ARC_REG_TLBPD1HI 0 /* Dummy: allows code sharing with ARC700 */ #define ARC_REG_TLBINDEX 0x407 #define ARC_REG_TLBCOMMAND 0x408 #define ARC_REG_PID 0x409 @@ -31,6 +32,7 @@ #else #define ARC_REG_TLBPD0 0x460 #define ARC_REG_TLBPD1 0x461 +#define ARC_REG_TLBPD1HI 0x463 #define ARC_REG_TLBINDEX 0x464 #define ARC_REG_TLBCOMMAND 0x465 #define ARC_REG_PID 0x468 @@ -83,6 +85,11 @@ void arc_mmu_init(void); extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len); void read_decode_mmu_bcr(void); +static inline int is_pae40_enabled(void) +{ + return IS_ENABLED(CONFIG_ARC_HAS_PAE40); +} + #endif /* !__ASSEMBLY__ */ #endif diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 9c8aa41e45c2..429957f1c236 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -43,7 +43,6 @@ typedef struct { typedef struct { unsigned long pgprot; } pgprot_t; -typedef unsigned long pgtable_t; #define pte_val(x) ((x).pte) #define pgd_val(x) ((x).pgd) @@ -57,20 +56,26 @@ typedef unsigned long pgtable_t; #else /* !STRICT_MM_TYPECHECKS */ +#ifdef CONFIG_ARC_HAS_PAE40 +typedef unsigned long long pte_t; +#else typedef unsigned long pte_t; +#endif typedef unsigned long pgd_t; typedef unsigned long pgprot_t; -typedef unsigned long pgtable_t; #define pte_val(x) (x) #define pgd_val(x) (x) #define pgprot_val(x) (x) #define __pte(x) (x) +#define __pgd(x) (x) #define __pgprot(x) (x) #define pte_pgprot(x) (x) #endif +typedef pte_t * pgtable_t; + #define ARCH_PFN_OFFSET (CONFIG_LINUX_LINK_BASE >> PAGE_SHIFT) #define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr) diff --git a/arch/arc/include/asm/pgalloc.h b/arch/arc/include/asm/pgalloc.h index 81208bfd9dcb..86ed671286df 100644 --- a/arch/arc/include/asm/pgalloc.h +++ b/arch/arc/include/asm/pgalloc.h @@ -49,7 +49,7 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t ptep) static inline int __get_order_pgd(void) { - return get_order(PTRS_PER_PGD * 4); + return get_order(PTRS_PER_PGD * sizeof(pgd_t)); } static inline pgd_t *pgd_alloc(struct mm_struct *mm) @@ -87,7 +87,7 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) static inline int __get_order_pte(void) { - return get_order(PTRS_PER_PTE * 4); + return get_order(PTRS_PER_PTE * sizeof(pte_t)); } static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, @@ -107,10 +107,10 @@ pte_alloc_one(struct mm_struct *mm, unsigned long address) pgtable_t pte_pg; struct page *page; - pte_pg = __get_free_pages(GFP_KERNEL | __GFP_REPEAT, __get_order_pte()); + pte_pg = (pgtable_t)__get_free_pages(GFP_KERNEL | __GFP_REPEAT, __get_order_pte()); if (!pte_pg) return 0; - memzero((void *)pte_pg, PTRS_PER_PTE * 4); + memzero((void *)pte_pg, PTRS_PER_PTE * sizeof(pte_t)); page = virt_to_page(pte_pg); if (!pgtable_page_ctor(page)) { __free_page(page); @@ -128,12 +128,12 @@ static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) static inline void pte_free(struct mm_struct *mm, pgtable_t ptep) { pgtable_page_dtor(virt_to_page(ptep)); - free_pages(ptep, __get_order_pte()); + free_pages((unsigned long)ptep, __get_order_pte()); } #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte) #define check_pgt_cache() do { } while (0) -#define pmd_pgtable(pmd) pmd_page_vaddr(pmd) +#define pmd_pgtable(pmd) ((pgtable_t) pmd_page_vaddr(pmd)) #endif /* _ASM_ARC_PGALLOC_H */ diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 1281718802f7..57af2f05ae84 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -38,6 +38,7 @@ #include <asm/page.h> #include <asm/mmu.h> #include <asm-generic/pgtable-nopmd.h> +#include <linux/const.h> /************************************************************************** * Page Table Flags @@ -60,7 +61,8 @@ #define _PAGE_EXECUTE (1<<3) /* Page has user execute perm (H) */ #define _PAGE_WRITE (1<<4) /* Page has user write perm (H) */ #define _PAGE_READ (1<<5) /* Page has user read perm (H) */ -#define _PAGE_MODIFIED (1<<6) /* Page modified (dirty) (S) */ +#define _PAGE_DIRTY (1<<6) /* Page modified (dirty) (S) */ +#define _PAGE_SPECIAL (1<<7) #define _PAGE_GLOBAL (1<<8) /* Page is global (H) */ #define _PAGE_PRESENT (1<<10) /* TLB entry is valid (H) */ @@ -71,7 +73,8 @@ #define _PAGE_WRITE (1<<2) /* Page has user write perm (H) */ #define _PAGE_READ (1<<3) /* Page has user read perm (H) */ #define _PAGE_ACCESSED (1<<4) /* Page is accessed (S) */ -#define _PAGE_MODIFIED (1<<5) /* Page modified (dirty) (S) */ +#define _PAGE_DIRTY (1<<5) /* Page modified (dirty) (S) */ +#define _PAGE_SPECIAL (1<<6) #if (CONFIG_ARC_MMU_VER >= 4) #define _PAGE_WTHRU (1<<7) /* Page cache mode write-thru (H) */ @@ -81,32 +84,33 @@ #define _PAGE_PRESENT (1<<9) /* TLB entry is valid (H) */ #if (CONFIG_ARC_MMU_VER >= 4) -#define _PAGE_SZ (1<<10) /* Page Size indicator (H) */ +#define _PAGE_HW_SZ (1<<10) /* Page Size indicator (H): 0 normal, 1 super */ #endif #define _PAGE_SHARED_CODE (1<<11) /* Shared Code page with cmn vaddr usable for shared TLB entries (H) */ + +#define _PAGE_UNUSED_BIT (1<<12) #endif /* vmalloc permissions */ #define _K_PAGE_PERMS (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ | \ _PAGE_GLOBAL | _PAGE_PRESENT) -#ifdef CONFIG_ARC_CACHE_PAGES -#define _PAGE_DEF_CACHEABLE _PAGE_CACHEABLE -#else -#define _PAGE_DEF_CACHEABLE (0) +#ifndef CONFIG_ARC_CACHE_PAGES +#undef _PAGE_CACHEABLE +#define _PAGE_CACHEABLE 0 #endif -/* Helper for every "user" page - * -kernel can R/W/X - * -by default cached, unless config otherwise - * -present in memory - */ -#define ___DEF (_PAGE_PRESENT | _PAGE_DEF_CACHEABLE) +#ifndef _PAGE_HW_SZ +#define _PAGE_HW_SZ 0 +#endif + +/* Defaults for every user page */ +#define ___DEF (_PAGE_PRESENT | _PAGE_CACHEABLE) /* Set of bits not changed in pte_modify */ -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) /* More Abbrevaited helpers */ #define PAGE_U_NONE __pgprot(___DEF) @@ -122,15 +126,20 @@ * user vaddr space - visible in all addr spaces, but kernel mode only * Thus Global, all-kernel-access, no-user-access, cached */ -#define PAGE_KERNEL __pgprot(_K_PAGE_PERMS | _PAGE_DEF_CACHEABLE) +#define PAGE_KERNEL __pgprot(_K_PAGE_PERMS | _PAGE_CACHEABLE) /* ioremap */ #define PAGE_KERNEL_NO_CACHE __pgprot(_K_PAGE_PERMS) /* Masks for actual TLB "PD"s */ -#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT) +#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_HW_SZ) #define PTE_BITS_RWX (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ) + +#ifdef CONFIG_ARC_HAS_PAE40 +#define PTE_BITS_NON_RWX_IN_PD1 (0xff00000000 | PAGE_MASK | _PAGE_CACHEABLE) +#else #define PTE_BITS_NON_RWX_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE) +#endif /************************************************************************** * Mapping of vm_flags (Generic VM) to PTE flags (arch specific) @@ -191,26 +200,22 @@ /* Optimal Sizing of Pg Tbl - based on MMU page size */ #if defined(CONFIG_ARC_PAGE_SIZE_8K) -#define BITS_FOR_PTE 8 +#define BITS_FOR_PTE 8 /* 11:8:13 */ #elif defined(CONFIG_ARC_PAGE_SIZE_16K) -#define BITS_FOR_PTE 8 +#define BITS_FOR_PTE 8 /* 10:8:14 */ #elif defined(CONFIG_ARC_PAGE_SIZE_4K) -#define BITS_FOR_PTE 9 +#define BITS_FOR_PTE 9 /* 11:9:12 */ #endif #define BITS_FOR_PGD (32 - BITS_FOR_PTE - BITS_IN_PAGE) -#define PGDIR_SHIFT (BITS_FOR_PTE + BITS_IN_PAGE) +#define PGDIR_SHIFT (32 - BITS_FOR_PGD) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) /* vaddr span, not PDG sz */ #define PGDIR_MASK (~(PGDIR_SIZE-1)) -#ifdef __ASSEMBLY__ -#define PTRS_PER_PTE (1 << BITS_FOR_PTE) -#define PTRS_PER_PGD (1 << BITS_FOR_PGD) -#else -#define PTRS_PER_PTE (1UL << BITS_FOR_PTE) -#define PTRS_PER_PGD (1UL << BITS_FOR_PGD) -#endif +#define PTRS_PER_PTE _BITUL(BITS_FOR_PTE) +#define PTRS_PER_PGD _BITUL(BITS_FOR_PGD) + /* * Number of entries a user land program use. * TASK_SIZE is the maximum vaddr that can be used by a userland program. @@ -270,15 +275,10 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) (unsigned long)(((pte_val(x) - CONFIG_LINUX_LINK_BASE) >> \ PAGE_SHIFT))) -#define mk_pte(page, pgprot) \ -({ \ - pte_t pte; \ - pte_val(pte) = __pa(page_address(page)) + pgprot_val(pgprot); \ - pte; \ -}) - +#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) -#define pfn_pte(pfn, prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) +#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | \ + pgprot_val(prot))) #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) /* @@ -295,23 +295,26 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) /* Zoo of pte_xxx function */ #define pte_read(pte) (pte_val(pte) & _PAGE_READ) #define pte_write(pte) (pte_val(pte) & _PAGE_WRITE) -#define pte_dirty(pte) (pte_val(pte) & _PAGE_MODIFIED) +#define pte_dirty(pte) (pte_val(pte) & _PAGE_DIRTY) #define pte_young(pte) (pte_val(pte) & _PAGE_ACCESSED) -#define pte_special(pte) (0) +#define pte_special(pte) (pte_val(pte) & _PAGE_SPECIAL) #define PTE_BIT_FUNC(fn, op) \ static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } +PTE_BIT_FUNC(mknotpresent, &= ~(_PAGE_PRESENT)); PTE_BIT_FUNC(wrprotect, &= ~(_PAGE_WRITE)); PTE_BIT_FUNC(mkwrite, |= (_PAGE_WRITE)); -PTE_BIT_FUNC(mkclean, &= ~(_PAGE_MODIFIED)); -PTE_BIT_FUNC(mkdirty, |= (_PAGE_MODIFIED)); +PTE_BIT_FUNC(mkclean, &= ~(_PAGE_DIRTY)); +PTE_BIT_FUNC(mkdirty, |= (_PAGE_DIRTY)); PTE_BIT_FUNC(mkold, &= ~(_PAGE_ACCESSED)); PTE_BIT_FUNC(mkyoung, |= (_PAGE_ACCESSED)); PTE_BIT_FUNC(exprotect, &= ~(_PAGE_EXECUTE)); PTE_BIT_FUNC(mkexec, |= (_PAGE_EXECUTE)); +PTE_BIT_FUNC(mkspecial, |= (_PAGE_SPECIAL)); +PTE_BIT_FUNC(mkhuge, |= (_PAGE_HW_SZ)); -static inline pte_t pte_mkspecial(pte_t pte) { return pte; } +#define __HAVE_ARCH_PTE_SPECIAL static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { @@ -357,7 +360,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, #define pgd_offset_fast(mm, addr) pgd_offset(mm, addr) #endif -extern void paging_init(void); extern pgd_t swapper_pg_dir[] __aligned(PAGE_SIZE); void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep); @@ -383,6 +385,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, * remap a physical page `pfn' of size `size' with page protection `prot' * into virtual address `from' */ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#include <asm/hugepage.h> +#endif + #include <asm-generic/pgtable.h> /* to cope with aliasing VIPT cache */ diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h index ee682d8e0213..44545354e9e8 100644 --- a/arch/arc/include/asm/processor.h +++ b/arch/arc/include/asm/processor.h @@ -114,7 +114,12 @@ extern unsigned int get_wchan(struct task_struct *p); * ----------------------------------------------------------------------------- */ #define VMALLOC_START 0x70000000 -#define VMALLOC_SIZE (PAGE_OFFSET - VMALLOC_START) + +/* + * 1 PGDIR_SIZE each for fixmap/pkmap, 2 PGDIR_SIZE gutter + * See asm/highmem.h for details + */ +#define VMALLOC_SIZE (PAGE_OFFSET - VMALLOC_START - PGDIR_SIZE * 4) #define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) #define USER_KERNEL_GUTTER 0x10000000 diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h index 6e3ef5ba4f74..307846691be6 100644 --- a/arch/arc/include/asm/setup.h +++ b/arch/arc/include/asm/setup.h @@ -33,4 +33,11 @@ extern int root_mountflags, end_mem; void setup_processor(void); void __init setup_arch_memory(void); +/* Helpers used in arc_*_mumbojumbo routines */ +#define IS_AVAIL1(v, s) ((v) ? s : "") +#define IS_DISABLED_RUN(v) ((v) ? "" : "(disabled) ") +#define IS_USED_RUN(v) ((v) ? "" : "(not used) ") +#define IS_USED_CFG(cfg) IS_USED_RUN(IS_ENABLED(cfg)) +#define IS_AVAIL2(v, s, cfg) IS_AVAIL1(v, s), IS_AVAIL1(v, IS_USED_CFG(cfg)) + #endif /* __ASMARC_SETUP_H */ diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h index 3845b9e94f69..133c867d15af 100644 --- a/arch/arc/include/asm/smp.h +++ b/arch/arc/include/asm/smp.h @@ -45,12 +45,19 @@ extern int smp_ipi_irq_setup(int cpu, int irq); * struct plat_smp_ops - SMP callbacks provided by platform to ARC SMP * * @info: SoC SMP specific info for /proc/cpuinfo etc + * @init_early_smp: A SMP specific h/w block can init itself + * Could be common across platforms so not covered by + * mach_desc->init_early() + * @init_irq_cpu: Called for each core so SMP h/w block driver can do + * any needed setup per cpu (e.g. IPI request) * @cpu_kick: For Master to kickstart a cpu (optionally at a PC) * @ipi_send: To send IPI to a @cpu * @ips_clear: To clear IPI received at @irq */ struct plat_smp_ops { const char *info; + void (*init_early_smp)(void); + void (*init_irq_cpu)(int cpu); void (*cpu_kick)(int cpu, unsigned long pc); void (*ipi_send)(int cpu); void (*ipi_clear)(int irq); diff --git a/arch/arc/include/asm/tlbflush.h b/arch/arc/include/asm/tlbflush.h index 71c7b2e4b874..1fe9c8c80280 100644 --- a/arch/arc/include/asm/tlbflush.h +++ b/arch/arc/include/asm/tlbflush.h @@ -17,6 +17,8 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +void local_flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); #ifndef CONFIG_SMP #define flush_tlb_range(vma, s, e) local_flush_tlb_range(vma, s, e) @@ -24,6 +26,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, #define flush_tlb_kernel_range(s, e) local_flush_tlb_kernel_range(s, e) #define flush_tlb_all() local_flush_tlb_all() #define flush_tlb_mm(mm) local_flush_tlb_mm(mm) +#define flush_pmd_tlb_range(vma, s, e) local_flush_pmd_tlb_range(vma, s, e) #else extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); @@ -31,5 +34,7 @@ extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); extern void flush_tlb_all(void); extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); + #endif /* CONFIG_SMP */ #endif diff --git a/arch/arc/include/uapi/asm/page.h b/arch/arc/include/uapi/asm/page.h index 9d129a2a1351..059aff38f10a 100644 --- a/arch/arc/include/uapi/asm/page.h +++ b/arch/arc/include/uapi/asm/page.h @@ -9,6 +9,8 @@ #ifndef _UAPI__ASM_ARC_PAGE_H #define _UAPI__ASM_ARC_PAGE_H +#include <linux/const.h> + /* PAGE_SHIFT determines the page size */ #if defined(CONFIG_ARC_PAGE_SIZE_16K) #define PAGE_SHIFT 14 @@ -25,13 +27,8 @@ #define PAGE_SHIFT 13 #endif -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (1 << PAGE_SHIFT) -#define PAGE_OFFSET (0x80000000) -#else -#define PAGE_SIZE (1UL << PAGE_SHIFT) /* Default 8K */ -#define PAGE_OFFSET (0x80000000UL) /* Kernel starts at 2G onwards */ -#endif +#define PAGE_SIZE _BITUL(PAGE_SHIFT) /* Default 8K */ +#define PAGE_OFFSET _AC(0x80000000, UL) /* Kernel starts at 2G onwrds */ #define PAGE_MASK (~(PAGE_SIZE-1)) diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S index 8fa76567e402..445e63a10754 100644 --- a/arch/arc/kernel/entry-arcv2.S +++ b/arch/arc/kernel/entry-arcv2.S @@ -24,7 +24,7 @@ .align 4 # Initial 16 slots are Exception Vectors -VECTOR stext ; Restart Vector (jump to entry point) +VECTOR res_service ; Reset Vector VECTOR mem_service ; Mem exception VECTOR instr_service ; Instrn Error VECTOR EV_MachineCheck ; Fatal Machine check diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S index 15d457b4403a..59f52035b4ea 100644 --- a/arch/arc/kernel/entry-compact.S +++ b/arch/arc/kernel/entry-compact.S @@ -86,7 +86,7 @@ */ ; ********* Critical System Events ********************** -VECTOR res_service ; 0x0, Restart Vector (0x0) +VECTOR res_service ; 0x0, Reset Vector (0x0) VECTOR mem_service ; 0x8, Mem exception (0x1) VECTOR instr_service ; 0x10, Instrn Error (0x2) @@ -155,13 +155,9 @@ int2_saved_reg: ; --------------------------------------------- .section .text, "ax",@progbits -res_service: ; processor restart - flag 0x1 ; not implemented - nop - nop -reserved: ; processor restart - rtie ; jump to processor initializations +reserved: + flag 1 ; Unexpected event, halt ;##################### Interrupt Handling ############################## @@ -175,12 +171,25 @@ ENTRY(handle_interrupt_level2) ;------------------------------------------------------ ; if L2 IRQ interrupted a L1 ISR, disable preemption + ; + ; This is to avoid a potential L1-L2-L1 scenario + ; -L1 IRQ taken + ; -L2 interrupts L1 (before L1 ISR could run) + ; -preemption off IRQ, user task in syscall picked to run + ; -RTIE to userspace + ; Returns from L2 context fine + ; But both L1 and L2 re-enabled, so another L1 can be taken + ; while prev L1 is still unserviced + ; ;------------------------------------------------------ + ; L2 interrupting L1 implies both L2 and L1 active + ; However both A2 and A1 are NOT set in STATUS32, thus + ; need to check STATUS32_L2 to determine if L1 was active + ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs) bbit0 r9, STATUS_A1_BIT, 1f ; L1 not active when L2 IRQ, so normal - ; A1 is set in status32_l2 ; bump thread_info->preempt_count (Disable preemption) GET_CURR_THR_INFO_FROM_SP r10 ld r9, [r10, THREAD_INFO_PREEMPT_COUNT] @@ -320,11 +329,10 @@ END(call_do_page_fault) ; Note that we use realtime STATUS32 (not pt_regs->status32) to ; decide that. - ; if Returning from Exception - btst r10, STATUS_AE_BIT - bnz .Lexcep_ret + and.f 0, r10, (STATUS_A1_MASK|STATUS_A2_MASK) + bz .Lexcep_or_pure_K_ret - ; Not Exception so maybe Interrupts (Level 1 or 2) + ; Returning from Interrupts (Level 1 or 2) #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS @@ -365,8 +373,7 @@ END(call_do_page_fault) st r9, [r10, THREAD_INFO_PREEMPT_COUNT] 149: - ;return from level 2 - INTERRUPT_EPILOGUE 2 + INTERRUPT_EPILOGUE 2 ; return from level 2 interrupt debug_marker_l2: rtie @@ -374,15 +381,11 @@ not_level2_interrupt: #endif - bbit0 r10, STATUS_A1_BIT, .Lpure_k_mode_ret - - ;return from level 1 - INTERRUPT_EPILOGUE 1 + INTERRUPT_EPILOGUE 1 ; return from level 1 interrupt debug_marker_l1: rtie -.Lexcep_ret: -.Lpure_k_mode_ret: +.Lexcep_or_pure_K_ret: ;this case is for syscalls or Exceptions or pure kernel mode diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S index 812f95e6ae69..689dd867fdff 100644 --- a/arch/arc/kernel/head.S +++ b/arch/arc/kernel/head.S @@ -50,28 +50,37 @@ .endm .section .init.text, "ax",@progbits - .type stext, @function - .globl stext -stext: - ;------------------------------------------------------------------- - ; Don't clobber r0-r2 yet. It might have bootloader provided info - ;------------------------------------------------------------------- + +;---------------------------------------------------------------- +; Default Reset Handler (jumped into from Reset vector) +; - Don't clobber r0,r1,r2 as they might have u-boot provided args +; - Platforms can override this weak version if needed +;---------------------------------------------------------------- +WEAK(res_service) + j stext +END(res_service) + +;---------------------------------------------------------------- +; Kernel Entry point +;---------------------------------------------------------------- +ENTRY(stext) CPU_EARLY_SETUP #ifdef CONFIG_SMP - ; Ensure Boot (Master) proceeds. Others wait in platform dependent way - ; IDENTITY Reg [ 3 2 1 0 ] - ; (cpu-id) ^^^ => Zero for UP ARC700 - ; => #Core-ID if SMP (Master 0) - ; Note that non-boot CPUs might not land here if halt-on-reset and - ; instead breath life from @first_lines_of_secondary, but we still - ; need to make sure only boot cpu takes this path. GET_CPU_ID r5 cmp r5, 0 - mov.ne r0, r5 - jne arc_platform_smp_wait_to_boot + mov.nz r0, r5 +#ifdef CONFIG_ARC_SMP_HALT_ON_RESET + ; Non-Master can proceed as system would be booted sufficiently + jnz first_lines_of_secondary +#else + ; Non-Masters wait for Master to boot enough and bring them up + jnz arc_platform_smp_wait_to_boot #endif + ; Master falls thru +#endif + ; Clear BSS before updating any globals ; XXX: use ZOL here mov r5, __bss_start @@ -102,18 +111,14 @@ stext: GET_TSK_STACK_BASE r9, sp ; r9 = tsk, sp = stack base(output) j start_kernel ; "C" entry point +END(stext) #ifdef CONFIG_SMP ;---------------------------------------------------------------- ; First lines of code run by secondary before jumping to 'C' ;---------------------------------------------------------------- .section .text, "ax",@progbits - .type first_lines_of_secondary, @function - .globl first_lines_of_secondary - -first_lines_of_secondary: - - CPU_EARLY_SETUP +ENTRY(first_lines_of_secondary) ; setup per-cpu idle task as "current" on this CPU ld r0, [@secondary_idle_tsk] @@ -126,5 +131,5 @@ first_lines_of_secondary: GET_TSK_STACK_BASE r0, sp j start_kernel_secondary - +END(first_lines_of_secondary) #endif diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c index 039fac30b5c1..06bcedf19b62 100644 --- a/arch/arc/kernel/intc-compact.c +++ b/arch/arc/kernel/intc-compact.c @@ -79,17 +79,16 @@ static struct irq_chip onchip_intc = { static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - /* - * XXX: the IPI IRQ needs to be handled like TIMER too. However ARC core - * code doesn't own it (like TIMER0). ISS IDU / ezchip define it - * in platform header which can't be included here as it goes - * against multi-platform image philisophy - */ - if (irq == TIMER0_IRQ) + switch (irq) { + case TIMER0_IRQ: +#ifdef CONFIG_SMP + case IPI_IRQ: +#endif irq_set_chip_and_handler(irq, &onchip_intc, handle_percpu_irq); - else + break; + default: irq_set_chip_and_handler(irq, &onchip_intc, handle_level_irq); - + } return 0; } @@ -148,78 +147,15 @@ IRQCHIP_DECLARE(arc_intc, "snps,arc700-intc", init_onchip_IRQ); void arch_local_irq_enable(void) { - unsigned long flags = arch_local_save_flags(); - /* Allow both L1 and L2 at the onset */ - flags |= (STATUS_E1_MASK | STATUS_E2_MASK); - - /* Called from hard ISR (between irq_enter and irq_exit) */ - if (in_irq()) { - - /* If in L2 ISR, don't re-enable any further IRQs as this can - * cause IRQ priorities to get upside down. e.g. it could allow - * L1 be taken while in L2 hard ISR which is wrong not only in - * theory, it can also cause the dreaded L1-L2-L1 scenario - */ - if (flags & STATUS_A2_MASK) - flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK); - - /* Even if in L1 ISR, allowe Higher prio L2 IRQs */ - else if (flags & STATUS_A1_MASK) - flags &= ~(STATUS_E1_MASK); - } - - /* called from soft IRQ, ideally we want to re-enable all levels */ - - else if (in_softirq()) { - - /* However if this is case of L1 interrupted by L2, - * re-enabling both may cause whaco L1-L2-L1 scenario - * because ARC700 allows level 1 to interrupt an active L2 ISR - * Thus we disable both - * However some code, executing in soft ISR wants some IRQs - * to be enabled so we re-enable L2 only - * - * How do we determine L1 intr by L2 - * -A2 is set (means in L2 ISR) - * -E1 is set in this ISR's pt_regs->status32 which is - * saved copy of status32_l2 when l2 ISR happened - */ - struct pt_regs *pt = get_irq_regs(); - - if ((flags & STATUS_A2_MASK) && pt && - (pt->status32 & STATUS_A1_MASK)) { - /*flags &= ~(STATUS_E1_MASK | STATUS_E2_MASK); */ - flags &= ~(STATUS_E1_MASK); - } - } + if (flags & STATUS_A2_MASK) + flags |= STATUS_E2_MASK; + else if (flags & STATUS_A1_MASK) + flags |= STATUS_E1_MASK; arch_local_irq_restore(flags); } -#else /* ! CONFIG_ARC_COMPACT_IRQ_LEVELS */ - -/* - * Simpler version for only 1 level of interrupt - * Here we only Worry about Level 1 Bits - */ -void arch_local_irq_enable(void) -{ - unsigned long flags; - - /* - * ARC IDE Drivers tries to re-enable interrupts from hard-isr - * context which is simply wrong - */ - if (in_irq()) { - WARN_ONCE(1, "IRQ enabled from hard-isr"); - return; - } - - flags = arch_local_save_flags(); - flags |= (STATUS_E1_MASK | STATUS_E2_MASK); - arch_local_irq_restore(flags); -} -#endif EXPORT_SYMBOL(arch_local_irq_enable); +#endif diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 2989a7bcf8a8..2ee226546c6a 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -10,6 +10,7 @@ #include <linux/interrupt.h> #include <linux/irqchip.h> #include <asm/mach_desc.h> +#include <asm/smp.h> /* * Late Interrupt system init called from start_kernel for Boot CPU only @@ -19,17 +20,20 @@ */ void __init init_IRQ(void) { - /* Any external intc can be setup here */ - if (machine_desc->init_irq) - machine_desc->init_irq(); - - /* process the entire interrupt tree in one go */ + /* + * process the entire interrupt tree in one go + * Any external intc will be setup provided DT chains them + * properly + */ irqchip_init(); #ifdef CONFIG_SMP - /* Master CPU can initialize it's side of IPI */ - if (machine_desc->init_smp) - machine_desc->init_smp(smp_processor_id()); + /* a SMP H/w block could do IPI IRQ request here */ + if (plat_smp_ops.init_irq_cpu) + plat_smp_ops.init_irq_cpu(smp_processor_id()); + + if (machine_desc->init_cpu_smp) + machine_desc->init_cpu_smp(smp_processor_id()); #endif } diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 4ffd1855f1bd..74a9b074ac3e 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -12,20 +12,14 @@ #include <linux/irq.h> #include <linux/spinlock.h> #include <asm/mcip.h> +#include <asm/setup.h> static char smp_cpuinfo_buf[128]; static int idu_detected; static DEFINE_RAW_SPINLOCK(mcip_lock); -/* - * Any SMP specific init any CPU does when it comes up. - * Here we setup the CPU to enable Inter-Processor-Interrupts - * Called for each CPU - * -Master : init_IRQ() - * -Other(s) : start_kernel_secondary() - */ -void mcip_init_smp(unsigned int cpu) +static void mcip_setup_per_cpu(int cpu) { smp_ipi_irq_setup(cpu, IPI_IRQ); } @@ -96,34 +90,8 @@ static void mcip_ipi_clear(int irq) #endif } -volatile int wake_flag; - -static void mcip_wakeup_cpu(int cpu, unsigned long pc) -{ - BUG_ON(cpu == 0); - wake_flag = cpu; -} - -void arc_platform_smp_wait_to_boot(int cpu) +static void mcip_probe_n_setup(void) { - while (wake_flag != cpu) - ; - - wake_flag = 0; - __asm__ __volatile__("j @first_lines_of_secondary \n"); -} - -struct plat_smp_ops plat_smp_ops = { - .info = smp_cpuinfo_buf, - .cpu_kick = mcip_wakeup_cpu, - .ipi_send = mcip_ipi_send, - .ipi_clear = mcip_ipi_clear, -}; - -void mcip_init_early_smp(void) -{ -#define IS_AVAIL1(var, str) ((var) ? str : "") - struct mcip_bcr { #ifdef CONFIG_CPU_BIG_ENDIAN unsigned int pad3:8, @@ -161,6 +129,14 @@ void mcip_init_early_smp(void) panic("kernel trying to use non-existent GRTC\n"); } +struct plat_smp_ops plat_smp_ops = { + .info = smp_cpuinfo_buf, + .init_early_smp = mcip_probe_n_setup, + .init_irq_cpu = mcip_setup_per_cpu, + .ipi_send = mcip_ipi_send, + .ipi_clear = mcip_ipi_clear, +}; + /*************************************************************************** * ARCv2 Interrupt Distribution Unit (IDU) * diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index cabde9dc0696..c33e77c0ad3e 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -160,10 +160,6 @@ static const struct cpuinfo_data arc_cpu_tbl[] = { { {0x00, NULL } } }; -#define IS_AVAIL1(v, s) ((v) ? s : "") -#define IS_USED_RUN(v) ((v) ? "" : "(not used) ") -#define IS_USED_CFG(cfg) IS_USED_RUN(IS_ENABLED(cfg)) -#define IS_AVAIL2(v, s, cfg) IS_AVAIL1(v, s), IS_AVAIL1(v, IS_USED_CFG(cfg)) static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) { @@ -415,8 +411,9 @@ void __init setup_arch(char **cmdline_p) if (machine_desc->init_early) machine_desc->init_early(); - setup_processor(); smp_init_cpus(); + + setup_processor(); setup_arch_memory(); /* copy flat DT out of .init and then unflatten it */ diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index be13d12420ba..580587805fa3 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -42,8 +42,13 @@ void __init smp_prepare_boot_cpu(void) } /* - * Initialise the CPU possible map early - this describes the CPUs - * which may be present or become present in the system. + * Called from setup_arch() before calling setup_processor() + * + * - Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + * - Call early smp init hook. This can initialize a specific multi-core + * IP which is say common to several platforms (hence not part of + * platform specific int_early() hook) */ void __init smp_init_cpus(void) { @@ -51,6 +56,9 @@ void __init smp_init_cpus(void) for (i = 0; i < NR_CPUS; i++) set_cpu_possible(i, true); + + if (plat_smp_ops.init_early_smp) + plat_smp_ops.init_early_smp(); } /* called from init ( ) => process 1 */ @@ -72,35 +80,29 @@ void __init smp_cpus_done(unsigned int max_cpus) } /* - * After power-up, a non Master CPU needs to wait for Master to kick start it - * - * The default implementation halts - * - * This relies on platform specific support allowing Master to directly set - * this CPU's PC (to be @first_lines_of_secondary() and kick start it. - * - * In lack of such h/w assist, platforms can override this function - * - make this function busy-spin on a token, eventually set by Master - * (from arc_platform_smp_wakeup_cpu()) - * - Once token is available, jump to @first_lines_of_secondary - * (using inline asm). - * - * Alert: can NOT use stack here as it has not been determined/setup for CPU. - * If it turns out to be elaborate, it's better to code it in assembly - * + * Default smp boot helper for Run-on-reset case where all cores start off + * together. Non-masters need to wait for Master to start running. + * This is implemented using a flag in memory, which Non-masters spin-wait on. + * Master sets it to cpu-id of core to "ungate" it. */ -void __weak arc_platform_smp_wait_to_boot(int cpu) +static volatile int wake_flag; + +static void arc_default_smp_cpu_kick(int cpu, unsigned long pc) { - /* - * As a hack for debugging - since debugger will single-step over the - * FLAG insn - wrap the halt itself it in a self loop - */ - __asm__ __volatile__( - "1: \n" - " flag 1 \n" - " b 1b \n"); + BUG_ON(cpu == 0); + wake_flag = cpu; +} + +void arc_platform_smp_wait_to_boot(int cpu) +{ + while (wake_flag != cpu) + ; + + wake_flag = 0; + __asm__ __volatile__("j @first_lines_of_secondary \n"); } + const char *arc_platform_smp_cpuinfo(void) { return plat_smp_ops.info ? : ""; @@ -129,8 +131,12 @@ void start_kernel_secondary(void) pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); - if (machine_desc->init_smp) - machine_desc->init_smp(cpu); + /* Some SMP H/w setup - for each cpu */ + if (plat_smp_ops.init_irq_cpu) + plat_smp_ops.init_irq_cpu(cpu); + + if (machine_desc->init_cpu_smp) + machine_desc->init_cpu_smp(cpu); arc_local_timer_setup(); @@ -161,6 +167,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) if (plat_smp_ops.cpu_kick) plat_smp_ops.cpu_kick(cpu, (unsigned long)first_lines_of_secondary); + else + arc_default_smp_cpu_kick(cpu, (unsigned long)NULL); /* wait for 1 sec after kicking the secondary */ wait_till = jiffies + HZ; diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 4294761a2b3e..dfad287f1db1 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -285,7 +285,4 @@ void __init time_init(void) /* sets up the periodic event timer */ arc_local_timer_setup(); - - if (machine_desc->init_time) - machine_desc->init_time(); } diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S index dd35bde39f69..894e696bddaa 100644 --- a/arch/arc/kernel/vmlinux.lds.S +++ b/arch/arc/kernel/vmlinux.lds.S @@ -12,7 +12,7 @@ #include <asm/thread_info.h> OUTPUT_ARCH(arc) -ENTRY(_stext) +ENTRY(res_service) #ifdef CONFIG_CPU_BIG_ENDIAN jiffies = jiffies_64 + 4; diff --git a/arch/arc/mm/Makefile b/arch/arc/mm/Makefile index 7beb941556c3..3703a4969349 100644 --- a/arch/arc/mm/Makefile +++ b/arch/arc/mm/Makefile @@ -8,3 +8,4 @@ obj-y := extable.o ioremap.o dma.o fault.o init.o obj-y += tlb.o tlbex.o cache.o mmap.o +obj-$(CONFIG_HIGHMEM) += highmem.o diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 0d1a6e96839f..ff7ff6cbb811 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -25,7 +25,7 @@ static int l2_line_sz; int ioc_exists; volatile int slc_enable = 1, ioc_enable = 1; -void (*_cache_line_loop_ic_fn)(unsigned long paddr, unsigned long vaddr, +void (*_cache_line_loop_ic_fn)(phys_addr_t paddr, unsigned long vaddr, unsigned long sz, const int cacheop); void (*__dma_cache_wback_inv)(unsigned long start, unsigned long sz); @@ -37,7 +37,6 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) int n = 0; struct cpuinfo_arc_cache *p; -#define IS_USED_RUN(v) ((v) ? "" : "(disabled) ") #define PR_CACHE(p, cfg, str) \ if (!(p)->ver) \ n += scnprintf(buf + n, len - n, str"\t\t: N/A\n"); \ @@ -47,7 +46,7 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) (p)->sz_k, (p)->assoc, (p)->line_len, \ (p)->vipt ? "VIPT" : "PIPT", \ (p)->alias ? " aliasing" : "", \ - IS_ENABLED(cfg) ? "" : " (not used)"); + IS_USED_CFG(cfg)); PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache"); PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache"); @@ -63,7 +62,7 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) if (ioc_exists) n += scnprintf(buf + n, len - n, "IOC\t\t:%s\n", - IS_USED_RUN(ioc_enable)); + IS_DISABLED_RUN(ioc_enable)); return buf; } @@ -217,7 +216,7 @@ slc_chk: */ static inline -void __cache_line_loop_v2(unsigned long paddr, unsigned long vaddr, +void __cache_line_loop_v2(phys_addr_t paddr, unsigned long vaddr, unsigned long sz, const int op) { unsigned int aux_cmd; @@ -254,8 +253,12 @@ void __cache_line_loop_v2(unsigned long paddr, unsigned long vaddr, } } +/* + * For ARC700 MMUv3 I-cache and D-cache flushes + * Also reused for HS38 aliasing I-cache configuration + */ static inline -void __cache_line_loop_v3(unsigned long paddr, unsigned long vaddr, +void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr, unsigned long sz, const int op) { unsigned int aux_cmd, aux_tag; @@ -290,6 +293,16 @@ void __cache_line_loop_v3(unsigned long paddr, unsigned long vaddr, if (full_page) write_aux_reg(aux_tag, paddr); + /* + * This is technically for MMU v4, using the MMU v3 programming model + * Special work for HS38 aliasing I-cache configuratino with PAE40 + * - upper 8 bits of paddr need to be written into PTAG_HI + * - (and needs to be written before the lower 32 bits) + * Note that PTAG_HI is hoisted outside the line loop + */ + if (is_pae40_enabled() && op == OP_INV_IC) + write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32); + while (num_lines-- > 0) { if (!full_page) { write_aux_reg(aux_tag, paddr); @@ -302,14 +315,20 @@ void __cache_line_loop_v3(unsigned long paddr, unsigned long vaddr, } /* - * In HS38x (MMU v4), although icache is VIPT, only paddr is needed for cache - * maintenance ops (in IVIL reg), as long as icache doesn't alias. + * In HS38x (MMU v4), I-cache is VIPT (can alias), D-cache is PIPT + * Here's how cache ops are implemented + * + * - D-cache: only paddr needed (in DC_IVDL/DC_FLDL) + * - I-cache Non Aliasing: Despite VIPT, only paddr needed (in IC_IVIL) + * - I-cache Aliasing: Both vaddr and paddr needed (in IC_IVIL, IC_PTAG + * respectively, similar to MMU v3 programming model, hence + * __cache_line_loop_v3() is used) * - * For Aliasing icache, vaddr is also needed (in IVIL), while paddr is - * specified in PTAG (similar to MMU v3) + * If PAE40 is enabled, independent of aliasing considerations, the higher bits + * needs to be written into PTAG_HI */ static inline -void __cache_line_loop_v4(unsigned long paddr, unsigned long vaddr, +void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr, unsigned long sz, const int cacheop) { unsigned int aux_cmd; @@ -336,6 +355,22 @@ void __cache_line_loop_v4(unsigned long paddr, unsigned long vaddr, num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES); + /* + * For HS38 PAE40 configuration + * - upper 8 bits of paddr need to be written into PTAG_HI + * - (and needs to be written before the lower 32 bits) + */ + if (is_pae40_enabled()) { + if (cacheop == OP_INV_IC) + /* + * Non aliasing I-cache in HS38, + * aliasing I-cache handled in __cache_line_loop_v3() + */ + write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32); + else + write_aux_reg(ARC_REG_DC_PTAG_HI, (u64)paddr >> 32); + } + while (num_lines-- > 0) { write_aux_reg(aux_cmd, paddr); paddr += L1_CACHE_BYTES; @@ -413,7 +448,7 @@ static inline void __dc_entire_op(const int op) /* * D-Cache Line ops: Per Line INV (discard or wback+discard) or FLUSH (wback) */ -static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr, +static inline void __dc_line_op(phys_addr_t paddr, unsigned long vaddr, unsigned long sz, const int op) { unsigned long flags; @@ -446,7 +481,7 @@ static inline void __ic_entire_inv(void) } static inline void -__ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr, +__ic_line_inv_vaddr_local(phys_addr_t paddr, unsigned long vaddr, unsigned long sz) { unsigned long flags; @@ -463,7 +498,7 @@ __ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr, #else struct ic_inv_args { - unsigned long paddr, vaddr; + phys_addr_t paddr, vaddr; int sz; }; @@ -474,7 +509,7 @@ static void __ic_line_inv_vaddr_helper(void *info) __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz); } -static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr, +static void __ic_line_inv_vaddr(phys_addr_t paddr, unsigned long vaddr, unsigned long sz) { struct ic_inv_args ic_inv = { @@ -495,7 +530,7 @@ static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr, #endif /* CONFIG_ARC_HAS_ICACHE */ -noinline void slc_op(unsigned long paddr, unsigned long sz, const int op) +noinline void slc_op(phys_addr_t paddr, unsigned long sz, const int op) { #ifdef CONFIG_ISA_ARCV2 /* @@ -585,7 +620,7 @@ void flush_dcache_page(struct page *page) } else if (page_mapped(page)) { /* kernel reading from page with U-mapping */ - unsigned long paddr = (unsigned long)page_address(page); + phys_addr_t paddr = (unsigned long)page_address(page); unsigned long vaddr = page->index << PAGE_CACHE_SHIFT; if (addr_not_cache_congruent(paddr, vaddr)) @@ -733,14 +768,14 @@ EXPORT_SYMBOL(flush_icache_range); * builtin kernel page will not have any virtual mappings. * kprobe on loadable module will be kernel vaddr. */ -void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len) +void __sync_icache_dcache(phys_addr_t paddr, unsigned long vaddr, int len) { __dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV); __ic_line_inv_vaddr(paddr, vaddr, len); } /* wrapper to compile time eliminate alignment checks in flush loop */ -void __inv_icache_page(unsigned long paddr, unsigned long vaddr) +void __inv_icache_page(phys_addr_t paddr, unsigned long vaddr) { __ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE); } @@ -749,7 +784,7 @@ void __inv_icache_page(unsigned long paddr, unsigned long vaddr) * wrapper to clearout kernel or userspace mappings of a page * For kernel mappings @vaddr == @paddr */ -void __flush_dcache_page(unsigned long paddr, unsigned long vaddr) +void __flush_dcache_page(phys_addr_t paddr, unsigned long vaddr) { __dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV); } @@ -807,8 +842,8 @@ void flush_anon_page(struct vm_area_struct *vma, struct page *page, void copy_user_highpage(struct page *to, struct page *from, unsigned long u_vaddr, struct vm_area_struct *vma) { - unsigned long kfrom = (unsigned long)page_address(from); - unsigned long kto = (unsigned long)page_address(to); + void *kfrom = kmap_atomic(from); + void *kto = kmap_atomic(to); int clean_src_k_mappings = 0; /* @@ -818,13 +853,16 @@ void copy_user_highpage(struct page *to, struct page *from, * * Note that while @u_vaddr refers to DST page's userspace vaddr, it is * equally valid for SRC page as well + * + * For !VIPT cache, all of this gets compiled out as + * addr_not_cache_congruent() is 0 */ if (page_mapped(from) && addr_not_cache_congruent(kfrom, u_vaddr)) { - __flush_dcache_page(kfrom, u_vaddr); + __flush_dcache_page((unsigned long)kfrom, u_vaddr); clean_src_k_mappings = 1; } - copy_page((void *)kto, (void *)kfrom); + copy_page(kto, kfrom); /* * Mark DST page K-mapping as dirty for a later finalization by @@ -841,11 +879,14 @@ void copy_user_highpage(struct page *to, struct page *from, * sync the kernel mapping back to physical page */ if (clean_src_k_mappings) { - __flush_dcache_page(kfrom, kfrom); + __flush_dcache_page((unsigned long)kfrom, (unsigned long)kfrom); set_bit(PG_dc_clean, &from->flags); } else { clear_bit(PG_dc_clean, &from->flags); } + + kunmap_atomic(kto); + kunmap_atomic(kfrom); } void clear_user_page(void *to, unsigned long u_vaddr, struct page *page) diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index d948e4e9d89c..af63f4a13e60 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -18,7 +18,14 @@ #include <asm/pgalloc.h> #include <asm/mmu.h> -static int handle_vmalloc_fault(unsigned long address) +/* + * kernel virtual address is required to implement vmalloc/pkmap/fixmap + * Refer to asm/processor.h for System Memory Map + * + * It simply copies the PMD entry (pointer to 2nd level page table or hugepage) + * from swapper pgdir to task pgdir. The 2nd level table/page is thus shared + */ +noinline static int handle_kernel_vaddr_fault(unsigned long address) { /* * Synchronize this task's top level page-table @@ -72,8 +79,8 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) * only copy the information from the master page table, * nothing more. */ - if (address >= VMALLOC_START && address <= VMALLOC_END) { - ret = handle_vmalloc_fault(address); + if (address >= VMALLOC_START) { + ret = handle_kernel_vaddr_fault(address); if (unlikely(ret)) goto bad_area_nosemaphore; else diff --git a/arch/arc/mm/highmem.c b/arch/arc/mm/highmem.c new file mode 100644 index 000000000000..065ee6bfa82a --- /dev/null +++ b/arch/arc/mm/highmem.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/bootmem.h> +#include <linux/export.h> +#include <linux/highmem.h> +#include <asm/processor.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> + +/* + * HIGHMEM API: + * + * kmap() API provides sleep semantics hence refered to as "permanent maps" + * It allows mapping LAST_PKMAP pages, using @last_pkmap_nr as the cursor + * for book-keeping + * + * kmap_atomic() can't sleep (calls pagefault_disable()), thus it provides + * shortlived ala "temporary mappings" which historically were implemented as + * fixmaps (compile time addr etc). Their book-keeping is done per cpu. + * + * Both these facts combined (preemption disabled and per-cpu allocation) + * means the total number of concurrent fixmaps will be limited to max + * such allocations in a single control path. Thus KM_TYPE_NR (another + * historic relic) is a small'ish number which caps max percpu fixmaps + * + * ARC HIGHMEM Details + * + * - the kernel vaddr space from 0x7z to 0x8z (currently used by vmalloc/module) + * is now shared between vmalloc and kmap (non overlapping though) + * + * - Both fixmap/pkmap use a dedicated page table each, hooked up to swapper PGD + * This means each only has 1 PGDIR_SIZE worth of kvaddr mappings, which means + * 2M of kvaddr space for typical config (8K page and 11:8:13 traversal split) + * + * - fixmap anyhow needs a limited number of mappings. So 2M kvaddr == 256 PTE + * slots across NR_CPUS would be more than sufficient (generic code defines + * KM_TYPE_NR as 20). + * + * - pkmap being preemptible, in theory could do with more than 256 concurrent + * mappings. However, generic pkmap code: map_new_virtual(), doesn't traverse + * the PGD and only works with a single page table @pkmap_page_table, hence + * sets the limit + */ + +extern pte_t * pkmap_page_table; +static pte_t * fixmap_page_table; + +void *kmap(struct page *page) +{ + BUG_ON(in_interrupt()); + if (!PageHighMem(page)) + return page_address(page); + + return kmap_high(page); +} + +void *kmap_atomic(struct page *page) +{ + int idx, cpu_idx; + unsigned long vaddr; + + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + cpu_idx = kmap_atomic_idx_push(); + idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); + vaddr = FIXMAP_ADDR(idx); + + set_pte_at(&init_mm, vaddr, fixmap_page_table + idx, + mk_pte(page, kmap_prot)); + + return (void *)vaddr; +} +EXPORT_SYMBOL(kmap_atomic); + +void __kunmap_atomic(void *kv) +{ + unsigned long kvaddr = (unsigned long)kv; + + if (kvaddr >= FIXMAP_BASE && kvaddr < (FIXMAP_BASE + FIXMAP_SIZE)) { + + /* + * Because preemption is disabled, this vaddr can be associated + * with the current allocated index. + * But in case of multiple live kmap_atomic(), it still relies on + * callers to unmap in right order. + */ + int cpu_idx = kmap_atomic_idx(); + int idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); + + WARN_ON(kvaddr != FIXMAP_ADDR(idx)); + + pte_clear(&init_mm, kvaddr, fixmap_page_table + idx); + local_flush_tlb_kernel_range(kvaddr, kvaddr + PAGE_SIZE); + + kmap_atomic_idx_pop(); + } + + pagefault_enable(); + preempt_enable(); +} +EXPORT_SYMBOL(__kunmap_atomic); + +noinline pte_t *alloc_kmap_pgtable(unsigned long kvaddr) +{ + pgd_t *pgd_k; + pud_t *pud_k; + pmd_t *pmd_k; + pte_t *pte_k; + + pgd_k = pgd_offset_k(kvaddr); + pud_k = pud_offset(pgd_k, kvaddr); + pmd_k = pmd_offset(pud_k, kvaddr); + + pte_k = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); + pmd_populate_kernel(&init_mm, pmd_k, pte_k); + return pte_k; +} + +void kmap_init(void) +{ + /* Due to recursive include hell, we can't do this in processor.h */ + BUILD_BUG_ON(PAGE_OFFSET < (VMALLOC_END + FIXMAP_SIZE + PKMAP_SIZE)); + + BUILD_BUG_ON(KM_TYPE_NR > PTRS_PER_PTE); + pkmap_page_table = alloc_kmap_pgtable(PKMAP_BASE); + + BUILD_BUG_ON(LAST_PKMAP > PTRS_PER_PTE); + fixmap_page_table = alloc_kmap_pgtable(FIXMAP_BASE); +} diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c index d44eedd8c322..a9305b5a2cd4 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -15,6 +15,7 @@ #endif #include <linux/swap.h> #include <linux/module.h> +#include <linux/highmem.h> #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/sections.h> @@ -24,16 +25,22 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD] __aligned(PAGE_SIZE); char empty_zero_page[PAGE_SIZE] __aligned(PAGE_SIZE); EXPORT_SYMBOL(empty_zero_page); -/* Default tot mem from .config */ -static unsigned long arc_mem_sz = 0x20000000; /* some default */ +static const unsigned long low_mem_start = CONFIG_LINUX_LINK_BASE; +static unsigned long low_mem_sz; + +#ifdef CONFIG_HIGHMEM +static unsigned long min_high_pfn; +static u64 high_mem_start; +static u64 high_mem_sz; +#endif /* User can over-ride above with "mem=nnn[KkMm]" in cmdline */ static int __init setup_mem_sz(char *str) { - arc_mem_sz = memparse(str, NULL) & PAGE_MASK; + low_mem_sz = memparse(str, NULL) & PAGE_MASK; /* early console might not be setup yet - it will show up later */ - pr_info("\"mem=%s\": mem sz set to %ldM\n", str, TO_MB(arc_mem_sz)); + pr_info("\"mem=%s\": mem sz set to %ldM\n", str, TO_MB(low_mem_sz)); return 0; } @@ -41,8 +48,22 @@ early_param("mem", setup_mem_sz); void __init early_init_dt_add_memory_arch(u64 base, u64 size) { - arc_mem_sz = size & PAGE_MASK; - pr_info("Memory size set via devicetree %ldM\n", TO_MB(arc_mem_sz)); + int in_use = 0; + + if (!low_mem_sz) { + BUG_ON(base != low_mem_start); + low_mem_sz = size; + in_use = 1; + } else { +#ifdef CONFIG_HIGHMEM + high_mem_start = base; + high_mem_sz = size; + in_use = 1; +#endif + } + + pr_info("Memory @ %llx [%lldM] %s\n", + base, TO_MB(size), !in_use ? "Not used":""); } #ifdef CONFIG_BLK_DEV_INITRD @@ -72,46 +93,62 @@ early_param("initrd", early_initrd); void __init setup_arch_memory(void) { unsigned long zones_size[MAX_NR_ZONES]; - unsigned long end_mem = CONFIG_LINUX_LINK_BASE + arc_mem_sz; + unsigned long zones_holes[MAX_NR_ZONES]; init_mm.start_code = (unsigned long)_text; init_mm.end_code = (unsigned long)_etext; init_mm.end_data = (unsigned long)_edata; init_mm.brk = (unsigned long)_end; - /* - * We do it here, so that memory is correctly instantiated - * even if "mem=xxx" cmline over-ride is given and/or - * DT has memory node. Each causes an update to @arc_mem_sz - * and we finally add memory one here - */ - memblock_add(CONFIG_LINUX_LINK_BASE, arc_mem_sz); - - /*------------- externs in mm need setting up ---------------*/ - /* first page of system - kernel .vector starts here */ min_low_pfn = ARCH_PFN_OFFSET; - /* Last usable page of low mem (no HIGHMEM yet for ARC port) */ - max_low_pfn = max_pfn = PFN_DOWN(end_mem); + /* Last usable page of low mem */ + max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz); - max_mapnr = max_low_pfn - min_low_pfn; +#ifdef CONFIG_HIGHMEM + min_high_pfn = PFN_DOWN(high_mem_start); + max_pfn = PFN_DOWN(high_mem_start + high_mem_sz); +#endif + + max_mapnr = max_pfn - min_low_pfn; - /*------------- reserve kernel image -----------------------*/ - memblock_reserve(CONFIG_LINUX_LINK_BASE, - __pa(_end) - CONFIG_LINUX_LINK_BASE); + /*------------- bootmem allocator setup -----------------------*/ + + /* + * seed the bootmem allocator after any DT memory node parsing or + * "mem=xxx" cmdline overrides have potentially updated @arc_mem_sz + * + * Only low mem is added, otherwise we have crashes when allocating + * mem_map[] itself. NO_BOOTMEM allocates mem_map[] at the end of + * avail memory, ending in highmem with a > 32-bit address. However + * it then tries to memset it with a truncaed 32-bit handle, causing + * the crash + */ + + memblock_add(low_mem_start, low_mem_sz); + memblock_reserve(low_mem_start, __pa(_end) - low_mem_start); #ifdef CONFIG_BLK_DEV_INITRD - /*------------- reserve initrd image -----------------------*/ if (initrd_start) memblock_reserve(__pa(initrd_start), initrd_end - initrd_start); #endif memblock_dump_all(); - /*-------------- node setup --------------------------------*/ + /*----------------- node/zones setup --------------------------*/ memset(zones_size, 0, sizeof(zones_size)); - zones_size[ZONE_NORMAL] = max_mapnr; + memset(zones_holes, 0, sizeof(zones_holes)); + + zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; + zones_holes[ZONE_NORMAL] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn; + + /* This handles the peripheral address space hole */ + zones_holes[ZONE_HIGHMEM] = min_high_pfn - max_low_pfn; +#endif /* * We can't use the helper free_area_init(zones[]) because it uses @@ -122,9 +159,12 @@ void __init setup_arch_memory(void) free_area_init_node(0, /* node-id */ zones_size, /* num pages per zone */ min_low_pfn, /* first pfn of node */ - NULL); /* NO holes */ + zones_holes); /* holes */ - high_memory = (void *)end_mem; +#ifdef CONFIG_HIGHMEM + high_memory = (void *)(min_high_pfn << PAGE_SHIFT); + kmap_init(); +#endif } /* @@ -135,6 +175,14 @@ void __init setup_arch_memory(void) */ void __init mem_init(void) { +#ifdef CONFIG_HIGHMEM + unsigned long tmp; + + reset_all_zones_managed_pages(); + for (tmp = min_high_pfn; tmp < max_pfn; tmp++) + free_highmem_page(pfn_to_page(tmp)); +#endif + free_all_bootmem(); mem_init_print_info(NULL); } diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 2c7ce8bb7475..0ee739846847 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -109,6 +109,10 @@ DEFINE_PER_CPU(unsigned int, asid_cache) = MM_CTXT_FIRST_CYCLE; static inline void __tlb_entry_erase(void) { write_aux_reg(ARC_REG_TLBPD1, 0); + + if (is_pae40_enabled()) + write_aux_reg(ARC_REG_TLBPD1HI, 0); + write_aux_reg(ARC_REG_TLBPD0, 0); write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite); } @@ -182,7 +186,7 @@ static void utlb_invalidate(void) } -static void tlb_entry_insert(unsigned int pd0, unsigned int pd1) +static void tlb_entry_insert(unsigned int pd0, pte_t pd1) { unsigned int idx; @@ -225,10 +229,14 @@ static void tlb_entry_erase(unsigned int vaddr_n_asid) write_aux_reg(ARC_REG_TLBCOMMAND, TLBDeleteEntry); } -static void tlb_entry_insert(unsigned int pd0, unsigned int pd1) +static void tlb_entry_insert(unsigned int pd0, pte_t pd1) { write_aux_reg(ARC_REG_TLBPD0, pd0); write_aux_reg(ARC_REG_TLBPD1, pd1); + + if (is_pae40_enabled()) + write_aux_reg(ARC_REG_TLBPD1HI, (u64)pd1 >> 32); + write_aux_reg(ARC_REG_TLBCOMMAND, TLBInsertEntry); } @@ -240,22 +248,39 @@ static void tlb_entry_insert(unsigned int pd0, unsigned int pd1) noinline void local_flush_tlb_all(void) { + struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu; unsigned long flags; unsigned int entry; - struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu; + int num_tlb = mmu->sets * mmu->ways; local_irq_save(flags); /* Load PD0 and PD1 with template for a Blank Entry */ write_aux_reg(ARC_REG_TLBPD1, 0); + + if (is_pae40_enabled()) + write_aux_reg(ARC_REG_TLBPD1HI, 0); + write_aux_reg(ARC_REG_TLBPD0, 0); - for (entry = 0; entry < mmu->num_tlb; entry++) { + for (entry = 0; entry < num_tlb; entry++) { /* write this entry to the TLB */ write_aux_reg(ARC_REG_TLBINDEX, entry); write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite); } + if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { + const int stlb_idx = 0x800; + + /* Blank sTLB entry */ + write_aux_reg(ARC_REG_TLBPD0, _PAGE_HW_SZ); + + for (entry = stlb_idx; entry < stlb_idx + 16; entry++) { + write_aux_reg(ARC_REG_TLBINDEX, entry); + write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite); + } + } + utlb_invalidate(); local_irq_restore(flags); @@ -409,6 +434,15 @@ static inline void ipi_flush_tlb_range(void *arg) local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline void ipi_flush_pmd_tlb_range(void *arg) +{ + struct tlb_args *ta = arg; + + local_flush_pmd_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); +} +#endif + static inline void ipi_flush_tlb_kernel_range(void *arg) { struct tlb_args *ta = (struct tlb_args *)arg; @@ -449,6 +483,20 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range, &ta, 1); } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct tlb_args ta = { + .ta_vma = vma, + .ta_start = start, + .ta_end = end + }; + + on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_pmd_tlb_range, &ta, 1); +} +#endif + void flush_tlb_kernel_range(unsigned long start, unsigned long end) { struct tlb_args ta = { @@ -463,11 +511,12 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) /* * Routine to create a TLB entry */ -void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) +void create_tlb(struct vm_area_struct *vma, unsigned long vaddr, pte_t *ptep) { unsigned long flags; unsigned int asid_or_sasid, rwx; - unsigned long pd0, pd1; + unsigned long pd0; + pte_t pd1; /* * create_tlb() assumes that current->mm == vma->mm, since @@ -499,9 +548,9 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) local_irq_save(flags); - tlb_paranoid_check(asid_mm(vma->vm_mm, smp_processor_id()), address); + tlb_paranoid_check(asid_mm(vma->vm_mm, smp_processor_id()), vaddr); - address &= PAGE_MASK; + vaddr &= PAGE_MASK; /* update this PTE credentials */ pte_val(*ptep) |= (_PAGE_PRESENT | _PAGE_ACCESSED); @@ -511,7 +560,7 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) /* ASID for this task */ asid_or_sasid = read_aux_reg(ARC_REG_PID) & 0xff; - pd0 = address | asid_or_sasid | (pte_val(*ptep) & PTE_BITS_IN_PD0); + pd0 = vaddr | asid_or_sasid | (pte_val(*ptep) & PTE_BITS_IN_PD0); /* * ARC MMU provides fully orthogonal access bits for K/U mode, @@ -547,7 +596,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned, pte_t *ptep) { unsigned long vaddr = vaddr_unaligned & PAGE_MASK; - unsigned long paddr = pte_val(*ptep) & PAGE_MASK; + phys_addr_t paddr = pte_val(*ptep) & PAGE_MASK; struct page *page = pfn_to_page(pte_pfn(*ptep)); create_tlb(vma, vaddr, ptep); @@ -580,6 +629,95 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned, } } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + +/* + * MMUv4 in HS38x cores supports Super Pages which are basis for Linux THP + * support. + * + * Normal and Super pages can co-exist (ofcourse not overlap) in TLB with a + * new bit "SZ" in TLB page desciptor to distinguish between them. + * Super Page size is configurable in hardware (4K to 16M), but fixed once + * RTL builds. + * + * The exact THP size a Linx configuration will support is a function of: + * - MMU page size (typical 8K, RTL fixed) + * - software page walker address split between PGD:PTE:PFN (typical + * 11:8:13, but can be changed with 1 line) + * So for above default, THP size supported is 8K * (2^8) = 2M + * + * Default Page Walker is 2 levels, PGD:PTE:PFN, which in THP regime + * reduces to 1 level (as PTE is folded into PGD and canonically referred + * to as PMD). + * Thus THP PMD accessors are implemented in terms of PTE (just like sparc) + */ + +void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd) +{ + pte_t pte = __pte(pmd_val(*pmd)); + update_mmu_cache(vma, addr, &pte); +} + +void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, + pgtable_t pgtable) +{ + struct list_head *lh = (struct list_head *) pgtable; + + assert_spin_locked(&mm->page_table_lock); + + /* FIFO */ + if (!pmd_huge_pte(mm, pmdp)) + INIT_LIST_HEAD(lh); + else + list_add(lh, (struct list_head *) pmd_huge_pte(mm, pmdp)); + pmd_huge_pte(mm, pmdp) = pgtable; +} + +pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp) +{ + struct list_head *lh; + pgtable_t pgtable; + + assert_spin_locked(&mm->page_table_lock); + + pgtable = pmd_huge_pte(mm, pmdp); + lh = (struct list_head *) pgtable; + if (list_empty(lh)) + pmd_huge_pte(mm, pmdp) = NULL; + else { + pmd_huge_pte(mm, pmdp) = (pgtable_t) lh->next; + list_del(lh); + } + + pte_val(pgtable[0]) = 0; + pte_val(pgtable[1]) = 0; + + return pgtable; +} + +void local_flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + unsigned int cpu; + unsigned long flags; + + local_irq_save(flags); + + cpu = smp_processor_id(); + + if (likely(asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID)) { + unsigned int asid = hw_pid(vma->vm_mm, cpu); + + /* No need to loop here: this will always be for 1 Huge Page */ + tlb_entry_erase(start | _PAGE_HW_SZ | asid); + } + + local_irq_restore(flags); +} + +#endif + /* Read the Cache Build Confuration Registers, Decode them and save into * the cpuinfo structure for later use. * No Validation is done here, simply read/convert the BCRs @@ -598,10 +736,10 @@ void read_decode_mmu_bcr(void) struct bcr_mmu_3 { #ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4, + unsigned int ver:8, ways:4, sets:4, res:3, sasid:1, pg_sz:4, u_itlb:4, u_dtlb:4; #else - unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4, + unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, sasid:1, res:3, sets:4, ways:4, ver:8; #endif } *mmu3; @@ -622,7 +760,7 @@ void read_decode_mmu_bcr(void) if (mmu->ver <= 2) { mmu2 = (struct bcr_mmu_1_2 *)&tmp; - mmu->pg_sz_k = TO_KB(PAGE_SIZE); + mmu->pg_sz_k = TO_KB(0x2000); mmu->sets = 1 << mmu2->sets; mmu->ways = 1 << mmu2->ways; mmu->u_dtlb = mmu2->u_dtlb; @@ -634,6 +772,7 @@ void read_decode_mmu_bcr(void) mmu->ways = 1 << mmu3->ways; mmu->u_dtlb = mmu3->u_dtlb; mmu->u_itlb = mmu3->u_itlb; + mmu->sasid = mmu3->sasid; } else { mmu4 = (struct bcr_mmu_4 *)&tmp; mmu->pg_sz_k = 1 << (mmu4->sz0 - 1); @@ -642,9 +781,9 @@ void read_decode_mmu_bcr(void) mmu->ways = mmu4->n_ways * 2; mmu->u_dtlb = mmu4->u_dtlb * 4; mmu->u_itlb = mmu4->u_itlb * 4; + mmu->sasid = mmu4->sasid; + mmu->pae = mmu4->pae; } - - mmu->num_tlb = mmu->sets * mmu->ways; } char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len) @@ -655,14 +794,15 @@ char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len) if (p_mmu->s_pg_sz_m) scnprintf(super_pg, 64, "%dM Super Page%s, ", - p_mmu->s_pg_sz_m, " (not used)"); + p_mmu->s_pg_sz_m, + IS_USED_CFG(CONFIG_TRANSPARENT_HUGEPAGE)); n += scnprintf(buf + n, len - n, - "MMU [v%x]\t: %dk PAGE, %sJTLB %d (%dx%d), uDTLB %d, uITLB %d %s\n", + "MMU [v%x]\t: %dk PAGE, %sJTLB %d (%dx%d), uDTLB %d, uITLB %d %s%s\n", p_mmu->ver, p_mmu->pg_sz_k, super_pg, - p_mmu->num_tlb, p_mmu->sets, p_mmu->ways, + p_mmu->sets * p_mmu->ways, p_mmu->sets, p_mmu->ways, p_mmu->u_dtlb, p_mmu->u_itlb, - IS_ENABLED(CONFIG_ARC_MMU_SASID) ? ",SASID" : ""); + IS_AVAIL2(p_mmu->pae, "PAE40 ", CONFIG_ARC_HAS_PAE40)); return buf; } @@ -690,6 +830,14 @@ void arc_mmu_init(void) if (mmu->pg_sz_k != TO_KB(PAGE_SIZE)) panic("MMU pg size != PAGE_SIZE (%luk)\n", TO_KB(PAGE_SIZE)); + if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && + mmu->s_pg_sz_m != TO_MB(HPAGE_PMD_SIZE)) + panic("MMU Super pg size != Linux HPAGE_PMD_SIZE (%luM)\n", + (unsigned long)TO_MB(HPAGE_PMD_SIZE)); + + if (IS_ENABLED(CONFIG_ARC_HAS_PAE40) && !mmu->pae) + panic("Hardware doesn't support PAE40\n"); + /* Enable the MMU */ write_aux_reg(ARC_REG_PID, MMU_ENABLE); @@ -725,15 +873,15 @@ void arc_mmu_init(void) * the duplicate one. * -Knob to be verbose abt it.(TODO: hook them up to debugfs) */ -volatile int dup_pd_verbose = 1;/* Be slient abt it or complain (default) */ +volatile int dup_pd_silent; /* Be slient abt it or complain (default) */ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, struct pt_regs *regs) { - int set, way, n; - unsigned long flags, is_valid; struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu; - unsigned int pd0[mmu->ways], pd1[mmu->ways]; + unsigned int pd0[mmu->ways]; + unsigned long flags; + int set; local_irq_save(flags); @@ -743,14 +891,16 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, /* loop thru all sets of TLB */ for (set = 0; set < mmu->sets; set++) { + int is_valid, way; + /* read out all the ways of current set */ for (way = 0, is_valid = 0; way < mmu->ways; way++) { write_aux_reg(ARC_REG_TLBINDEX, SET_WAY_TO_IDX(mmu, set, way)); write_aux_reg(ARC_REG_TLBCOMMAND, TLBRead); pd0[way] = read_aux_reg(ARC_REG_TLBPD0); - pd1[way] = read_aux_reg(ARC_REG_TLBPD1); is_valid |= pd0[way] & _PAGE_PRESENT; + pd0[way] &= PAGE_MASK; } /* If all the WAYS in SET are empty, skip to next SET */ @@ -759,30 +909,28 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, /* Scan the set for duplicate ways: needs a nested loop */ for (way = 0; way < mmu->ways - 1; way++) { + + int n; + if (!pd0[way]) continue; for (n = way + 1; n < mmu->ways; n++) { - if ((pd0[way] & PAGE_MASK) == - (pd0[n] & PAGE_MASK)) { - - if (dup_pd_verbose) { - pr_info("Duplicate PD's @" - "[%d:%d]/[%d:%d]\n", - set, way, set, n); - pr_info("TLBPD0[%u]: %08x\n", - way, pd0[way]); - } - - /* - * clear entry @way and not @n. This is - * critical to our optimised loop - */ - pd0[way] = pd1[way] = 0; - write_aux_reg(ARC_REG_TLBINDEX, + if (pd0[way] != pd0[n]) + continue; + + if (!dup_pd_silent) + pr_info("Dup TLB PD0 %08x @ set %d ways %d,%d\n", + pd0[way], set, way, n); + + /* + * clear entry @way and not @n. + * This is critical to our optimised loop + */ + pd0[way] = 0; + write_aux_reg(ARC_REG_TLBINDEX, SET_WAY_TO_IDX(mmu, set, way)); - __tlb_entry_erase(); - } + __tlb_entry_erase(); } } } diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S index f6f4c3cb505d..63860adc4814 100644 --- a/arch/arc/mm/tlbex.S +++ b/arch/arc/mm/tlbex.S @@ -205,20 +205,38 @@ ex_saved_reg1: #endif lsr r0, r2, PGDIR_SHIFT ; Bits for indexing into PGD - ld.as r1, [r1, r0] ; PGD entry corresp to faulting addr - and.f r1, r1, PAGE_MASK ; Ignoring protection and other flags - ; contains Ptr to Page Table - bz.d do_slow_path_pf ; if no Page Table, do page fault + ld.as r3, [r1, r0] ; PGD entry corresp to faulting addr + tst r3, r3 + bz do_slow_path_pf ; if no Page Table, do page fault + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + and.f 0, r3, _PAGE_HW_SZ ; Is this Huge PMD (thp) + add2.nz r1, r1, r0 + bnz.d 2f ; YES: PGD == PMD has THP PTE: stop pgd walk + mov.nz r0, r3 + +#endif + and r1, r3, PAGE_MASK ; Get the PTE entry: The idea is ; (1) x = addr >> PAGE_SHIFT -> masks page-off bits from @fault-addr ; (2) y = x & (PTRS_PER_PTE - 1) -> to get index - ; (3) z = pgtbl[y] - ; To avoid the multiply by in end, we do the -2, <<2 below + ; (3) z = (pgtbl + y * 4) + +#ifdef CONFIG_ARC_HAS_PAE40 +#define PTE_SIZE_LOG 3 /* 8 == 2 ^ 3 */ +#else +#define PTE_SIZE_LOG 2 /* 4 == 2 ^ 2 */ +#endif + + ; multiply in step (3) above avoided by shifting lesser in step (1) + lsr r0, r2, ( PAGE_SHIFT - PTE_SIZE_LOG ) + and r0, r0, ( (PTRS_PER_PTE - 1) << PTE_SIZE_LOG ) + ld.aw r0, [r1, r0] ; r0: PTE (lower word only for PAE40) + ; r1: PTE ptr + +2: - lsr r0, r2, (PAGE_SHIFT - 2) - and r0, r0, ( (PTRS_PER_PTE - 1) << 2) - ld.aw r0, [r1, r0] ; get PTE and PTE ptr for fault addr #ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT and.f 0, r0, _PAGE_PRESENT bz 1f @@ -233,18 +251,23 @@ ex_saved_reg1: ;----------------------------------------------------------------- ; Convert Linux PTE entry into TLB entry ; A one-word PTE entry is programmed as two-word TLB Entry [PD0:PD1] in mmu +; (for PAE40, two-words PTE, while three-word TLB Entry [PD0:PD1:PD1HI]) ; IN: r0 = PTE, r1 = ptr to PTE .macro CONV_PTE_TO_TLB - and r3, r0, PTE_BITS_RWX ; r w x - lsl r2, r3, 3 ; r w x 0 0 0 (GLOBAL, kernel only) + and r3, r0, PTE_BITS_RWX ; r w x + lsl r2, r3, 3 ; Kr Kw Kx 0 0 0 (GLOBAL, kernel only) and.f 0, r0, _PAGE_GLOBAL - or.z r2, r2, r3 ; r w x r w x (!GLOBAL, user page) + or.z r2, r2, r3 ; Kr Kw Kx Ur Uw Ux (!GLOBAL, user page) and r3, r0, PTE_BITS_NON_RWX_IN_PD1 ; Extract PFN+cache bits from PTE or r3, r3, r2 - sr r3, [ARC_REG_TLBPD1] ; these go in PD1 + sr r3, [ARC_REG_TLBPD1] ; paddr[31..13] | Kr Kw Kx Ur Uw Ux | C +#ifdef CONFIG_ARC_HAS_PAE40 + ld r3, [r1, 4] ; paddr[39..32] + sr r3, [ARC_REG_TLBPD1HI] +#endif and r2, r0, PTE_BITS_IN_PD0 ; Extract other PTE flags: (V)alid, (G)lb @@ -365,7 +388,7 @@ ENTRY(EV_TLBMissD) lr r3, [ecr] or r0, r0, _PAGE_ACCESSED ; Accessed bit always btst_s r3, ECR_C_BIT_DTLB_ST_MISS ; See if it was a Write Access ? - or.nz r0, r0, _PAGE_MODIFIED ; if Write, set Dirty bit as well + or.nz r0, r0, _PAGE_DIRTY ; if Write, set Dirty bit as well st_s r0, [r1] ; Write back PTE CONV_PTE_TO_TLB diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index 0a77b19e1df8..1b0f0f458a2b 100644 --- a/arch/arc/plat-axs10x/axs10x.c +++ b/arch/arc/plat-axs10x/axs10x.c @@ -455,11 +455,6 @@ static void __init axs103_early_init(void) axs10x_print_board_ver(AXC003_CREG + 4088, "AXC003 CPU Card"); axs10x_early_init(); - -#ifdef CONFIG_ARC_MCIP - /* No Hardware init, but filling the smp ops callbacks */ - mcip_init_early_smp(); -#endif } #endif @@ -487,9 +482,6 @@ static const char *axs103_compat[] __initconst = { MACHINE_START(AXS103, "axs103") .dt_compat = axs103_compat, .init_early = axs103_early_init, -#ifdef CONFIG_ARC_MCIP - .init_smp = mcip_init_smp, -#endif MACHINE_END /* diff --git a/arch/arc/plat-sim/platform.c b/arch/arc/plat-sim/platform.c index d9e35b4a2f08..dde692812bc1 100644 --- a/arch/arc/plat-sim/platform.c +++ b/arch/arc/plat-sim/platform.c @@ -30,8 +30,4 @@ static const char *simulation_compat[] __initconst = { MACHINE_START(SIMULATION, "simulation") .dt_compat = simulation_compat, -#ifdef CONFIG_ARC_MCIP - .init_early = mcip_init_early_smp, - .init_smp = mcip_init_smp, -#endif MACHINE_END diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 72ad724c67ae..f1ed1109f488 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -645,6 +645,7 @@ config ARCH_SHMOBILE_LEGACY config ARCH_RPC bool "RiscPC" + depends on MMU select ARCH_ACORN select ARCH_MAY_HAVE_PC_FDC select ARCH_SPARSEMEM_ENABLE @@ -819,6 +820,7 @@ config ARCH_VIRT bool "Dummy Virtual Machine" if ARCH_MULTI_V7 select ARM_AMBA select ARM_GIC + select ARM_GIC_V3 select ARM_PSCI select HAVE_ARM_ARCH_TIMER @@ -1410,7 +1412,6 @@ config HAVE_ARM_ARCH_TIMER config HAVE_ARM_TWD bool - depends on SMP select CLKSRC_OF if OF help This options enables support for the ARM timer and watchdog unit @@ -1470,6 +1471,8 @@ choice config VMSPLIT_3G bool "3G/1G user/kernel split" + config VMSPLIT_3G_OPT + bool "3G/1G user/kernel split (for full 1G low memory)" config VMSPLIT_2G bool "2G/2G user/kernel split" config VMSPLIT_1G @@ -1481,6 +1484,7 @@ config PAGE_OFFSET default PHYS_OFFSET if !MMU default 0x40000000 if VMSPLIT_1G default 0x80000000 if VMSPLIT_2G + default 0xB0000000 if VMSPLIT_3G_OPT default 0xC0000000 config NR_CPUS @@ -1695,8 +1699,9 @@ config HIGHMEM If unsure, say n. config HIGHPTE - bool "Allocate 2nd-level pagetables from highmem" + bool "Allocate 2nd-level pagetables from highmem" if EXPERT depends on HIGHMEM + default y help The VM uses one page of physical memory for each page table. For systems with a lot of processes, this can use a lot of diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts index 568adf5efde0..d55e3ea89fda 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15.dts +++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts @@ -402,11 +402,12 @@ /* SMPS9 unused */ ldo1_reg: ldo1 { - /* VDD_SD */ + /* VDD_SD / VDDSHV8 */ regulator-name = "ldo1"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; regulator-boot-on; + regulator-always-on; }; ldo2_reg: ldo2 { diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts index 89f5a95954ed..4047621b137e 100644 --- a/arch/arm/boot/dts/armada-385-db-ap.dts +++ b/arch/arm/boot/dts/armada-385-db-ap.dts @@ -46,7 +46,7 @@ / { model = "Marvell Armada 385 Access Point Development Board"; - compatible = "marvell,a385-db-ap", "marvell,armada385", "marvell,armada38x"; + compatible = "marvell,a385-db-ap", "marvell,armada385", "marvell,armada380"; chosen { stdout-path = "serial1:115200n8"; diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi index 63a48490e2f9..d4dbd28d348c 100644 --- a/arch/arm/boot/dts/berlin2q.dtsi +++ b/arch/arm/boot/dts/berlin2q.dtsi @@ -152,7 +152,7 @@ }; usb_phy2: phy@a2f400 { - compatible = "marvell,berlin2-usb-phy"; + compatible = "marvell,berlin2cd-usb-phy"; reg = <0xa2f400 0x128>; #phy-cells = <0>; resets = <&chip_rst 0x104 14>; @@ -170,7 +170,7 @@ }; usb_phy0: phy@b74000 { - compatible = "marvell,berlin2-usb-phy"; + compatible = "marvell,berlin2cd-usb-phy"; reg = <0xb74000 0x128>; #phy-cells = <0>; resets = <&chip_rst 0x104 12>; @@ -178,7 +178,7 @@ }; usb_phy1: phy@b78000 { - compatible = "marvell,berlin2-usb-phy"; + compatible = "marvell,berlin2cd-usb-phy"; reg = <0xb78000 0x128>; #phy-cells = <0>; resets = <&chip_rst 0x104 13>; diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts index 955c24ee4a8c..8c24975e8f9d 100644 --- a/arch/arm/boot/dts/emev2-kzm9d.dts +++ b/arch/arm/boot/dts/emev2-kzm9d.dts @@ -35,28 +35,28 @@ button@1 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; label = "DSW2-1"; linux,code = <KEY_1>; gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; }; button@2 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; label = "DSW2-2"; linux,code = <KEY_2>; gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; }; button@3 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; label = "DSW2-3"; linux,code = <KEY_3>; gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; }; button@4 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; label = "DSW2-4"; linux,code = <KEY_4>; gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 8f4d76c5e11c..1b95da79293c 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -915,6 +915,11 @@ }; }; +&pmu_system_controller { + assigned-clocks = <&pmu_system_controller 0>; + assigned-clock-parents = <&clock CLK_FIN_PLL>; +}; + &rtc { status = "okay"; clocks = <&clock CLK_RTC>, <&max77802 MAX77802_CLK_32K_AP>; diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index 7d5b386b5ae6..8f40c7e549bd 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts @@ -878,6 +878,11 @@ }; }; +&pmu_system_controller { + assigned-clocks = <&pmu_system_controller 0>; + assigned-clock-parents = <&clock CLK_FIN_PLL>; +}; + &rtc { status = "okay"; clocks = <&clock CLK_RTC>, <&max77802 MAX77802_CLK_32K_AP>; diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index b738ce0f9d9b..6e444bb873f9 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -588,10 +588,10 @@ status = "disabled"; }; - uart2: serial@30870000 { + uart2: serial@30890000 { compatible = "fsl,imx7d-uart", "fsl,imx6q-uart"; - reg = <0x30870000 0x10000>; + reg = <0x30890000 0x10000>; interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX7D_UART2_ROOT_CLK>, <&clks IMX7D_UART2_ROOT_CLK>; diff --git a/arch/arm/boot/dts/kirkwood-net5big.dts b/arch/arm/boot/dts/kirkwood-net5big.dts index 36155b749d9f..d2d44df9c8c0 100644 --- a/arch/arm/boot/dts/kirkwood-net5big.dts +++ b/arch/arm/boot/dts/kirkwood-net5big.dts @@ -86,6 +86,66 @@ clock-frequency = <32768>; }; }; + + netxbig-leds { + blue-sata2 { + label = "netxbig:blue:sata2"; + mode-addr = <5>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 7 + NETXBIG_LED_SATA 1 + NETXBIG_LED_TIMER1 3>; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata2 { + label = "netxbig:red:sata2"; + mode-addr = <5>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 2 + NETXBIG_LED_TIMER1 4>; + bright-addr = <2>; + max-brightness = <7>; + }; + blue-sata3 { + label = "netxbig:blue:sata3"; + mode-addr = <6>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 7 + NETXBIG_LED_SATA 1 + NETXBIG_LED_TIMER1 3>; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata3 { + label = "netxbig:red:sata3"; + mode-addr = <6>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 2 + NETXBIG_LED_TIMER1 4>; + bright-addr = <2>; + max-brightness = <7>; + }; + blue-sata4 { + label = "netxbig:blue:sata4"; + mode-addr = <7>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 7 + NETXBIG_LED_SATA 1 + NETXBIG_LED_TIMER1 3>; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata4 { + label = "netxbig:red:sata4"; + mode-addr = <7>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 2 + NETXBIG_LED_TIMER1 4>; + bright-addr = <2>; + max-brightness = <7>; + }; + }; }; &mdio { diff --git a/arch/arm/boot/dts/kirkwood-netxbig.dtsi b/arch/arm/boot/dts/kirkwood-netxbig.dtsi index 1508b12147df..62515a8b99b9 100644 --- a/arch/arm/boot/dts/kirkwood-netxbig.dtsi +++ b/arch/arm/boot/dts/kirkwood-netxbig.dtsi @@ -13,6 +13,7 @@ * warranty of any kind, whether express or implied. */ +#include <dt-bindings/leds/leds-netxbig.h> #include "kirkwood.dtsi" #include "kirkwood-6281.dtsi" @@ -105,6 +106,85 @@ gpio = <&gpio0 16 GPIO_ACTIVE_HIGH>; }; }; + + netxbig_gpio_ext: netxbig-gpio-ext { + compatible = "lacie,netxbig-gpio-ext"; + + addr-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH + &gpio1 16 GPIO_ACTIVE_HIGH + &gpio1 17 GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH + &gpio1 13 GPIO_ACTIVE_HIGH + &gpio1 14 GPIO_ACTIVE_HIGH>; + enable-gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>; + }; + + netxbig-leds { + compatible = "lacie,netxbig-leds"; + + gpio-ext = <&netxbig_gpio_ext>; + + timers = <NETXBIG_LED_TIMER1 500 500 + NETXBIG_LED_TIMER2 500 1000>; + + blue-power { + label = "netxbig:blue:power"; + mode-addr = <0>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 1 + NETXBIG_LED_TIMER1 3 + NETXBIG_LED_TIMER2 7>; + bright-addr = <1>; + max-brightness = <7>; + }; + red-power { + label = "netxbig:red:power"; + mode-addr = <0>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 2 + NETXBIG_LED_TIMER1 4>; + bright-addr = <1>; + max-brightness = <7>; + }; + blue-sata0 { + label = "netxbig:blue:sata0"; + mode-addr = <3>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 7 + NETXBIG_LED_SATA 1 + NETXBIG_LED_TIMER1 3>; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata0 { + label = "netxbig:red:sata0"; + mode-addr = <3>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 2 + NETXBIG_LED_TIMER1 4>; + bright-addr = <2>; + max-brightness = <7>; + }; + blue-sata1 { + label = "netxbig:blue:sata1"; + mode-addr = <4>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 7 + NETXBIG_LED_SATA 1 + NETXBIG_LED_TIMER1 3>; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata1 { + label = "netxbig:red:sata1"; + mode-addr = <4>; + mode-val = <NETXBIG_LED_OFF 0 + NETXBIG_LED_ON 2 + NETXBIG_LED_TIMER1 4>; + bright-addr = <2>; + max-brightness = <7>; + }; + }; }; &mdio { diff --git a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts index 91146c318798..5b0430041ec6 100644 --- a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts +++ b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts @@ -12,7 +12,7 @@ / { model = "LogicPD Zoom DM3730 Torpedo Development Kit"; - compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap36xx"; + compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap3630", "ti,omap3"; gpio_keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/meson.dtsi b/arch/arm/boot/dts/meson.dtsi index 548441384d2a..8c77c87660cd 100644 --- a/arch/arm/boot/dts/meson.dtsi +++ b/arch/arm/boot/dts/meson.dtsi @@ -67,7 +67,7 @@ timer@c1109940 { compatible = "amlogic,meson6-timer"; - reg = <0xc1109940 0x14>; + reg = <0xc1109940 0x18>; interrupts = <0 10 1>; }; @@ -80,36 +80,37 @@ wdt: watchdog@c1109900 { compatible = "amlogic,meson6-wdt"; reg = <0xc1109900 0x8>; + interrupts = <0 0 1>; }; uart_AO: serial@c81004c0 { compatible = "amlogic,meson-uart"; - reg = <0xc81004c0 0x14>; + reg = <0xc81004c0 0x18>; interrupts = <0 90 1>; clocks = <&clk81>; status = "disabled"; }; - uart_A: serial@c81084c0 { + uart_A: serial@c11084c0 { compatible = "amlogic,meson-uart"; - reg = <0xc81084c0 0x14>; - interrupts = <0 90 1>; + reg = <0xc11084c0 0x18>; + interrupts = <0 26 1>; clocks = <&clk81>; status = "disabled"; }; - uart_B: serial@c81084dc { + uart_B: serial@c11084dc { compatible = "amlogic,meson-uart"; - reg = <0xc81084dc 0x14>; - interrupts = <0 90 1>; + reg = <0xc11084dc 0x18>; + interrupts = <0 75 1>; clocks = <&clk81>; status = "disabled"; }; - uart_C: serial@c8108700 { + uart_C: serial@c1108700 { compatible = "amlogic,meson-uart"; - reg = <0xc8108700 0x14>; - interrupts = <0 90 1>; + reg = <0xc1108700 0x18>; + interrupts = <0 93 1>; clocks = <&clk81>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts index 16e8ce350dda..bb339d1648e0 100644 --- a/arch/arm/boot/dts/omap3-evm-37xx.dts +++ b/arch/arm/boot/dts/omap3-evm-37xx.dts @@ -13,7 +13,7 @@ / { model = "TI OMAP37XX EVM (TMDSEVM3730)"; - compatible = "ti,omap3-evm-37xx", "ti,omap36xx"; + compatible = "ti,omap3-evm-37xx", "ti,omap3630", "ti,omap3"; memory { device_type = "memory"; diff --git a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi index b5334ecff13c..fec076eb7aef 100644 --- a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi +++ b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi @@ -90,7 +90,7 @@ regulators { vccio_sd: LDO_REG4 { regulator-name = "vccio_sd"; - regulator-min-microvolt = <3300000>; + regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; regulator-state-mem { regulator-off-in-suspend; @@ -116,7 +116,12 @@ cap-sd-highspeed; card-detect-delay = <200>; cd-gpios = <&gpio7 5 GPIO_ACTIVE_LOW>; + rockchip,default-sample-phase = <90>; num-slots = <1>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; vmmc-supply = <&vcc33_sd>; vqmmc-supply = <&vccio_sd>; }; diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi index 275c78ccc0f3..860cea0a7613 100644 --- a/arch/arm/boot/dts/rk3288-veyron.dtsi +++ b/arch/arm/boot/dts/rk3288-veyron.dtsi @@ -149,7 +149,9 @@ broken-cd; bus-width = <8>; cap-mmc-highspeed; + rockchip,default-sample-phase = <158>; disable-wp; + mmc-hs200-1_8v; mmc-pwrseq = <&emmc_pwrseq>; non-removable; num-slots = <1>; @@ -355,6 +357,10 @@ num-slots = <1>; pinctrl-names = "default"; pinctrl-0 = <&sdio0_clk &sdio0_cmd &sdio0_bus4>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; vmmc-supply = <&vcc33_sys>; vqmmc-supply = <&vcc18_wl>; }; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 906e938fb6bf..4e7c6b7392af 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -222,8 +222,9 @@ sdmmc: dwmmc@ff0c0000 { compatible = "rockchip,rk3288-dw-mshc"; clock-freq-min-max = <400000 150000000>; - clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; - clock-names = "biu", "ciu"; + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0c0000 0x4000>; @@ -233,8 +234,9 @@ sdio0: dwmmc@ff0d0000 { compatible = "rockchip,rk3288-dw-mshc"; clock-freq-min-max = <400000 150000000>; - clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>; - clock-names = "biu", "ciu"; + clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>, + <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0d0000 0x4000>; @@ -244,8 +246,9 @@ sdio1: dwmmc@ff0e0000 { compatible = "rockchip,rk3288-dw-mshc"; clock-freq-min-max = <400000 150000000>; - clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>; - clock-names = "biu", "ciu"; + clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>, + <&cru SCLK_SDIO1_DRV>, <&cru SCLK_SDIO1_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0e0000 0x4000>; @@ -255,8 +258,9 @@ emmc: dwmmc@ff0f0000 { compatible = "rockchip,rk3288-dw-mshc"; clock-freq-min-max = <400000 150000000>; - clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>; - clock-names = "biu", "ciu"; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, + <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; reg = <0xff0f0000 0x4000>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 034cd48ae28b..cc05cde0f9a4 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -921,6 +921,20 @@ clocks = <&twi1_clk>; status = "disabled"; }; + + pioA: pinctrl@fc038000 { + compatible = "atmel,sama5d2-pinctrl"; + reg = <0xfc038000 0x600>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH 7>, + <68 IRQ_TYPE_LEVEL_HIGH 7>, + <69 IRQ_TYPE_LEVEL_HIGH 7>, + <70 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pioA_clk>; + }; }; }; }; diff --git a/arch/arm/boot/dts/ste-hrefv60plus.dtsi b/arch/arm/boot/dts/ste-hrefv60plus.dtsi index 810cda743b6d..9c2387b34d0c 100644 --- a/arch/arm/boot/dts/ste-hrefv60plus.dtsi +++ b/arch/arm/boot/dts/ste-hrefv60plus.dtsi @@ -56,7 +56,7 @@ /* VMMCI level-shifter enable */ default_hrefv60_cfg2 { pins = "GPIO169_D22"; - ste,config = <&gpio_out_lo>; + ste,config = <&gpio_out_hi>; }; /* VMMCI level-shifter voltage select */ default_hrefv60_cfg3 { diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index 32a5ccb14e7e..e80e42163883 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -47,35 +47,35 @@ button@1 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <2>; label = "userpb"; gpios = <&gpio1 0 0x4>; }; button@2 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <3>; label = "extkb1"; gpios = <&gpio4 23 0x4>; }; button@3 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <4>; label = "extkb2"; gpios = <&gpio4 24 0x4>; }; button@4 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <5>; label = "extkb3"; gpios = <&gpio5 1 0x4>; }; button@5 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <6>; label = "extkb4"; gpios = <&gpio5 2 0x4>; diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 9d4f86e9c50a..d845bd1448b5 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -234,7 +234,9 @@ gpio-controller; #interrupt-cells = <2>; interrupt-controller; + /* gpio-ranges = <&pinmux 0 0 246>; + */ }; apbmisc@70000800 { diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index 1e204a6de12c..819e2ae2cabe 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -258,7 +258,9 @@ gpio-controller; #interrupt-cells = <2>; interrupt-controller; + /* gpio-ranges = <&pinmux 0 0 251>; + */ }; apbdma: dma@0,60020000 { diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index e058709e6d98..969b828505ae 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -244,7 +244,9 @@ gpio-controller; #interrupt-cells = <2>; interrupt-controller; + /* gpio-ranges = <&pinmux 0 0 224>; + */ }; apbmisc@70000800 { diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index fe04fb5e155f..c6938ad1b543 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -349,7 +349,9 @@ gpio-controller; #interrupt-cells = <2>; interrupt-controller; + /* gpio-ranges = <&pinmux 0 0 248>; + */ }; apbmisc@70000800 { diff --git a/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts b/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts index 33963acd7e8f..f80f772d99fb 100644 --- a/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts +++ b/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts @@ -85,7 +85,7 @@ }; ðsc { - interrupts = <0 50 4>; + interrupts = <0 52 4>; }; &serial0 { diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 1ff2bfa2e183..13ba48c4b03b 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -166,7 +166,6 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_S3C=y CONFIG_MMC_SDHCI_S3C_DMA=y CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y CONFIG_MMC_DW_EXYNOS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_MAX77686=y diff --git a/arch/arm/configs/hisi_defconfig b/arch/arm/configs/hisi_defconfig index 5997dbc69822..b2e340b272ee 100644 --- a/arch/arm/configs/hisi_defconfig +++ b/arch/arm/configs/hisi_defconfig @@ -69,7 +69,6 @@ CONFIG_NOP_USB_XCEIV=y CONFIG_MMC=y CONFIG_RTC_CLASS=y CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y CONFIG_MMC_DW_PLTFM=y CONFIG_RTC_DRV_PL031=y CONFIG_DMADEVICES=y diff --git a/arch/arm/configs/lpc18xx_defconfig b/arch/arm/configs/lpc18xx_defconfig index 1c47f86c3970..b7e8cdab51f9 100644 --- a/arch/arm/configs/lpc18xx_defconfig +++ b/arch/arm/configs/lpc18xx_defconfig @@ -119,7 +119,6 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_MMC=y CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_PCA9532=y diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h new file mode 100644 index 000000000000..6607d976e07d --- /dev/null +++ b/arch/arm/include/asm/arch_gicv3.h @@ -0,0 +1,188 @@ +/* + * arch/arm/include/asm/arch_gicv3.h + * + * Copyright (C) 2015 ARM Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_ARCH_GICV3_H +#define __ASM_ARCH_GICV3_H + +#ifndef __ASSEMBLY__ + +#include <linux/io.h> + +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 +#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm + +#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) +#define ICC_DIR __ACCESS_CP15(c12, 0, c11, 1) +#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) +#define ICC_SGI1R __ACCESS_CP15_64(0, c12) +#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) +#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) +#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) +#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) + +#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) + +#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) +#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0) +#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1) +#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2) +#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3) +#define ICH_ELSR __ACCESS_CP15(c12, 4, c11, 5) +#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7) + +#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x) +#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x) + +#define ICH_LR0 __LR0(0) +#define ICH_LR1 __LR0(1) +#define ICH_LR2 __LR0(2) +#define ICH_LR3 __LR0(3) +#define ICH_LR4 __LR0(4) +#define ICH_LR5 __LR0(5) +#define ICH_LR6 __LR0(6) +#define ICH_LR7 __LR0(7) +#define ICH_LR8 __LR8(0) +#define ICH_LR9 __LR8(1) +#define ICH_LR10 __LR8(2) +#define ICH_LR11 __LR8(3) +#define ICH_LR12 __LR8(4) +#define ICH_LR13 __LR8(5) +#define ICH_LR14 __LR8(6) +#define ICH_LR15 __LR8(7) + +/* LR top half */ +#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x) +#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x) + +#define ICH_LRC0 __LRC0(0) +#define ICH_LRC1 __LRC0(1) +#define ICH_LRC2 __LRC0(2) +#define ICH_LRC3 __LRC0(3) +#define ICH_LRC4 __LRC0(4) +#define ICH_LRC5 __LRC0(5) +#define ICH_LRC6 __LRC0(6) +#define ICH_LRC7 __LRC0(7) +#define ICH_LRC8 __LRC8(0) +#define ICH_LRC9 __LRC8(1) +#define ICH_LRC10 __LRC8(2) +#define ICH_LRC11 __LRC8(3) +#define ICH_LRC12 __LRC8(4) +#define ICH_LRC13 __LRC8(5) +#define ICH_LRC14 __LRC8(6) +#define ICH_LRC15 __LRC8(7) + +#define __AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x) +#define ICH_AP0R0 __AP0Rx(0) +#define ICH_AP0R1 __AP0Rx(1) +#define ICH_AP0R2 __AP0Rx(2) +#define ICH_AP0R3 __AP0Rx(3) + +#define __AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x) +#define ICH_AP1R0 __AP1Rx(0) +#define ICH_AP1R1 __AP1Rx(1) +#define ICH_AP1R2 __AP1Rx(2) +#define ICH_AP1R3 __AP1Rx(3) + +/* Low-level accessors */ + +static inline void gic_write_eoir(u32 irq) +{ + asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (irq)); + isb(); +} + +static inline void gic_write_dir(u32 val) +{ + asm volatile("mcr " __stringify(ICC_DIR) : : "r" (val)); + isb(); +} + +static inline u32 gic_read_iar(void) +{ + u32 irqstat; + + asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat)); + return irqstat; +} + +static inline void gic_write_pmr(u32 val) +{ + asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val)); +} + +static inline void gic_write_ctlr(u32 val) +{ + asm volatile("mcr " __stringify(ICC_CTLR) : : "r" (val)); + isb(); +} + +static inline void gic_write_grpen1(u32 val) +{ + asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val)); + isb(); +} + +static inline void gic_write_sgi1r(u64 val) +{ + asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val)); +} + +static inline u32 gic_read_sre(void) +{ + u32 val; + + asm volatile("mrc " __stringify(ICC_SRE) : "=r" (val)); + return val; +} + +static inline void gic_write_sre(u32 val) +{ + asm volatile("mcr " __stringify(ICC_SRE) : : "r" (val)); + isb(); +} + +/* + * Even in 32bit systems that use LPAE, there is no guarantee that the I/O + * interface provides true 64bit atomic accesses, so using strd/ldrd doesn't + * make much sense. + * Moreover, 64bit I/O emulation is extremely difficult to implement on + * AArch32, since the syndrome register doesn't provide any information for + * them. + * Consequently, the following IO helpers use 32bit accesses. + * + * There are only two registers that need 64bit accesses in this driver: + * - GICD_IROUTERn, contain the affinity values associated to each interrupt. + * The upper-word (aff3) will always be 0, so there is no need for a lock. + * - GICR_TYPER is an ID register and doesn't need atomicity. + */ +static inline void gic_write_irouter(u64 val, volatile void __iomem *addr) +{ + writel_relaxed((u32)val, addr); + writel_relaxed((u32)(val >> 32), addr + 4); +} + +static inline u64 gic_read_typer(const volatile void __iomem *addr) +{ + u64 val; + + val = readl_relaxed(addr); + val |= (u64)readl_relaxed(addr + 4) << 32; + return val; +} + +#endif /* !__ASSEMBLY__ */ +#endif /* !__ASM_ARCH_GICV3_H */ diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index fe3ef397f5a4..9e10c4567eb4 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -27,8 +27,8 @@ * strex/ldrex monitor on some implementations. The reason we can use it for * atomic_set() is the clrex or dummy strex done on every exception return. */ -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v,i) WRITE_ONCE(((v)->counter), (i)) #if __LINUX_ARM_ARCH__ >= 6 @@ -210,8 +210,8 @@ ATOMIC_OP(xor, ^=, eor) #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) -#define atomic_inc_return(v) (atomic_add_return(1, v)) -#define atomic_dec_return(v) (atomic_sub_return(1, v)) +#define atomic_inc_return_relaxed(v) (atomic_add_return_relaxed(1, v)) +#define atomic_dec_return_relaxed(v) (atomic_sub_return_relaxed(1, v)) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) @@ -442,11 +442,11 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) #define atomic64_inc(v) atomic64_add(1LL, (v)) -#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define atomic64_inc_return_relaxed(v) atomic64_add_return_relaxed(1LL, (v)) #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) #define atomic64_dec(v) atomic64_sub(1LL, (v)) -#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) +#define atomic64_dec_return_relaxed(v) atomic64_sub_return_relaxed(1LL, (v)) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h index 916a2744d5c6..97882f9bad12 100644 --- a/arch/arm/include/asm/cmpxchg.h +++ b/arch/arm/include/asm/cmpxchg.h @@ -39,6 +39,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size switch (size) { #if __LINUX_ARM_ARCH__ >= 6 +#ifndef CONFIG_CPU_V6 /* MIN ARCH >= V6K */ case 1: asm volatile("@ __xchg1\n" "1: ldrexb %0, [%3]\n" @@ -49,6 +50,17 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size : "r" (x), "r" (ptr) : "memory", "cc"); break; + case 2: + asm volatile("@ __xchg2\n" + "1: ldrexh %0, [%3]\n" + " strexh %1, %2, [%3]\n" + " teq %1, #0\n" + " bne 1b" + : "=&r" (ret), "=&r" (tmp) + : "r" (x), "r" (ptr) + : "memory", "cc"); + break; +#endif case 4: asm volatile("@ __xchg4\n" "1: ldrex %0, [%3]\n" diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h index 43908146a5cf..e6b70d9d084e 100644 --- a/arch/arm/include/asm/irqflags.h +++ b/arch/arm/include/asm/irqflags.h @@ -54,6 +54,14 @@ static inline void arch_local_irq_disable(void) #define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc") #define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc") + +#ifndef CONFIG_CPU_V7M +#define local_abt_enable() __asm__("cpsie a @ __sta" : : : "memory", "cc") +#define local_abt_disable() __asm__("cpsid a @ __cla" : : : "memory", "cc") +#else +#define local_abt_enable() do { } while (0) +#define local_abt_disable() do { } while (0) +#endif #else /* @@ -136,6 +144,8 @@ static inline void arch_local_irq_disable(void) : "memory", "cc"); \ }) +#define local_abt_enable() do { } while (0) +#define local_abt_disable() do { } while (0) #endif /* diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index cb3a40717edd..5c1ad11aa392 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -47,7 +47,7 @@ struct machine_desc { unsigned l2c_aux_val; /* L2 cache aux value */ unsigned l2c_aux_mask; /* L2 cache aux mask */ void (*l2c_write_sec)(unsigned long, unsigned); - struct smp_operations *smp; /* SMP operations */ + const struct smp_operations *smp; /* SMP operations */ bool (*smp_init)(void); void (*fixup)(struct tag *, char **); void (*dt_fixup)(void); diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 98d58bb04ac5..c79b57bf71c4 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -76,10 +76,12 @@ */ #define XIP_VIRT_ADDR(physaddr) (MODULES_VADDR + ((physaddr) & 0x000fffff)) +#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE) /* * Allow 16MB-aligned ioremap pages */ #define IOREMAP_MAX_ORDER 24 +#endif #else /* CONFIG_MMU */ diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index f40354198bad..348caabb7625 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -43,7 +43,7 @@ */ #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) -#define VMALLOC_END 0xff000000UL +#define VMALLOC_END 0xff800000UL #define LIBRARY_TEXT_START 0x0c000000 diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index ef356659b4f4..3d6dc8b460e4 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -112,7 +112,7 @@ struct smp_operations { struct of_cpu_method { const char *method; - struct smp_operations *ops; + const struct smp_operations *ops; }; #define CPU_METHOD_OF_DECLARE(name, _method, _ops) \ @@ -122,6 +122,6 @@ struct of_cpu_method { /* * set platform specific SMP operations */ -extern void smp_set_ops(struct smp_operations *); +extern void smp_set_ops(const struct smp_operations *); #endif /* ifndef __ASM_ARM_SMP_H */ diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 7cba573c2cc9..7b84657fba35 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -21,13 +21,6 @@ */ #define __NR_syscalls (392) -/* - * *NOTE*: This is a ghost syscall private to the kernel. Only the - * __kuser_cmpxchg code in entry-armv.S should be aware of its - * existence. Don't ever use this from user code. - */ -#define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0) - #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_PAUSE diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 11c54de9f8cf..65addcbf5b30 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -101,6 +101,7 @@ void __init arm_dt_init_cpu_maps(void) if (of_property_read_u32(cpu, "reg", &hwid)) { pr_debug(" * %s missing reg property\n", cpu->full_name); + of_node_put(cpu); return; } @@ -108,8 +109,10 @@ void __init arm_dt_init_cpu_maps(void) * 8 MSBs must be set to 0 in the DT since the reg property * defines the MPIDR[23:0]. */ - if (hwid & ~MPIDR_HWID_BITMASK) + if (hwid & ~MPIDR_HWID_BITMASK) { + of_node_put(cpu); return; + } /* * Duplicate MPIDRs are a recipe for disaster. @@ -119,9 +122,11 @@ void __init arm_dt_init_cpu_maps(void) * to avoid matching valid MPIDR[23:0] values. */ for (j = 0; j < cpuidx; j++) - if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg " - "properties in the DT\n")) + if (WARN(tmp_map[j] == hwid, + "Duplicate /cpu reg properties in the DT\n")) { + of_node_put(cpu); return; + } /* * Build a stashed array of MPIDR values. Numbering scheme @@ -143,6 +148,7 @@ void __init arm_dt_init_cpu_maps(void) "max cores %u, capping them\n", cpuidx, nr_cpu_ids)) { cpuidx = nr_cpu_ids; + of_node_put(cpu); break; } diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 3e1c26eb32b4..3ce377f7251f 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -427,8 +427,7 @@ ENDPROC(__fiq_abt) .endm .macro kuser_cmpxchg_check -#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \ - !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) +#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) #ifndef CONFIG_MMU #warning "NPTL on non MMU needs fixing" #else @@ -859,20 +858,7 @@ __kuser_helper_start: __kuser_cmpxchg64: @ 0xffff0f60 -#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) - - /* - * Poor you. No fast solution possible... - * The kernel itself must perform the operation. - * A special ghost syscall is used for that (see traps.c). - */ - stmfd sp!, {r7, lr} - ldr r7, 1f @ it's 20 bits - swi __ARM_NR_cmpxchg64 - ldmfd sp!, {r7, pc} -1: .word __ARM_NR_cmpxchg64 - -#elif defined(CONFIG_CPU_32v6K) +#if defined(CONFIG_CPU_32v6K) stmfd sp!, {r4, r5, r6, r7} ldrd r4, r5, [r0] @ load old val @@ -948,20 +934,7 @@ __kuser_memory_barrier: @ 0xffff0fa0 __kuser_cmpxchg: @ 0xffff0fc0 -#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) - - /* - * Poor you. No fast solution possible... - * The kernel itself must perform the operation. - * A special ghost syscall is used for that (see traps.c). - */ - stmfd sp!, {r7, lr} - ldr r7, 1f @ it's 20 bits - swi __ARM_NR_cmpxchg - ldmfd sp!, {r7, pc} -1: .word __ARM_NR_cmpxchg - -#elif __LINUX_ARM_ARCH__ < 6 +#if __LINUX_ARM_ARCH__ < 6 #ifdef CONFIG_MMU diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index dc7d0a95bd36..6284779d64ee 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -35,7 +35,6 @@ #include <asm/cputype.h> #include <asm/current.h> #include <asm/hw_breakpoint.h> -#include <asm/kdebug.h> #include <asm/traps.h> /* Breakpoint currently in use for each BRP. */ diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index fd9eefce0a7b..9232caee7060 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -74,7 +74,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) { - struct pt_regs *thread_regs; + struct thread_info *ti; int regno; /* Just making sure... */ @@ -86,24 +86,17 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) gdb_regs[regno] = 0; /* Otherwise, we have only some registers from switch_to() */ - thread_regs = task_pt_regs(task); - gdb_regs[_R0] = thread_regs->ARM_r0; - gdb_regs[_R1] = thread_regs->ARM_r1; - gdb_regs[_R2] = thread_regs->ARM_r2; - gdb_regs[_R3] = thread_regs->ARM_r3; - gdb_regs[_R4] = thread_regs->ARM_r4; - gdb_regs[_R5] = thread_regs->ARM_r5; - gdb_regs[_R6] = thread_regs->ARM_r6; - gdb_regs[_R7] = thread_regs->ARM_r7; - gdb_regs[_R8] = thread_regs->ARM_r8; - gdb_regs[_R9] = thread_regs->ARM_r9; - gdb_regs[_R10] = thread_regs->ARM_r10; - gdb_regs[_FP] = thread_regs->ARM_fp; - gdb_regs[_IP] = thread_regs->ARM_ip; - gdb_regs[_SPT] = thread_regs->ARM_sp; - gdb_regs[_LR] = thread_regs->ARM_lr; - gdb_regs[_PC] = thread_regs->ARM_pc; - gdb_regs[_CPSR] = thread_regs->ARM_cpsr; + ti = task_thread_info(task); + gdb_regs[_R4] = ti->cpu_context.r4; + gdb_regs[_R5] = ti->cpu_context.r5; + gdb_regs[_R6] = ti->cpu_context.r6; + gdb_regs[_R7] = ti->cpu_context.r7; + gdb_regs[_R8] = ti->cpu_context.r8; + gdb_regs[_R9] = ti->cpu_context.r9; + gdb_regs[_R10] = ti->cpu_context.sl; + gdb_regs[_FP] = ti->cpu_context.fp; + gdb_regs[_SPT] = ti->cpu_context.sp; + gdb_regs[_PC] = ti->cpu_context.pc; } void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 48185a773852..b26361355dae 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -80,7 +80,7 @@ static DECLARE_COMPLETION(cpu_running); static struct smp_operations smp_ops; -void __init smp_set_ops(struct smp_operations *ops) +void __init smp_set_ops(const struct smp_operations *ops) { if (ops) smp_ops = *ops; @@ -400,6 +400,7 @@ asmlinkage void secondary_start_kernel(void) local_irq_enable(); local_fiq_enable(); + local_abt_enable(); /* * OK, it's off to the idle thread for us @@ -748,6 +749,15 @@ core_initcall(register_cpufreq_notifier); static void raise_nmi(cpumask_t *mask) { + /* + * Generate the backtrace directly if we are running in a calling + * context that is not preemptible by the backtrace IPI. Note + * that nmi_cpu_backtrace() automatically removes the current cpu + * from mask. + */ + if (cpumask_test_cpu(smp_processor_id(), mask) && irqs_disabled()) + nmi_cpu_backtrace(NULL); + smp_cross_call(mask, IPI_CPU_BACKTRACE); } diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index e9035cda1485..1bfa7a7f5533 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -23,7 +23,6 @@ #include <linux/of_irq.h> #include <linux/of_address.h> -#include <asm/smp_plat.h> #include <asm/smp_twd.h> /* set up by the platform code */ @@ -34,6 +33,8 @@ static unsigned long twd_timer_rate; static DEFINE_PER_CPU(bool, percpu_setup_called); static struct clock_event_device __percpu *twd_evt; +static unsigned int twd_features = + CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; static int twd_ppi; static int twd_shutdown(struct clock_event_device *clk) @@ -294,8 +295,7 @@ static void twd_timer_setup(void) writel_relaxed(0, twd_base + TWD_TIMER_CONTROL); clk->name = "local_timer"; - clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_C3STOP; + clk->features = twd_features; clk->rating = 350; clk->set_state_shutdown = twd_shutdown; clk->set_state_periodic = twd_set_periodic; @@ -350,6 +350,8 @@ static int __init twd_local_timer_common_register(struct device_node *np) goto out_irq; twd_get_clock(np); + if (!of_property_read_bool(np, "always-on")) + twd_features |= CLOCK_EVT_FEAT_C3STOP; /* * Immediately configure the timer on the boot CPU, unless we need @@ -392,9 +394,6 @@ static void __init twd_local_timer_of_register(struct device_node *np) { int err; - if (!is_smp() || !setup_max_cpus) - return; - twd_ppi = irq_of_parse_and_map(np, 0); if (!twd_ppi) { err = -EINVAL; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 969f9d9e665f..bc698383e822 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -625,58 +625,6 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) set_tls(regs->ARM_r0); return 0; -#ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG - /* - * Atomically store r1 in *r2 if *r2 is equal to r0 for user space. - * Return zero in r0 if *MEM was changed or non-zero if no exchange - * happened. Also set the user C flag accordingly. - * If access permissions have to be fixed up then non-zero is - * returned and the operation has to be re-attempted. - * - * *NOTE*: This is a ghost syscall private to the kernel. Only the - * __kuser_cmpxchg code in entry-armv.S should be aware of its - * existence. Don't ever use this from user code. - */ - case NR(cmpxchg): - for (;;) { - extern void do_DataAbort(unsigned long addr, unsigned int fsr, - struct pt_regs *regs); - unsigned long val; - unsigned long addr = regs->ARM_r2; - struct mm_struct *mm = current->mm; - pgd_t *pgd; pmd_t *pmd; pte_t *pte; - spinlock_t *ptl; - - regs->ARM_cpsr &= ~PSR_C_BIT; - down_read(&mm->mmap_sem); - pgd = pgd_offset(mm, addr); - if (!pgd_present(*pgd)) - goto bad_access; - pmd = pmd_offset(pgd, addr); - if (!pmd_present(*pmd)) - goto bad_access; - pte = pte_offset_map_lock(mm, pmd, addr, &ptl); - if (!pte_present(*pte) || !pte_write(*pte) || !pte_dirty(*pte)) { - pte_unmap_unlock(pte, ptl); - goto bad_access; - } - val = *(unsigned long *)addr; - val -= regs->ARM_r0; - if (val == 0) { - *(unsigned long *)addr = regs->ARM_r1; - regs->ARM_cpsr |= PSR_C_BIT; - } - pte_unmap_unlock(pte, ptl); - up_read(&mm->mmap_sem); - return val; - - bad_access: - up_read(&mm->mmap_sem); - /* simulate a write access fault */ - do_DataAbort(addr, 15 + (1 << 11), regs); - } -#endif - default: /* Calls 9f00xx..9f07ff are defined to return -ENOSYS if not implemented, rather than raising SIGILL. This diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig index 210eccadb69a..356970f3b25e 100644 --- a/arch/arm/kvm/Kconfig +++ b/arch/arm/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM depends on MMU && OF select PREEMPT_NOTIFIERS select ANON_INODES + select ARM_GIC select HAVE_KVM_CPU_RELAX_INTERCEPT select HAVE_KVM_ARCH_TLB_FLUSH_ALL select KVM_MMIO diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index dc017adfddc8..78b286994577 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -1080,7 +1080,7 @@ static int init_hyp_mode(void) */ err = kvm_timer_hyp_init(); if (err) - goto out_free_mappings; + goto out_free_context; #ifndef CONFIG_HOTPLUG_CPU free_boot_hyp_pgd(); diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S index 970d6c043774..e936352ccb00 100644 --- a/arch/arm/lib/clear_user.S +++ b/arch/arm/lib/clear_user.S @@ -9,6 +9,7 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> +#include <asm/unwind.h> .text @@ -20,6 +21,8 @@ */ ENTRY(__clear_user_std) WEAK(arm_clear_user) +UNWIND(.fnstart) +UNWIND(.save {r1, lr}) stmfd sp!, {r1, lr} mov r2, #0 cmp r1, #4 @@ -44,6 +47,7 @@ WEAK(arm_clear_user) USER( strnebt r2, [r0]) mov r0, #0 ldmfd sp!, {r1, pc} +UNWIND(.fnend) ENDPROC(arm_clear_user) ENDPROC(__clear_user_std) diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index 4a87e86dec45..7c21760f590f 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -200,15 +200,15 @@ no_clk: args.args_count = 0; child_domain = of_genpd_get_from_provider(&args); if (IS_ERR(child_domain)) - goto next_pd; + continue; if (of_parse_phandle_with_args(np, "power-domains", "#power-domain-cells", 0, &args) != 0) - goto next_pd; + continue; parent_domain = of_genpd_get_from_provider(&args); if (IS_ERR(parent_domain)) - goto next_pd; + continue; if (pm_genpd_add_subdomain(parent_domain, child_domain)) pr_warn("%s failed to add subdomain: %s\n", @@ -216,8 +216,6 @@ no_clk: else pr_info("%s has as child subdomain: %s.\n", parent_domain->name, child_domain->name); -next_pd: - of_node_put(np); } return 0; diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index e00eb39453a4..5a7e47ceec91 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -177,54 +177,57 @@ static struct irq_chip exynos_pmu_chip = { #endif }; -static int exynos_pmu_domain_xlate(struct irq_domain *domain, - struct device_node *controller, - const u32 *intspec, - unsigned int intsize, - unsigned long *out_hwirq, - unsigned int *out_type) +static int exynos_pmu_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (domain->of_node != controller) - return -EINVAL; /* Shouldn't happen, really... */ - if (intsize != 3) - return -EINVAL; /* Not GIC compliant */ - if (intspec[0] != 0) - return -EINVAL; /* No PPI should point to this domain */ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - *out_hwirq = intspec[1]; - *out_type = intspec[2]; - return 0; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } + + return -EINVAL; } static int exynos_pmu_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { - struct of_phandle_args *args = data; - struct of_phandle_args parent_args; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq; int i; - if (args->args_count != 3) + if (fwspec->param_count != 3) return -EINVAL; /* Not GIC compliant */ - if (args->args[0] != 0) + if (fwspec->param[0] != 0) return -EINVAL; /* No PPI should point to this domain */ - hwirq = args->args[1]; + hwirq = fwspec->param[1]; for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &exynos_pmu_chip, NULL); - parent_args = *args; - parent_args.np = domain->parent->of_node; - return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args); + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); } static const struct irq_domain_ops exynos_pmu_domain_ops = { - .xlate = exynos_pmu_domain_xlate, - .alloc = exynos_pmu_domain_alloc, - .free = irq_domain_free_irqs_common, + .translate = exynos_pmu_domain_translate, + .alloc = exynos_pmu_domain_alloc, + .free = irq_domain_free_irqs_common, }; static int __init exynos_pmu_irq_init(struct device_node *node, diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 8c4467fad837..10bf7159b27d 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -181,40 +181,42 @@ static struct irq_chip imx_gpc_chip = { #endif }; -static int imx_gpc_domain_xlate(struct irq_domain *domain, - struct device_node *controller, - const u32 *intspec, - unsigned int intsize, - unsigned long *out_hwirq, - unsigned int *out_type) +static int imx_gpc_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (domain->of_node != controller) - return -EINVAL; /* Shouldn't happen, really... */ - if (intsize != 3) - return -EINVAL; /* Not GIC compliant */ - if (intspec[0] != 0) - return -EINVAL; /* No PPI should point to this domain */ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - *out_hwirq = intspec[1]; - *out_type = intspec[2]; - return 0; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } + + return -EINVAL; } static int imx_gpc_domain_alloc(struct irq_domain *domain, unsigned int irq, unsigned int nr_irqs, void *data) { - struct of_phandle_args *args = data; - struct of_phandle_args parent_args; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq; int i; - if (args->args_count != 3) + if (fwspec->param_count != 3) return -EINVAL; /* Not GIC compliant */ - if (args->args[0] != 0) + if (fwspec->param[0] != 0) return -EINVAL; /* No PPI should point to this domain */ - hwirq = args->args[1]; + hwirq = fwspec->param[1]; if (hwirq >= GPC_MAX_IRQS) return -EINVAL; /* Can't deal with this */ @@ -222,15 +224,16 @@ static int imx_gpc_domain_alloc(struct irq_domain *domain, irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i, &imx_gpc_chip, NULL); - parent_args = *args; - parent_args.np = domain->parent->of_node; - return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args); + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, + &parent_fwspec); } static const struct irq_domain_ops imx_gpc_domain_ops = { - .xlate = imx_gpc_domain_xlate, - .alloc = imx_gpc_domain_alloc, - .free = irq_domain_free_irqs_common, + .translate = imx_gpc_domain_translate, + .alloc = imx_gpc_domain_alloc, + .free = irq_domain_free_irqs_common, }; static int __init imx_gpc_init(struct device_node *node, diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index c86a5a0aefac..e20fc4178b15 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -117,11 +117,4 @@ config MACH_KIRKWOOD Say 'Y' here if you want your kernel to support boards based on the Marvell Kirkwood device tree. -config MACH_NETXBIG - bool "LaCie 2Big and 5Big Network v2" - depends on MACH_KIRKWOOD - help - Say 'Y' here if you want your kernel to support the - LaCie 2Big and 5Big Network v2 - endif diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index b4f01497ce0b..ecf9e0c3b107 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -13,4 +13,3 @@ endif obj-$(CONFIG_MACH_DOVE) += dove.o obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o -obj-$(CONFIG_MACH_NETXBIG) += netxbig.o diff --git a/arch/arm/mach-mvebu/board.h b/arch/arm/mach-mvebu/board.h deleted file mode 100644 index 98e32cc2ef3d..000000000000 --- a/arch/arm/mach-mvebu/board.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Board functions for Marvell System On Chip - * - * Copyright (C) 2014 - * - * Andrew Lunn <andrew@lunn.ch> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __ARCH_MVEBU_BOARD_H -#define __ARCH_MVEBU_BOARD_H - -#ifdef CONFIG_MACH_NETXBIG -void netxbig_init(void); -#else -static inline void netxbig_init(void) {}; -#endif -#endif diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c index 925f75f54268..f9d8e1ea7183 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -25,7 +25,6 @@ #include "kirkwood.h" #include "kirkwood-pm.h" #include "common.h" -#include "board.h" static struct resource kirkwood_cpufreq_resources[] = { [0] = { @@ -180,9 +179,6 @@ static void __init kirkwood_dt_init(void) kirkwood_pm_init(); kirkwood_dt_eth_fixup(); - if (of_machine_is_compatible("lacie,netxbig")) - netxbig_init(); - of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL); } diff --git a/arch/arm/mach-mvebu/netxbig.c b/arch/arm/mach-mvebu/netxbig.c deleted file mode 100644 index 94b11b6585a4..000000000000 --- a/arch/arm/mach-mvebu/netxbig.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * arch/arm/mach-mvbu/board-netxbig.c - * - * LaCie 2Big and 5Big Network v2 board setup - * - * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/platform_data/leds-kirkwood-netxbig.h> -#include "common.h" - -/***************************************************************************** - * GPIO extension LEDs - ****************************************************************************/ - -/* - * The LEDs are controlled by a CPLD and can be configured through a GPIO - * extension bus: - * - * - address register : bit [0-2] -> GPIO [47-49] - * - data register : bit [0-2] -> GPIO [44-46] - * - enable register : GPIO 29 - */ - -static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 }; -static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 }; - -static struct netxbig_gpio_ext netxbig_v2_gpio_ext = { - .addr = netxbig_v2_gpio_ext_addr, - .num_addr = ARRAY_SIZE(netxbig_v2_gpio_ext_addr), - .data = netxbig_v2_gpio_ext_data, - .num_data = ARRAY_SIZE(netxbig_v2_gpio_ext_data), - .enable = 29, -}; - -/* - * Address register selection: - * - * addr | register - * ---------------------------- - * 0 | front LED - * 1 | front LED brightness - * 2 | SATA LED brightness - * 3 | SATA0 LED - * 4 | SATA1 LED - * 5 | SATA2 LED - * 6 | SATA3 LED - * 7 | SATA4 LED - * - * Data register configuration: - * - * data | LED brightness - * ------------------------------------------------- - * 0 | min (off) - * - | - - * 7 | max - * - * data | front LED mode - * ------------------------------------------------- - * 0 | fix off - * 1 | fix blue on - * 2 | fix red on - * 3 | blink blue on=1 sec and blue off=1 sec - * 4 | blink red on=1 sec and red off=1 sec - * 5 | blink blue on=2.5 sec and red on=0.5 sec - * 6 | blink blue on=1 sec and red on=1 sec - * 7 | blink blue on=0.5 sec and blue off=2.5 sec - * - * data | SATA LED mode - * ------------------------------------------------- - * 0 | fix off - * 1 | SATA activity blink - * 2 | fix red on - * 3 | blink blue on=1 sec and blue off=1 sec - * 4 | blink red on=1 sec and red off=1 sec - * 5 | blink blue on=2.5 sec and red on=0.5 sec - * 6 | blink blue on=1 sec and red on=1 sec - * 7 | fix blue on - */ - -static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = { - [NETXBIG_LED_OFF] = 0, - [NETXBIG_LED_ON] = 2, - [NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE, - [NETXBIG_LED_TIMER1] = 4, - [NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE, -}; - -static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = { - [NETXBIG_LED_OFF] = 0, - [NETXBIG_LED_ON] = 1, - [NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE, - [NETXBIG_LED_TIMER1] = 3, - [NETXBIG_LED_TIMER2] = 7, -}; - -static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = { - [NETXBIG_LED_OFF] = 0, - [NETXBIG_LED_ON] = 7, - [NETXBIG_LED_SATA] = 1, - [NETXBIG_LED_TIMER1] = 3, - [NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE, -}; - -static struct netxbig_led_timer netxbig_v2_led_timer[] = { - [0] = { - .delay_on = 500, - .delay_off = 500, - .mode = NETXBIG_LED_TIMER1, - }, - [1] = { - .delay_on = 500, - .delay_off = 1000, - .mode = NETXBIG_LED_TIMER2, - }, -}; - -#define NETXBIG_LED(_name, maddr, mval, baddr) \ - { .name = _name, \ - .mode_addr = maddr, \ - .mode_val = mval, \ - .bright_addr = baddr } - -static struct netxbig_led net2big_v2_leds_ctrl[] = { - NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1), - NETXBIG_LED("net2big-v2:red:power", 0, netxbig_v2_red_mled, 1), - NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net2big-v2:red:sata0", 3, netxbig_v2_red_mled, 2), - NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net2big-v2:red:sata1", 4, netxbig_v2_red_mled, 2), -}; - -static struct netxbig_led_platform_data net2big_v2_leds_data = { - .gpio_ext = &netxbig_v2_gpio_ext, - .timer = netxbig_v2_led_timer, - .num_timer = ARRAY_SIZE(netxbig_v2_led_timer), - .leds = net2big_v2_leds_ctrl, - .num_leds = ARRAY_SIZE(net2big_v2_leds_ctrl), -}; - -static struct netxbig_led net5big_v2_leds_ctrl[] = { - NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1), - NETXBIG_LED("net5big-v2:red:power", 0, netxbig_v2_red_mled, 1), - NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net5big-v2:red:sata0", 3, netxbig_v2_red_mled, 2), - NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net5big-v2:red:sata1", 4, netxbig_v2_red_mled, 2), - NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net5big-v2:red:sata2", 5, netxbig_v2_red_mled, 2), - NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net5big-v2:red:sata3", 6, netxbig_v2_red_mled, 2), - NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2), - NETXBIG_LED("net5big-v2:red:sata4", 7, netxbig_v2_red_mled, 2), -}; - -static struct netxbig_led_platform_data net5big_v2_leds_data = { - .gpio_ext = &netxbig_v2_gpio_ext, - .timer = netxbig_v2_led_timer, - .num_timer = ARRAY_SIZE(netxbig_v2_led_timer), - .leds = net5big_v2_leds_ctrl, - .num_leds = ARRAY_SIZE(net5big_v2_leds_ctrl), -}; - -static struct platform_device netxbig_v2_leds = { - .name = "leds-netxbig", - .id = -1, - .dev = { - .platform_data = &net2big_v2_leds_data, - }, -}; - -void __init netxbig_init(void) -{ - - if (of_machine_is_compatible("lacie,net5big_v2")) - netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data; - platform_device_register(&netxbig_v2_leds); -} diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index b3a0dff67e3f..33d1460a5639 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -49,6 +49,7 @@ config SOC_OMAP5 select OMAP_INTERCONNECT select OMAP_INTERCONNECT_BARRIER select PM_OPP if PM + select ZONE_DMA if ARM_LPAE config SOC_AM33XX bool "TI AM33XX" @@ -78,6 +79,7 @@ config SOC_DRA7XX select OMAP_INTERCONNECT select OMAP_INTERCONNECT_BARRIER select PM_OPP if PM + select ZONE_DMA if ARM_LPAE config ARCH_OMAP2PLUS bool diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 6133eaac685d..fb219a30c10c 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -106,6 +106,7 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)") MACHINE_END static const char *const omap36xx_boards_compat[] __initconst = { + "ti,omap3630", "ti,omap36xx", NULL, }; @@ -243,6 +244,9 @@ static const char *const omap5_boards_compat[] __initconst = { }; DT_MACHINE_START(OMAP5_DT, "Generic OMAP5 (Flattened Device Tree)") +#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) + .dma_zone_size = SZ_2G, +#endif .reserve = omap_reserve, .smp = smp_ops(omap4_smp_ops), .map_io = omap5_map_io, @@ -288,6 +292,9 @@ static const char *const dra74x_boards_compat[] __initconst = { }; DT_MACHINE_START(DRA74X_DT, "Generic DRA74X (Flattened Device Tree)") +#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) + .dma_zone_size = SZ_2G, +#endif .reserve = omap_reserve, .smp = smp_ops(omap4_smp_ops), .map_io = dra7xx_map_io, @@ -308,6 +315,9 @@ static const char *const dra72x_boards_compat[] __initconst = { }; DT_MACHINE_START(DRA72X_DT, "Generic DRA72X (Flattened Device Tree)") +#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) + .dma_zone_size = SZ_2G, +#endif .reserve = omap_reserve, .map_io = dra7xx_map_io, .init_early = dra7xx_init_early, diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index e1d2e991d17a..db7e0bab3587 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -399,40 +399,42 @@ static struct irq_chip wakeupgen_chip = { #endif }; -static int wakeupgen_domain_xlate(struct irq_domain *domain, - struct device_node *controller, - const u32 *intspec, - unsigned int intsize, - unsigned long *out_hwirq, - unsigned int *out_type) +static int wakeupgen_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (domain->of_node != controller) - return -EINVAL; /* Shouldn't happen, really... */ - if (intsize != 3) - return -EINVAL; /* Not GIC compliant */ - if (intspec[0] != 0) - return -EINVAL; /* No PPI should point to this domain */ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - *out_hwirq = intspec[1]; - *out_type = intspec[2]; - return 0; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } + + return -EINVAL; } static int wakeupgen_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { - struct of_phandle_args *args = data; - struct of_phandle_args parent_args; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq; int i; - if (args->args_count != 3) + if (fwspec->param_count != 3) return -EINVAL; /* Not GIC compliant */ - if (args->args[0] != 0) + if (fwspec->param[0] != 0) return -EINVAL; /* No PPI should point to this domain */ - hwirq = args->args[1]; + hwirq = fwspec->param[1]; if (hwirq >= MAX_IRQS) return -EINVAL; /* Can't deal with this */ @@ -440,15 +442,16 @@ static int wakeupgen_domain_alloc(struct irq_domain *domain, irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &wakeupgen_chip, NULL); - parent_args = *args; - parent_args.np = domain->parent->of_node; - return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args); + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); } static const struct irq_domain_ops wakeupgen_domain_ops = { - .xlate = wakeupgen_domain_xlate, - .alloc = wakeupgen_domain_alloc, - .free = irq_domain_free_irqs_common, + .translate = wakeupgen_domain_translate, + .alloc = wakeupgen_domain_alloc, + .free = irq_domain_free_irqs_common, }; /* diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index ea56397599c2..1dfe34654c43 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -559,7 +559,14 @@ static void pdata_quirks_check(struct pdata_init *quirks) void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table) { - omap_sdrc_init(NULL, NULL); + /* + * We still need this for omap2420 and omap3 PM to work, others are + * using drivers/misc/sram.c already. + */ + if (of_machine_is_compatible("ti,omap2420") || + of_machine_is_compatible("ti,omap3")) + omap_sdrc_init(NULL, NULL); + pdata_quirks_check(auxdata_quirks); of_platform_populate(NULL, omap_dt_match_table, omap_auxdata_lookup, NULL); diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 06005d3f2ba3..20ce2d386f17 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -42,10 +42,6 @@ #define PECR_IS(n) ((1 << ((n) * 2)) << 29) extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)); -#ifdef CONFIG_PM - -#define ISRAM_START 0x5c000000 -#define ISRAM_SIZE SZ_256K /* * NAND NFC: DFI bus arbitration subset @@ -54,6 +50,11 @@ extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)); #define NDCR_ND_ARB_EN (1 << 12) #define NDCR_ND_ARB_CNTL (1 << 19) +#ifdef CONFIG_PM + +#define ISRAM_START 0x5c000000 +#define ISRAM_SIZE SZ_256K + static void __iomem *sram; static unsigned long wakeup_src; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index df7537f12469..c21941349b3e 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -419,28 +419,24 @@ config CPU_THUMBONLY config CPU_32v3 bool select CPU_USE_DOMAINS if MMU - select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEED_KUSER_HELPERS select TLS_REG_EMUL if SMP || !MMU config CPU_32v4 bool select CPU_USE_DOMAINS if MMU - select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEED_KUSER_HELPERS select TLS_REG_EMUL if SMP || !MMU config CPU_32v4T bool select CPU_USE_DOMAINS if MMU - select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEED_KUSER_HELPERS select TLS_REG_EMUL if SMP || !MMU config CPU_32v5 bool select CPU_USE_DOMAINS if MMU - select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEED_KUSER_HELPERS select TLS_REG_EMUL if SMP || !MMU @@ -805,14 +801,6 @@ config TLS_REG_EMUL a few prototypes like that in existence) and therefore access to that required register must be emulated. -config NEEDS_SYSCALL_FOR_CMPXCHG - bool - select NEED_KUSER_HELPERS - help - SMP on a pre-ARMv6 processor? Well OK then. - Forget about fast user space cmpxchg support. - It is just not possible. - config NEED_KUSER_HELPERS bool diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 1a7815e5421b..ad4eb2d26e16 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1407,12 +1407,19 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, unsigned long uaddr = vma->vm_start; unsigned long usize = vma->vm_end - vma->vm_start; struct page **pages = __iommu_get_pages(cpu_addr, attrs); + unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + unsigned long off = vma->vm_pgoff; vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); if (!pages) return -ENXIO; + if (off >= nr_pages || (usize >> PAGE_SHIFT) > nr_pages - off) + return -ENXIO; + + pages += off; + do { int ret = vm_insert_page(vma, uaddr, *pages++); if (ret) { diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 0d629b8f973f..daafcf121ce0 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -593,6 +593,28 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) arm_notify_die("", regs, &info, ifsr, 0); } +/* + * Abort handler to be used only during first unmasking of asynchronous aborts + * on the boot CPU. This makes sure that the machine will not die if the + * firmware/bootloader left an imprecise abort pending for us to trip over. + */ +static int __init early_abort_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + pr_warn("Hit pending asynchronous external abort (FSR=0x%08x) during " + "first unmask, this is most likely caused by a " + "firmware/bootloader bug.\n", fsr); + + return 0; +} + +void __init early_abt_enable(void) +{ + fsr_info[22].fn = early_abort_handler; + local_abt_enable(); + fsr_info[22].fn = do_bad; +} + #ifndef CONFIG_ARM_LPAE static int __init exceptions_init(void) { diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index cf08bdfbe0d6..05ec5e0df32d 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h @@ -24,5 +24,6 @@ static inline int fsr_fs(unsigned int fsr) void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); unsigned long search_exception_table(unsigned long addr); +void early_abt_enable(void); #endif /* __ARCH_ARM_FAULT_H */ diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 7cd15143a507..4867f5daf82c 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -38,6 +38,7 @@ #include <asm/mach/pci.h> #include <asm/fixmap.h> +#include "fault.h" #include "mm.h" #include "tcm.h" @@ -1363,6 +1364,9 @@ static void __init devicemaps_init(const struct machine_desc *mdesc) */ local_flush_tlb_all(); flush_cache_all(); + + /* Enable asynchronous aborts */ + early_abt_enable(); } static void __init kmap_init(void) diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 876060bcceeb..b8efb8cd1f73 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -614,6 +614,7 @@ load_common: case BPF_LD | BPF_B | BPF_IND: load_order = 0; load_ind: + update_on_xread(ctx); OP_IMM3(ARM_ADD, r_off, r_X, k, ctx); goto load_common; case BPF_LDX | BPF_IMM: diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 2235081a04ee..8861c367d061 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -495,7 +495,7 @@ void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq) d->netdev = &orion_ge00.dev; for (i = 0; i < d->nr_chips; i++) - d->chip[i].host_dev = &orion_ge00_shared.dev; + d->chip[i].host_dev = &orion_ge_mvmdio.dev; orion_switch_device.dev.platform_data = d; platform_device_register(&orion_switch_device); diff --git a/arch/arm/vdso/vdsomunge.c b/arch/arm/vdso/vdsomunge.c index aedec81d1198..f6455273b2f8 100644 --- a/arch/arm/vdso/vdsomunge.c +++ b/arch/arm/vdso/vdsomunge.c @@ -45,7 +45,6 @@ * it does. */ -#include <byteswap.h> #include <elf.h> #include <errno.h> #include <fcntl.h> @@ -59,6 +58,16 @@ #include <sys/types.h> #include <unistd.h> +#define swab16(x) \ + ((((x) & 0x00ff) << 8) | \ + (((x) & 0xff00) >> 8)) + +#define swab32(x) \ + ((((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24)) + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define HOST_ORDER ELFDATA2LSB #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ @@ -104,17 +113,17 @@ static void cleanup(void) static Elf32_Word read_elf_word(Elf32_Word word, bool swap) { - return swap ? bswap_32(word) : word; + return swap ? swab32(word) : word; } static Elf32_Half read_elf_half(Elf32_Half half, bool swap) { - return swap ? bswap_16(half) : half; + return swap ? swab16(half) : half; } static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) { - *dst = swap ? bswap_32(val) : val; + *dst = swap ? swab32(val) : val; } int main(int argc, char **argv) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 07d1811aa03f..440d906429de 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -348,6 +348,33 @@ config ARM64_ERRATUM_843419 If unsure, say Y. +config CAVIUM_ERRATUM_22375 + bool "Cavium erratum 22375, 24313" + default y + help + Enable workaround for erratum 22375, 24313. + + This implements two gicv3-its errata workarounds for ThunderX. Both + with small impact affecting only ITS table allocation. + + erratum 22375: only alloc 8MB table size + erratum 24313: ignore memory access type + + The fixes are in ITS initialization and basically ignore memory access + type and table size provided by the TYPER and BASER registers. + + If unsure, say Y. + +config CAVIUM_ERRATUM_23154 + bool "Cavium erratum 23154: Access to ICC_IAR1_EL1 is not sync'ed" + default y + help + The gicv3 of ThunderX requires a modified version for + reading the IAR status to ensure data synchronization + (access to icc_iar1_el1 is not sync'ed before and after). + + If unsure, say Y. + endmenu diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index f9914d7c1bb0..d10b5d483022 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -42,7 +42,7 @@ endif CHECKFLAGS += -D__aarch64__ ifeq ($(CONFIG_ARM64_ERRATUM_843419), y) -CFLAGS_MODULE += -mcmodel=large +KBUILD_CFLAGS_MODULE += -mcmodel=large endif # Default value diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi index d831bc2ac204..fac1720472f9 100644 --- a/arch/arm64/boot/dts/apm/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi @@ -477,6 +477,16 @@ reg = <0x0 0x7c600000 0x0 0x200000>; pmd-controller = <3>; }; + + edacl3@7e600000 { + compatible = "apm,xgene-edac-l3"; + reg = <0x0 0x7e600000 0x0 0x1000>; + }; + + edacsoc@7e930000 { + compatible = "apm,xgene-edac-soc-v1"; + reg = <0x0 0x7e930000 0x0 0x1000>; + }; }; pcie0: pcie@1f2b0000 { diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi index 637e046f0e36..3c386680357e 100644 --- a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi +++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi @@ -61,42 +61,42 @@ button@1 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <116>; label = "POWER"; gpios = <&iofpga_gpio0 0 0x4>; }; button@2 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <102>; label = "HOME"; gpios = <&iofpga_gpio0 1 0x4>; }; button@3 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <152>; label = "RLOCK"; gpios = <&iofpga_gpio0 2 0x4>; }; button@4 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <115>; label = "VOL+"; gpios = <&iofpga_gpio0 3 0x4>; }; button@5 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <114>; label = "VOL-"; gpios = <&iofpga_gpio0 4 0x4>; }; button@6 { debounce_interval = <50>; - wakeup = <1>; + wakeup-source; linux,code = <99>; label = "NMI"; gpios = <&iofpga_gpio0 5 0x4>; diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 208cec08a74f..5f8a38dee274 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -92,4 +92,9 @@ static inline const char *acpi_get_enable_method(int cpu) { return acpi_psci_present() ? "psci" : NULL; } + +#ifdef CONFIG_ACPI_APEI +pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr); +#endif + #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h new file mode 100644 index 000000000000..030cdcb46c6b --- /dev/null +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -0,0 +1,170 @@ +/* + * arch/arm64/include/asm/arch_gicv3.h + * + * Copyright (C) 2015 ARM Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_ARCH_GICV3_H +#define __ASM_ARCH_GICV3_H + +#include <asm/sysreg.h> + +#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) +#define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1) +#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) +#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) +#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) +#define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4) +#define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5) +#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) + +#define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5) + +/* + * System register definitions + */ +#define ICH_VSEIR_EL2 sys_reg(3, 4, 12, 9, 4) +#define ICH_HCR_EL2 sys_reg(3, 4, 12, 11, 0) +#define ICH_VTR_EL2 sys_reg(3, 4, 12, 11, 1) +#define ICH_MISR_EL2 sys_reg(3, 4, 12, 11, 2) +#define ICH_EISR_EL2 sys_reg(3, 4, 12, 11, 3) +#define ICH_ELSR_EL2 sys_reg(3, 4, 12, 11, 5) +#define ICH_VMCR_EL2 sys_reg(3, 4, 12, 11, 7) + +#define __LR0_EL2(x) sys_reg(3, 4, 12, 12, x) +#define __LR8_EL2(x) sys_reg(3, 4, 12, 13, x) + +#define ICH_LR0_EL2 __LR0_EL2(0) +#define ICH_LR1_EL2 __LR0_EL2(1) +#define ICH_LR2_EL2 __LR0_EL2(2) +#define ICH_LR3_EL2 __LR0_EL2(3) +#define ICH_LR4_EL2 __LR0_EL2(4) +#define ICH_LR5_EL2 __LR0_EL2(5) +#define ICH_LR6_EL2 __LR0_EL2(6) +#define ICH_LR7_EL2 __LR0_EL2(7) +#define ICH_LR8_EL2 __LR8_EL2(0) +#define ICH_LR9_EL2 __LR8_EL2(1) +#define ICH_LR10_EL2 __LR8_EL2(2) +#define ICH_LR11_EL2 __LR8_EL2(3) +#define ICH_LR12_EL2 __LR8_EL2(4) +#define ICH_LR13_EL2 __LR8_EL2(5) +#define ICH_LR14_EL2 __LR8_EL2(6) +#define ICH_LR15_EL2 __LR8_EL2(7) + +#define __AP0Rx_EL2(x) sys_reg(3, 4, 12, 8, x) +#define ICH_AP0R0_EL2 __AP0Rx_EL2(0) +#define ICH_AP0R1_EL2 __AP0Rx_EL2(1) +#define ICH_AP0R2_EL2 __AP0Rx_EL2(2) +#define ICH_AP0R3_EL2 __AP0Rx_EL2(3) + +#define __AP1Rx_EL2(x) sys_reg(3, 4, 12, 9, x) +#define ICH_AP1R0_EL2 __AP1Rx_EL2(0) +#define ICH_AP1R1_EL2 __AP1Rx_EL2(1) +#define ICH_AP1R2_EL2 __AP1Rx_EL2(2) +#define ICH_AP1R3_EL2 __AP1Rx_EL2(3) + +#ifndef __ASSEMBLY__ + +#include <linux/stringify.h> + +/* + * Low-level accessors + * + * These system registers are 32 bits, but we make sure that the compiler + * sets the GP register's most significant bits to 0 with an explicit cast. + */ + +static inline void gic_write_eoir(u32 irq) +{ + asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); + isb(); +} + +static inline void gic_write_dir(u32 irq) +{ + asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); + isb(); +} + +static inline u64 gic_read_iar_common(void) +{ + u64 irqstat; + + asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); + return irqstat; +} + +/* + * Cavium ThunderX erratum 23154 + * + * The gicv3 of ThunderX requires a modified version for reading the + * IAR status to ensure data synchronization (access to icc_iar1_el1 + * is not sync'ed before and after). + */ +static inline u64 gic_read_iar_cavium_thunderx(void) +{ + u64 irqstat; + + asm volatile( + "nop;nop;nop;nop\n\t" + "nop;nop;nop;nop\n\t" + "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" + "nop;nop;nop;nop" + : "=r" (irqstat)); + mb(); + + return irqstat; +} + +static inline void gic_write_pmr(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); +} + +static inline void gic_write_ctlr(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" ((u64)val)); + isb(); +} + +static inline void gic_write_grpen1(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); + isb(); +} + +static inline void gic_write_sgi1r(u64 val) +{ + asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); +} + +static inline u32 gic_read_sre(void) +{ + u64 val; + + asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); + return val; +} + +static inline void gic_write_sre(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); + isb(); +} + +#define gic_read_typer(c) readq_relaxed(c) +#define gic_write_irouter(v, c) writeq_relaxed(v, c) + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_ARCH_GICV3_H */ diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 35a67783cfa0..1e247ac2601a 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -54,7 +54,7 @@ #define ATOMIC_INIT(i) { (i) } #define atomic_read(v) READ_ONCE((v)->counter) -#define atomic_set(v, i) (((v)->counter) = (i)) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) #define atomic_xchg(v, new) xchg(&((v)->counter), (new)) #define atomic_cmpxchg(v, old, new) cmpxchg(&((v)->counter), (old), (new)) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 171570702bb8..dbc78d2b8cc6 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -27,8 +27,9 @@ #define ARM64_HAS_SYSREG_GIC_CPUIF 3 #define ARM64_HAS_PAN 4 #define ARM64_HAS_LSE_ATOMICS 5 +#define ARM64_WORKAROUND_CAVIUM_23154 6 -#define ARM64_NCAPS 6 +#define ARM64_NCAPS 7 #ifndef __ASSEMBLY__ diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index ee6403df9fe4..100a3d1b17c8 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -62,15 +62,18 @@ (0xf << MIDR_ARCHITECTURE_SHIFT) | \ ((partnum) << MIDR_PARTNUM_SHIFT)) -#define ARM_CPU_IMP_ARM 0x41 -#define ARM_CPU_IMP_APM 0x50 +#define ARM_CPU_IMP_ARM 0x41 +#define ARM_CPU_IMP_APM 0x50 +#define ARM_CPU_IMP_CAVIUM 0x43 -#define ARM_CPU_PART_AEM_V8 0xD0F -#define ARM_CPU_PART_FOUNDATION 0xD00 -#define ARM_CPU_PART_CORTEX_A57 0xD07 -#define ARM_CPU_PART_CORTEX_A53 0xD03 +#define ARM_CPU_PART_AEM_V8 0xD0F +#define ARM_CPU_PART_FOUNDATION 0xD00 +#define ARM_CPU_PART_CORTEX_A57 0xD07 +#define ARM_CPU_PART_CORTEX_A53 0xD03 -#define APM_CPU_PART_POTENZA 0x000 +#define APM_CPU_PART_POTENZA 0x000 + +#define CAVIUM_CPU_PART_THUNDERX 0x0A1 #define ID_AA64MMFR0_BIGENDEL0_SHIFT 16 #define ID_AA64MMFR0_BIGENDEL0_MASK (0xf << ID_AA64MMFR0_BIGENDEL0_SHIFT) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 6b4c3ad75a2a..67027c611dbd 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -94,6 +94,7 @@ #define MT_DEVICE_GRE 2 #define MT_NORMAL_NC 3 #define MT_NORMAL 4 +#define MT_NORMAL_WT 5 /* * Memory types for Stage-2 translation diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 26b066690593..571ca0ed4f05 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -60,8 +60,10 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) +#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC)) +#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_WT)) #define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL)) #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE)) diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 3bc498c250dc..41e58fe3c041 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -44,7 +44,7 @@ #define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2) #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5) -#define __NR_compat_syscalls 388 +#define __NR_compat_syscalls 390 #endif #define __ARCH_WANT_SYS_CLONE diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index cef934a90f17..5b925b761a2a 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -797,3 +797,12 @@ __SYSCALL(__NR_memfd_create, sys_memfd_create) __SYSCALL(__NR_bpf, sys_bpf) #define __NR_execveat 387 __SYSCALL(__NR_execveat, compat_sys_execveat) +#define __NR_userfaultfd 388 +__SYSCALL(__NR_userfaultfd, sys_userfaultfd) +#define __NR_membarrier 389 +__SYSCALL(__NR_membarrier, sys_membarrier) + +/* + * Please add new compat syscalls above this comment and update + * __NR_compat_syscalls in asm/unistd.h. + */ diff --git a/arch/arm64/include/uapi/asm/signal.h b/arch/arm64/include/uapi/asm/signal.h index 8d1e7236431b..991bf5db2ca1 100644 --- a/arch/arm64/include/uapi/asm/signal.h +++ b/arch/arm64/include/uapi/asm/signal.h @@ -19,6 +19,9 @@ /* Required for AArch32 compatibility. */ #define SA_RESTORER 0x04000000 +#define MINSIGSTKSZ 5120 +#define SIGSTKSZ 16384 + #include <asm-generic/signal.h> #endif diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 19de7537e7d3..137d537ddceb 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -29,6 +29,11 @@ #include <asm/cpu_ops.h> #include <asm/smp_plat.h> +#ifdef CONFIG_ACPI_APEI +# include <linux/efi.h> +# include <asm/pgtable.h> +#endif + int acpi_noirq = 1; /* skip ACPI IRQ initialization */ int acpi_disabled = 1; EXPORT_SYMBOL(acpi_disabled); @@ -230,3 +235,27 @@ void __init acpi_gic_init(void) early_acpi_os_unmap_memory((char *)table, tbl_size); } + +#ifdef CONFIG_ACPI_APEI +pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr) +{ + /* + * According to "Table 8 Map: EFI memory types to AArch64 memory + * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is + * mapped to a corresponding MAIR attribute encoding. + * The EFI memory attribute advises all possible capabilities + * of a memory region. We use the most efficient capability. + */ + + u64 attr; + + attr = efi_mem_attributes(addr); + if (attr & EFI_MEMORY_WB) + return PAGE_KERNEL; + if (attr & EFI_MEMORY_WT) + return __pgprot(PROT_NORMAL_WT); + if (attr & EFI_MEMORY_WC) + return __pgprot(PROT_NORMAL_NC); + return __pgprot(PROT_DEVICE_nGnRnE); +} +#endif diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index bcee7abac68e..937f5e58a4d3 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -284,21 +284,23 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) __asm__ __volatile__( \ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ - " mov %w2, %w1\n" \ - "0: ldxr"B" %w1, [%3]\n" \ - "1: stxr"B" %w0, %w2, [%3]\n" \ + "0: ldxr"B" %w2, [%3]\n" \ + "1: stxr"B" %w0, %w1, [%3]\n" \ " cbz %w0, 2f\n" \ " mov %w0, %w4\n" \ + " b 3f\n" \ "2:\n" \ + " mov %w1, %w2\n" \ + "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ - "3: mov %w0, %w5\n" \ - " b 2b\n" \ + "4: mov %w0, %w5\n" \ + " b 3b\n" \ " .popsection" \ " .pushsection __ex_table,\"a\"\n" \ " .align 3\n" \ - " .quad 0b, 3b\n" \ - " .quad 1b, 3b\n" \ + " .quad 0b, 4b\n" \ + " .quad 1b, 4b\n" \ " .popsection\n" \ ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 6ffd91438560..574450c257a4 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -23,6 +23,7 @@ #define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) +#define MIDR_THUNDERX MIDR_CPU_PART(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) @@ -82,6 +83,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x04), }, #endif +#ifdef CONFIG_CAVIUM_ERRATUM_23154 + { + /* Cavium ThunderX, pass 1.x */ + .desc = "Cavium erratum 23154", + .capability = ARM64_WORKAROUND_CAVIUM_23154, + MIDR_RANGE(MIDR_THUNDERX, 0x00, 0x01), + }, +#endif { } }; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 3c9aed32f70b..305f30dc9e63 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -23,6 +23,8 @@ #include <asm/cpufeature.h> #include <asm/processor.h> +#include <linux/irqchip/arm-gic-v3.h> + static bool feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) { @@ -45,11 +47,26 @@ __ID_FEAT_CHK(id_aa64pfr0); __ID_FEAT_CHK(id_aa64mmfr1); __ID_FEAT_CHK(id_aa64isar0); +static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry) +{ + bool has_sre; + + if (!has_id_aa64pfr0_feature(entry)) + return false; + + has_sre = gic_enable_sre(); + if (!has_sre) + pr_warn_once("%s present but disabled by higher exception level\n", + entry->desc); + + return has_sre; +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", .capability = ARM64_HAS_SYSREG_GIC_CPUIF, - .matches = has_id_aa64pfr0_feature, + .matches = has_useable_gicv3_cpuif, .field_pos = 24, .min_field_value = 1, }, diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c index 816120ece6bc..78dfbd34b6bf 100644 --- a/arch/arm64/kernel/efi-stub.c +++ b/arch/arm64/kernel/efi-stub.c @@ -25,10 +25,20 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, unsigned long kernel_size, kernel_memsize = 0; unsigned long nr_pages; void *old_image_addr = (void *)*image_addr; + unsigned long preferred_offset; + + /* + * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond + * a 2 MB aligned base, which itself may be lower than dram_base, as + * long as the resulting offset equals or exceeds it. + */ + preferred_offset = round_down(dram_base, SZ_2M) + TEXT_OFFSET; + if (preferred_offset < dram_base) + preferred_offset += SZ_2M; /* Relocate the image, if required. */ kernel_size = _edata - _text; - if (*image_addr != (dram_base + TEXT_OFFSET)) { + if (*image_addr != preferred_offset) { kernel_memsize = kernel_size + (_end - _edata); /* @@ -42,7 +52,7 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, * Mustang), we can still place the kernel at the address * 'dram_base + TEXT_OFFSET'. */ - *image_addr = *reserve_addr = dram_base + TEXT_OFFSET; + *image_addr = *reserve_addr = preferred_offset; nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 13671a9cf016..61eb1d17586a 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -51,15 +51,6 @@ static struct mm_struct efi_mm = { INIT_MM_CONTEXT(efi_mm) }; -static int uefi_debug __initdata; -static int __init uefi_debug_setup(char *str) -{ - uefi_debug = 1; - - return 0; -} -early_param("uefi_debug", uefi_debug_setup); - static int __init is_normal_ram(efi_memory_desc_t *md) { if (md->attribute & EFI_MEMORY_WB) @@ -171,14 +162,14 @@ static __init void reserve_regions(void) efi_memory_desc_t *md; u64 paddr, npages, size; - if (uefi_debug) + if (efi_enabled(EFI_DBG)) pr_info("Processing EFI memory map:\n"); for_each_efi_memory_desc(&memmap, md) { paddr = md->phys_addr; npages = md->num_pages; - if (uefi_debug) { + if (efi_enabled(EFI_DBG)) { char buf[64]; pr_info(" 0x%012llx-0x%012llx %s", @@ -194,11 +185,11 @@ static __init void reserve_regions(void) if (is_reserve_region(md)) { memblock_reserve(paddr, size); - if (uefi_debug) + if (efi_enabled(EFI_DBG)) pr_cont("*"); } - if (uefi_debug) + if (efi_enabled(EFI_DBG)) pr_cont("\n"); } @@ -210,14 +201,14 @@ void __init efi_init(void) struct efi_fdt_params params; /* Grab UEFI information placed in FDT by stub */ - if (!efi_get_fdt_params(¶ms, uefi_debug)) + if (!efi_get_fdt_params(¶ms)) return; efi_system_table = params.system_table; memblock_reserve(params.mmap & PAGE_MASK, PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); - memmap.phys_map = (void *)params.mmap; + memmap.phys_map = params.mmap; memmap.map = early_memremap(params.mmap, params.mmap_size); memmap.map_end = memmap.map + params.mmap_size; memmap.desc_size = params.desc_size; @@ -291,7 +282,7 @@ static int __init arm64_enable_runtime_services(void) pr_info("Remapping and enabling EFI services.\n"); mapsize = memmap.map_end - memmap.map; - memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, + memmap.map = (__force void *)ioremap_cache(memmap.phys_map, mapsize); if (!memmap.map) { pr_err("Failed to remap EFI memory map\n"); diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 90d09eddd5b2..351a4de1b1e2 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -498,6 +498,8 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1 orr x0, x0, #ICC_SRE_EL2_ENABLE // Set ICC_SRE_EL2.Enable==1 msr_s ICC_SRE_EL2, x0 isb // Make sure SRE is now set + mrs_s x0, ICC_SRE_EL2 // Read SRE back, + tbz x0, #0, 3f // and check that it sticks msr_s ICH_HCR_EL2, xzr // Reset ICC_HCR_EL2 to defaults 3: diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 407991bf79f5..ccb6078ed9f2 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -48,11 +48,7 @@ int notrace unwind_frame(struct stackframe *frame) frame->sp = fp + 0x10; frame->fp = *(unsigned long *)(fp); - /* - * -4 here because we care about the PC at time of bl, - * not where the return will go. - */ - frame->pc = *(unsigned long *)(fp + 8) - 4; + frame->pc = *(unsigned long *)(fp + 8); return 0; } diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 8297d502217e..44ca4143b013 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -80,17 +80,21 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) if (ret == 0) { /* * We are resuming from reset with TTBR0_EL1 set to the - * idmap to enable the MMU; restore the active_mm mappings in - * TTBR0_EL1 unless the active_mm == &init_mm, in which case - * the thread entered cpu_suspend with TTBR0_EL1 set to - * reserved TTBR0 page tables and should be restored as such. + * idmap to enable the MMU; set the TTBR0 to the reserved + * page tables to prevent speculative TLB allocations, flush + * the local tlb and set the default tcr_el1.t0sz so that + * the TTBR0 address space set-up is properly restored. + * If the current active_mm != &init_mm we entered cpu_suspend + * with mappings in TTBR0 that must be restored, so we switch + * them back to complete the address space configuration + * restoration before returning. */ - if (mm == &init_mm) - cpu_set_reserved_ttbr0(); - else - cpu_switch_mm(mm->pgd, mm); - + cpu_set_reserved_ttbr0(); flush_tlb_all(); + cpu_set_default_tcr_t0sz(); + + if (mm != &init_mm) + cpu_switch_mm(mm->pgd, mm); /* * Restore per-cpu offset before any kernel diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 5c7e920e4861..ff5292c6277c 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -16,6 +16,9 @@ menuconfig VIRTUALIZATION if VIRTUALIZATION +config KVM_ARM_VGIC_V3 + bool + config KVM bool "Kernel-based Virtual Machine (KVM) support" depends on OF @@ -31,6 +34,7 @@ config KVM select KVM_VFIO select HAVE_KVM_EVENTFD select HAVE_KVM_IRQFD + select KVM_ARM_VGIC_V3 ---help--- Support hosting virtualized guest machines. diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index e4ee7bd8830a..7783ff05f74c 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -163,12 +163,14 @@ ENTRY(__cpu_setup) * DEVICE_GRE 010 00001100 * NORMAL_NC 011 01000100 * NORMAL 100 11111111 + * NORMAL_WT 101 10111011 */ ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ MAIR(0x04, MT_DEVICE_nGnRE) | \ MAIR(0x0c, MT_DEVICE_GRE) | \ MAIR(0x44, MT_NORMAL_NC) | \ - MAIR(0xff, MT_NORMAL) + MAIR(0xff, MT_NORMAL) | \ + MAIR(0xbb, MT_NORMAL_WT) msr mair_el1, x5 /* * Prepare SCTLR diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c index 91146b416cdb..99b0a7984950 100644 --- a/arch/avr32/boards/atngw100/mrmt.c +++ b/arch/avr32/boards/atngw100/mrmt.c @@ -21,7 +21,6 @@ #include <linux/leds_pwm.h> #include <linux/input.h> #include <linux/gpio_keys.h> -#include <linux/atmel_serial.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index 97c9bdf83409..d74fd8ce980a 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -19,8 +19,8 @@ #define ATOMIC_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v, i) (((v)->counter) = i) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) #define ATOMIC_OP_RETURN(op, asm_op, asm_con) \ static inline int __atomic_##op##_return(int i, atomic_t *v) \ diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index ddcb45d7dfa7..43afc03e4125 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -178,7 +178,7 @@ static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output) static void __init parse_priority_map(struct megamod_pic *pic, int *mapping, int size) { - struct device_node *np = pic->irqhost->of_node; + struct device_node *np = irq_domain_get_of_node(pic->irqhost); const __be32 *map; int i, maplen; u32 val; diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 8da5653bd895..e086f9e93728 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -57,7 +57,6 @@ config CRIS select ARCH_WANT_IPC_PARSE_VERSION select GENERIC_IRQ_SHOW select GENERIC_IOMAP - select GENERIC_CMOS_UPDATE select MODULES_USE_ELF_RELA select CLONE_BACKWARDS2 select OLD_SIGSUSPEND diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index 4a146e1749c9..a4877a421756 100644 --- a/arch/cris/arch-v10/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -354,63 +354,6 @@ no_command_line: blo 1b nop -#ifdef CONFIG_BLK_DEV_ETRAXIDE - ;; disable ATA before enabling it in genconfig below - moveq 0,$r0 - move.d $r0,[R_ATA_CTRL_DATA] - move.d $r0,[R_ATA_TRANSFER_CNT] - move.d $r0,[R_ATA_CONFIG] -#if 0 - move.d R_PORT_G_DATA, $r1 - move.d $r0, [$r1]; assert ATA bus-reset - nop - nop - nop - nop - nop - nop - move.d 0x08000000,$r0 - move.d $r0,[$r1] -#endif -#endif - -#ifdef CONFIG_JULIETTE - ;; configure external DMA channel 0 before enabling it in genconfig - - moveq 0,$r0 - move.d $r0,[R_EXT_DMA_0_ADDR] - ; cnt enable, word size, output, stop, size 0 - move.d IO_STATE (R_EXT_DMA_0_CMD, cnt, enable) \ - | IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh) \ - | IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh) \ - | IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst) \ - | IO_STATE (R_EXT_DMA_0_CMD, wid, word) \ - | IO_STATE (R_EXT_DMA_0_CMD, dir, output) \ - | IO_STATE (R_EXT_DMA_0_CMD, run, stop) \ - | IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),$r0 - move.d $r0,[R_EXT_DMA_0_CMD] - - ;; reset dma4 and wait for completion - - moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 - move.b $r0,[R_DMA_CH4_CMD] -1: move.b [R_DMA_CH4_CMD],$r0 - and.b IO_MASK (R_DMA_CH4_CMD, cmd),$r0 - cmp.b IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 - beq 1b - nop - - ;; reset dma5 and wait for completion - - moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 - move.b $r0,[R_DMA_CH5_CMD] -1: move.b [R_DMA_CH5_CMD],$r0 - and.b IO_MASK (R_DMA_CH5_CMD, cmd),$r0 - cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 - beq 1b - nop -#endif - ;; Etrax product HW genconfig setup moveq 0,$r0 @@ -447,21 +390,6 @@ no_command_line: | IO_STATE (R_GEN_CONFIG, dma9, usb),$r0 -#if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) - or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 -#endif - -#if defined(CONFIG_ETRAX_DEF_R_PORT_G8_15_DIR_OUT) - or.d IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0 -#endif -#if defined(CONFIG_ETRAX_DEF_R_PORT_G16_23_DIR_OUT) - or.d IO_STATE (R_GEN_CONFIG, g16_23dir, out),$r0 -#endif - -#if defined(CONFIG_ETRAX_DEF_R_PORT_G24_DIR_OUT) - or.d IO_STATE (R_GEN_CONFIG, g24dir, out),$r0 -#endif - move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG move.d $r0,[R_GEN_CONFIG] @@ -500,19 +428,9 @@ no_command_line: ;; including their shadow registers move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0 -#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) - or.b IO_STATE (R_PORT_PA_DIR, dir7, output),$r0 -#endif move.b $r0,[port_pa_dir_shadow] move.b $r0,[R_PORT_PA_DIR] move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0 -#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) -#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) - and.b ~(1 << 7),$r0 -#else - or.b (1 << 7),$r0 -#endif -#endif move.b $r0,[port_pa_data_shadow] move.b $r0,[R_PORT_PA_DATA] @@ -520,19 +438,9 @@ no_command_line: move.b $r0,[port_pb_config_shadow] move.b $r0,[R_PORT_PB_CONFIG] move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR,$r0 -#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5) - or.b IO_STATE (R_PORT_PB_DIR, dir5, output),$r0 -#endif move.b $r0,[port_pb_dir_shadow] move.b $r0,[R_PORT_PB_DIR] move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA,$r0 -#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5) -#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) - and.b ~(1 << 5),$r0 -#else - or.b (1 << 5),$r0 -#endif -#endif move.b $r0,[port_pb_data_shadow] move.b $r0,[R_PORT_PB_DATA] @@ -541,20 +449,6 @@ no_command_line: move.d $r0, [R_PORT_PB_I2C] moveq 0,$r0 -#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G10) -#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) - and.d ~(1 << 10),$r0 -#else - or.d (1 << 10),$r0 -#endif -#endif -#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G11) -#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) - and.d ~(1 << 11),$r0 -#else - or.d (1 << 11),$r0 -#endif -#endif move.d $r0,[port_g_data_shadow] move.d $r0,[R_PORT_G_DATA] diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index 22d846bfc570..ed71ade93a73 100644 --- a/arch/cris/arch-v10/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -275,7 +275,7 @@ static char remcomOutBuffer[BUFMAX]; /* Error and warning messages. */ enum error_type { - SUCCESS, E01, E02, E03, E04, E05, E06, E07 + SUCCESS, E01, E02, E03, E04, E05, E06, E07, E08 }; static char *error_message[] = { @@ -286,7 +286,8 @@ static char *error_message[] = "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.", "E05 Change register content - P - the register is not implemented..", "E06 Change memory content - M - internal error.", - "E07 Change register content - P - the register is not stored on the stack" + "E07 Change register content - P - the register is not stored on the stack", + "E08 Invalid parameter" }; /********************************* Register image ****************************/ /* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's @@ -351,7 +352,7 @@ char internal_stack[INTERNAL_STACK_SIZE]; breakpoint to be handled. A static breakpoint uses the content of register BRP as it is whereas a dynamic breakpoint requires subtraction with 2 in order to execute the instruction. The first breakpoint is static. */ -static unsigned char is_dyn_brkp = 0; +static unsigned char __used is_dyn_brkp; /********************************* String library ****************************/ /* Single-step over library functions creates trap loops. */ @@ -413,18 +414,6 @@ gdb_cris_strtol (const char *s, char **endptr, int base) } /********************************** Packet I/O ******************************/ -/* Returns the integer equivalent of a hexadecimal character. */ -static int -hex (char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch - 'a' + 10); - if ((ch >= '0') && (ch <= '9')) - return (ch - '0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch - 'A' + 10); - return (-1); -} /* Convert the memory, pointed to by mem into hexadecimal representation. Put the result in buf, and return a pointer to the last character @@ -455,22 +444,6 @@ mem2hex(char *buf, unsigned char *mem, int count) return (buf); } -/* Convert the array, in hexadecimal representation, pointed to by buf into - binary representation. Put the result in mem, and return a pointer to - the character after the last byte written. */ -static unsigned char* -hex2mem (unsigned char *mem, char *buf, int count) -{ - int i; - unsigned char ch; - for (i = 0; i < count; i++) { - ch = hex (*buf++) << 4; - ch = ch + hex (*buf++); - *mem++ = ch; - } - return (mem); -} - /* Put the content of the array, in binary representation, pointed to by buf into memory pointed to by mem, and return a pointer to the character after the last byte written. @@ -524,8 +497,8 @@ getpacket (char *buffer) buffer[count] = '\0'; if (ch == '#') { - xmitcsum = hex (getDebugChar ()) << 4; - xmitcsum += hex (getDebugChar ()); + xmitcsum = hex_to_bin(getDebugChar()) << 4; + xmitcsum += hex_to_bin(getDebugChar()); if (checksum != xmitcsum) { /* Wrong checksum */ putDebugChar ('-'); @@ -599,7 +572,7 @@ putDebugString (const unsigned char *str, int length) /********************************* Register image ****************************/ /* Write a value to a specified register in the register image of the current - thread. Returns status code SUCCESS, E02 or E05. */ + thread. Returns status code SUCCESS, E02, E05 or E08. */ static int write_register (int regno, char *val) { @@ -608,8 +581,9 @@ write_register (int regno, char *val) if (regno >= R0 && regno <= PC) { /* 32-bit register with simple offset. */ - hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int), - val, sizeof(unsigned int)); + if (hex2bin((unsigned char *)current_reg + regno * sizeof(unsigned int), + val, sizeof(unsigned int))) + status = E08; } else if (regno == P0 || regno == VR || regno == P4 || regno == P8) { /* Do not support read-only registers. */ @@ -618,13 +592,15 @@ write_register (int regno, char *val) else if (regno == CCR) { /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, and P7 (MOF) is 32 bits in ETRAX 100LX. */ - hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short), - val, sizeof(unsigned short)); + if (hex2bin((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short), + val, sizeof(unsigned short))) + status = E08; } else if (regno >= MOF && regno <= USP) { /* 32 bit register with complex offset. (P8 has been taken care of.) */ - hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int), - val, sizeof(unsigned int)); + if (hex2bin((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int), + val, sizeof(unsigned int))) + status = E08; } else { /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ @@ -759,9 +735,11 @@ handle_exception (int sigval) /* Write registers. GXX..XX Each byte of register data is described by two hex digits. Success: OK - Failure: void. */ - hex2mem((char *)&cris_reg, &remcomInBuffer[1], sizeof(registers)); - gdb_cris_strcpy (remcomOutBuffer, "OK"); + Failure: E08. */ + if (hex2bin((char *)&cris_reg, &remcomInBuffer[1], sizeof(registers))) + gdb_cris_strcpy (remcomOutBuffer, error_message[E08]); + else + gdb_cris_strcpy (remcomOutBuffer, "OK"); break; case 'P': @@ -771,7 +749,7 @@ handle_exception (int sigval) for each byte in the register (target byte order). P1f=11223344 means set register 31 to 44332211. Success: OK - Failure: E02, E05 */ + Failure: E02, E05, E08 */ { char *suffix; int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); @@ -791,6 +769,10 @@ handle_exception (int sigval) /* Do not support non-existing registers on the stack. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E07]); break; + case E08: + /* Invalid parameter. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E08]); + break; default: /* Valid register number. */ gdb_cris_strcpy (remcomOutBuffer, "OK"); @@ -826,7 +808,7 @@ handle_exception (int sigval) AA..AA is the start address, LLLL is the number of bytes, and XX..XX is the hexadecimal data. Success: OK - Failure: void. */ + Failure: E08. */ { char *lenptr; char *dataptr; @@ -835,14 +817,15 @@ handle_exception (int sigval) int length = gdb_cris_strtol(lenptr+1, &dataptr, 16); if (*lenptr == ',' && *dataptr == ':') { if (remcomInBuffer[0] == 'M') { - hex2mem(addr, dataptr + 1, length); - } - else /* X */ { + if (hex2bin(addr, dataptr + 1, length)) + gdb_cris_strcpy (remcomOutBuffer, error_message[E08]); + else + gdb_cris_strcpy (remcomOutBuffer, "OK"); + } else /* X */ { bin2mem(addr, dataptr + 1, length); + gdb_cris_strcpy (remcomOutBuffer, "OK"); } - gdb_cris_strcpy (remcomOutBuffer, "OK"); - } - else { + } else { gdb_cris_strcpy (remcomOutBuffer, error_message[E06]); } } @@ -970,7 +953,7 @@ asm ("\n" " move $ibr,[cris_reg+0x4E] ; P9,\n" " move $irp,[cris_reg+0x52] ; P10,\n" " move $srp,[cris_reg+0x56] ; P11,\n" -" move $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n" +" move $bar,[cris_reg+0x5A] ; P12,\n" " ; P13, register DCCR already saved\n" ";; Due to the old assembler-versions BRP might not be recognized\n" " .word 0xE670 ; move brp,r0\n" @@ -1063,7 +1046,7 @@ asm ("\n" " move $ibr,[cris_reg+0x4E] ; P9,\n" " move $irp,[cris_reg+0x52] ; P10,\n" " move $srp,[cris_reg+0x56] ; P11,\n" -" move $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n" +" move $bar,[cris_reg+0x5A] ; P12,\n" " ; P13, register DCCR already saved\n" ";; Due to the old assembler-versions BRP might not be recognized\n" " .word 0xE670 ; move brp,r0\n" diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c index e7f8066105aa..85e3f1b1f3ac 100644 --- a/arch/cris/arch-v10/mm/init.c +++ b/arch/cris/arch-v10/mm/init.c @@ -68,14 +68,10 @@ paging_init(void) *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* bootrom */ IO_STATE(R_MMU_KSEG, seg_e, page ) | - IO_STATE(R_MMU_KSEG, seg_d, page ) | - IO_STATE(R_MMU_KSEG, seg_c, page ) | + IO_STATE(R_MMU_KSEG, seg_d, page ) | + IO_STATE(R_MMU_KSEG, seg_c, page ) | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ -#ifdef CONFIG_JULIETTE - IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ -#else IO_STATE(R_MMU_KSEG, seg_a, page ) | -#endif IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ @@ -92,14 +88,10 @@ paging_init(void) IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | -#ifdef CONFIG_JULIETTE - IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | -#else IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | -#endif IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); - + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig index 21bbd93be34f..17dbe03af5f4 100644 --- a/arch/cris/arch-v32/Kconfig +++ b/arch/cris/arch-v32/Kconfig @@ -11,95 +11,6 @@ config ETRAX_DRAM_VIRTUAL_BASE default "c0000000" choice - prompt "Nbr of Ethernet LED groups" - depends on ETRAX_ARCH_V32 - default ETRAX_NBR_LED_GRP_ONE - help - Select how many Ethernet LED groups that can be used. Usually one per Ethernet - interface is a good choice. - -config ETRAX_NBR_LED_GRP_ZERO - bool "Use zero LED groups" - help - Select this if you do not want any Ethernet LEDs. - -config ETRAX_NBR_LED_GRP_ONE - bool "Use one LED group" - help - Select this if you want one Ethernet LED group. This LED group - can be used for one or more Ethernet interfaces. However, it is - recommended that each Ethernet interface use a dedicated LED group. - -config ETRAX_NBR_LED_GRP_TWO - bool "Use two LED groups" - help - Select this if you want two Ethernet LED groups. This is the - best choice if you have more than one Ethernet interface and - would like to have separate LEDs for the interfaces. - -endchoice - -config ETRAX_LED_G_NET0 - string "Ethernet LED group 0 green LED bit" - depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO) - default "PA3" - help - Bit to use for the green LED in Ethernet LED group 0. - -config ETRAX_LED_R_NET0 - string "Ethernet LED group 0 red LED bit" - depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO) - default "PA4" - help - Bit to use for the red LED in Ethernet LED group 0. - -config ETRAX_LED_G_NET1 - string "Ethernet group 1 green LED bit" - depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO - default "" - help - Bit to use for the green LED in Ethernet LED group 1. - -config ETRAX_LED_R_NET1 - string "Ethernet group 1 red LED bit" - depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO - default "" - help - Bit to use for the red LED in Ethernet LED group 1. - -config ETRAX_V32_LED2G - string "Second green LED bit" - depends on ETRAX_ARCH_V32 - default "PA5" - help - Bit to use for the first green LED (status LED). - Most Axis products use bit A5 here. - -config ETRAX_V32_LED2R - string "Second red LED bit" - depends on ETRAX_ARCH_V32 - default "PA6" - help - Bit to use for the first red LED (network LED). - Most Axis products use bit A6 here. - -config ETRAX_V32_LED3G - string "Third green LED bit" - depends on ETRAX_ARCH_V32 - default "PA7" - help - Bit to use for the first green LED (drive/power LED). - Most Axis products use bit A7 here. - -config ETRAX_V32_LED3R - string "Third red LED bit" - depends on ETRAX_ARCH_V32 - default "PA7" - help - Bit to use for the first red LED (drive/power LED). - Most Axis products use bit A7 here. - -choice prompt "Kernel GDB port" depends on ETRAX_KGDB default ETRAX_KGDB_PORT0 diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index e6c523cc40bc..2735eb7671a5 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -149,173 +149,6 @@ config ETRAX_NANDBOOT Say Y if your boot code, kernel and root file system is in NAND flash. Say N if they are in NOR flash. -config ETRAX_I2C - bool "I2C driver" - depends on ETRAX_ARCH_V32 - help - This option enables the I2C driver used by e.g. the RTC driver. - -config ETRAX_V32_I2C_DATA_PORT - string "I2C data pin" - depends on ETRAX_I2C - help - The pin to use for I2C data. - -config ETRAX_V32_I2C_CLK_PORT - string "I2C clock pin" - depends on ETRAX_I2C - help - The pin to use for I2C clock. - -config ETRAX_GPIO - bool "GPIO support" - depends on ETRAX_ARCH_V32 - ---help--- - Enables the ETRAX general port device (major 120, minors 0-4). - You can use this driver to access the general port bits. It supports - these ioctl's: - #include <linux/etraxgpio.h> - fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob - ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set); - ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear); - err = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READ_INBITS), &val); - Remember that you need to setup the port directions appropriately in - the General configuration. - -config ETRAX_VIRTUAL_GPIO - bool "Virtual GPIO support" - depends on ETRAX_GPIO - help - Enables the virtual Etrax general port device (major 120, minor 6). - It uses an I/O expander for the I2C-bus. - -config ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN - int "Virtual GPIO interrupt pin on PA pin" - range 0 7 - depends on ETRAX_VIRTUAL_GPIO - help - The pin to use on PA for virtual gpio interrupt. - -config ETRAX_PA_CHANGEABLE_DIR - hex "PA user changeable dir mask" - depends on ETRAX_GPIO - default "0x00" if ETRAXFS - default "0x00000000" if !ETRAXFS - help - This is a bitmask with information of what bits in PA that a - user can change direction on using ioctl's. - Bit set = changeable. - You probably want 0 here, but it depends on your hardware. - -config ETRAX_PA_CHANGEABLE_BITS - hex "PA user changeable bits mask" - depends on ETRAX_GPIO - default "0x00" if ETRAXFS - default "0x00000000" if !ETRAXFS - help - This is a bitmask with information of what bits in PA - that a user can change the value on using ioctl's. - Bit set = changeable. - -config ETRAX_PB_CHANGEABLE_DIR - hex "PB user changeable dir mask" - depends on ETRAX_GPIO - default "0x00000" if ETRAXFS - default "0x00000000" if !ETRAXFS - help - This is a bitmask with information of what bits in PB - that a user can change direction on using ioctl's. - Bit set = changeable. - You probably want 0 here, but it depends on your hardware. - -config ETRAX_PB_CHANGEABLE_BITS - hex "PB user changeable bits mask" - depends on ETRAX_GPIO - default "0x00000" if ETRAXFS - default "0x00000000" if !ETRAXFS - help - This is a bitmask with information of what bits in PB - that a user can change the value on using ioctl's. - Bit set = changeable. - -config ETRAX_PC_CHANGEABLE_DIR - hex "PC user changeable dir mask" - depends on ETRAX_GPIO - default "0x00000" if ETRAXFS - default "0x00000000" if !ETRAXFS - help - This is a bitmask with information of what bits in PC - that a user can change direction on using ioctl's. - Bit set = changeable. - You probably want 0 here, but it depends on your hardware. - -config ETRAX_PC_CHANGEABLE_BITS - hex "PC user changeable bits mask" - depends on ETRAX_GPIO - default "0x00000" if ETRAXFS - default "0x00000000" if !ETRAXFS - help - This is a bitmask with information of what bits in PC - that a user can change the value on using ioctl's. - Bit set = changeable. - -config ETRAX_PD_CHANGEABLE_DIR - hex "PD user changeable dir mask" - depends on ETRAX_GPIO && ETRAXFS - default "0x00000" - help - This is a bitmask with information of what bits in PD - that a user can change direction on using ioctl's. - Bit set = changeable. - You probably want 0x00000 here, but it depends on your hardware. - -config ETRAX_PD_CHANGEABLE_BITS - hex "PD user changeable bits mask" - depends on ETRAX_GPIO && ETRAXFS - default "0x00000" - help - This is a bitmask (18 bits) with information of what bits in PD - that a user can change the value on using ioctl's. - Bit set = changeable. - -config ETRAX_PE_CHANGEABLE_DIR - hex "PE user changeable dir mask" - depends on ETRAX_GPIO && ETRAXFS - default "0x00000" - help - This is a bitmask (18 bits) with information of what bits in PE - that a user can change direction on using ioctl's. - Bit set = changeable. - You probably want 0x00000 here, but it depends on your hardware. - -config ETRAX_PE_CHANGEABLE_BITS - hex "PE user changeable bits mask" - depends on ETRAX_GPIO && ETRAXFS - default "0x00000" - help - This is a bitmask (18 bits) with information of what bits in PE - that a user can change the value on using ioctl's. - Bit set = changeable. - -config ETRAX_PV_CHANGEABLE_DIR - hex "PV user changeable dir mask" - depends on ETRAX_VIRTUAL_GPIO - default "0x0000" - help - This is a bitmask (16 bits) with information of what bits in PV - that a user can change direction on using ioctl's. - Bit set = changeable. - You probably want 0x0000 here, but it depends on your hardware. - -config ETRAX_PV_CHANGEABLE_BITS - hex "PV user changeable bits mask" - depends on ETRAX_VIRTUAL_GPIO - default "0x0000" - help - This is a bitmask (16 bits) with information of what bits in PV - that a user can change the value on using ioctl's. - Bit set = changeable. - config ETRAX_CARDBUS bool "Cardbus support" depends on ETRAX_ARCH_V32 diff --git a/arch/cris/arch-v32/drivers/Makefile b/arch/cris/arch-v32/drivers/Makefile index 15fbfefced2c..b5a75fdce77b 100644 --- a/arch/cris/arch-v32/drivers/Makefile +++ b/arch/cris/arch-v32/drivers/Makefile @@ -7,6 +7,5 @@ obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o obj-$(CONFIG_ETRAXFS) += mach-fs/ obj-$(CONFIG_CRIS_MACH_ARTPEC3) += mach-a3/ obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o -obj-$(CONFIG_ETRAX_I2C) += i2c.o obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o obj-$(CONFIG_PCI) += pci/ diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index 5387424683cc..c6309a182f46 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c @@ -361,7 +361,7 @@ static int __init init_axis_flash(void) #if 0 /* Dump flash memory so we can see what is going on */ if (main_mtd) { - int sectoraddr, i; + int sectoraddr; for (sectoraddr = 0; sectoraddr < 2*65536+4096; sectoraddr += PAGESIZE) { main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len, @@ -369,21 +369,7 @@ static int __init init_axis_flash(void) printk(KERN_INFO "Sector at %d (length %d):\n", sectoraddr, len); - for (i = 0; i < PAGESIZE; i += 16) { - printk(KERN_INFO - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - page[i] & 255, page[i+1] & 255, - page[i+2] & 255, page[i+3] & 255, - page[i+4] & 255, page[i+5] & 255, - page[i+6] & 255, page[i+7] & 255, - page[i+8] & 255, page[i+9] & 255, - page[i+10] & 255, page[i+11] & 255, - page[i+12] & 255, page[i+13] & 255, - page[i+14] & 255, page[i+15] & 255); - } + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, page, PAGESIZE, false); } } #endif @@ -417,25 +403,11 @@ static int __init init_axis_flash(void) #if 0 /* Dump partition table so we can see what is going on */ printk(KERN_INFO - "axisflashmap: flash read %d bytes at 0x%08x, data: " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - len, CONFIG_ETRAX_PTABLE_SECTOR, - page[0] & 255, page[1] & 255, - page[2] & 255, page[3] & 255, - page[4] & 255, page[5] & 255, - page[6] & 255, page[7] & 255); + "axisflashmap: flash read %d bytes at 0x%08x, data: %8ph\n", + len, CONFIG_ETRAX_PTABLE_SECTOR, page); printk(KERN_INFO - "axisflashmap: partition table offset %d, data: " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - PARTITION_TABLE_OFFSET, - page[PARTITION_TABLE_OFFSET+0] & 255, - page[PARTITION_TABLE_OFFSET+1] & 255, - page[PARTITION_TABLE_OFFSET+2] & 255, - page[PARTITION_TABLE_OFFSET+3] & 255, - page[PARTITION_TABLE_OFFSET+4] & 255, - page[PARTITION_TABLE_OFFSET+5] & 255, - page[PARTITION_TABLE_OFFSET+6] & 255, - page[PARTITION_TABLE_OFFSET+7] & 255); + "axisflashmap: partition table offset %d, data: %8ph\n", + PARTITION_TABLE_OFFSET, page + PARTITION_TABLE_OFFSET); #endif } diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c deleted file mode 100644 index 3b2c82ce8147..000000000000 --- a/arch/cris/arch-v32/drivers/i2c.c +++ /dev/null @@ -1,751 +0,0 @@ -/*!*************************************************************************** -*! -*! FILE NAME : i2c.c -*! -*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other -*! kernel modules (i2c_writereg/readreg) and from userspace using -*! ioctl()'s -*! -*! Nov 30 1998 Torbjorn Eliasson Initial version. -*! Bjorn Wesen Elinux kernel version. -*! Jan 14 2000 Johan Adolfsson Fixed PB shadow register stuff - -*! don't use PB_I2C if DS1302 uses same bits, -*! use PB. -*| June 23 2003 Pieter Grimmerink Added 'i2c_sendnack'. i2c_readreg now -*| generates nack on last received byte, -*| instead of ack. -*| i2c_getack changed data level while clock -*| was high, causing DS75 to see a stop condition -*! -*! --------------------------------------------------------------------------- -*! -*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN -*! -*!***************************************************************************/ - -/****************** INCLUDE FILES SECTION ***********************************/ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/mutex.h> - -#include <asm/etraxi2c.h> - -#include <asm/io.h> -#include <asm/delay.h> - -#include "i2c.h" - -/****************** I2C DEFINITION SECTION *************************/ - -#define D(x) - -#define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */ -static DEFINE_MUTEX(i2c_mutex); -static const char i2c_name[] = "i2c"; - -#define CLOCK_LOW_TIME 8 -#define CLOCK_HIGH_TIME 8 -#define START_CONDITION_HOLD_TIME 8 -#define STOP_CONDITION_HOLD_TIME 8 -#define ENABLE_OUTPUT 0x01 -#define ENABLE_INPUT 0x00 -#define I2C_CLOCK_HIGH 1 -#define I2C_CLOCK_LOW 0 -#define I2C_DATA_HIGH 1 -#define I2C_DATA_LOW 0 - -#define i2c_enable() -#define i2c_disable() - -/* enable or disable output-enable, to select output or input on the i2c bus */ - -#define i2c_dir_out() crisv32_io_set_dir(&cris_i2c_data, crisv32_io_dir_out) -#define i2c_dir_in() crisv32_io_set_dir(&cris_i2c_data, crisv32_io_dir_in) - -/* control the i2c clock and data signals */ - -#define i2c_clk(x) crisv32_io_set(&cris_i2c_clk, x) -#define i2c_data(x) crisv32_io_set(&cris_i2c_data, x) - -/* read a bit from the i2c interface */ - -#define i2c_getbit() crisv32_io_rd(&cris_i2c_data) - -#define i2c_delay(usecs) udelay(usecs) - -static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ - -/****************** VARIABLE SECTION ************************************/ - -static struct crisv32_iopin cris_i2c_clk; -static struct crisv32_iopin cris_i2c_data; - -/****************** FUNCTION DEFINITION SECTION *************************/ - - -/* generate i2c start condition */ - -void -i2c_start(void) -{ - /* - * SCL=1 SDA=1 - */ - i2c_dir_out(); - i2c_delay(CLOCK_HIGH_TIME/6); - i2c_data(I2C_DATA_HIGH); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); - /* - * SCL=1 SDA=0 - */ - i2c_data(I2C_DATA_LOW); - i2c_delay(START_CONDITION_HOLD_TIME); - /* - * SCL=0 SDA=0 - */ - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); -} - -/* generate i2c stop condition */ - -void -i2c_stop(void) -{ - i2c_dir_out(); - - /* - * SCL=0 SDA=0 - */ - i2c_clk(I2C_CLOCK_LOW); - i2c_data(I2C_DATA_LOW); - i2c_delay(CLOCK_LOW_TIME*2); - /* - * SCL=1 SDA=0 - */ - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME*2); - /* - * SCL=1 SDA=1 - */ - i2c_data(I2C_DATA_HIGH); - i2c_delay(STOP_CONDITION_HOLD_TIME); - - i2c_dir_in(); -} - -/* write a byte to the i2c interface */ - -void -i2c_outbyte(unsigned char x) -{ - int i; - - i2c_dir_out(); - - for (i = 0; i < 8; i++) { - if (x & 0x80) { - i2c_data(I2C_DATA_HIGH); - } else { - i2c_data(I2C_DATA_LOW); - } - - i2c_delay(CLOCK_LOW_TIME/2); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME/2); - x <<= 1; - } - i2c_data(I2C_DATA_LOW); - i2c_delay(CLOCK_LOW_TIME/2); - - /* - * enable input - */ - i2c_dir_in(); -} - -/* read a byte from the i2c interface */ - -unsigned char -i2c_inbyte(void) -{ - unsigned char aBitByte = 0; - int i; - - /* Switch off I2C to get bit */ - i2c_disable(); - i2c_dir_in(); - i2c_delay(CLOCK_HIGH_TIME/2); - - /* Get bit */ - aBitByte |= i2c_getbit(); - - /* Enable I2C */ - i2c_enable(); - i2c_delay(CLOCK_LOW_TIME/2); - - for (i = 1; i < 8; i++) { - aBitByte <<= 1; - /* Clock pulse */ - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - - /* Switch off I2C to get bit */ - i2c_disable(); - i2c_dir_in(); - i2c_delay(CLOCK_HIGH_TIME/2); - - /* Get bit */ - aBitByte |= i2c_getbit(); - - /* Enable I2C */ - i2c_enable(); - i2c_delay(CLOCK_LOW_TIME/2); - } - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); - - /* - * we leave the clock low, getbyte is usually followed - * by sendack/nack, they assume the clock to be low - */ - i2c_clk(I2C_CLOCK_LOW); - return aBitByte; -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: i2c_getack -*# -*# DESCRIPTION : checks if ack was received from ic2 -*# -*#--------------------------------------------------------------------------*/ - -int -i2c_getack(void) -{ - int ack = 1; - /* - * enable output - */ - i2c_dir_out(); - /* - * Release data bus by setting - * data high - */ - i2c_data(I2C_DATA_HIGH); - /* - * enable input - */ - i2c_dir_in(); - i2c_delay(CLOCK_HIGH_TIME/4); - /* - * generate ACK clock pulse - */ - i2c_clk(I2C_CLOCK_HIGH); -#if 0 - /* - * Use PORT PB instead of I2C - * for input. (I2C not working) - */ - i2c_clk(1); - i2c_data(1); - /* - * switch off I2C - */ - i2c_data(1); - i2c_disable(); - i2c_dir_in(); -#endif - - /* - * now wait for ack - */ - i2c_delay(CLOCK_HIGH_TIME/2); - /* - * check for ack - */ - if (i2c_getbit()) - ack = 0; - i2c_delay(CLOCK_HIGH_TIME/2); - if (!ack) { - if (!i2c_getbit()) /* receiver pulld SDA low */ - ack = 1; - i2c_delay(CLOCK_HIGH_TIME/2); - } - - /* - * our clock is high now, make sure data is low - * before we enable our output. If we keep data high - * and enable output, we would generate a stop condition. - */ -#if 0 - i2c_data(I2C_DATA_LOW); - - /* - * end clock pulse - */ - i2c_enable(); - i2c_dir_out(); -#endif - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_HIGH_TIME/4); - /* - * enable output - */ - i2c_dir_out(); - /* - * remove ACK clock pulse - */ - i2c_data(I2C_DATA_HIGH); - i2c_delay(CLOCK_LOW_TIME/2); - return ack; -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: I2C::sendAck -*# -*# DESCRIPTION : Send ACK on received data -*# -*#--------------------------------------------------------------------------*/ -void -i2c_sendack(void) -{ - /* - * enable output - */ - i2c_delay(CLOCK_LOW_TIME); - i2c_dir_out(); - /* - * set ack pulse high - */ - i2c_data(I2C_DATA_LOW); - /* - * generate clock pulse - */ - i2c_delay(CLOCK_HIGH_TIME/6); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME/6); - /* - * reset data out - */ - i2c_data(I2C_DATA_HIGH); - i2c_delay(CLOCK_LOW_TIME); - - i2c_dir_in(); -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: i2c_sendnack -*# -*# DESCRIPTION : Sends NACK on received data -*# -*#--------------------------------------------------------------------------*/ -void -i2c_sendnack(void) -{ - /* - * enable output - */ - i2c_delay(CLOCK_LOW_TIME); - i2c_dir_out(); - /* - * set data high - */ - i2c_data(I2C_DATA_HIGH); - /* - * generate clock pulse - */ - i2c_delay(CLOCK_HIGH_TIME/6); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - - i2c_dir_in(); -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: i2c_write -*# -*# DESCRIPTION : Writes a value to an I2C device -*# -*#--------------------------------------------------------------------------*/ -int -i2c_write(unsigned char theSlave, void *data, size_t nbytes) -{ - int error, cntr = 3; - unsigned char bytes_wrote = 0; - unsigned char value; - unsigned long flags; - - spin_lock_irqsave(&i2c_lock, flags); - - do { - error = 0; - - i2c_start(); - /* - * send slave address - */ - i2c_outbyte((theSlave & 0xfe)); - /* - * wait for ack - */ - if (!i2c_getack()) - error = 1; - /* - * send data - */ - for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) { - memcpy(&value, data + bytes_wrote, sizeof value); - i2c_outbyte(value); - /* - * now it's time to wait for ack - */ - if (!i2c_getack()) - error |= 4; - } - /* - * end byte stream - */ - i2c_stop(); - - } while (error && cntr--); - - i2c_delay(CLOCK_LOW_TIME); - - spin_unlock_irqrestore(&i2c_lock, flags); - - return -error; -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: i2c_read -*# -*# DESCRIPTION : Reads a value from an I2C device -*# -*#--------------------------------------------------------------------------*/ -int -i2c_read(unsigned char theSlave, void *data, size_t nbytes) -{ - unsigned char b = 0; - unsigned char bytes_read = 0; - int error, cntr = 3; - unsigned long flags; - - spin_lock_irqsave(&i2c_lock, flags); - - do { - error = 0; - memset(data, 0, nbytes); - /* - * generate start condition - */ - i2c_start(); - /* - * send slave address - */ - i2c_outbyte((theSlave | 0x01)); - /* - * wait for ack - */ - if (!i2c_getack()) - error = 1; - /* - * fetch data - */ - for (bytes_read = 0; bytes_read < nbytes; bytes_read++) { - b = i2c_inbyte(); - memcpy(data + bytes_read, &b, sizeof b); - - if (bytes_read < (nbytes - 1)) - i2c_sendack(); - } - /* - * last received byte needs to be nacked - * instead of acked - */ - i2c_sendnack(); - /* - * end sequence - */ - i2c_stop(); - } while (error && cntr--); - - spin_unlock_irqrestore(&i2c_lock, flags); - - return -error; -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: i2c_writereg -*# -*# DESCRIPTION : Writes a value to an I2C device -*# -*#--------------------------------------------------------------------------*/ -int -i2c_writereg(unsigned char theSlave, unsigned char theReg, - unsigned char theValue) -{ - int error, cntr = 3; - unsigned long flags; - - spin_lock_irqsave(&i2c_lock, flags); - - do { - error = 0; - - i2c_start(); - /* - * send slave address - */ - i2c_outbyte((theSlave & 0xfe)); - /* - * wait for ack - */ - if(!i2c_getack()) - error = 1; - /* - * now select register - */ - i2c_dir_out(); - i2c_outbyte(theReg); - /* - * now it's time to wait for ack - */ - if(!i2c_getack()) - error |= 2; - /* - * send register register data - */ - i2c_outbyte(theValue); - /* - * now it's time to wait for ack - */ - if(!i2c_getack()) - error |= 4; - /* - * end byte stream - */ - i2c_stop(); - } while(error && cntr--); - - i2c_delay(CLOCK_LOW_TIME); - - spin_unlock_irqrestore(&i2c_lock, flags); - - return -error; -} - -/*#--------------------------------------------------------------------------- -*# -*# FUNCTION NAME: i2c_readreg -*# -*# DESCRIPTION : Reads a value from the decoder registers. -*# -*#--------------------------------------------------------------------------*/ -unsigned char -i2c_readreg(unsigned char theSlave, unsigned char theReg) -{ - unsigned char b = 0; - int error, cntr = 3; - unsigned long flags; - - spin_lock_irqsave(&i2c_lock, flags); - - do { - error = 0; - /* - * generate start condition - */ - i2c_start(); - - /* - * send slave address - */ - i2c_outbyte((theSlave & 0xfe)); - /* - * wait for ack - */ - if(!i2c_getack()) - error = 1; - /* - * now select register - */ - i2c_dir_out(); - i2c_outbyte(theReg); - /* - * now it's time to wait for ack - */ - if(!i2c_getack()) - error |= 2; - /* - * repeat start condition - */ - i2c_delay(CLOCK_LOW_TIME); - i2c_start(); - /* - * send slave address - */ - i2c_outbyte(theSlave | 0x01); - /* - * wait for ack - */ - if(!i2c_getack()) - error |= 4; - /* - * fetch register - */ - b = i2c_inbyte(); - /* - * last received byte needs to be nacked - * instead of acked - */ - i2c_sendnack(); - /* - * end sequence - */ - i2c_stop(); - - } while(error && cntr--); - - spin_unlock_irqrestore(&i2c_lock, flags); - - return b; -} - -static int -i2c_open(struct inode *inode, struct file *filp) -{ - return 0; -} - -static int -i2c_release(struct inode *inode, struct file *filp) -{ - return 0; -} - -/* Main device API. ioctl's to write or read to/from i2c registers. - */ - -static long -i2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { - return -ENOTTY; - } - - switch (_IOC_NR(cmd)) { - case I2C_WRITEREG: - /* write to an i2c slave */ - D(printk("i2cw %d %d %d\n", - I2C_ARGSLAVE(arg), - I2C_ARGREG(arg), - I2C_ARGVALUE(arg))); - - mutex_lock(&i2c_mutex); - ret = i2c_writereg(I2C_ARGSLAVE(arg), - I2C_ARGREG(arg), - I2C_ARGVALUE(arg)); - mutex_unlock(&i2c_mutex); - return ret; - - case I2C_READREG: - { - unsigned char val; - /* read from an i2c slave */ - D(printk("i2cr %d %d ", - I2C_ARGSLAVE(arg), - I2C_ARGREG(arg))); - mutex_lock(&i2c_mutex); - val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg)); - mutex_unlock(&i2c_mutex); - D(printk("= %d\n", val)); - return val; - } - default: - return -EINVAL; - - } - - return 0; -} - -static const struct file_operations i2c_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = i2c_ioctl, - .open = i2c_open, - .release = i2c_release, - .llseek = noop_llseek, -}; - -static int __init i2c_init(void) -{ - static int res; - static int first = 1; - - if (!first) - return res; - - first = 0; - - /* Setup and enable the DATA and CLK pins */ - - res = crisv32_io_get_name(&cris_i2c_data, - CONFIG_ETRAX_V32_I2C_DATA_PORT); - if (res < 0) - return res; - - res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT); - crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out); - - return res; -} - - -static int __init i2c_register(void) -{ - int res; - - res = i2c_init(); - if (res < 0) - return res; - - /* register char device */ - - res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); - if (res < 0) { - printk(KERN_ERR "i2c: couldn't get a major number.\n"); - return res; - } - - printk(KERN_INFO - "I2C driver v2.2, (c) 1999-2007 Axis Communications AB\n"); - - return 0; -} -/* this makes sure that i2c_init is called during boot */ -module_init(i2c_register); - -/****************** END OF FILE i2c.c ********************************/ diff --git a/arch/cris/arch-v32/drivers/i2c.h b/arch/cris/arch-v32/drivers/i2c.h deleted file mode 100644 index d9cc856f89fb..000000000000 --- a/arch/cris/arch-v32/drivers/i2c.h +++ /dev/null @@ -1,16 +0,0 @@ - -#include <linux/init.h> - -/* High level I2C actions */ -int i2c_write(unsigned char theSlave, void *data, size_t nbytes); -int i2c_read(unsigned char theSlave, void *data, size_t nbytes); -int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); -unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); - -/* Low level I2C */ -void i2c_start(void); -void i2c_stop(void); -void i2c_outbyte(unsigned char x); -unsigned char i2c_inbyte(void); -int i2c_getack(void); -void i2c_sendack(void); diff --git a/arch/cris/arch-v32/drivers/mach-a3/Makefile b/arch/cris/arch-v32/drivers/mach-a3/Makefile index 5c6d2a2a080e..59028d0b981c 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/Makefile +++ b/arch/cris/arch-v32/drivers/mach-a3/Makefile @@ -3,4 +3,3 @@ # obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o -obj-$(CONFIG_ETRAX_GPIO) += gpio.o diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c deleted file mode 100644 index c92e1da3684d..000000000000 --- a/arch/cris/arch-v32/drivers/mach-a3/gpio.c +++ /dev/null @@ -1,999 +0,0 @@ -/* - * Artec-3 general port I/O device - * - * Copyright (c) 2007 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Ola Knutsson (LED handling) - * Johan Adolfsson (read/set directions, write, port G, - * port to ETRAX FS. - * Ricard Wanderlof (PWM for Artpec-3) - * - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> - -#include <asm/etraxgpio.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/gio_defs.h> -#include <hwregs/intr_vect_defs.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <mach/pinmux.h> - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -#include "../i2c.h" - -#define VIRT_I2C_ADDR 0x40 -#endif - -/* The following gio ports on ARTPEC-3 is available: - * pa 32 bits - * pb 32 bits - * pc 16 bits - * each port has a rw_px_dout, r_px_din and rw_px_oe register. - */ - -#define GPIO_MAJOR 120 /* experimental MAJOR number */ - -#define I2C_INTERRUPT_BITS 0x300 /* i2c0_done and i2c1_done bits */ - -#define D(x) - -#if 0 -static int dp_cnt; -#define DP(x) \ - do { \ - dp_cnt++; \ - if (dp_cnt % 1000 == 0) \ - x; \ - } while (0) -#else -#define DP(x) -#endif - -static DEFINE_MUTEX(gpio_mutex); -static char gpio_name[] = "etrax gpio"; - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -#endif -static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static ssize_t gpio_write(struct file *file, const char __user *buf, - size_t count, loff_t *off); -static int gpio_open(struct inode *inode, struct file *filp); -static int gpio_release(struct inode *inode, struct file *filp); -static unsigned int gpio_poll(struct file *filp, - struct poll_table_struct *wait); - -/* private data per open() of this driver */ - -struct gpio_private { - struct gpio_private *next; - /* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */ - unsigned char clk_mask; - unsigned char data_mask; - unsigned char write_msb; - unsigned char pad1; - /* These fields are generic */ - unsigned long highalarm, lowalarm; - wait_queue_head_t alarm_wq; - int minor; -}; - -static void gpio_set_alarm(struct gpio_private *priv); -static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg); -static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, - unsigned long arg); - - -/* linked list of alarms to check for */ - -static struct gpio_private *alarmlist; - -static int wanted_interrupts; - -static DEFINE_SPINLOCK(gpio_lock); - -#define NUM_PORTS (GPIO_MINOR_LAST+1) -#define GIO_REG_RD_ADDR(reg) \ - (unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) -#define GIO_REG_WR_ADDR(reg) \ - (unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg) -static unsigned long led_dummy; -static unsigned long port_d_dummy; /* Only input on Artpec-3 */ -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static unsigned long port_e_dummy; /* Non existent on Artpec-3 */ -static unsigned long virtual_dummy; -static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; -static unsigned short cached_virtual_gpio_read; -#endif - -static unsigned long *data_out[NUM_PORTS] = { - GIO_REG_WR_ADDR(rw_pa_dout), - GIO_REG_WR_ADDR(rw_pb_dout), - &led_dummy, - GIO_REG_WR_ADDR(rw_pc_dout), - &port_d_dummy, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - &port_e_dummy, - &virtual_dummy, -#endif -}; - -static unsigned long *data_in[NUM_PORTS] = { - GIO_REG_RD_ADDR(r_pa_din), - GIO_REG_RD_ADDR(r_pb_din), - &led_dummy, - GIO_REG_RD_ADDR(r_pc_din), - GIO_REG_RD_ADDR(r_pd_din), -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - &port_e_dummy, - &virtual_dummy, -#endif -}; - -static unsigned long changeable_dir[NUM_PORTS] = { - CONFIG_ETRAX_PA_CHANGEABLE_DIR, - CONFIG_ETRAX_PB_CHANGEABLE_DIR, - 0, - CONFIG_ETRAX_PC_CHANGEABLE_DIR, - 0, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - 0, - CONFIG_ETRAX_PV_CHANGEABLE_DIR, -#endif -}; - -static unsigned long changeable_bits[NUM_PORTS] = { - CONFIG_ETRAX_PA_CHANGEABLE_BITS, - CONFIG_ETRAX_PB_CHANGEABLE_BITS, - 0, - CONFIG_ETRAX_PC_CHANGEABLE_BITS, - 0, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - 0, - CONFIG_ETRAX_PV_CHANGEABLE_BITS, -#endif -}; - -static unsigned long *dir_oe[NUM_PORTS] = { - GIO_REG_WR_ADDR(rw_pa_oe), - GIO_REG_WR_ADDR(rw_pb_oe), - &led_dummy, - GIO_REG_WR_ADDR(rw_pc_oe), - &port_d_dummy, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - &port_e_dummy, - &virtual_rw_pv_oe, -#endif -}; - -static void gpio_set_alarm(struct gpio_private *priv) -{ - int bit; - int intr_cfg; - int mask; - int pins; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg); - pins = REG_RD_INT(gio, regi_gio, rw_intr_pins); - mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS; - - for (bit = 0; bit < 32; bit++) { - int intr = bit % 8; - int pin = bit / 8; - if (priv->minor < GPIO_MINOR_LEDS) - pin += priv->minor * 4; - else - pin += (priv->minor - 1) * 4; - - if (priv->highalarm & (1<<bit)) { - intr_cfg |= (regk_gio_hi << (intr * 3)); - mask |= 1 << intr; - wanted_interrupts = mask & 0xff; - pins |= pin << (intr * 4); - } else if (priv->lowalarm & (1<<bit)) { - intr_cfg |= (regk_gio_lo << (intr * 3)); - mask |= 1 << intr; - wanted_interrupts = mask & 0xff; - pins |= pin << (intr * 4); - } - } - - REG_WR_INT(gio, regi_gio, rw_intr_cfg, intr_cfg); - REG_WR_INT(gio, regi_gio, rw_intr_pins, pins); - REG_WR_INT(gio, regi_gio, rw_intr_mask, mask); - - spin_unlock_irqrestore(&gpio_lock, flags); -} - -static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait) -{ - unsigned int mask = 0; - struct gpio_private *priv = file->private_data; - unsigned long data; - unsigned long tmp; - - if (priv->minor >= GPIO_MINOR_PWM0 && - priv->minor <= GPIO_MINOR_LAST_PWM) - return 0; - - poll_wait(file, &priv->alarm_wq, wait); - if (priv->minor <= GPIO_MINOR_D) { - data = readl(data_in[priv->minor]); - REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts); - tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask); - tmp &= I2C_INTERRUPT_BITS; - tmp |= wanted_interrupts; - REG_WR_INT(gio, regi_gio, rw_intr_mask, tmp); - } else - return 0; - - if ((data & priv->highalarm) || (~data & priv->lowalarm)) - mask = POLLIN|POLLRDNORM; - - DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask)); - return mask; -} - -static irqreturn_t gpio_interrupt(int irq, void *dev_id) -{ - reg_gio_rw_intr_mask intr_mask; - reg_gio_r_masked_intr masked_intr; - reg_gio_rw_ack_intr ack_intr; - unsigned long flags; - unsigned long tmp; - unsigned long tmp2; -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - unsigned char enable_gpiov_ack = 0; -#endif - - /* Find what PA interrupts are active */ - masked_intr = REG_RD(gio, regi_gio, r_masked_intr); - tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr); - - /* Find those that we have enabled */ - spin_lock_irqsave(&gpio_lock, flags); - tmp &= wanted_interrupts; - spin_unlock_irqrestore(&gpio_lock, flags); - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - /* Something changed on virtual GPIO. Interrupt is acked by - * reading the device. - */ - if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) { - i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read, - sizeof(cached_virtual_gpio_read)); - enable_gpiov_ack = 1; - } -#endif - - /* Ack them */ - ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp); - REG_WR(gio, regi_gio, rw_ack_intr, ack_intr); - - /* Disable those interrupts.. */ - intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); - tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask); - tmp2 &= ~tmp; -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - /* Do not disable interrupt on virtual GPIO. Changes on virtual - * pins are only noticed by an interrupt. - */ - if (enable_gpiov_ack) - tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); -#endif - intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2); - REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); - - return IRQ_RETVAL(tmp); -} - -static void gpio_write_bit(unsigned long *port, unsigned char data, int bit, - unsigned char clk_mask, unsigned char data_mask) -{ - unsigned long shadow = readl(port) & ~clk_mask; - writel(shadow, port); - if (data & 1 << bit) - shadow |= data_mask; - else - shadow &= ~data_mask; - writel(shadow, port); - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - shadow |= clk_mask; - writel(shadow, port); -} - -static void gpio_write_byte(struct gpio_private *priv, unsigned long *port, - unsigned char data) -{ - int i; - - if (priv->write_msb) - for (i = 7; i >= 0; i--) - gpio_write_bit(port, data, i, priv->clk_mask, - priv->data_mask); - else - for (i = 0; i <= 7; i++) - gpio_write_bit(port, data, i, priv->clk_mask, - priv->data_mask); -} - - -static ssize_t gpio_write(struct file *file, const char __user *buf, - size_t count, loff_t *off) -{ - struct gpio_private *priv = file->private_data; - unsigned long flags; - ssize_t retval = count; - /* Only bits 0-7 may be used for write operations but allow all - devices except leds... */ -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - if (priv->minor == GPIO_MINOR_V) - return -EFAULT; -#endif - if (priv->minor == GPIO_MINOR_LEDS) - return -EFAULT; - - if (priv->minor >= GPIO_MINOR_PWM0 && - priv->minor <= GPIO_MINOR_LAST_PWM) - return -EFAULT; - - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - - /* It must have been configured using the IO_CFG_WRITE_MODE */ - /* Perhaps a better error code? */ - if (priv->clk_mask == 0 || priv->data_mask == 0) - return -EPERM; - - D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " - "msb: %i\n", - count, priv->data_mask, priv->clk_mask, priv->write_msb)); - - spin_lock_irqsave(&gpio_lock, flags); - - while (count--) - gpio_write_byte(priv, data_out[priv->minor], *buf++); - - spin_unlock_irqrestore(&gpio_lock, flags); - return retval; -} - -static int gpio_open(struct inode *inode, struct file *filp) -{ - struct gpio_private *priv; - int p = iminor(inode); - - if (p > GPIO_MINOR_LAST_PWM || - (p > GPIO_MINOR_LAST && p < GPIO_MINOR_PWM0)) - return -EINVAL; - - priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL); - - if (!priv) - return -ENOMEM; - - mutex_lock(&gpio_mutex); - memset(priv, 0, sizeof(*priv)); - - priv->minor = p; - filp->private_data = priv; - - /* initialize the io/alarm struct, not for PWM ports though */ - if (p <= GPIO_MINOR_LAST) { - - priv->clk_mask = 0; - priv->data_mask = 0; - priv->highalarm = 0; - priv->lowalarm = 0; - - init_waitqueue_head(&priv->alarm_wq); - - /* link it into our alarmlist */ - spin_lock_irq(&gpio_lock); - priv->next = alarmlist; - alarmlist = priv; - spin_unlock_irq(&gpio_lock); - } - - mutex_unlock(&gpio_mutex); - return 0; -} - -static int gpio_release(struct inode *inode, struct file *filp) -{ - struct gpio_private *p; - struct gpio_private *todel; - /* local copies while updating them: */ - unsigned long a_high, a_low; - - /* prepare to free private structure */ - todel = filp->private_data; - - /* unlink from alarmlist - only for non-PWM ports though */ - if (todel->minor <= GPIO_MINOR_LAST) { - spin_lock_irq(&gpio_lock); - p = alarmlist; - - if (p == todel) - alarmlist = todel->next; - else { - while (p->next != todel) - p = p->next; - p->next = todel->next; - } - - /* Check if there are still any alarms set */ - p = alarmlist; - a_high = 0; - a_low = 0; - while (p) { - if (p->minor == GPIO_MINOR_A) { -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); -#endif - a_high |= p->highalarm; - a_low |= p->lowalarm; - } - - p = p->next; - } - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - /* Variable 'a_low' needs to be set here again - * to ensure that interrupt for virtual GPIO is handled. - */ - a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); -#endif - - spin_unlock_irq(&gpio_lock); - } - kfree(todel); - - return 0; -} - -/* Main device API. ioctl's to read/set/clear bits, as well as to - * set alarms to wait for using a subsequent select(). - */ - -inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) -{ - /* Set direction 0=unchanged 1=input, - * return mask with 1=input - */ - unsigned long flags; - unsigned long dir_shadow; - - spin_lock_irqsave(&gpio_lock, flags); - - dir_shadow = readl(dir_oe[priv->minor]) & - ~(arg & changeable_dir[priv->minor]); - writel(dir_shadow, dir_oe[priv->minor]); - - spin_unlock_irqrestore(&gpio_lock, flags); - - if (priv->minor == GPIO_MINOR_C) - dir_shadow ^= 0xFFFF; /* Only 16 bits */ -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - else if (priv->minor == GPIO_MINOR_V) - dir_shadow ^= 0xFFFF; /* Only 16 bits */ -#endif - else - dir_shadow ^= 0xFFFFFFFF; /* PA, PB and PD 32 bits */ - - return dir_shadow; - -} /* setget_input */ - -static inline unsigned long setget_output(struct gpio_private *priv, - unsigned long arg) -{ - unsigned long flags; - unsigned long dir_shadow; - - spin_lock_irqsave(&gpio_lock, flags); - - dir_shadow = readl(dir_oe[priv->minor]) | - (arg & changeable_dir[priv->minor]); - writel(dir_shadow, dir_oe[priv->minor]); - - spin_unlock_irqrestore(&gpio_lock, flags); - return dir_shadow; -} /* setget_output */ - -static long gpio_ioctl_unlocked(struct file *file, - unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - unsigned long val; - unsigned long shadow; - struct gpio_private *priv = file->private_data; - - if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) - return -ENOTTY; - - /* Check for special ioctl handlers first */ - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - if (priv->minor == GPIO_MINOR_V) - return virtual_gpio_ioctl(file, cmd, arg); -#endif - - if (priv->minor == GPIO_MINOR_LEDS) - return gpio_leds_ioctl(cmd, arg); - - if (priv->minor >= GPIO_MINOR_PWM0 && - priv->minor <= GPIO_MINOR_LAST_PWM) - return gpio_pwm_ioctl(priv, cmd, arg); - - switch (_IOC_NR(cmd)) { - case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ - /* Read the port. */ - return readl(data_in[priv->minor]); - case IO_SETBITS: - spin_lock_irqsave(&gpio_lock, flags); - /* Set changeable bits with a 1 in arg. */ - shadow = readl(data_out[priv->minor]) | - (arg & changeable_bits[priv->minor]); - writel(shadow, data_out[priv->minor]); - spin_unlock_irqrestore(&gpio_lock, flags); - break; - case IO_CLRBITS: - spin_lock_irqsave(&gpio_lock, flags); - /* Clear changeable bits with a 1 in arg. */ - shadow = readl(data_out[priv->minor]) & - ~(arg & changeable_bits[priv->minor]); - writel(shadow, data_out[priv->minor]); - spin_unlock_irqrestore(&gpio_lock, flags); - break; - case IO_HIGHALARM: - /* Set alarm when bits with 1 in arg go high. */ - priv->highalarm |= arg; - gpio_set_alarm(priv); - break; - case IO_LOWALARM: - /* Set alarm when bits with 1 in arg go low. */ - priv->lowalarm |= arg; - gpio_set_alarm(priv); - break; - case IO_CLRALARM: - /* Clear alarm for bits with 1 in arg. */ - priv->highalarm &= ~arg; - priv->lowalarm &= ~arg; - gpio_set_alarm(priv); - break; - case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ - /* Read direction 0=input 1=output */ - return readl(dir_oe[priv->minor]); - - case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ - /* Set direction 0=unchanged 1=input, - * return mask with 1=input - */ - return setget_input(priv, arg); - - case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ - /* Set direction 0=unchanged 1=output, - * return mask with 1=output - */ - return setget_output(priv, arg); - - case IO_CFG_WRITE_MODE: - { - int res = -EPERM; - unsigned long dir_shadow, clk_mask, data_mask, write_msb; - - clk_mask = arg & 0xFF; - data_mask = (arg >> 8) & 0xFF; - write_msb = (arg >> 16) & 0x01; - - /* Check if we're allowed to change the bits and - * the direction is correct - */ - spin_lock_irqsave(&gpio_lock, flags); - dir_shadow = readl(dir_oe[priv->minor]); - if ((clk_mask & changeable_bits[priv->minor]) && - (data_mask & changeable_bits[priv->minor]) && - (clk_mask & dir_shadow) && - (data_mask & dir_shadow)) { - priv->clk_mask = clk_mask; - priv->data_mask = data_mask; - priv->write_msb = write_msb; - res = 0; - } - spin_unlock_irqrestore(&gpio_lock, flags); - - return res; - } - case IO_READ_INBITS: - /* *arg is result of reading the input pins */ - val = readl(data_in[priv->minor]); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - return 0; - case IO_READ_OUTBITS: - /* *arg is result of reading the output shadow */ - val = *data_out[priv->minor]; - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - break; - case IO_SETGET_INPUT: - /* bits set in *arg is set to input, - * *arg updated with current input pins. - */ - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) - return -EFAULT; - val = setget_input(priv, val); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - break; - case IO_SETGET_OUTPUT: - /* bits set in *arg is set to output, - * *arg updated with current output pins. - */ - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) - return -EFAULT; - val = setget_output(priv, val); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - break; - default: - return -EINVAL; - } /* switch */ - - return 0; -} - -static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&gpio_mutex); - ret = gpio_ioctl_unlocked(file, cmd, arg); - mutex_unlock(&gpio_mutex); - - return ret; -} - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - unsigned long flags; - unsigned short val; - unsigned short shadow; - struct gpio_private *priv = file->private_data; - - switch (_IOC_NR(cmd)) { - case IO_SETBITS: - spin_lock_irqsave(&gpio_lock, flags); - /* Set changeable bits with a 1 in arg. */ - i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - shadow |= ~readl(dir_oe[priv->minor]) | - (arg & changeable_bits[priv->minor]); - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - spin_unlock_irqrestore(&gpio_lock, flags); - break; - case IO_CLRBITS: - spin_lock_irqsave(&gpio_lock, flags); - /* Clear changeable bits with a 1 in arg. */ - i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - shadow |= ~readl(dir_oe[priv->minor]) & - ~(arg & changeable_bits[priv->minor]); - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - spin_unlock_irqrestore(&gpio_lock, flags); - break; - case IO_HIGHALARM: - /* Set alarm when bits with 1 in arg go high. */ - priv->highalarm |= arg; - break; - case IO_LOWALARM: - /* Set alarm when bits with 1 in arg go low. */ - priv->lowalarm |= arg; - break; - case IO_CLRALARM: - /* Clear alarm for bits with 1 in arg. */ - priv->highalarm &= ~arg; - priv->lowalarm &= ~arg; - break; - case IO_CFG_WRITE_MODE: - { - unsigned long dir_shadow; - dir_shadow = readl(dir_oe[priv->minor]); - - priv->clk_mask = arg & 0xFF; - priv->data_mask = (arg >> 8) & 0xFF; - priv->write_msb = (arg >> 16) & 0x01; - /* Check if we're allowed to change the bits and - * the direction is correct - */ - if (!((priv->clk_mask & changeable_bits[priv->minor]) && - (priv->data_mask & changeable_bits[priv->minor]) && - (priv->clk_mask & dir_shadow) && - (priv->data_mask & dir_shadow))) { - priv->clk_mask = 0; - priv->data_mask = 0; - return -EPERM; - } - break; - } - case IO_READ_INBITS: - /* *arg is result of reading the input pins */ - val = cached_virtual_gpio_read & ~readl(dir_oe[priv->minor]); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - return 0; - - case IO_READ_OUTBITS: - /* *arg is result of reading the output shadow */ - i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); - val &= readl(dir_oe[priv->minor]); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - break; - case IO_SETGET_INPUT: - { - /* bits set in *arg is set to input, - * *arg updated with current input pins. - */ - unsigned short input_mask = ~readl(dir_oe[priv->minor]); - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) - return -EFAULT; - val = setget_input(priv, val); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - if ((input_mask & val) != input_mask) { - /* Input pins changed. All ports desired as input - * should be set to logic 1. - */ - unsigned short change = input_mask ^ val; - i2c_read(VIRT_I2C_ADDR, (void *)&shadow, - sizeof(shadow)); - shadow &= ~change; - shadow |= val; - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, - sizeof(shadow)); - } - break; - } - case IO_SETGET_OUTPUT: - /* bits set in *arg is set to output, - * *arg updated with current output pins. - */ - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) - return -EFAULT; - val = setget_output(priv, val); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) - return -EFAULT; - break; - default: - return -EINVAL; - } /* switch */ - return 0; -} -#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ - -static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg) -{ - unsigned char green; - unsigned char red; - - switch (_IOC_NR(cmd)) { - case IO_LEDACTIVE_SET: - green = ((unsigned char) arg) & 1; - red = (((unsigned char) arg) >> 1) & 1; - CRIS_LED_ACTIVE_SET_G(green); - CRIS_LED_ACTIVE_SET_R(red); - break; - - default: - return -EINVAL; - } /* switch */ - - return 0; -} - -static int gpio_pwm_set_mode(unsigned long arg, int pwm_port) -{ - int pinmux_pwm = pinmux_pwm0 + pwm_port; - int mode; - reg_gio_rw_pwm0_ctrl rw_pwm_ctrl = { - .ccd_val = 0, - .ccd_override = regk_gio_no, - .mode = regk_gio_no - }; - int allocstatus; - - if (get_user(mode, &((struct io_pwm_set_mode *) arg)->mode)) - return -EFAULT; - rw_pwm_ctrl.mode = mode; - if (mode != PWM_OFF) - allocstatus = crisv32_pinmux_alloc_fixed(pinmux_pwm); - else - allocstatus = crisv32_pinmux_dealloc_fixed(pinmux_pwm); - if (allocstatus) - return allocstatus; - REG_WRITE(reg_gio_rw_pwm0_ctrl, REG_ADDR(gio, regi_gio, rw_pwm0_ctrl) + - 12 * pwm_port, rw_pwm_ctrl); - return 0; -} - -static int gpio_pwm_set_period(unsigned long arg, int pwm_port) -{ - struct io_pwm_set_period periods; - reg_gio_rw_pwm0_var rw_pwm_widths; - - if (copy_from_user(&periods, (void __user *)arg, sizeof(periods))) - return -EFAULT; - if (periods.lo > 8191 || periods.hi > 8191) - return -EINVAL; - rw_pwm_widths.lo = periods.lo; - rw_pwm_widths.hi = periods.hi; - REG_WRITE(reg_gio_rw_pwm0_var, REG_ADDR(gio, regi_gio, rw_pwm0_var) + - 12 * pwm_port, rw_pwm_widths); - return 0; -} - -static int gpio_pwm_set_duty(unsigned long arg, int pwm_port) -{ - unsigned int duty; - reg_gio_rw_pwm0_data rw_pwm_duty; - - if (get_user(duty, &((struct io_pwm_set_duty *) arg)->duty)) - return -EFAULT; - if (duty > 255) - return -EINVAL; - rw_pwm_duty.data = duty; - REG_WRITE(reg_gio_rw_pwm0_data, REG_ADDR(gio, regi_gio, rw_pwm0_data) + - 12 * pwm_port, rw_pwm_duty); - return 0; -} - -static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, - unsigned long arg) -{ - int pwm_port = priv->minor - GPIO_MINOR_PWM0; - - switch (_IOC_NR(cmd)) { - case IO_PWM_SET_MODE: - return gpio_pwm_set_mode(arg, pwm_port); - case IO_PWM_SET_PERIOD: - return gpio_pwm_set_period(arg, pwm_port); - case IO_PWM_SET_DUTY: - return gpio_pwm_set_duty(arg, pwm_port); - default: - return -EINVAL; - } - return 0; -} - -static const struct file_operations gpio_fops = { - .owner = THIS_MODULE, - .poll = gpio_poll, - .unlocked_ioctl = gpio_ioctl, - .write = gpio_write, - .open = gpio_open, - .release = gpio_release, - .llseek = noop_llseek, -}; - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static void __init virtual_gpio_init(void) -{ - reg_gio_rw_intr_cfg intr_cfg; - reg_gio_rw_intr_mask intr_mask; - unsigned short shadow; - - shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */ - shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT; - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - - /* Set interrupt mask and on what state the interrupt shall trigger. - * For virtual gpio the interrupt shall trigger on logic '0'. - */ - intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); - intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); - - switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) { - case 0: - intr_cfg.pa0 = regk_gio_lo; - intr_mask.pa0 = regk_gio_yes; - break; - case 1: - intr_cfg.pa1 = regk_gio_lo; - intr_mask.pa1 = regk_gio_yes; - break; - case 2: - intr_cfg.pa2 = regk_gio_lo; - intr_mask.pa2 = regk_gio_yes; - break; - case 3: - intr_cfg.pa3 = regk_gio_lo; - intr_mask.pa3 = regk_gio_yes; - break; - case 4: - intr_cfg.pa4 = regk_gio_lo; - intr_mask.pa4 = regk_gio_yes; - break; - case 5: - intr_cfg.pa5 = regk_gio_lo; - intr_mask.pa5 = regk_gio_yes; - break; - case 6: - intr_cfg.pa6 = regk_gio_lo; - intr_mask.pa6 = regk_gio_yes; - break; - case 7: - intr_cfg.pa7 = regk_gio_lo; - intr_mask.pa7 = regk_gio_yes; - break; - } - - REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); - REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); -} -#endif - -/* main driver initialization routine, called from mem.c */ - -static int __init gpio_init(void) -{ - int res, res2; - - printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 " - "Axis Communications AB\n"); - - /* do the formalities */ - - res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); - if (res < 0) { - printk(KERN_ERR "gpio: couldn't get a major number.\n"); - return res; - } - - /* Clear all leds */ - CRIS_LED_NETWORK_GRP0_SET(0); - CRIS_LED_NETWORK_GRP1_SET(0); - CRIS_LED_ACTIVE_SET(0); - CRIS_LED_DISK_READ(0); - CRIS_LED_DISK_WRITE(0); - - res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, - IRQF_SHARED, "gpio", &alarmlist); - if (res2) { - printk(KERN_ERR "err: irq for gpio\n"); - return res2; - } - - /* No IRQs by default. */ - REG_WR_INT(gio, regi_gio, rw_intr_pins, 0); - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - virtual_gpio_init(); -#endif - - return res; -} - -/* this makes sure that gpio_init is called during kernel boot */ - -module_init(gpio_init); diff --git a/arch/cris/arch-v32/drivers/mach-fs/Makefile b/arch/cris/arch-v32/drivers/mach-fs/Makefile index 5c6d2a2a080e..59028d0b981c 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/Makefile +++ b/arch/cris/arch-v32/drivers/mach-fs/Makefile @@ -3,4 +3,3 @@ # obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o -obj-$(CONFIG_ETRAX_GPIO) += gpio.o diff --git a/arch/cris/arch-v32/drivers/mach-fs/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c deleted file mode 100644 index 72968fbf814b..000000000000 --- a/arch/cris/arch-v32/drivers/mach-fs/gpio.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * ETRAX CRISv32 general port I/O device - * - * Copyright (c) 1999-2006 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Ola Knutsson (LED handling) - * Johan Adolfsson (read/set directions, write, port G, - * port to ETRAX FS. - * - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> - -#include <asm/etraxgpio.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/gio_defs.h> -#include <hwregs/intr_vect_defs.h> -#include <asm/io.h> -#include <asm/irq.h> - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -#include "../i2c.h" - -#define VIRT_I2C_ADDR 0x40 -#endif - -/* The following gio ports on ETRAX FS is available: - * pa 8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge - * pb 18 bits - * pc 18 bits - * pd 18 bits - * pe 18 bits - * each port has a rw_px_dout, r_px_din and rw_px_oe register. - */ - -#define GPIO_MAJOR 120 /* experimental MAJOR number */ - -#define D(x) - -#if 0 -static int dp_cnt; -#define DP(x) \ - do { \ - dp_cnt++; \ - if (dp_cnt % 1000 == 0) \ - x; \ - } while (0) -#else -#define DP(x) -#endif - -static DEFINE_MUTEX(gpio_mutex); -static char gpio_name[] = "etrax gpio"; - -#if 0 -static wait_queue_head_t *gpio_wq; -#endif - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -#endif -static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static ssize_t gpio_write(struct file *file, const char *buf, size_t count, - loff_t *off); -static int gpio_open(struct inode *inode, struct file *filp); -static int gpio_release(struct inode *inode, struct file *filp); -static unsigned int gpio_poll(struct file *filp, - struct poll_table_struct *wait); - -/* private data per open() of this driver */ - -struct gpio_private { - struct gpio_private *next; - /* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */ - unsigned char clk_mask; - unsigned char data_mask; - unsigned char write_msb; - unsigned char pad1; - /* These fields are generic */ - unsigned long highalarm, lowalarm; - wait_queue_head_t alarm_wq; - int minor; -}; - -/* linked list of alarms to check for */ - -static struct gpio_private *alarmlist; - -static int gpio_some_alarms; /* Set if someone uses alarm */ -static unsigned long gpio_pa_high_alarms; -static unsigned long gpio_pa_low_alarms; - -static DEFINE_SPINLOCK(alarm_lock); - -#define NUM_PORTS (GPIO_MINOR_LAST+1) -#define GIO_REG_RD_ADDR(reg) \ - (volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) -#define GIO_REG_WR_ADDR(reg) \ - (volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) -unsigned long led_dummy; -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static unsigned long virtual_dummy; -static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; -static unsigned short cached_virtual_gpio_read; -#endif - -static volatile unsigned long *data_out[NUM_PORTS] = { - GIO_REG_WR_ADDR(rw_pa_dout), - GIO_REG_WR_ADDR(rw_pb_dout), - &led_dummy, - GIO_REG_WR_ADDR(rw_pc_dout), - GIO_REG_WR_ADDR(rw_pd_dout), - GIO_REG_WR_ADDR(rw_pe_dout), -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - &virtual_dummy, -#endif -}; - -static volatile unsigned long *data_in[NUM_PORTS] = { - GIO_REG_RD_ADDR(r_pa_din), - GIO_REG_RD_ADDR(r_pb_din), - &led_dummy, - GIO_REG_RD_ADDR(r_pc_din), - GIO_REG_RD_ADDR(r_pd_din), - GIO_REG_RD_ADDR(r_pe_din), -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - &virtual_dummy, -#endif -}; - -static unsigned long changeable_dir[NUM_PORTS] = { - CONFIG_ETRAX_PA_CHANGEABLE_DIR, - CONFIG_ETRAX_PB_CHANGEABLE_DIR, - 0, - CONFIG_ETRAX_PC_CHANGEABLE_DIR, - CONFIG_ETRAX_PD_CHANGEABLE_DIR, - CONFIG_ETRAX_PE_CHANGEABLE_DIR, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - CONFIG_ETRAX_PV_CHANGEABLE_DIR, -#endif -}; - -static unsigned long changeable_bits[NUM_PORTS] = { - CONFIG_ETRAX_PA_CHANGEABLE_BITS, - CONFIG_ETRAX_PB_CHANGEABLE_BITS, - 0, - CONFIG_ETRAX_PC_CHANGEABLE_BITS, - CONFIG_ETRAX_PD_CHANGEABLE_BITS, - CONFIG_ETRAX_PE_CHANGEABLE_BITS, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - CONFIG_ETRAX_PV_CHANGEABLE_BITS, -#endif -}; - -static volatile unsigned long *dir_oe[NUM_PORTS] = { - GIO_REG_WR_ADDR(rw_pa_oe), - GIO_REG_WR_ADDR(rw_pb_oe), - &led_dummy, - GIO_REG_WR_ADDR(rw_pc_oe), - GIO_REG_WR_ADDR(rw_pd_oe), - GIO_REG_WR_ADDR(rw_pe_oe), -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - &virtual_rw_pv_oe, -#endif -}; - - - -static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait) -{ - unsigned int mask = 0; - struct gpio_private *priv = file->private_data; - unsigned long data; - poll_wait(file, &priv->alarm_wq, wait); - if (priv->minor == GPIO_MINOR_A) { - reg_gio_rw_intr_cfg intr_cfg; - unsigned long tmp; - unsigned long flags; - - local_irq_save(flags); - data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, - REG_RD(gio, regi_gio, r_pa_din)); - /* PA has support for interrupt - * lets activate high for those low and with highalarm set - */ - intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); - - tmp = ~data & priv->highalarm & 0xFF; - if (tmp & (1 << 0)) - intr_cfg.pa0 = regk_gio_hi; - if (tmp & (1 << 1)) - intr_cfg.pa1 = regk_gio_hi; - if (tmp & (1 << 2)) - intr_cfg.pa2 = regk_gio_hi; - if (tmp & (1 << 3)) - intr_cfg.pa3 = regk_gio_hi; - if (tmp & (1 << 4)) - intr_cfg.pa4 = regk_gio_hi; - if (tmp & (1 << 5)) - intr_cfg.pa5 = regk_gio_hi; - if (tmp & (1 << 6)) - intr_cfg.pa6 = regk_gio_hi; - if (tmp & (1 << 7)) - intr_cfg.pa7 = regk_gio_hi; - /* - * lets activate low for those high and with lowalarm set - */ - tmp = data & priv->lowalarm & 0xFF; - if (tmp & (1 << 0)) - intr_cfg.pa0 = regk_gio_lo; - if (tmp & (1 << 1)) - intr_cfg.pa1 = regk_gio_lo; - if (tmp & (1 << 2)) - intr_cfg.pa2 = regk_gio_lo; - if (tmp & (1 << 3)) - intr_cfg.pa3 = regk_gio_lo; - if (tmp & (1 << 4)) - intr_cfg.pa4 = regk_gio_lo; - if (tmp & (1 << 5)) - intr_cfg.pa5 = regk_gio_lo; - if (tmp & (1 << 6)) - intr_cfg.pa6 = regk_gio_lo; - if (tmp & (1 << 7)) - intr_cfg.pa7 = regk_gio_lo; - - REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); - local_irq_restore(flags); - } else if (priv->minor <= GPIO_MINOR_E) - data = *data_in[priv->minor]; - else - return 0; - - if ((data & priv->highalarm) || (~data & priv->lowalarm)) - mask = POLLIN|POLLRDNORM; - - DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask)); - return mask; -} - -int etrax_gpio_wake_up_check(void) -{ - struct gpio_private *priv; - unsigned long data = 0; - unsigned long flags; - int ret = 0; - spin_lock_irqsave(&alarm_lock, flags); - priv = alarmlist; - while (priv) { -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - if (priv->minor == GPIO_MINOR_V) - data = (unsigned long)cached_virtual_gpio_read; - else { - data = *data_in[priv->minor]; - if (priv->minor == GPIO_MINOR_A) - priv->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); - } -#else - data = *data_in[priv->minor]; -#endif - if ((data & priv->highalarm) || - (~data & priv->lowalarm)) { - DP(printk(KERN_DEBUG - "etrax_gpio_wake_up_check %i\n", priv->minor)); - wake_up_interruptible(&priv->alarm_wq); - ret = 1; - } - priv = priv->next; - } - spin_unlock_irqrestore(&alarm_lock, flags); - return ret; -} - -static irqreturn_t -gpio_poll_timer_interrupt(int irq, void *dev_id) -{ - if (gpio_some_alarms) - return IRQ_RETVAL(etrax_gpio_wake_up_check()); - return IRQ_NONE; -} - -static irqreturn_t -gpio_pa_interrupt(int irq, void *dev_id) -{ - reg_gio_rw_intr_mask intr_mask; - reg_gio_r_masked_intr masked_intr; - reg_gio_rw_ack_intr ack_intr; - unsigned long tmp; - unsigned long tmp2; -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - unsigned char enable_gpiov_ack = 0; -#endif - - /* Find what PA interrupts are active */ - masked_intr = REG_RD(gio, regi_gio, r_masked_intr); - tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr); - - /* Find those that we have enabled */ - spin_lock(&alarm_lock); - tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms); - spin_unlock(&alarm_lock); - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - /* Something changed on virtual GPIO. Interrupt is acked by - * reading the device. - */ - if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) { - i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read, - sizeof(cached_virtual_gpio_read)); - enable_gpiov_ack = 1; - } -#endif - - /* Ack them */ - ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp); - REG_WR(gio, regi_gio, rw_ack_intr, ack_intr); - - /* Disable those interrupts.. */ - intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); - tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask); - tmp2 &= ~tmp; -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - /* Do not disable interrupt on virtual GPIO. Changes on virtual - * pins are only noticed by an interrupt. - */ - if (enable_gpiov_ack) - tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); -#endif - intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2); - REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); - - if (gpio_some_alarms) - return IRQ_RETVAL(etrax_gpio_wake_up_check()); - return IRQ_NONE; -} - - -static ssize_t gpio_write(struct file *file, const char *buf, size_t count, - loff_t *off) -{ - struct gpio_private *priv = file->private_data; - unsigned char data, clk_mask, data_mask, write_msb; - unsigned long flags; - unsigned long shadow; - volatile unsigned long *port; - ssize_t retval = count; - /* Only bits 0-7 may be used for write operations but allow all - devices except leds... */ -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - if (priv->minor == GPIO_MINOR_V) - return -EFAULT; -#endif - if (priv->minor == GPIO_MINOR_LEDS) - return -EFAULT; - - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - clk_mask = priv->clk_mask; - data_mask = priv->data_mask; - /* It must have been configured using the IO_CFG_WRITE_MODE */ - /* Perhaps a better error code? */ - if (clk_mask == 0 || data_mask == 0) - return -EPERM; - write_msb = priv->write_msb; - D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " - "msb: %i\n", count, data_mask, clk_mask, write_msb)); - port = data_out[priv->minor]; - - while (count--) { - int i; - data = *buf++; - if (priv->write_msb) { - for (i = 7; i >= 0; i--) { - local_irq_save(flags); - shadow = *port; - *port = shadow &= ~clk_mask; - if (data & 1<<i) - *port = shadow |= data_mask; - else - *port = shadow &= ~data_mask; - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - *port = shadow |= clk_mask; - local_irq_restore(flags); - } - } else { - for (i = 0; i <= 7; i++) { - local_irq_save(flags); - shadow = *port; - *port = shadow &= ~clk_mask; - if (data & 1<<i) - *port = shadow |= data_mask; - else - *port = shadow &= ~data_mask; - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - *port = shadow |= clk_mask; - local_irq_restore(flags); - } - } - } - return retval; -} - - - -static int -gpio_open(struct inode *inode, struct file *filp) -{ - struct gpio_private *priv; - int p = iminor(inode); - - if (p > GPIO_MINOR_LAST) - return -EINVAL; - - priv = kzalloc(sizeof(struct gpio_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - mutex_lock(&gpio_mutex); - - priv->minor = p; - - /* initialize the io/alarm struct */ - - priv->clk_mask = 0; - priv->data_mask = 0; - priv->highalarm = 0; - priv->lowalarm = 0; - init_waitqueue_head(&priv->alarm_wq); - - filp->private_data = (void *)priv; - - /* link it into our alarmlist */ - spin_lock_irq(&alarm_lock); - priv->next = alarmlist; - alarmlist = priv; - spin_unlock_irq(&alarm_lock); - - mutex_unlock(&gpio_mutex); - return 0; -} - -static int -gpio_release(struct inode *inode, struct file *filp) -{ - struct gpio_private *p; - struct gpio_private *todel; - /* local copies while updating them: */ - unsigned long a_high, a_low; - unsigned long some_alarms; - - /* unlink from alarmlist and free the private structure */ - - spin_lock_irq(&alarm_lock); - p = alarmlist; - todel = filp->private_data; - - if (p == todel) { - alarmlist = todel->next; - } else { - while (p->next != todel) - p = p->next; - p->next = todel->next; - } - - kfree(todel); - /* Check if there are still any alarms set */ - p = alarmlist; - some_alarms = 0; - a_high = 0; - a_low = 0; - while (p) { - if (p->minor == GPIO_MINOR_A) { -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); -#endif - a_high |= p->highalarm; - a_low |= p->lowalarm; - } - - if (p->highalarm | p->lowalarm) - some_alarms = 1; - p = p->next; - } - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - /* Variables 'some_alarms' and 'a_low' needs to be set here again - * to ensure that interrupt for virtual GPIO is handled. - */ - some_alarms = 1; - a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); -#endif - - gpio_some_alarms = some_alarms; - gpio_pa_high_alarms = a_high; - gpio_pa_low_alarms = a_low; - spin_unlock_irq(&alarm_lock); - - return 0; -} - -/* Main device API. ioctl's to read/set/clear bits, as well as to - * set alarms to wait for using a subsequent select(). - */ - -inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) -{ - /* Set direction 0=unchanged 1=input, - * return mask with 1=input - */ - unsigned long flags; - unsigned long dir_shadow; - - local_irq_save(flags); - dir_shadow = *dir_oe[priv->minor]; - dir_shadow &= ~(arg & changeable_dir[priv->minor]); - *dir_oe[priv->minor] = dir_shadow; - local_irq_restore(flags); - - if (priv->minor == GPIO_MINOR_A) - dir_shadow ^= 0xFF; /* Only 8 bits */ -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - else if (priv->minor == GPIO_MINOR_V) - dir_shadow ^= 0xFFFF; /* Only 16 bits */ -#endif - else - dir_shadow ^= 0x3FFFF; /* Only 18 bits */ - return dir_shadow; - -} /* setget_input */ - -inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg) -{ - unsigned long flags; - unsigned long dir_shadow; - - local_irq_save(flags); - dir_shadow = *dir_oe[priv->minor]; - dir_shadow |= (arg & changeable_dir[priv->minor]); - *dir_oe[priv->minor] = dir_shadow; - local_irq_restore(flags); - return dir_shadow; -} /* setget_output */ - -static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg); - -static int -gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - unsigned long val; - unsigned long shadow; - struct gpio_private *priv = file->private_data; - if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) - return -EINVAL; - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - if (priv->minor == GPIO_MINOR_V) - return virtual_gpio_ioctl(file, cmd, arg); -#endif - - switch (_IOC_NR(cmd)) { - case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ - /* Read the port. */ - return *data_in[priv->minor]; - break; - case IO_SETBITS: - local_irq_save(flags); - /* Set changeable bits with a 1 in arg. */ - shadow = *data_out[priv->minor]; - shadow |= (arg & changeable_bits[priv->minor]); - *data_out[priv->minor] = shadow; - local_irq_restore(flags); - break; - case IO_CLRBITS: - local_irq_save(flags); - /* Clear changeable bits with a 1 in arg. */ - shadow = *data_out[priv->minor]; - shadow &= ~(arg & changeable_bits[priv->minor]); - *data_out[priv->minor] = shadow; - local_irq_restore(flags); - break; - case IO_HIGHALARM: - /* Set alarm when bits with 1 in arg go high. */ - priv->highalarm |= arg; - spin_lock_irqsave(&alarm_lock, flags); - gpio_some_alarms = 1; - if (priv->minor == GPIO_MINOR_A) - gpio_pa_high_alarms |= arg; - spin_unlock_irqrestore(&alarm_lock, flags); - break; - case IO_LOWALARM: - /* Set alarm when bits with 1 in arg go low. */ - priv->lowalarm |= arg; - spin_lock_irqsave(&alarm_lock, flags); - gpio_some_alarms = 1; - if (priv->minor == GPIO_MINOR_A) - gpio_pa_low_alarms |= arg; - spin_unlock_irqrestore(&alarm_lock, flags); - break; - case IO_CLRALARM: - /* Clear alarm for bits with 1 in arg. */ - priv->highalarm &= ~arg; - priv->lowalarm &= ~arg; - spin_lock_irqsave(&alarm_lock, flags); - if (priv->minor == GPIO_MINOR_A) { - if (gpio_pa_high_alarms & arg || - gpio_pa_low_alarms & arg) - /* Must update the gpio_pa_*alarms masks */ - ; - } - spin_unlock_irqrestore(&alarm_lock, flags); - break; - case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ - /* Read direction 0=input 1=output */ - return *dir_oe[priv->minor]; - case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ - /* Set direction 0=unchanged 1=input, - * return mask with 1=input - */ - return setget_input(priv, arg); - break; - case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ - /* Set direction 0=unchanged 1=output, - * return mask with 1=output - */ - return setget_output(priv, arg); - - case IO_CFG_WRITE_MODE: - { - unsigned long dir_shadow; - dir_shadow = *dir_oe[priv->minor]; - - priv->clk_mask = arg & 0xFF; - priv->data_mask = (arg >> 8) & 0xFF; - priv->write_msb = (arg >> 16) & 0x01; - /* Check if we're allowed to change the bits and - * the direction is correct - */ - if (!((priv->clk_mask & changeable_bits[priv->minor]) && - (priv->data_mask & changeable_bits[priv->minor]) && - (priv->clk_mask & dir_shadow) && - (priv->data_mask & dir_shadow))) { - priv->clk_mask = 0; - priv->data_mask = 0; - return -EPERM; - } - break; - } - case IO_READ_INBITS: - /* *arg is result of reading the input pins */ - val = *data_in[priv->minor]; - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - return 0; - break; - case IO_READ_OUTBITS: - /* *arg is result of reading the output shadow */ - val = *data_out[priv->minor]; - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - break; - case IO_SETGET_INPUT: - /* bits set in *arg is set to input, - * *arg updated with current input pins. - */ - if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) - return -EFAULT; - val = setget_input(priv, val); - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - break; - case IO_SETGET_OUTPUT: - /* bits set in *arg is set to output, - * *arg updated with current output pins. - */ - if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) - return -EFAULT; - val = setget_output(priv, val); - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - break; - default: - if (priv->minor == GPIO_MINOR_LEDS) - return gpio_leds_ioctl(cmd, arg); - else - return -EINVAL; - } /* switch */ - - return 0; -} - -static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&gpio_mutex); - ret = gpio_ioctl_unlocked(file, cmd, arg); - mutex_unlock(&gpio_mutex); - - return ret; -} - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static int -virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - unsigned short val; - unsigned short shadow; - struct gpio_private *priv = file->private_data; - - switch (_IOC_NR(cmd)) { - case IO_SETBITS: - local_irq_save(flags); - /* Set changeable bits with a 1 in arg. */ - i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - shadow |= ~*dir_oe[priv->minor]; - shadow |= (arg & changeable_bits[priv->minor]); - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - local_irq_restore(flags); - break; - case IO_CLRBITS: - local_irq_save(flags); - /* Clear changeable bits with a 1 in arg. */ - i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - shadow |= ~*dir_oe[priv->minor]; - shadow &= ~(arg & changeable_bits[priv->minor]); - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - local_irq_restore(flags); - break; - case IO_HIGHALARM: - /* Set alarm when bits with 1 in arg go high. */ - priv->highalarm |= arg; - spin_lock(&alarm_lock); - gpio_some_alarms = 1; - spin_unlock(&alarm_lock); - break; - case IO_LOWALARM: - /* Set alarm when bits with 1 in arg go low. */ - priv->lowalarm |= arg; - spin_lock(&alarm_lock); - gpio_some_alarms = 1; - spin_unlock(&alarm_lock); - break; - case IO_CLRALARM: - /* Clear alarm for bits with 1 in arg. */ - priv->highalarm &= ~arg; - priv->lowalarm &= ~arg; - spin_lock(&alarm_lock); - spin_unlock(&alarm_lock); - break; - case IO_CFG_WRITE_MODE: - { - unsigned long dir_shadow; - dir_shadow = *dir_oe[priv->minor]; - - priv->clk_mask = arg & 0xFF; - priv->data_mask = (arg >> 8) & 0xFF; - priv->write_msb = (arg >> 16) & 0x01; - /* Check if we're allowed to change the bits and - * the direction is correct - */ - if (!((priv->clk_mask & changeable_bits[priv->minor]) && - (priv->data_mask & changeable_bits[priv->minor]) && - (priv->clk_mask & dir_shadow) && - (priv->data_mask & dir_shadow))) { - priv->clk_mask = 0; - priv->data_mask = 0; - return -EPERM; - } - break; - } - case IO_READ_INBITS: - /* *arg is result of reading the input pins */ - val = cached_virtual_gpio_read; - val &= ~*dir_oe[priv->minor]; - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - return 0; - break; - case IO_READ_OUTBITS: - /* *arg is result of reading the output shadow */ - i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); - val &= *dir_oe[priv->minor]; - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - break; - case IO_SETGET_INPUT: - { - /* bits set in *arg is set to input, - * *arg updated with current input pins. - */ - unsigned short input_mask = ~*dir_oe[priv->minor]; - if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) - return -EFAULT; - val = setget_input(priv, val); - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - if ((input_mask & val) != input_mask) { - /* Input pins changed. All ports desired as input - * should be set to logic 1. - */ - unsigned short change = input_mask ^ val; - i2c_read(VIRT_I2C_ADDR, (void *)&shadow, - sizeof(shadow)); - shadow &= ~change; - shadow |= val; - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, - sizeof(shadow)); - } - break; - } - case IO_SETGET_OUTPUT: - /* bits set in *arg is set to output, - * *arg updated with current output pins. - */ - if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) - return -EFAULT; - val = setget_output(priv, val); - if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) - return -EFAULT; - break; - default: - return -EINVAL; - } /* switch */ - return 0; -} -#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ - -static int -gpio_leds_ioctl(unsigned int cmd, unsigned long arg) -{ - unsigned char green; - unsigned char red; - - switch (_IOC_NR(cmd)) { - case IO_LEDACTIVE_SET: - green = ((unsigned char) arg) & 1; - red = (((unsigned char) arg) >> 1) & 1; - CRIS_LED_ACTIVE_SET_G(green); - CRIS_LED_ACTIVE_SET_R(red); - break; - - default: - return -EINVAL; - } /* switch */ - - return 0; -} - -static const struct file_operations gpio_fops = { - .owner = THIS_MODULE, - .poll = gpio_poll, - .unlocked_ioctl = gpio_ioctl, - .write = gpio_write, - .open = gpio_open, - .release = gpio_release, - .llseek = noop_llseek, -}; - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -static void -virtual_gpio_init(void) -{ - reg_gio_rw_intr_cfg intr_cfg; - reg_gio_rw_intr_mask intr_mask; - unsigned short shadow; - - shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */ - shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT; - i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); - - /* Set interrupt mask and on what state the interrupt shall trigger. - * For virtual gpio the interrupt shall trigger on logic '0'. - */ - intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); - intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); - - switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) { - case 0: - intr_cfg.pa0 = regk_gio_lo; - intr_mask.pa0 = regk_gio_yes; - break; - case 1: - intr_cfg.pa1 = regk_gio_lo; - intr_mask.pa1 = regk_gio_yes; - break; - case 2: - intr_cfg.pa2 = regk_gio_lo; - intr_mask.pa2 = regk_gio_yes; - break; - case 3: - intr_cfg.pa3 = regk_gio_lo; - intr_mask.pa3 = regk_gio_yes; - break; - case 4: - intr_cfg.pa4 = regk_gio_lo; - intr_mask.pa4 = regk_gio_yes; - break; - case 5: - intr_cfg.pa5 = regk_gio_lo; - intr_mask.pa5 = regk_gio_yes; - break; - case 6: - intr_cfg.pa6 = regk_gio_lo; - intr_mask.pa6 = regk_gio_yes; - break; - case 7: - intr_cfg.pa7 = regk_gio_lo; - intr_mask.pa7 = regk_gio_yes; - break; - } - - REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); - REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); - - gpio_pa_low_alarms |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); - gpio_some_alarms = 1; -} -#endif - -/* main driver initialization routine, called from mem.c */ - -static __init int -gpio_init(void) -{ - int res; - - /* do the formalities */ - - res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); - if (res < 0) { - printk(KERN_ERR "gpio: couldn't get a major number.\n"); - return res; - } - - /* Clear all leds */ - CRIS_LED_NETWORK_GRP0_SET(0); - CRIS_LED_NETWORK_GRP1_SET(0); - CRIS_LED_ACTIVE_SET(0); - CRIS_LED_DISK_READ(0); - CRIS_LED_DISK_WRITE(0); - - printk(KERN_INFO "ETRAX FS GPIO driver v2.5, (c) 2003-2007 " - "Axis Communications AB\n"); - /* We call etrax_gpio_wake_up_check() from timer interrupt */ - if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt, - IRQF_SHARED, "gpio poll", &alarmlist)) - printk(KERN_ERR "timer0 irq for gpio\n"); - - if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt, - IRQF_SHARED, "gpio PA", &alarmlist)) - printk(KERN_ERR "PA irq for gpio\n"); - -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - virtual_gpio_init(); -#endif - - return res; -} - -/* this makes sure that gpio_init is called during kernel boot */ - -module_init(gpio_init); diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c index bde8d1a10cad..b0566350a840 100644 --- a/arch/cris/arch-v32/kernel/crisksyms.c +++ b/arch/cris/arch-v32/kernel/crisksyms.c @@ -3,7 +3,6 @@ #include <arch/dma.h> #include <arch/intmem.h> #include <mach/pinmux.h> -#include <arch/io.h> /* Functions for allocating DMA channels */ EXPORT_SYMBOL(crisv32_request_dma); @@ -20,8 +19,6 @@ EXPORT_SYMBOL(crisv32_pinmux_alloc); EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed); EXPORT_SYMBOL(crisv32_pinmux_dealloc); EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed); -EXPORT_SYMBOL(crisv32_io_get_name); -EXPORT_SYMBOL(crisv32_io_get); /* Functions masking/unmasking interrupts */ EXPORT_SYMBOL(crisv32_mask_irq); diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c index 02e33ebe51ec..d2f3f9c37102 100644 --- a/arch/cris/arch-v32/kernel/debugport.c +++ b/arch/cris/arch-v32/kernel/debugport.c @@ -77,8 +77,6 @@ static struct dbg_port *port = &ports[2]; #elif defined(CONFIG_ETRAX_DEBUG_PORT3) &ports[3]; -#elif defined(CONFIG_ETRAX_DEBUG_PORT4) - &ports[4]; #else NULL; #endif diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S index 74a66e0e3777..ea6366800df7 100644 --- a/arch/cris/arch-v32/kernel/head.S +++ b/arch/cris/arch-v32/kernel/head.S @@ -292,11 +292,7 @@ _no_romfs_in_flash: ;; For cramfs, partition starts with magic and length. ;; For jffs2, a jhead is prepended which contains with magic and length. ;; The jhead is not part of the jffs2 partition however. -#ifndef CONFIG_ETRAXFS_SIM move.d __bss_start, $r0 -#else - move.d __end, $r0 -#endif move.d [$r0], $r1 cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic? beq 2f ; yes, jump diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index 6a881e0e92b4..6de8db67cb09 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -37,7 +37,7 @@ #define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ)) #elif defined(CONFIG_ETRAX_KGDB_PORT1) #define IGNOREMASK (1 << (SER1_INTR_VECT - FIRST_IRQ)) -#elif defined(CONFIG_ETRAX_KGB_PORT2) +#elif defined(CONFIG_ETRAX_KGDB_PORT2) #define IGNOREMASK (1 << (SER2_INTR_VECT - FIRST_IRQ)) #elif defined(CONFIG_ETRAX_KGDB_PORT3) #define IGNOREMASK (1 << (SER3_INTR_VECT - FIRST_IRQ)) @@ -464,14 +464,14 @@ init_IRQ(void) etrax_irv->v[i] = weird_irq; np = of_find_compatible_node(NULL, NULL, "axis,crisv32-intc"); - domain = irq_domain_add_legacy(np, NR_IRQS - FIRST_IRQ, + domain = irq_domain_add_legacy(np, NBR_INTR_VECT - FIRST_IRQ, FIRST_IRQ, FIRST_IRQ, &crisv32_irq_ops, NULL); BUG_ON(!domain); irq_set_default_host(domain); of_node_put(np); - for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) { + for (i = FIRST_IRQ, j = 0; j < NBR_INTR_VECT; i++, j++) { set_exception_vector(i, interrupt[j]); } diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c index b06813aeb120..e0fdea706eca 100644 --- a/arch/cris/arch-v32/kernel/kgdb.c +++ b/arch/cris/arch-v32/kernel/kgdb.c @@ -384,19 +384,11 @@ int getDebugChar(void); /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ void putDebugChar(int val); -/* Returns the integer equivalent of a hexadecimal character. */ -static int hex(char ch); - /* Convert the memory, pointed to by mem into hexadecimal representation. Put the result in buf, and return a pointer to the last character in buf (null). */ static char *mem2hex(char *buf, unsigned char *mem, int count); -/* Convert the array, in hexadecimal representation, pointed to by buf into - binary representation. Put the result in mem, and return a pointer to - the character after the last byte written. */ -static unsigned char *hex2mem(unsigned char *mem, char *buf, int count); - /* Put the content of the array, in binary representation, pointed to by buf into memory pointed to by mem, and return a pointer to the character after the last byte written. */ @@ -449,7 +441,7 @@ static char output_buffer[BUFMAX]; /* Error and warning messages. */ enum error_type { - SUCCESS, E01, E02, E03, E04, E05, E06, + SUCCESS, E01, E02, E03, E04, E05, E06, E07, E08 }; static char *error_message[] = @@ -461,6 +453,8 @@ static char *error_message[] = "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.", "E05 Change register content - P - the register is not implemented..", "E06 Change memory content - M - internal error.", + "E07 Change register content - P - the register is not stored on the stack", + "E08 Invalid parameter" }; /********************************** Breakpoint *******************************/ @@ -539,7 +533,7 @@ gdb_cris_strtol(const char *s, char **endptr, int base) /********************************* Register image ****************************/ /* Write a value to a specified register in the register image of the current - thread. Returns status code SUCCESS, E02 or E05. */ + thread. Returns status code SUCCESS, E02, E05 or E08. */ static int write_register(int regno, char *val) { @@ -547,8 +541,9 @@ write_register(int regno, char *val) if (regno >= R0 && regno <= ACR) { /* Consecutive 32-bit registers. */ - hex2mem((unsigned char *)®.r0 + (regno - R0) * sizeof(unsigned int), - val, sizeof(unsigned int)); + if (hex2bin((unsigned char *)®.r0 + (regno - R0) * sizeof(unsigned int), + val, sizeof(unsigned int))) + status = E08; } else if (regno == BZ || regno == VR || regno == WZ || regno == DZ) { /* Read-only registers. */ @@ -557,16 +552,19 @@ write_register(int regno, char *val) } else if (regno == PID) { /* 32-bit register. (Even though we already checked SRS and WZ, we cannot combine this with the EXS - SPC write since SRS and WZ have different size.) */ - hex2mem((unsigned char *)®.pid, val, sizeof(unsigned int)); + if (hex2bin((unsigned char *)®.pid, val, sizeof(unsigned int))) + status = E08; } else if (regno == SRS) { /* 8-bit register. */ - hex2mem((unsigned char *)®.srs, val, sizeof(unsigned char)); + if (hex2bin((unsigned char *)®.srs, val, sizeof(unsigned char))) + status = E08; } else if (regno >= EXS && regno <= SPC) { /* Consecutive 32-bit registers. */ - hex2mem((unsigned char *)®.exs + (regno - EXS) * sizeof(unsigned int), - val, sizeof(unsigned int)); + if (hex2bin((unsigned char *)®.exs + (regno - EXS) * sizeof(unsigned int), + val, sizeof(unsigned int))) + status = E08; } else if (regno == PC) { /* Pseudo-register. Treat as read-only. */ @@ -574,7 +572,9 @@ write_register(int regno, char *val) } else if (regno >= S0 && regno <= S15) { /* 32-bit registers. */ - hex2mem((unsigned char *)&sreg.s0_0 + (reg.srs * 16 * sizeof(unsigned int)) + (regno - S0) * sizeof(unsigned int), val, sizeof(unsigned int)); + if (hex2bin((unsigned char *)&sreg.s0_0 + (reg.srs * 16 * sizeof(unsigned int)) + (regno - S0) * sizeof(unsigned int), + val, sizeof(unsigned int))) + status = E08; } else { /* Non-existing register. */ status = E05; @@ -630,19 +630,6 @@ read_register(char regno, unsigned int *valptr) } /********************************** Packet I/O ******************************/ -/* Returns the integer equivalent of a hexadecimal character. */ -static int -hex(char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch - 'a' + 10); - if ((ch >= '0') && (ch <= '9')) - return (ch - '0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch - 'A' + 10); - return -1; -} - /* Convert the memory, pointed to by mem into hexadecimal representation. Put the result in buf, and return a pointer to the last character in buf (null). */ @@ -689,22 +676,6 @@ mem2hex_nbo(char *buf, unsigned char *mem, int count) return buf; } -/* Convert the array, in hexadecimal representation, pointed to by buf into - binary representation. Put the result in mem, and return a pointer to - the character after the last byte written. */ -static unsigned char* -hex2mem(unsigned char *mem, char *buf, int count) -{ - int i; - unsigned char ch; - for (i = 0; i < count; i++) { - ch = hex (*buf++) << 4; - ch = ch + hex (*buf++); - *mem++ = ch; - } - return mem; -} - /* Put the content of the array, in binary representation, pointed to by buf into memory pointed to by mem, and return a pointer to the character after the last byte written. @@ -763,8 +734,8 @@ getpacket(char *buffer) buffer[count] = 0; if (ch == '#') { - xmitcsum = hex(getDebugChar()) << 4; - xmitcsum += hex(getDebugChar()); + xmitcsum = hex_to_bin(getDebugChar()) << 4; + xmitcsum += hex_to_bin(getDebugChar()); if (checksum != xmitcsum) { /* Wrong checksum */ putDebugChar('-'); @@ -1304,14 +1275,17 @@ handle_exception(int sigval) /* Write registers. GXX..XX Each byte of register data is described by two hex digits. Success: OK - Failure: void. */ + Failure: E08. */ /* General and special registers. */ - hex2mem((char *)®, &input_buffer[1], sizeof(registers)); + if (hex2bin((char *)®, &input_buffer[1], sizeof(registers))) + gdb_cris_strcpy(output_buffer, error_message[E08]); /* Support registers. */ - hex2mem((char *)&sreg + (reg.srs * 16 * sizeof(unsigned int)), + else if (hex2bin((char *)&sreg + (reg.srs * 16 * sizeof(unsigned int)), &input_buffer[1] + sizeof(registers), - 16 * sizeof(unsigned int)); - gdb_cris_strcpy(output_buffer, "OK"); + 16 * sizeof(unsigned int))) + gdb_cris_strcpy(output_buffer, error_message[E08]); + else + gdb_cris_strcpy(output_buffer, "OK"); break; case 'P': @@ -1338,6 +1312,10 @@ handle_exception(int sigval) /* Do not support non-existing registers. */ gdb_cris_strcpy(output_buffer, error_message[E05]); break; + case E08: + /* Invalid parameter. */ + gdb_cris_strcpy(output_buffer, error_message[E08]); + break; default: /* Valid register number. */ gdb_cris_strcpy(output_buffer, "OK"); @@ -1380,7 +1358,7 @@ handle_exception(int sigval) AA..AA is the start address, LLLL is the number of bytes, and XX..XX is the hexadecimal data. Success: OK - Failure: void. */ + Failure: E08. */ { char *lenptr; char *dataptr; @@ -1389,13 +1367,15 @@ handle_exception(int sigval) int len = gdb_cris_strtol(lenptr+1, &dataptr, 16); if (*lenptr == ',' && *dataptr == ':') { if (input_buffer[0] == 'M') { - hex2mem(addr, dataptr + 1, len); + if (hex2bin(addr, dataptr + 1, len)) + gdb_cris_strcpy(output_buffer, error_message[E08]); + else + gdb_cris_strcpy(output_buffer, "OK"); } else /* X */ { bin2mem(addr, dataptr + 1, len); + gdb_cris_strcpy(output_buffer, "OK"); } - gdb_cris_strcpy(output_buffer, "OK"); - } - else { + } else { gdb_cris_strcpy(output_buffer, error_message[E06]); } } diff --git a/arch/cris/arch-v32/kernel/setup.c b/arch/cris/arch-v32/kernel/setup.c index cd1865d68b2e..fe50287aa928 100644 --- a/arch/cris/arch-v32/kernel/setup.c +++ b/arch/cris/arch-v32/kernel/setup.c @@ -129,10 +129,6 @@ static struct i2c_board_info __initdata i2c_info[] = { #ifdef CONFIG_RTC_DRV_PCF8563 {I2C_BOARD_INFO("pcf8563", 0x51)}, #endif -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - {I2C_BOARD_INFO("vgpio", 0x20)}, - {I2C_BOARD_INFO("vgpio", 0x21)}, -#endif {I2C_BOARD_INFO("pca9536", 0x41)}, {I2C_BOARD_INFO("fnp300", 0x40)}, {I2C_BOARD_INFO("fnp300", 0x42)}, @@ -146,10 +142,6 @@ static struct i2c_board_info __initdata i2c_info2[] = { {I2C_BOARD_INFO("tmp100", 0x4C)}, {I2C_BOARD_INFO("tmp100", 0x4D)}, {I2C_BOARD_INFO("tmp100", 0x4E)}, -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO - {I2C_BOARD_INFO("vgpio", 0x20)}, - {I2C_BOARD_INFO("vgpio", 0x21)}, -#endif {I2C_BOARD_INFO("pca9536", 0x41)}, {I2C_BOARD_INFO("fnp300", 0x40)}, {I2C_BOARD_INFO("fnp300", 0x42)}, diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile index 18a227196a41..0cc6eebacbed 100644 --- a/arch/cris/arch-v32/mach-a3/Makefile +++ b/arch/cris/arch-v32/mach-a3/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := dma.o pinmux.o io.o arbiter.o +obj-y := dma.o pinmux.o arbiter.o clean: diff --git a/arch/cris/arch-v32/mach-a3/io.c b/arch/cris/arch-v32/mach-a3/io.c deleted file mode 100644 index 090ceb99ef0b..000000000000 --- a/arch/cris/arch-v32/mach-a3/io.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Helper functions for I/O pins. - * - * Copyright (c) 2005-2007 Axis Communications AB. - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <asm/io.h> -#include <mach/pinmux.h> -#include <hwregs/gio_defs.h> - -struct crisv32_ioport crisv32_ioports[] = { - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din), - 32 - }, - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din), - 32 - }, - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din), - 16 - }, -}; - -#define NBR_OF_PORTS ARRAY_SIZE(crisv32_ioports) - -struct crisv32_iopin crisv32_led_net0_green; -struct crisv32_iopin crisv32_led_net0_red; -struct crisv32_iopin crisv32_led2_green; -struct crisv32_iopin crisv32_led2_red; -struct crisv32_iopin crisv32_led3_green; -struct crisv32_iopin crisv32_led3_red; - -/* Dummy port used when green LED and red LED is on the same bit */ -static unsigned long io_dummy; -static struct crisv32_ioport dummy_port = { - &io_dummy, - &io_dummy, - &io_dummy, - 32 -}; -static struct crisv32_iopin dummy_led = { - &dummy_port, - 0 -}; - -static int __init crisv32_io_init(void) -{ - int ret = 0; - - u32 i; - - /* Locks *should* be dynamically initialized. */ - for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++) - spin_lock_init(&crisv32_ioports[i].lock); - spin_lock_init(&dummy_port.lock); - - /* Initialize LEDs */ -#if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO)) - ret += crisv32_io_get_name(&crisv32_led_net0_green, - CONFIG_ETRAX_LED_G_NET0); - crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out); - if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) { - ret += crisv32_io_get_name(&crisv32_led_net0_red, - CONFIG_ETRAX_LED_R_NET0); - crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out); - } else - crisv32_led_net0_red = dummy_led; -#endif - - ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G); - ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R); - ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G); - ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R); - - crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); - - return ret; -} - -__initcall(crisv32_io_init); - -int crisv32_io_get(struct crisv32_iopin *iopin, - unsigned int port, unsigned int pin) -{ - if (port > NBR_OF_PORTS) - return -EINVAL; - if (port > crisv32_ioports[port].pin_count) - return -EINVAL; - - iopin->bit = 1 << pin; - iopin->port = &crisv32_ioports[port]; - - if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) - return -EIO; - - return 0; -} - -int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name) -{ - int port; - int pin; - - if (toupper(*name) == 'P') - name++; - - if (toupper(*name) < 'A' || toupper(*name) > 'E') - return -EINVAL; - - port = toupper(*name) - 'A'; - name++; - pin = simple_strtoul(name, NULL, 10); - - if (pin < 0 || pin > crisv32_ioports[port].pin_count) - return -EINVAL; - - iopin->bit = 1 << pin; - iopin->port = &crisv32_ioports[port]; - - if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) - return -EIO; - - return 0; -} - -#ifdef CONFIG_PCI -/* PCI I/O access stuff */ -struct cris_io_operations *cris_iops = NULL; -EXPORT_SYMBOL(cris_iops); -#endif - diff --git a/arch/cris/arch-v32/mach-fs/Kconfig b/arch/cris/arch-v32/mach-fs/Kconfig index 774de82abef6..7d1ab972bc0f 100644 --- a/arch/cris/arch-v32/mach-fs/Kconfig +++ b/arch/cris/arch-v32/mach-fs/Kconfig @@ -192,25 +192,6 @@ config ETRAX_DEF_GIO_PE_OUT Configures the initial data for the general port E bits. Most products should use 00000 here. -config ETRAX_DEF_GIO_PV_OE - hex "GIO_PV_OE" - depends on ETRAX_VIRTUAL_GPIO - default "0000" - help - Configures the direction of virtual general port V bits. 1 is out, - 0 is in. This is often totally different depending on the product - used. These bits are used for all kinds of stuff. If you don't know - what to use, it is always safe to put all as inputs, although - floating inputs isn't good. - -config ETRAX_DEF_GIO_PV_OUT - hex "GIO_PV_OUT" - depends on ETRAX_VIRTUAL_GPIO - default "0000" - help - Configures the initial data for the virtual general port V bits. - Most products should use 0000 here. - endmenu endif diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile index 18a227196a41..0cc6eebacbed 100644 --- a/arch/cris/arch-v32/mach-fs/Makefile +++ b/arch/cris/arch-v32/mach-fs/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := dma.o pinmux.o io.o arbiter.o +obj-y := dma.o pinmux.o arbiter.o clean: diff --git a/arch/cris/arch-v32/mach-fs/io.c b/arch/cris/arch-v32/mach-fs/io.c deleted file mode 100644 index a6958661fa8e..000000000000 --- a/arch/cris/arch-v32/mach-fs/io.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Helper functions for I/O pins. - * - * Copyright (c) 2004-2007 Axis Communications AB. - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <asm/io.h> -#include <mach/pinmux.h> -#include <hwregs/gio_defs.h> - -#ifndef DEBUG -#define DEBUG(x) -#endif - -struct crisv32_ioport crisv32_ioports[] = { - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din), - 8 - }, - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din), - 18 - }, - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din), - 18 - }, - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pd_din), - 18 - }, - { - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_oe), - (unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_dout), - (unsigned long *)REG_ADDR(gio, regi_gio, r_pe_din), - 18 - } -}; - -#define NBR_OF_PORTS ARRAY_SIZE(crisv32_ioports) - -struct crisv32_iopin crisv32_led_net0_green; -struct crisv32_iopin crisv32_led_net0_red; -struct crisv32_iopin crisv32_led_net1_green; -struct crisv32_iopin crisv32_led_net1_red; -struct crisv32_iopin crisv32_led2_green; -struct crisv32_iopin crisv32_led2_red; -struct crisv32_iopin crisv32_led3_green; -struct crisv32_iopin crisv32_led3_red; - -/* Dummy port used when green LED and red LED is on the same bit */ -static unsigned long io_dummy; -static struct crisv32_ioport dummy_port = { - &io_dummy, - &io_dummy, - &io_dummy, - 18 -}; -static struct crisv32_iopin dummy_led = { - &dummy_port, - 0 -}; - -static int __init crisv32_io_init(void) -{ - int ret = 0; - - u32 i; - - /* Locks *should* be dynamically initialized. */ - for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++) - spin_lock_init(&crisv32_ioports[i].lock); - spin_lock_init(&dummy_port.lock); - - /* Initialize LEDs */ -#if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO)) - ret += - crisv32_io_get_name(&crisv32_led_net0_green, - CONFIG_ETRAX_LED_G_NET0); - crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out); - if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) { - ret += - crisv32_io_get_name(&crisv32_led_net0_red, - CONFIG_ETRAX_LED_R_NET0); - crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out); - } else - crisv32_led_net0_red = dummy_led; -#endif - -#ifdef CONFIG_ETRAX_NBR_LED_GRP_TWO - ret += - crisv32_io_get_name(&crisv32_led_net1_green, - CONFIG_ETRAX_LED_G_NET1); - crisv32_io_set_dir(&crisv32_led_net1_green, crisv32_io_dir_out); - if (strcmp(CONFIG_ETRAX_LED_G_NET1, CONFIG_ETRAX_LED_R_NET1)) { - crisv32_io_get_name(&crisv32_led_net1_red, - CONFIG_ETRAX_LED_R_NET1); - crisv32_io_set_dir(&crisv32_led_net1_red, crisv32_io_dir_out); - } else - crisv32_led_net1_red = dummy_led; -#endif - - ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G); - ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R); - ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G); - ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R); - - crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); - - return ret; -} - -__initcall(crisv32_io_init); - -int crisv32_io_get(struct crisv32_iopin *iopin, - unsigned int port, unsigned int pin) -{ - if (port > NBR_OF_PORTS) - return -EINVAL; - if (port > crisv32_ioports[port].pin_count) - return -EINVAL; - - iopin->bit = 1 << pin; - iopin->port = &crisv32_ioports[port]; - - /* Only allocate pinmux gpiopins if port != PORT_A (port 0) */ - /* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */ - if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio)) - return -EIO; - DEBUG(printk(KERN_DEBUG "crisv32_io_get: Allocated pin %d on port %d\n", - pin, port)); - - return 0; -} - -int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name) -{ - int port; - int pin; - - if (toupper(*name) == 'P') - name++; - - if (toupper(*name) < 'A' || toupper(*name) > 'E') - return -EINVAL; - - port = toupper(*name) - 'A'; - name++; - pin = simple_strtoul(name, NULL, 10); - - if (pin < 0 || pin > crisv32_ioports[port].pin_count) - return -EINVAL; - - iopin->bit = 1 << pin; - iopin->port = &crisv32_ioports[port]; - - /* Only allocate pinmux gpiopins if port != PORT_A (port 0) */ - /* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */ - if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio)) - return -EIO; - - DEBUG(printk(KERN_DEBUG - "crisv32_io_get_name: Allocated pin %d on port %d\n", - pin, port)); - - return 0; -} - -#ifdef CONFIG_PCI -/* PCI I/O access stuff */ -struct cris_io_operations *cris_iops = NULL; -EXPORT_SYMBOL(cris_iops); -#endif diff --git a/arch/cris/boot/dts/artpec3.dtsi b/arch/cris/boot/dts/artpec3.dtsi new file mode 100644 index 000000000000..be15be67b653 --- /dev/null +++ b/arch/cris/boot/dts/artpec3.dtsi @@ -0,0 +1,46 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "axis,crisv32"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + model = "artpec3"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + intc: interrupt-controller { + compatible = "axis,crisv32-intc"; + reg = <0xb002a000 0x1000>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gio: gpio@b0020000 { + compatible = "axis,artpec3-gio"; + reg = <0xb0020000 0x1000>; + interrupts = <61>; + gpio-controller; + #gpio-cells = <3>; + }; + + serial@b003e000 { + compatible = "axis,etraxfs-uart"; + reg = <0xb003e000 0x1000>; + interrupts = <64>; + status = "disabled"; + }; + }; +}; diff --git a/arch/cris/boot/dts/dev88.dts b/arch/cris/boot/dts/dev88.dts index 4fa5a3f9d0ec..b9a230d10874 100644 --- a/arch/cris/boot/dts/dev88.dts +++ b/arch/cris/boot/dts/dev88.dts @@ -1,5 +1,7 @@ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> + /include/ "etraxfs.dtsi" / { @@ -15,4 +17,51 @@ status = "okay"; }; }; + + spi { + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + gpio-sck = <&gio 1 0 0xd>; + gpio-miso = <&gio 4 0 0xd>; + gpio-mosi = <&gio 0 0 0xd>; + cs-gpios = <&gio 3 0 0xd>; + num-chipselects = <1>; + + temp-sensor@0 { + compatible = "ti,lm70"; + reg = <0>; + + spi-max-frequency = <100000>; + }; + }; + + i2c { + compatible = "i2c-gpio"; + gpios = <&gio 5 0 0xd>, <&gio 6 0 0xd>; + i2c-gpio,delay-us = <2>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + + leds { + compatible = "gpio-leds"; + + network { + label = "network"; + gpios = <&gio 2 GPIO_ACTIVE_LOW 0xa>; + }; + + status { + label = "status"; + gpios = <&gio 3 GPIO_ACTIVE_LOW 0xa>; + linux,default-trigger = "heartbeat"; + }; + }; }; diff --git a/arch/cris/boot/dts/etraxfs.dtsi b/arch/cris/boot/dts/etraxfs.dtsi index 909bcedc3565..bf1b8582d4d8 100644 --- a/arch/cris/boot/dts/etraxfs.dtsi +++ b/arch/cris/boot/dts/etraxfs.dtsi @@ -28,6 +28,14 @@ #interrupt-cells = <1>; }; + gio: gpio@b001a000 { + compatible = "axis,etraxfs-gio"; + reg = <0xb001a000 0x1000>; + interrupts = <50>; + gpio-controller; + #gpio-cells = <3>; + }; + serial@b00260000 { compatible = "axis,etraxfs-uart"; reg = <0xb0026000 0x1000>; diff --git a/arch/cris/boot/dts/include/dt-bindings b/arch/cris/boot/dts/include/dt-bindings new file mode 120000 index 000000000000..08c00e4972fa --- /dev/null +++ b/arch/cris/boot/dts/include/dt-bindings @@ -0,0 +1 @@ +../../../../../include/dt-bindings
\ No newline at end of file diff --git a/arch/cris/boot/dts/p1343.dts b/arch/cris/boot/dts/p1343.dts new file mode 100644 index 000000000000..fab7bdbd0f15 --- /dev/null +++ b/arch/cris/boot/dts/p1343.dts @@ -0,0 +1,76 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +/include/ "artpec3.dtsi" + +/ { + model = "Axis P1343 Network Camera"; + compatible = "axis,p1343"; + + aliases { + serial0 = &uart0; + }; + + soc { + uart0: serial@b003e000 { + status = "okay"; + }; + }; + + i2c { + compatible = "i2c-gpio"; + gpios = <&gio 3 0 0xa>, <&gio 2 0 0xa>; + i2c-gpio,delay-us = <2>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + + leds { + compatible = "gpio-leds"; + + status_green { + label = "status:green"; + gpios = <&gio 0 GPIO_ACTIVE_LOW 0xc>; + linux,default-trigger = "heartbeat"; + }; + + status_red { + label = "status:red"; + gpios = <&gio 1 GPIO_ACTIVE_LOW 0xc>; + }; + + network_green { + label = "network:green"; + gpios = <&gio 2 GPIO_ACTIVE_LOW 0xc>; + }; + + network_red { + label = "network:red"; + gpios = <&gio 3 GPIO_ACTIVE_LOW 0xc>; + }; + + power_red { + label = "power:red"; + gpios = <&gio 4 GPIO_ACTIVE_LOW 0xc>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + activity-button@0 { + label = "Activity Button"; + linux,code = <KEY_FN>; + gpios = <&gio 13 GPIO_ACTIVE_LOW 0xd>; + }; + }; +}; diff --git a/arch/cris/boot/rescue/head_v10.S b/arch/cris/boot/rescue/head_v10.S index af55df0994b3..1c05492f3eb2 100644 --- a/arch/cris/boot/rescue/head_v10.S +++ b/arch/cris/boot/rescue/head_v10.S @@ -281,9 +281,6 @@ wait_ser: #ifdef CONFIG_ETRAX_PB_LEDS move.b $r2, [R_PORT_PB_DATA] #endif -#ifdef CONFIG_ETRAX_90000000_LEDS - move.b $r2, [0x90000000] -#endif #endif ;; check if we got something on the serial port diff --git a/arch/cris/include/arch-v32/arch/io.h b/arch/cris/include/arch-v32/arch/io.h deleted file mode 100644 index adc5484351bf..000000000000 --- a/arch/cris/include/arch-v32/arch/io.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef _ASM_ARCH_CRIS_IO_H -#define _ASM_ARCH_CRIS_IO_H - -#include <linux/spinlock.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/gio_defs.h> - -enum crisv32_io_dir -{ - crisv32_io_dir_in = 0, - crisv32_io_dir_out = 1 -}; - -struct crisv32_ioport -{ - volatile unsigned long *oe; - volatile unsigned long *data; - volatile unsigned long *data_in; - unsigned int pin_count; - spinlock_t lock; -}; - -struct crisv32_iopin -{ - struct crisv32_ioport* port; - int bit; -}; - -extern struct crisv32_ioport crisv32_ioports[]; - -extern struct crisv32_iopin crisv32_led1_green; -extern struct crisv32_iopin crisv32_led1_red; -extern struct crisv32_iopin crisv32_led2_green; -extern struct crisv32_iopin crisv32_led2_red; -extern struct crisv32_iopin crisv32_led3_green; -extern struct crisv32_iopin crisv32_led3_red; - -extern struct crisv32_iopin crisv32_led_net0_green; -extern struct crisv32_iopin crisv32_led_net0_red; -extern struct crisv32_iopin crisv32_led_net1_green; -extern struct crisv32_iopin crisv32_led_net1_red; - -static inline void crisv32_io_set(struct crisv32_iopin *iopin, int val) -{ - unsigned long flags; - spin_lock_irqsave(&iopin->port->lock, flags); - - if (iopin->port->data) { - if (val) - *iopin->port->data |= iopin->bit; - else - *iopin->port->data &= ~iopin->bit; - } - - spin_unlock_irqrestore(&iopin->port->lock, flags); -} - -static inline void crisv32_io_set_dir(struct crisv32_iopin* iopin, - enum crisv32_io_dir dir) -{ - unsigned long flags; - spin_lock_irqsave(&iopin->port->lock, flags); - - if (iopin->port->oe) { - if (dir == crisv32_io_dir_in) - *iopin->port->oe &= ~iopin->bit; - else - *iopin->port->oe |= iopin->bit; - } - - spin_unlock_irqrestore(&iopin->port->lock, flags); -} - -static inline int crisv32_io_rd(struct crisv32_iopin* iopin) -{ - return ((*iopin->port->data_in & iopin->bit) ? 1 : 0); -} - -int crisv32_io_get(struct crisv32_iopin* iopin, - unsigned int port, unsigned int pin); -int crisv32_io_get_name(struct crisv32_iopin* iopin, - const char *name); - -#define CRIS_LED_OFF 0x00 -#define CRIS_LED_GREEN 0x01 -#define CRIS_LED_RED 0x02 -#define CRIS_LED_ORANGE (CRIS_LED_GREEN | CRIS_LED_RED) - -#if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO)) -#define CRIS_LED_NETWORK_GRP0_SET(x) \ - do { \ - CRIS_LED_NETWORK_GRP0_SET_G((x) & CRIS_LED_GREEN); \ - CRIS_LED_NETWORK_GRP0_SET_R((x) & CRIS_LED_RED); \ - } while (0) -#else -#define CRIS_LED_NETWORK_GRP0_SET(x) while (0) {} -#endif - -#define CRIS_LED_NETWORK_GRP0_SET_G(x) \ - crisv32_io_set(&crisv32_led_net0_green, !(x)); - -#define CRIS_LED_NETWORK_GRP0_SET_R(x) \ - crisv32_io_set(&crisv32_led_net0_red, !(x)); - -#if defined(CONFIG_ETRAX_NBR_LED_GRP_TWO) -#define CRIS_LED_NETWORK_GRP1_SET(x) \ - do { \ - CRIS_LED_NETWORK_GRP1_SET_G((x) & CRIS_LED_GREEN); \ - CRIS_LED_NETWORK_GRP1_SET_R((x) & CRIS_LED_RED); \ - } while (0) -#else -#define CRIS_LED_NETWORK_GRP1_SET(x) while (0) {} -#endif - -#define CRIS_LED_NETWORK_GRP1_SET_G(x) \ - crisv32_io_set(&crisv32_led_net1_green, !(x)); - -#define CRIS_LED_NETWORK_GRP1_SET_R(x) \ - crisv32_io_set(&crisv32_led_net1_red, !(x)); - -#define CRIS_LED_ACTIVE_SET(x) \ - do { \ - CRIS_LED_ACTIVE_SET_G((x) & CRIS_LED_GREEN); \ - CRIS_LED_ACTIVE_SET_R((x) & CRIS_LED_RED); \ - } while (0) - -#define CRIS_LED_ACTIVE_SET_G(x) \ - crisv32_io_set(&crisv32_led2_green, !(x)); -#define CRIS_LED_ACTIVE_SET_R(x) \ - crisv32_io_set(&crisv32_led2_red, !(x)); -#define CRIS_LED_DISK_WRITE(x) \ - do{\ - crisv32_io_set(&crisv32_led3_green, !(x)); \ - crisv32_io_set(&crisv32_led3_red, !(x)); \ - }while(0) -#define CRIS_LED_DISK_READ(x) \ - crisv32_io_set(&crisv32_led3_green, !(x)); - -#endif diff --git a/arch/cris/include/arch-v32/arch/irq.h b/arch/cris/include/arch-v32/arch/irq.h index 0c1b4d3a34e7..8270a1bbfdb6 100644 --- a/arch/cris/include/arch-v32/arch/irq.h +++ b/arch/cris/include/arch-v32/arch/irq.h @@ -4,7 +4,7 @@ #include <hwregs/intr_vect.h> /* Number of non-cpu interrupts. */ -#define NR_IRQS NBR_INTR_VECT /* Exceptions + IRQs */ +#define NR_IRQS (NBR_INTR_VECT + 256) /* Exceptions + IRQs */ #define FIRST_IRQ 0x31 /* Exception number for first IRQ */ #define NR_REAL_IRQS (NBR_INTR_VECT - FIRST_IRQ) /* IRQs */ #if NR_REAL_IRQS > 32 diff --git a/arch/cris/include/asm/eshlibld.h b/arch/cris/include/asm/eshlibld.h index 10ce36cf79a9..70aa448256b0 100644 --- a/arch/cris/include/asm/eshlibld.h +++ b/arch/cris/include/asm/eshlibld.h @@ -45,8 +45,7 @@ assumed that we want to share code when debugging (exposes more trouble). */ #ifndef SHARE_LIB_CORE -# if (defined(__KERNEL__) || !defined(RELOC_DEBUG)) \ - && !defined(CONFIG_SHARE_SHLIB_CORE) +# if (defined(__KERNEL__) || !defined(RELOC_DEBUG)) # define SHARE_LIB_CORE 0 # else # define SHARE_LIB_CORE 1 diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h index 752a3f45df60..cce8664d5dd6 100644 --- a/arch/cris/include/asm/io.h +++ b/arch/cris/include/asm/io.h @@ -2,7 +2,9 @@ #define _ASM_CRIS_IO_H #include <asm/page.h> /* for __va, __pa */ +#ifdef CONFIG_ETRAX_ARCH_V10 #include <arch/io.h> +#endif #include <asm-generic/iomap.h> #include <linux/kernel.h> diff --git a/arch/cris/include/uapi/asm/etraxgpio.h b/arch/cris/include/uapi/asm/etraxgpio.h index 461c089db765..c6e7d57c8b24 100644 --- a/arch/cris/include/uapi/asm/etraxgpio.h +++ b/arch/cris/include/uapi/asm/etraxgpio.h @@ -11,26 +11,6 @@ * g1-g7 and g25-g31 is both input and outputs but on different pins * Also note that some bits change pins depending on what interfaces * are enabled. - * - * For ETRAX FS (CONFIG_ETRAXFS): - * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction - * /dev/gpiob minor 1, 18 bit GPIO, each bit can change direction - * /dev/gpioc minor 3, 18 bit GPIO, each bit can change direction - * /dev/gpiod minor 4, 18 bit GPIO, each bit can change direction - * /dev/gpioe minor 5, 18 bit GPIO, each bit can change direction - * /dev/leds minor 2, Access to leds depending on kernelconfig - * - * For ARTPEC-3 (CONFIG_CRIS_MACH_ARTPEC3): - * /dev/gpioa minor 0, 32 bit GPIO, each bit can change direction - * /dev/gpiob minor 1, 32 bit GPIO, each bit can change direction - * /dev/gpioc minor 3, 16 bit GPIO, each bit can change direction - * /dev/gpiod minor 4, 32 bit GPIO, input only - * /dev/leds minor 2, Access to leds depending on kernelconfig - * /dev/pwm0 minor 16, PWM channel 0 on PA30 - * /dev/pwm1 minor 17, PWM channel 1 on PA31 - * /dev/pwm2 minor 18, PWM channel 2 on PB26 - * /dev/ppwm minor 19, PPWM channel - * */ #ifndef _ASM_ETRAXGPIO_H #define _ASM_ETRAXGPIO_H @@ -40,52 +20,12 @@ #define ETRAXGPIO_IOCTYPE 43 /* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ -#ifdef CONFIG_ETRAX_ARCH_V10 #define GPIO_MINOR_A 0 #define GPIO_MINOR_B 1 #define GPIO_MINOR_LEDS 2 #define GPIO_MINOR_G 3 #define GPIO_MINOR_LAST 3 #define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST -#endif - -#ifdef CONFIG_ETRAXFS -#define GPIO_MINOR_A 0 -#define GPIO_MINOR_B 1 -#define GPIO_MINOR_LEDS 2 -#define GPIO_MINOR_C 3 -#define GPIO_MINOR_D 4 -#define GPIO_MINOR_E 5 -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -#define GPIO_MINOR_V 6 -#define GPIO_MINOR_LAST 6 -#else -#define GPIO_MINOR_LAST 5 -#endif -#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST -#endif - -#ifdef CONFIG_CRIS_MACH_ARTPEC3 -#define GPIO_MINOR_A 0 -#define GPIO_MINOR_B 1 -#define GPIO_MINOR_LEDS 2 -#define GPIO_MINOR_C 3 -#define GPIO_MINOR_D 4 -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -#define GPIO_MINOR_V 6 -#define GPIO_MINOR_LAST 6 -#else -#define GPIO_MINOR_LAST 4 -#endif -#define GPIO_MINOR_FIRST_PWM 16 -#define GPIO_MINOR_PWM0 (GPIO_MINOR_FIRST_PWM+0) -#define GPIO_MINOR_PWM1 (GPIO_MINOR_FIRST_PWM+1) -#define GPIO_MINOR_PWM2 (GPIO_MINOR_FIRST_PWM+2) -#define GPIO_MINOR_PPWM (GPIO_MINOR_FIRST_PWM+3) -#define GPIO_MINOR_LAST_PWM GPIO_MINOR_PPWM -#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST_PWM -#endif - /* supported ioctl _IOC_NR's */ @@ -139,101 +79,4 @@ #define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output, */ /* *arg updated with current output pins. */ -/* The following ioctl's are applicable to the PWM channels only */ - -#define IO_PWM_SET_MODE 0x20 - -enum io_pwm_mode { - PWM_OFF = 0, /* disabled, deallocated */ - PWM_STANDARD = 1, /* 390 kHz, duty cycle 0..255/256 */ - PWM_FAST = 2, /* variable freq, w/ 10ns active pulse len */ - PWM_VARFREQ = 3, /* individually configurable high/low periods */ - PWM_SOFT = 4 /* software generated */ -}; - -struct io_pwm_set_mode { - enum io_pwm_mode mode; -}; - -/* Only for mode PWM_VARFREQ. Period lo/high set in increments of 10ns - * from 10ns (value = 0) to 81920ns (value = 8191) - * (Resulting frequencies range from 50 MHz (10ns + 10ns) down to - * 6.1 kHz (81920ns + 81920ns) at 50% duty cycle, to 12.2 kHz at min/max duty - * cycle (81920 + 10ns or 10ns + 81920ns, respectively).) - */ -#define IO_PWM_SET_PERIOD 0x21 - -struct io_pwm_set_period { - unsigned int lo; /* 0..8191 */ - unsigned int hi; /* 0..8191 */ -}; - -/* Only for modes PWM_STANDARD and PWM_FAST. - * For PWM_STANDARD, set duty cycle of 390 kHz PWM output signal, from - * 0 (value = 0) to 255/256 (value = 255). - * For PWM_FAST, set duty cycle of PWM output signal from - * 0% (value = 0) to 100% (value = 255). Output signal in this mode - * is a 10ns pulse surrounded by a high or low level depending on duty - * cycle (except for 0% and 100% which result in a constant output). - * Resulting output frequency varies from 50 MHz at 50% duty cycle, - * down to 390 kHz at min/max duty cycle. - */ -#define IO_PWM_SET_DUTY 0x22 - -struct io_pwm_set_duty { - int duty; /* 0..255 */ -}; - -/* Returns information about the latest PWM pulse. - * lo: Length of the latest low period, in units of 10ns. - * hi: Length of the latest high period, in units of 10ns. - * cnt: Time since last detected edge, in units of 10ns. - * - * The input source to PWM is decied by IO_PWM_SET_INPUT_SRC. - * - * NOTE: All PWM devices is connected to the same input source. - */ -#define IO_PWM_GET_PERIOD 0x23 - -struct io_pwm_get_period { - unsigned int lo; - unsigned int hi; - unsigned int cnt; -}; - -/* Sets the input source for the PWM input. For the src value see the - * register description for gio:rw_pwm_in_cfg. - * - * NOTE: All PWM devices is connected to the same input source. - */ -#define IO_PWM_SET_INPUT_SRC 0x24 -struct io_pwm_set_input_src { - unsigned int src; /* 0..7 */ -}; - -/* Sets the duty cycles in steps of 1/256, 0 = 0%, 255 = 100% duty cycle */ -#define IO_PPWM_SET_DUTY 0x25 - -struct io_ppwm_set_duty { - int duty; /* 0..255 */ -}; - -/* Configuraton struct for the IO_PWMCLK_SET_CONFIG ioctl to configure - * PWM capable gpio pins: - */ -#define IO_PWMCLK_SETGET_CONFIG 0x26 -struct gpio_pwmclk_conf { - unsigned int gpiopin; /* The pin number based on the opened device */ - unsigned int baseclk; /* The base clock to use, or sw will select one close*/ - unsigned int low; /* The number of low periods of the baseclk */ - unsigned int high; /* The number of high periods of the baseclk */ -}; - -/* Examples: - * To get a symmetric 12 MHz clock without knowing anything about the hardware: - * baseclk = 12000000, low = 0, high = 0 - * To just get info of current setting: - * baseclk = 0, low = 0, high = 0, the values will be updated by driver. - */ - #endif diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index e704f81f85cc..31b4bd288cad 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c @@ -18,7 +18,6 @@ #include <asm/pgtable.h> #include <asm/fasttimer.h> -extern unsigned long get_cmos_time(void); extern void __Udiv(void); extern void __Umod(void); extern void __Div(void); @@ -30,7 +29,6 @@ extern void __negdi2(void); extern void iounmap(volatile void * __iomem); /* Platform dependent support */ -EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(loops_per_usec); /* Math functions */ diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index 7780d379522f..2dda6da71521 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -39,31 +39,6 @@ extern unsigned long loops_per_jiffy; /* init/main.c */ unsigned long loops_per_usec; -int set_rtc_mmss(unsigned long nowtime) -{ - D(printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime)); - return 0; -} - -/* grab the time from the RTC chip */ -unsigned long get_cmos_time(void) -{ - return 0; -} - - -int update_persistent_clock(struct timespec now) -{ - return set_rtc_mmss(now.tv_sec); -} - -void read_persistent_clock(struct timespec *ts) -{ - ts->tv_sec = 0; - ts->tv_nsec = 0; -} - - extern void cris_profile_sample(struct pt_regs* regs); void diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 0da689def4cc..64f02d451aa8 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -32,8 +32,8 @@ */ #define ATOMIC_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v, i) (((v)->counter) = (i)) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) static inline int atomic_inc_return(atomic_t *v) { diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index 702ee539f87d..4435a445ae7e 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -11,8 +11,8 @@ #define ATOMIC_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v, i) (((v)->counter) = i) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) #include <linux/kernel.h> diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 811d61f6422d..55696c4100d4 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -48,7 +48,7 @@ static inline void atomic_set(atomic_t *v, int new) * * Assumes all word reads on our architecture are atomic. */ -#define atomic_read(v) ((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) /** * atomic_xchg - atomic diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index be4beeb77d57..8dfb5f6f6c35 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -21,11 +21,11 @@ #define ATOMIC_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic64_read(v) ACCESS_ONCE((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic64_read(v) READ_ONCE((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) -#define atomic64_set(v,i) (((v)->counter) = (i)) +#define atomic_set(v,i) WRITE_ONCE(((v)->counter), (i)) +#define atomic64_set(v,i) WRITE_ONCE(((v)->counter), (i)) #define ATOMIC_OP(op, c_op) \ static __inline__ int \ diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 99c96a5e6016..db73390568c8 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -11,7 +11,7 @@ -#define NR_syscalls 321 /* length of syscall table */ +#define NR_syscalls 322 /* length of syscall table */ /* * The following defines stop scripts/checksyscalls.sh from complaining about diff --git a/arch/ia64/include/uapi/asm/unistd.h b/arch/ia64/include/uapi/asm/unistd.h index 98e94e19a5a0..9038726e7d26 100644 --- a/arch/ia64/include/uapi/asm/unistd.h +++ b/arch/ia64/include/uapi/asm/unistd.h @@ -334,5 +334,6 @@ #define __NR_execveat 1342 #define __NR_userfaultfd 1343 #define __NR_membarrier 1344 +#define __NR_kcmp 1345 #endif /* _UAPI_ASM_IA64_UNISTD_H */ diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 37cc7a65cd3e..dcd97f84d065 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1770,5 +1770,6 @@ sys_call_table: data8 sys_execveat data8 sys_userfaultfd data8 sys_membarrier + data8 sys_kcmp // 1345 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 025e2a170493..ea35160d632b 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -28,7 +28,7 @@ * * Atomically reads the value of @v. */ -#define atomic_read(v) ACCESS_ONCE((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) /** * atomic_set - set atomic variable @@ -37,7 +37,7 @@ * * Atomically sets the value of @v to @i. */ -#define atomic_set(v,i) (((v)->counter) = (i)) +#define atomic_set(v,i) WRITE_ONCE(((v)->counter), (i)) #ifdef CONFIG_CHIP_M32700_TS1 #define __ATOMIC_CLOBBER , "r4" diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 039fac120cc0..4858178260f9 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -17,8 +17,8 @@ #define ATOMIC_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v, i) (((v)->counter) = i) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) /* * The ColdFire parts cannot do some immediate to memory operations, diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c index c86ac37d1983..cfe9aa422343 100644 --- a/arch/m68k/sun3/idprom.c +++ b/arch/m68k/sun3/idprom.c @@ -125,8 +125,5 @@ void __init idprom_init(void) display_system_type(idprom->id_machtype); - printk("Ethernet address: %x:%x:%x:%x:%x:%x\n", - idprom->id_ethaddr[0], idprom->id_ethaddr[1], - idprom->id_ethaddr[2], idprom->id_ethaddr[3], - idprom->id_ethaddr[4], idprom->id_ethaddr[5]); + printk("Ethernet address: %pM\n", idprom->id_ethaddr); } diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index 21c4c268b86c..a62581815624 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h @@ -3,7 +3,7 @@ #define ATOMIC_INIT(i) { (i) } -#define atomic_set(v, i) ((v)->counter = (i)) +#define atomic_set(v, i) WRITE_ONCE((v)->counter, (i)) #include <linux/compiler.h> diff --git a/arch/metag/include/asm/atomic_lock1.h b/arch/metag/include/asm/atomic_lock1.h index f8efe380fe8b..0295d9b8d5bf 100644 --- a/arch/metag/include/asm/atomic_lock1.h +++ b/arch/metag/include/asm/atomic_lock1.h @@ -10,7 +10,7 @@ static inline int atomic_read(const atomic_t *v) { - return (v)->counter; + return READ_ONCE((v)->counter); } /* diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 0352bc8d56b3..4f9eb0576884 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1094,7 +1094,7 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d, unsigned int pin; unsigned int trigger; - if (d->of_node != node) + if (irq_domain_get_of_node(d) != node) return -EINVAL; if (intsize < 2) @@ -2163,7 +2163,7 @@ static int octeon_irq_cib_map(struct irq_domain *d, if (hw >= host_data->max_bits) { pr_err("ERROR: %s mapping %u is to big!\n", - d->of_node->name, (unsigned)hw); + irq_domain_get_of_node(d)->name, (unsigned)hw); return -EINVAL; } diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig index 642b50946943..8b7429127a1d 100644 --- a/arch/mips/configs/pistachio_defconfig +++ b/arch/mips/configs/pistachio_defconfig @@ -257,7 +257,6 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_TEST=m CONFIG_MMC_DW=y -CONFIG_MMC_DW_IDMAC=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_RTC_CLASS=y diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 4c42fd9af777..f82d3af07931 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -30,7 +30,7 @@ * * Atomically reads the value of @v. */ -#define atomic_read(v) ACCESS_ONCE((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) /* * atomic_set - set atomic variable @@ -39,7 +39,7 @@ * * Atomically sets the value of @v to @i. */ -#define atomic_set(v, i) ((v)->counter = (i)) +#define atomic_set(v, i) WRITE_ONCE((v)->counter, (i)) #define ATOMIC_OP(op, c_op, asm_op) \ static __inline__ void atomic_##op(int i, atomic_t * v) \ @@ -315,14 +315,14 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) * @v: pointer of type atomic64_t * */ -#define atomic64_read(v) ACCESS_ONCE((v)->counter) +#define atomic64_read(v) READ_ONCE((v)->counter) /* * atomic64_set - set atomic variable * @v: pointer of type atomic64_t * @i: required value */ -#define atomic64_set(v, i) ((v)->counter = (i)) +#define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) #define ATOMIC64_OP(op, c_op, asm_op) \ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index 2e52cbd20ceb..7a584e0bf933 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -12,6 +12,4 @@ obj-y := sead3-lcd.o sead3-display.o sead3-init.o \ sead3-int.o sead3-platform.o sead3-reset.o \ sead3-setup.o sead3-time.o -obj-y += leds-sead3.o - obj-$(CONFIG_EARLY_PRINTK) += sead3-console.o diff --git a/arch/mips/mti-sead3/leds-sead3.c b/arch/mips/mti-sead3/leds-sead3.c deleted file mode 100644 index c938ceeb8848..000000000000 --- a/arch/mips/mti-sead3/leds-sead3.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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) 2012 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2015 Imagination Technologies, Inc. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/err.h> -#include <linux/io.h> - -#include <asm/mips-boards/sead3-addr.h> - -static void sead3_pled_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - writel(value, (void __iomem *)SEAD3_CPLD_P_LED); -} - -static void sead3_fled_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - writel(value, (void __iomem *)SEAD3_CPLD_F_LED); -} - -static struct led_classdev sead3_pled = { - .name = "sead3::pled", - .brightness_set = sead3_pled_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static struct led_classdev sead3_fled = { - .name = "sead3::fled", - .brightness_set = sead3_fled_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static int sead3_led_probe(struct platform_device *pdev) -{ - int ret; - - ret = led_classdev_register(&pdev->dev, &sead3_pled); - if (ret < 0) - return ret; - - ret = led_classdev_register(&pdev->dev, &sead3_fled); - if (ret < 0) - led_classdev_unregister(&sead3_pled); - - return ret; -} - -static int sead3_led_remove(struct platform_device *pdev) -{ - led_classdev_unregister(&sead3_pled); - led_classdev_unregister(&sead3_fled); - return 0; -} - -static struct platform_driver sead3_led_driver = { - .probe = sead3_led_probe, - .remove = sead3_led_remove, - .driver = { - .name = "sead3-led", - }, -}; - -module_platform_driver(sead3_led_driver); - -MODULE_AUTHOR("Kristian Kielhofner <kris@krisk.org>"); -MODULE_DESCRIPTION("SEAD3 LED driver"); -MODULE_LICENSE("GPL"); diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index 375e59140c9c..ce318d5ab23b 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -34,7 +34,7 @@ * * Atomically reads the value of @v. Note that the guaranteed */ -#define atomic_read(v) (ACCESS_ONCE((v)->counter)) +#define atomic_read(v) READ_ONCE((v)->counter) /** * atomic_set - set atomic variable @@ -43,7 +43,7 @@ * * Atomically sets the value of @v to @i. Note that the guaranteed */ -#define atomic_set(v, i) (((v)->counter) = (i)) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) #define ATOMIC_OP(op) \ static inline void atomic_##op(int i, atomic_t *v) \ diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 2536965d00ea..1d109990a022 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -67,7 +67,7 @@ static __inline__ void atomic_set(atomic_t *v, int i) static __inline__ int atomic_read(const atomic_t *v) { - return ACCESS_ONCE((v)->counter); + return READ_ONCE((v)->counter); } /* exported interface */ diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 6bc0ee4b1070..2c041b535a64 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -111,7 +111,7 @@ CONFIG_SCSI_QLA_FC=m CONFIG_SCSI_QLA_ISCSI=m CONFIG_SCSI_LPFC=m CONFIG_SCSI_VIRTIO=m -CONFIG_SCSI_DH=m +CONFIG_SCSI_DH=y CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 7991f37e5fe2..36871a4bfa54 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -114,7 +114,7 @@ CONFIG_SCSI_QLA_FC=m CONFIG_SCSI_QLA_ISCSI=m CONFIG_SCSI_LPFC=m CONFIG_SCSI_VIRTIO=m -CONFIG_SCSI_DH=m +CONFIG_SCSI_DH=y CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 0dc42c5082b7..5f8229e24fe6 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -3,7 +3,6 @@ #ifdef __KERNEL__ -#include <asm/reg.h> /* bytes per L1 cache line */ #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) @@ -40,12 +39,6 @@ struct ppc64_caches { }; extern struct ppc64_caches ppc64_caches; - -static inline void logmpp(u64 x) -{ - asm volatile(PPC_LOGMPP(R1) : : "r" (x)); -} - #endif /* __powerpc64__ && ! __ASSEMBLY__ */ #if defined(__ASSEMBLY__) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 827a38d7a9db..887c259556df 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -297,8 +297,6 @@ struct kvmppc_vcore { u32 arch_compat; ulong pcr; ulong dpdes; /* doorbell state (POWER8) */ - void *mpp_buffer; /* Micro Partition Prefetch buffer */ - bool mpp_buffer_is_valid; ulong conferring_threads; }; diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index cab6753f1be5..3f191f573d4f 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -61,8 +61,13 @@ struct machdep_calls { unsigned long addr, unsigned char *hpte_slot_array, int psize, int ssize, int local); - /* special for kexec, to be called in real mode, linear mapping is - * destroyed as well */ + /* + * Special for kexec. + * To be called in real mode with interrupts disabled. No locks are + * taken as such, concurrent access on pre POWER5 hardware could result + * in a deadlock. + * The linear mapping is destroyed as well. + */ void (*hpte_clear_all)(void); void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size, diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 790f5d1d9a46..7ab04fc59e24 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -141,7 +141,6 @@ #define PPC_INST_ISEL 0x7c00001e #define PPC_INST_ISEL_MASK 0xfc00003e #define PPC_INST_LDARX 0x7c0000a8 -#define PPC_INST_LOGMPP 0x7c0007e4 #define PPC_INST_LSWI 0x7c0004aa #define PPC_INST_LSWX 0x7c00042a #define PPC_INST_LWARX 0x7c000028 @@ -285,20 +284,6 @@ #define __PPC_EH(eh) 0 #endif -/* POWER8 Micro Partition Prefetch (MPP) parameters */ -/* Address mask is common for LOGMPP instruction and MPPR SPR */ -#define PPC_MPPE_ADDRESS_MASK 0xffffffffc000ULL - -/* Bits 60 and 61 of MPP SPR should be set to one of the following */ -/* Aborting the fetch is indeed setting 00 in the table size bits */ -#define PPC_MPPR_FETCH_ABORT (0x0ULL << 60) -#define PPC_MPPR_FETCH_WHOLE_TABLE (0x2ULL << 60) - -/* Bits 54 and 55 of register for LOGMPP instruction should be set to: */ -#define PPC_LOGMPP_LOG_L2 (0x02ULL << 54) -#define PPC_LOGMPP_LOG_L2L3 (0x01ULL << 54) -#define PPC_LOGMPP_LOG_ABORT (0x03ULL << 54) - /* Deal with instructions that older assemblers aren't aware of */ #define PPC_DCBAL(a, b) stringify_in_c(.long PPC_INST_DCBAL | \ __PPC_RA(a) | __PPC_RB(b)) @@ -307,8 +292,6 @@ #define PPC_LDARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LDARX | \ ___PPC_RT(t) | ___PPC_RA(a) | \ ___PPC_RB(b) | __PPC_EH(eh)) -#define PPC_LOGMPP(b) stringify_in_c(.long PPC_INST_LOGMPP | \ - __PPC_RB(b)) #define PPC_LWARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LWARX | \ ___PPC_RT(t) | ___PPC_RA(a) | \ ___PPC_RB(b) | __PPC_EH(eh)) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index aa1cc5f015ee..a908ada8e0a5 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -226,7 +226,6 @@ #define CTRL_TE 0x00c00000 /* thread enable */ #define CTRL_RUNLATCH 0x1 #define SPRN_DAWR 0xB4 -#define SPRN_MPPR 0xB8 /* Micro Partition Prefetch Register */ #define SPRN_RPR 0xBA /* Relative Priority Register */ #define SPRN_CIABR 0xBB #define CIABR_PRIV 0x3 diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 59503ed98e5f..3f1472a78f39 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -303,7 +303,7 @@ int dma_set_coherent_mask(struct device *dev, u64 mask) dev->coherent_dma_mask = mask; return 0; } -EXPORT_SYMBOL_GPL(dma_set_coherent_mask); +EXPORT_SYMBOL(dma_set_coherent_mask); #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 84bf934cf748..5a753fae8265 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -1043,6 +1043,9 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (!rtas.entry) + return -EINVAL; + if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 228049786888..9c26c5a96ea2 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -36,7 +36,6 @@ #include <asm/reg.h> #include <asm/cputable.h> -#include <asm/cache.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> #include <asm/uaccess.h> @@ -75,12 +74,6 @@ static DECLARE_BITMAP(default_enabled_hcalls, MAX_HCALL_OPCODE/4 + 1); -#if defined(CONFIG_PPC_64K_PAGES) -#define MPP_BUFFER_ORDER 0 -#elif defined(CONFIG_PPC_4K_PAGES) -#define MPP_BUFFER_ORDER 3 -#endif - static int dynamic_mt_modes = 6; module_param(dynamic_mt_modes, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dynamic_mt_modes, "Set of allowed dynamic micro-threading modes: 0 (= none), 2, 4, or 6 (= 2 or 4)"); @@ -1455,13 +1448,6 @@ static struct kvmppc_vcore *kvmppc_vcore_create(struct kvm *kvm, int core) vcore->kvm = kvm; INIT_LIST_HEAD(&vcore->preempt_list); - vcore->mpp_buffer_is_valid = false; - - if (cpu_has_feature(CPU_FTR_ARCH_207S)) - vcore->mpp_buffer = (void *)__get_free_pages( - GFP_KERNEL|__GFP_ZERO, - MPP_BUFFER_ORDER); - return vcore; } @@ -1894,33 +1880,6 @@ static int on_primary_thread(void) return 1; } -static void kvmppc_start_saving_l2_cache(struct kvmppc_vcore *vc) -{ - phys_addr_t phy_addr, mpp_addr; - - phy_addr = (phys_addr_t)virt_to_phys(vc->mpp_buffer); - mpp_addr = phy_addr & PPC_MPPE_ADDRESS_MASK; - - mtspr(SPRN_MPPR, mpp_addr | PPC_MPPR_FETCH_ABORT); - logmpp(mpp_addr | PPC_LOGMPP_LOG_L2); - - vc->mpp_buffer_is_valid = true; -} - -static void kvmppc_start_restoring_l2_cache(const struct kvmppc_vcore *vc) -{ - phys_addr_t phy_addr, mpp_addr; - - phy_addr = virt_to_phys(vc->mpp_buffer); - mpp_addr = phy_addr & PPC_MPPE_ADDRESS_MASK; - - /* We must abort any in-progress save operations to ensure - * the table is valid so that prefetch engine knows when to - * stop prefetching. */ - logmpp(mpp_addr | PPC_LOGMPP_LOG_ABORT); - mtspr(SPRN_MPPR, mpp_addr | PPC_MPPR_FETCH_WHOLE_TABLE); -} - /* * A list of virtual cores for each physical CPU. * These are vcores that could run but their runner VCPU tasks are @@ -2471,14 +2430,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) srcu_idx = srcu_read_lock(&vc->kvm->srcu); - if (vc->mpp_buffer_is_valid) - kvmppc_start_restoring_l2_cache(vc); - __kvmppc_vcore_entry(); - if (vc->mpp_buffer) - kvmppc_start_saving_l2_cache(vc); - srcu_read_unlock(&vc->kvm->srcu, srcu_idx); spin_lock(&vc->lock); @@ -3073,14 +3026,8 @@ static void kvmppc_free_vcores(struct kvm *kvm) { long int i; - for (i = 0; i < KVM_MAX_VCORES; ++i) { - if (kvm->arch.vcores[i] && kvm->arch.vcores[i]->mpp_buffer) { - struct kvmppc_vcore *vc = kvm->arch.vcores[i]; - free_pages((unsigned long)vc->mpp_buffer, - MPP_BUFFER_ORDER); - } + for (i = 0; i < KVM_MAX_VCORES; ++i) kfree(kvm->arch.vcores[i]); - } kvm->arch.online_vcores = 0; } diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 13befa35d8a8..c8822af10a58 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -582,13 +582,21 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, * be when they isi), and we are the only one left. We rely on our kernel * mapping being 0xC0's and the hardware ignoring those two real bits. * + * This must be called with interrupts disabled. + * + * Taking the native_tlbie_lock is unsafe here due to the possibility of + * lockdep being on. On pre POWER5 hardware, not taking the lock could + * cause deadlock. POWER5 and newer not taking the lock is fine. This only + * gets called during boot before secondary CPUs have come up and during + * crashdump and all bets are off anyway. + * * TODO: add batching support when enabled. remember, no dynamic memory here, * athough there is the control page available... */ static void native_hpte_clear(void) { unsigned long vpn = 0; - unsigned long slot, slots, flags; + unsigned long slot, slots; struct hash_pte *hptep = htab_address; unsigned long hpte_v; unsigned long pteg_count; @@ -596,13 +604,6 @@ static void native_hpte_clear(void) pteg_count = htab_hash_mask + 1; - local_irq_save(flags); - - /* we take the tlbie lock and hold it. Some hardware will - * deadlock if we try to tlbie from two processors at once. - */ - raw_spin_lock(&native_tlbie_lock); - slots = pteg_count * HPTES_PER_GROUP; for (slot = 0; slot < slots; slot++, hptep++) { @@ -614,8 +615,8 @@ static void native_hpte_clear(void) hpte_v = be64_to_cpu(hptep->v); /* - * Call __tlbie() here rather than tlbie() since we - * already hold the native_tlbie_lock. + * Call __tlbie() here rather than tlbie() since we can't take the + * native_tlbie_lock. */ if (hpte_v & HPTE_V_VALID) { hpte_decode(hptep, slot, &psize, &apsize, &ssize, &vpn); @@ -625,8 +626,6 @@ static void native_hpte_clear(void) } asm volatile("eieio; tlbsync; ptesync":::"memory"); - raw_spin_unlock(&native_tlbie_lock); - local_irq_restore(flags); } /* diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index b0382f3f1095..d1e65ce545b3 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -48,7 +48,7 @@ struct cpu_hw_events { unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES]; unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES]; - unsigned int group_flag; + unsigned int txn_flags; int n_txn_start; /* BHRB bits */ @@ -1441,7 +1441,7 @@ static int power_pmu_add(struct perf_event *event, int ef_flags) * skip the schedulability test here, it will be performed * at commit time(->commit_txn) as a whole */ - if (cpuhw->group_flag & PERF_EVENT_TXN) + if (cpuhw->txn_flags & PERF_PMU_TXN_ADD) goto nocheck; if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1)) @@ -1586,13 +1586,22 @@ static void power_pmu_stop(struct perf_event *event, int ef_flags) * Start group events scheduling transaction * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time + * + * We only support PERF_PMU_TXN_ADD transactions. Save the + * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD + * transactions. */ -static void power_pmu_start_txn(struct pmu *pmu) +static void power_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ + + cpuhw->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); - cpuhw->group_flag |= PERF_EVENT_TXN; cpuhw->n_txn_start = cpuhw->n_events; } @@ -1604,8 +1613,15 @@ static void power_pmu_start_txn(struct pmu *pmu) static void power_pmu_cancel_txn(struct pmu *pmu) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + unsigned int txn_flags; + + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + txn_flags = cpuhw->txn_flags; + cpuhw->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; - cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); } @@ -1621,7 +1637,15 @@ static int power_pmu_commit_txn(struct pmu *pmu) if (!ppmu) return -EAGAIN; + cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + if (cpuhw->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuhw->txn_flags = 0; + return 0; + } + n = cpuhw->n_events; if (check_excludes(cpuhw->event, cpuhw->flags, 0, n)) return -EAGAIN; @@ -1632,7 +1656,7 @@ static int power_pmu_commit_txn(struct pmu *pmu) for (i = cpuhw->n_txn_start; i < n; ++i) cpuhw->event[i]->hw.config = cpuhw->events[i]; - cpuhw->group_flag &= ~PERF_EVENT_TXN; + cpuhw->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index 527c8b98e97e..9f9dfda9ed2c 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -142,6 +142,15 @@ static struct attribute_group event_long_desc_group = { static struct kmem_cache *hv_page_cache; +DEFINE_PER_CPU(int, hv_24x7_txn_flags); +DEFINE_PER_CPU(int, hv_24x7_txn_err); + +struct hv_24x7_hw { + struct perf_event *events[255]; +}; + +DEFINE_PER_CPU(struct hv_24x7_hw, hv_24x7_hw); + /* * request_buffer and result_buffer are not required to be 4k aligned, * but are not allowed to cross any 4k boundary. Aligning them to 4k is @@ -1231,9 +1240,48 @@ static void update_event_count(struct perf_event *event, u64 now) static void h_24x7_event_read(struct perf_event *event) { u64 now; + struct hv_24x7_request_buffer *request_buffer; + struct hv_24x7_hw *h24x7hw; + int txn_flags; + + txn_flags = __this_cpu_read(hv_24x7_txn_flags); + + /* + * If in a READ transaction, add this counter to the list of + * counters to read during the next HCALL (i.e commit_txn()). + * If not in a READ transaction, go ahead and make the HCALL + * to read this counter by itself. + */ + + if (txn_flags & PERF_PMU_TXN_READ) { + int i; + int ret; - now = h_24x7_get_value(event); - update_event_count(event, now); + if (__this_cpu_read(hv_24x7_txn_err)) + return; + + request_buffer = (void *)get_cpu_var(hv_24x7_reqb); + + ret = add_event_to_24x7_request(event, request_buffer); + if (ret) { + __this_cpu_write(hv_24x7_txn_err, ret); + } else { + /* + * Assoicate the event with the HCALL request index, + * so ->commit_txn() can quickly find/update count. + */ + i = request_buffer->num_requests - 1; + + h24x7hw = &get_cpu_var(hv_24x7_hw); + h24x7hw->events[i] = event; + put_cpu_var(h24x7hw); + } + + put_cpu_var(hv_24x7_reqb); + } else { + now = h_24x7_get_value(event); + update_event_count(event, now); + } } static void h_24x7_event_start(struct perf_event *event, int flags) @@ -1255,6 +1303,117 @@ static int h_24x7_event_add(struct perf_event *event, int flags) return 0; } +/* + * 24x7 counters only support READ transactions. They are + * always counting and dont need/support ADD transactions. + * Cache the flags, but otherwise ignore transactions that + * are not PERF_PMU_TXN_READ. + */ +static void h_24x7_event_start_txn(struct pmu *pmu, unsigned int flags) +{ + struct hv_24x7_request_buffer *request_buffer; + struct hv_24x7_data_result_buffer *result_buffer; + + /* We should not be called if we are already in a txn */ + WARN_ON_ONCE(__this_cpu_read(hv_24x7_txn_flags)); + + __this_cpu_write(hv_24x7_txn_flags, flags); + if (flags & ~PERF_PMU_TXN_READ) + return; + + request_buffer = (void *)get_cpu_var(hv_24x7_reqb); + result_buffer = (void *)get_cpu_var(hv_24x7_resb); + + init_24x7_request(request_buffer, result_buffer); + + put_cpu_var(hv_24x7_resb); + put_cpu_var(hv_24x7_reqb); +} + +/* + * Clean up transaction state. + * + * NOTE: Ignore state of request and result buffers for now. + * We will initialize them during the next read/txn. + */ +static void reset_txn(void) +{ + __this_cpu_write(hv_24x7_txn_flags, 0); + __this_cpu_write(hv_24x7_txn_err, 0); +} + +/* + * 24x7 counters only support READ transactions. They are always counting + * and dont need/support ADD transactions. Clear ->txn_flags but otherwise + * ignore transactions that are not of type PERF_PMU_TXN_READ. + * + * For READ transactions, submit all pending 24x7 requests (i.e requests + * that were queued by h_24x7_event_read()), to the hypervisor and update + * the event counts. + */ +static int h_24x7_event_commit_txn(struct pmu *pmu) +{ + struct hv_24x7_request_buffer *request_buffer; + struct hv_24x7_data_result_buffer *result_buffer; + struct hv_24x7_result *resb; + struct perf_event *event; + u64 count; + int i, ret, txn_flags; + struct hv_24x7_hw *h24x7hw; + + txn_flags = __this_cpu_read(hv_24x7_txn_flags); + WARN_ON_ONCE(!txn_flags); + + ret = 0; + if (txn_flags & ~PERF_PMU_TXN_READ) + goto out; + + ret = __this_cpu_read(hv_24x7_txn_err); + if (ret) + goto out; + + request_buffer = (void *)get_cpu_var(hv_24x7_reqb); + result_buffer = (void *)get_cpu_var(hv_24x7_resb); + + ret = make_24x7_request(request_buffer, result_buffer); + if (ret) { + log_24x7_hcall(request_buffer, result_buffer, ret); + goto put_reqb; + } + + h24x7hw = &get_cpu_var(hv_24x7_hw); + + /* Update event counts from hcall */ + for (i = 0; i < request_buffer->num_requests; i++) { + resb = &result_buffer->results[i]; + count = be64_to_cpu(resb->elements[0].element_data[0]); + event = h24x7hw->events[i]; + h24x7hw->events[i] = NULL; + update_event_count(event, count); + } + + put_cpu_var(hv_24x7_hw); + +put_reqb: + put_cpu_var(hv_24x7_resb); + put_cpu_var(hv_24x7_reqb); +out: + reset_txn(); + return ret; +} + +/* + * 24x7 counters only support READ transactions. They are always counting + * and dont need/support ADD transactions. However, regardless of type + * of transaction, all we need to do is cleanup, so we don't have to check + * the type of transaction. + */ +static void h_24x7_event_cancel_txn(struct pmu *pmu) +{ + WARN_ON_ONCE(!__this_cpu_read(hv_24x7_txn_flags)); + reset_txn(); +} + static struct pmu h_24x7_pmu = { .task_ctx_nr = perf_invalid_context, @@ -1266,6 +1425,9 @@ static struct pmu h_24x7_pmu = { .start = h_24x7_event_start, .stop = h_24x7_event_stop, .read = h_24x7_event_read, + .start_txn = h_24x7_event_start_txn, + .commit_txn = h_24x7_event_commit_txn, + .cancel_txn = h_24x7_event_cancel_txn, }; static int hv_24x7_init(void) diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c index 396351db601b..7d5e295255b7 100644 --- a/arch/powerpc/perf/power8-pmu.c +++ b/arch/powerpc/perf/power8-pmu.c @@ -676,6 +676,9 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type) if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL) return -1; + if (branch_sample_type & PERF_SAMPLE_BRANCH_CALL) + return -1; + if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) { pmu_bhrb_filter |= POWER8_MMCRA_IFM1; return pmu_bhrb_filter; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index e0e68a1c0d3c..aed7714495c1 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -327,7 +327,7 @@ static void axon_msi_shutdown(struct platform_device *device) u32 tmp; pr_devel("axon_msi: disabling %s\n", - msic->irq_domain->of_node->full_name); + irq_domain_get_of_node(msic->irq_domain)->full_name); tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; msic_dcr_write(msic, MSIC_CTRL_REG, tmp); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 9d27de62dc62..54ee5743cb72 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -231,20 +231,23 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) const u32 *imap, *tmp; int imaplen, intsize, unit; struct device_node *iic; + struct device_node *of_node; + + of_node = irq_domain_get_of_node(pic->host); /* First, we check whether we have a real "interrupts" in the device * tree in case the device-tree is ever fixed */ - virq = irq_of_parse_and_map(pic->host->of_node, 0); + virq = irq_of_parse_and_map(of_node, 0); if (virq) return virq; /* Now do the horrible hacks */ - tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL); + tmp = of_get_property(of_node, "#interrupt-cells", NULL); if (tmp == NULL) return NO_IRQ; intsize = *tmp; - imap = of_get_property(pic->host->of_node, "interrupt-map", &imaplen); + imap = of_get_property(of_node, "interrupt-map", &imaplen); if (imap == NULL || imaplen < (intsize + 1)) return NO_IRQ; iic = of_find_node_by_phandle(imap[intsize]); diff --git a/arch/powerpc/platforms/pasemi/msi.c b/arch/powerpc/platforms/pasemi/msi.c index b304a9fe55cc..d9af76342d99 100644 --- a/arch/powerpc/platforms/pasemi/msi.c +++ b/arch/powerpc/platforms/pasemi/msi.c @@ -144,9 +144,11 @@ int mpic_pasemi_msi_init(struct mpic *mpic) { int rc; struct pci_controller *phb; + struct device_node *of_node; - if (!mpic->irqhost->of_node || - !of_device_is_compatible(mpic->irqhost->of_node, + of_node = irq_domain_get_of_node(mpic->irqhost); + if (!of_node || + !of_device_is_compatible(of_node, "pasemi,pwrficient-openpic")) return -ENODEV; diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c index 2c91ee7800b9..6ccfb6c1c707 100644 --- a/arch/powerpc/platforms/powernv/opal-irqchip.c +++ b/arch/powerpc/platforms/powernv/opal-irqchip.c @@ -137,7 +137,7 @@ static void opal_handle_irq_work(struct irq_work *work) static int opal_event_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { - return h->of_node == node; + return irq_domain_get_of_node(h) == node; } static int opal_event_xlate(struct irq_domain *h, struct device_node *np, diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 230f3a7cdea4..4296d55e88f3 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -487,9 +487,12 @@ int opal_machine_check(struct pt_regs *regs) * PRD component would have already got notified about this * error through other channels. * - * In any case, let us just fall through. We anyway heading - * down to panic path. + * If hardware marked this as an unrecoverable MCE, we are + * going to panic anyway. Even if it didn't, it's not safe to + * continue at this point, so we should explicitly panic. */ + + panic("PowerNV Unrecovered Machine Check"); return 0; } diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 8f70ba681a78..ca264833ee64 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -171,7 +171,26 @@ static void pnv_smp_cpu_kill_self(void) * so clear LPCR:PECE1. We keep PECE2 enabled. */ mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); + + /* + * Hard-disable interrupts, and then clear irq_happened flags + * that we can safely ignore while off-line, since they + * are for things for which we do no processing when off-line + * (or in the case of HMI, all the processing we need to do + * is done in lower-level real-mode code). + */ + hard_irq_disable(); + local_paca->irq_happened &= ~(PACA_IRQ_DEC | PACA_IRQ_HMI); + while (!generic_check_cpu_restart(cpu)) { + /* + * Clear IPI flag, since we don't handle IPIs while + * offline, except for those when changing micro-threading + * mode, which are handled explicitly below, and those + * for coming online, which are handled via + * generic_check_cpu_restart() calls. + */ + kvmppc_set_host_ipi(cpu, 0); ppc64_runlatch_off(); @@ -196,20 +215,20 @@ static void pnv_smp_cpu_kill_self(void) * having finished executing in a KVM guest, then srr1 * contains 0. */ - if ((srr1 & wmask) == SRR1_WAKEEE) { + if (((srr1 & wmask) == SRR1_WAKEEE) || + (local_paca->irq_happened & PACA_IRQ_EE)) { icp_native_flush_interrupt(); - local_paca->irq_happened &= PACA_IRQ_HARD_DIS; - smp_mb(); } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); - kvmppc_set_host_ipi(cpu, 0); } + local_paca->irq_happened &= ~(PACA_IRQ_EE | PACA_IRQ_DBELL); + smp_mb(); if (cpu_core_split_required()) continue; - if (!generic_check_cpu_restart(cpu)) + if (srr1 && !generic_check_cpu_restart(cpu)) DBG("CPU%d Unexpected exit while offline !\n", cpu); } mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 09787139834d..3db53e8aff92 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -194,11 +194,6 @@ static const struct os_area_db_id os_area_db_id_rtc_diff = { .key = OS_AREA_DB_KEY_RTC_DIFF }; -static const struct os_area_db_id os_area_db_id_video_mode = { - .owner = OS_AREA_DB_OWNER_LINUX, - .key = OS_AREA_DB_KEY_VIDEO_MODE -}; - #define SECONDS_FROM_1970_TO_2000 946684800LL /** diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index eca0b00794fa..bffcc7a486a1 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -181,7 +181,8 @@ static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { /* Exact match, unless ehv_pic node is NULL */ - return h->of_node == NULL || h->of_node == node; + struct device_node *of_node = irq_domain_get_of_node(h); + return of_node == NULL || of_node == node; } static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq, diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 48a576aa47b9..3a2be3676f43 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -110,7 +110,7 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data) int rc, hwirq; rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS_MAX, - msi_data->irqhost->of_node); + irq_domain_get_of_node(msi_data->irqhost)); if (rc) return rc; diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index e1a9c2c2d5d3..6f99ed3967fd 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -165,7 +165,8 @@ static struct resource pic_edgectrl_iores = { static int i8259_host_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { - return h->of_node == NULL || h->of_node == node; + struct device_node *of_node = irq_domain_get_of_node(h); + return of_node == NULL || of_node == node; } static int i8259_host_map(struct irq_domain *h, unsigned int virq, diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index b1297ab1599b..f76ee39cb337 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -675,7 +675,8 @@ static int ipic_host_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { /* Exact match, unless ipic node is NULL */ - return h->of_node == NULL || h->of_node == node; + struct device_node *of_node = irq_domain_get_of_node(h); + return of_node == NULL || of_node == node; } static int ipic_host_map(struct irq_domain *h, unsigned int virq, diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 537e5db85a06..cecd1156c185 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1011,7 +1011,8 @@ static int mpic_host_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { /* Exact match, unless mpic node is NULL */ - return h->of_node == NULL || h->of_node == node; + struct device_node *of_node = irq_domain_get_of_node(h); + return of_node == NULL || of_node == node; } static int mpic_host_map(struct irq_domain *h, unsigned int virq, diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 7dc39f35a4cc..1d48a5385905 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -84,7 +84,7 @@ int mpic_msi_init_allocator(struct mpic *mpic) int rc; rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources, - mpic->irqhost->of_node); + irq_domain_get_of_node(mpic->irqhost)); if (rc) return rc; diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index fbcc1f855a7f..ef36f16f9f6f 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -248,7 +248,8 @@ static int qe_ic_host_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { /* Exact match, unless qe_ic node is NULL */ - return h->of_node == NULL || h->of_node == node; + struct device_node *of_node = irq_domain_get_of_node(h); + return of_node == NULL || of_node == node; } static int qe_ic_host_map(struct irq_domain *h, unsigned int virq, diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index a9563409c36e..929c147e07b4 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -72,6 +72,7 @@ struct cpu_hw_events { atomic_t ctr_set[CPUMF_CTR_SET_MAX]; u64 state, tx_state; unsigned int flags; + unsigned int txn_flags; }; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .ctr_set = { @@ -82,6 +83,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { }, .state = 0, .flags = 0, + .txn_flags = 0, }; static int get_counter_set(u64 event) @@ -538,7 +540,7 @@ static int cpumf_pmu_add(struct perf_event *event, int flags) * For group events transaction, the authorization check is * done in cpumf_pmu_commit_txn(). */ - if (!(cpuhw->flags & PERF_EVENT_TXN)) + if (!(cpuhw->txn_flags & PERF_PMU_TXN_ADD)) if (validate_ctr_auth(&event->hw)) return -ENOENT; @@ -576,13 +578,22 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) /* * Start group events scheduling transaction. * Set flags to perform a single test at commit time. + * + * We only support PERF_PMU_TXN_ADD transactions. Save the + * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD + * transactions. */ -static void cpumf_pmu_start_txn(struct pmu *pmu) +static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ + + cpuhw->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); - cpuhw->flags |= PERF_EVENT_TXN; cpuhw->tx_state = cpuhw->state; } @@ -593,11 +604,18 @@ static void cpumf_pmu_start_txn(struct pmu *pmu) */ static void cpumf_pmu_cancel_txn(struct pmu *pmu) { + unsigned int txn_flags; struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + txn_flags = cpuhw->txn_flags; + cpuhw->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + WARN_ON(cpuhw->tx_state != cpuhw->state); - cpuhw->flags &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); } @@ -611,13 +629,20 @@ static int cpumf_pmu_commit_txn(struct pmu *pmu) struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); u64 state; + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + if (cpuhw->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuhw->txn_flags = 0; + return 0; + } + /* check if the updated state can be scheduled */ state = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); state >>= CPUMF_LCCTL_ENABLE_SHIFT; if ((state & cpuhw->info.auth_ctl) != state) return -ENOENT; - cpuhw->flags &= ~PERF_EVENT_TXN; + cpuhw->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index 05b9f74ce2d5..c399e1c55685 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -14,8 +14,8 @@ #define ATOMIC_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v,i) ((v)->counter = (i)) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) #if defined(CONFIG_GUSA_RB) #include <asm/atomic-grb.h> diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index fe20d14ae051..ceb5201a30ed 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -59,6 +59,7 @@ pages_do_alias(unsigned long addr1, unsigned long addr2) #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) extern void copy_page(void *to, void *from); +#define copy_user_page(to, from, vaddr, pg) __copy_user(to, from, PAGE_SIZE) struct page; struct vm_area_struct; diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c index 2e48eb8813ff..c90930de76ba 100644 --- a/arch/sparc/crypto/aes_glue.c +++ b/arch/sparc/crypto/aes_glue.c @@ -433,6 +433,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, .setkey = aes_set_key, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, @@ -452,6 +453,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, .setkey = aes_set_key, .encrypt = ctr_crypt, .decrypt = ctr_crypt, diff --git a/arch/sparc/crypto/camellia_glue.c b/arch/sparc/crypto/camellia_glue.c index 6bf2479a12fb..561a84d93cf6 100644 --- a/arch/sparc/crypto/camellia_glue.c +++ b/arch/sparc/crypto/camellia_glue.c @@ -274,6 +274,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = CAMELLIA_MIN_KEY_SIZE, .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, .setkey = camellia_set_key, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, diff --git a/arch/sparc/crypto/des_glue.c b/arch/sparc/crypto/des_glue.c index dd6a34fa6e19..61af794aa2d3 100644 --- a/arch/sparc/crypto/des_glue.c +++ b/arch/sparc/crypto/des_glue.c @@ -429,6 +429,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, .setkey = des_set_key, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, @@ -485,6 +486,7 @@ static struct crypto_alg algs[] = { { .blkcipher = { .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, .setkey = des3_ede_set_key, .encrypt = cbc3_encrypt, .decrypt = cbc3_decrypt, diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 917084ace49d..f2fbf9e16faf 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -14,11 +14,11 @@ #define ATOMIC_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) } -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic64_read(v) ACCESS_ONCE((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic64_read(v) READ_ONCE((v)->counter) -#define atomic_set(v, i) (((v)->counter) = i) -#define atomic64_set(v, i) (((v)->counter) = i) +#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) +#define atomic64_set(v, i) WRITE_ONCE(((v)->counter), (i)) #define ATOMIC_OP(op) \ void atomic_##op(int, atomic_t *); \ diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 689db65f8529..b0da5aedb336 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -108,7 +108,7 @@ struct cpu_hw_events { /* Enabled/disable state. */ int enabled; - unsigned int group_flag; + unsigned int txn_flags; }; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; @@ -1379,7 +1379,7 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags) * skip the schedulability test here, it will be performed * at commit time(->commit_txn) as a whole */ - if (cpuc->group_flag & PERF_EVENT_TXN) + if (cpuc->txn_flags & PERF_PMU_TXN_ADD) goto nocheck; if (check_excludes(cpuc->event, n0, 1)) @@ -1494,12 +1494,17 @@ static int sparc_pmu_event_init(struct perf_event *event) * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time */ -static void sparc_pmu_start_txn(struct pmu *pmu) +static void sparc_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ + + cpuhw->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); - cpuhw->group_flag |= PERF_EVENT_TXN; } /* @@ -1510,8 +1515,15 @@ static void sparc_pmu_start_txn(struct pmu *pmu) static void sparc_pmu_cancel_txn(struct pmu *pmu) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + unsigned int txn_flags; + + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + txn_flags = cpuhw->txn_flags; + cpuhw->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; - cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); } @@ -1528,14 +1540,20 @@ static int sparc_pmu_commit_txn(struct pmu *pmu) if (!sparc_pmu) return -EINVAL; - cpuc = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(!cpuc->txn_flags); /* no txn in flight */ + + if (cpuc->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuc->txn_flags = 0; + return 0; + } + n = cpuc->n_events; if (check_excludes(cpuc->event, 0, n)) return -EINVAL; if (sparc_check_constraints(cpuc->event, cpuc->events, n)) return -EAGAIN; - cpuc->group_flag &= ~PERF_EVENT_TXN; + cpuc->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h index 709798460763..9fc0107a9c5e 100644 --- a/arch/tile/include/asm/atomic.h +++ b/arch/tile/include/asm/atomic.h @@ -34,7 +34,7 @@ */ static inline int atomic_read(const atomic_t *v) { - return ACCESS_ONCE(v->counter); + return READ_ONCE(v->counter); } /** diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index 096a56d6ead4..51cabc26e387 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h @@ -24,7 +24,7 @@ /* First, the 32-bit atomic ops that are "real" on our 64-bit platform. */ -#define atomic_set(v, i) ((v)->counter = (i)) +#define atomic_set(v, i) WRITE_ONCE((v)->counter, (i)) /* * The smp_mb() operations throughout are to support the fact that @@ -82,8 +82,8 @@ static inline void atomic_xor(int i, atomic_t *v) #define ATOMIC64_INIT(i) { (i) } -#define atomic64_read(v) ((v)->counter) -#define atomic64_set(v, i) ((v)->counter = (i)) +#define atomic64_read(v) READ_ONCE((v)->counter) +#define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) static inline void atomic64_add(long i, atomic64_t *v) { diff --git a/arch/um/Makefile b/arch/um/Makefile index 098ab3333e7c..e3abe6f3156d 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -70,8 +70,8 @@ KBUILD_AFLAGS += $(ARCH_INCLUDE) USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ $(ARCH_INCLUDE) $(MODE_INCLUDE) $(filter -I%,$(CFLAGS)) \ - -D_FILE_OFFSET_BITS=64 -idirafter include \ - -D__KERNEL__ -D__UM_HOST__ + -D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \ + -idirafter $(obj)/include -D__KERNEL__ -D__UM_HOST__ #This will adjust *FLAGS accordingly to the platform. include $(ARCH_DIR)/Makefile-os-$(OS) diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index d8a9fce6ee2e..98783dd0fa2e 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -220,7 +220,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, show_regs(container_of(regs, struct pt_regs, regs)); panic("Segfault with no mm"); } - else if (!is_user && address < TASK_SIZE) { + else if (!is_user && address > PAGE_SIZE && address < TASK_SIZE) { show_regs(container_of(regs, struct pt_regs, regs)); panic("Kernel tried to access user memory at addr 0x%lx, ip 0x%lx", address, ip); diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index e3ee4a51ef63..3f02d4232812 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -96,7 +96,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) "ret = %d\n", -n); ret = n; } - CATCH_EINTR(waitpid(pid, NULL, __WCLONE)); + CATCH_EINTR(waitpid(pid, NULL, __WALL)); } out_free2: @@ -129,7 +129,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, return err; } if (stack_out == NULL) { - CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE)); + CATCH_EINTR(pid = waitpid(pid, &status, __WALL)); if (pid < 0) { err = -errno; printk(UM_KERN_ERR "run_helper_thread - wait failed, " @@ -148,7 +148,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, int helper_wait(int pid) { int ret, status; - int wflags = __WCLONE; + int wflags = __WALL; CATCH_EINTR(ret = waitpid(pid, &status, wflags)); if (ret < 0) { diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 96d058a87100..db3622f22b61 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1123,8 +1123,10 @@ config X86_REBOOTFIXUPS Say N otherwise. config MICROCODE - tristate "CPU microcode loading support" + bool "CPU microcode loading support" + default y depends on CPU_SUP_AMD || CPU_SUP_INTEL + depends on BLK_DEV_INITRD select FW_LOADER ---help--- @@ -1166,24 +1168,6 @@ config MICROCODE_OLD_INTERFACE def_bool y depends on MICROCODE -config MICROCODE_INTEL_EARLY - bool - -config MICROCODE_AMD_EARLY - bool - -config MICROCODE_EARLY - bool "Early load microcode" - depends on MICROCODE=y && BLK_DEV_INITRD - select MICROCODE_INTEL_EARLY if MICROCODE_INTEL - select MICROCODE_AMD_EARLY if MICROCODE_AMD - default y - help - This option provides functionality to read additional microcode data - at the beginning of initrd image. The data tells kernel to load - microcode to CPU's as early as possible. No functional change if no - microcode data is glued to the initrd, therefore it's safe to say Y. - config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" ---help--- @@ -2043,6 +2027,55 @@ config COMPAT_VDSO If unsure, say N: if you are compiling your own kernel, you are unlikely to be using a buggy version of glibc. +choice + prompt "vsyscall table for legacy applications" + depends on X86_64 + default LEGACY_VSYSCALL_EMULATE + help + Legacy user code that does not know how to find the vDSO expects + to be able to issue three syscalls by calling fixed addresses in + kernel space. Since this location is not randomized with ASLR, + it can be used to assist security vulnerability exploitation. + + This setting can be changed at boot time via the kernel command + line parameter vsyscall=[native|emulate|none]. + + On a system with recent enough glibc (2.14 or newer) and no + static binaries, you can say None without a performance penalty + to improve security. + + If unsure, select "Emulate". + + config LEGACY_VSYSCALL_NATIVE + bool "Native" + help + Actual executable code is located in the fixed vsyscall + address mapping, implementing time() efficiently. Since + this makes the mapping executable, it can be used during + security vulnerability exploitation (traditionally as + ROP gadgets). This configuration is not recommended. + + config LEGACY_VSYSCALL_EMULATE + bool "Emulate" + help + The kernel traps and emulates calls into the fixed + vsyscall address mapping. This makes the mapping + non-executable, but it still contains known contents, + which could be used in certain rare security vulnerability + exploits. This configuration is recommended when userspace + still uses the vsyscall area. + + config LEGACY_VSYSCALL_NONE + bool "None" + help + There will be no vsyscall mapping at all. This will + eliminate any risk of ASLR bypass due to the vsyscall + fixed address mapping. Attempts to use the vsyscalls + will be reported to dmesg, so that either old or + malicious userspace programs can be identified. + +endchoice + config CMDLINE_BOOL bool "Built-in kernel command line" ---help--- diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 747860c696e1..2dfaa72260b4 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -159,6 +159,12 @@ endif sp-$(CONFIG_X86_32) := esp sp-$(CONFIG_X86_64) := rsp +# do binutils support CFI? +cfi := $(call as-instr,.cfi_startproc\n.cfi_rel_offset $(sp-y)$(comma)0\n.cfi_endproc,-DCONFIG_AS_CFI=1) +# is .cfi_signal_frame supported too? +cfi-sigframe := $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1) +cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTIONS=1) + # does binutils support specific instructions? asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1) asinstr += $(call as-instr,pshufb %xmm0$(comma)%xmm0,-DCONFIG_AS_SSSE3=1) @@ -166,8 +172,8 @@ asinstr += $(call as-instr,crc32l %eax$(comma)%eax,-DCONFIG_AS_CRC32=1) avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1) avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1) -KBUILD_AFLAGS += $(asinstr) $(avx_instr) $(avx2_instr) -KBUILD_CFLAGS += $(asinstr) $(avx_instr) $(avx2_instr) +KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) +KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) LDFLAGS := -m elf_$(UTS_MACHINE) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index ee1b6d346b98..583d539a4197 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, static efi_status_t __gop_query32(struct efi_graphics_output_protocol_32 *gop32, struct efi_graphics_output_mode_info **info, - unsigned long *size, u32 *fb_base) + unsigned long *size, u64 *fb_base) { struct efi_graphics_output_protocol_mode_32 *mode; efi_status_t status; @@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, unsigned long nr_gops; u16 width, height; u32 pixels_per_scan_line; - u32 fb_base; + u32 ext_lfb_base; + u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; efi_status_t status; @@ -667,6 +668,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, bool conout_found = false; void *dummy = NULL; u32 h = handles[i]; + u64 current_fb_base; status = efi_call_early(handle_protocol, h, proto, (void **)&gop32); @@ -678,7 +680,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query32(gop32, &info, &size, &fb_base); + status = __gop_query32(gop32, &info, &size, ¤t_fb_base); if (status == EFI_SUCCESS && (!first_gop || conout_found)) { /* * Systems that use the UEFI Console Splitter may @@ -692,6 +694,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, pixel_format = info->pixel_format; pixel_info = info->pixel_information; pixels_per_scan_line = info->pixels_per_scan_line; + fb_base = current_fb_base; /* * Once we've found a GOP supporting ConOut, @@ -713,6 +716,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, si->lfb_width = width; si->lfb_height = height; si->lfb_base = fb_base; + + ext_lfb_base = (u64)(unsigned long)fb_base >> 32; + if (ext_lfb_base) { + si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; + si->ext_lfb_base = ext_lfb_base; + } + si->pages = 1; setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); @@ -727,7 +737,7 @@ out: static efi_status_t __gop_query64(struct efi_graphics_output_protocol_64 *gop64, struct efi_graphics_output_mode_info **info, - unsigned long *size, u32 *fb_base) + unsigned long *size, u64 *fb_base) { struct efi_graphics_output_protocol_mode_64 *mode; efi_status_t status; @@ -753,7 +763,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, unsigned long nr_gops; u16 width, height; u32 pixels_per_scan_line; - u32 fb_base; + u32 ext_lfb_base; + u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; efi_status_t status; @@ -770,6 +781,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, bool conout_found = false; void *dummy = NULL; u64 h = handles[i]; + u64 current_fb_base; status = efi_call_early(handle_protocol, h, proto, (void **)&gop64); @@ -781,7 +793,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query64(gop64, &info, &size, &fb_base); + status = __gop_query64(gop64, &info, &size, ¤t_fb_base); if (status == EFI_SUCCESS && (!first_gop || conout_found)) { /* * Systems that use the UEFI Console Splitter may @@ -795,6 +807,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, pixel_format = info->pixel_format; pixel_info = info->pixel_information; pixels_per_scan_line = info->pixels_per_scan_line; + fb_base = current_fb_base; /* * Once we've found a GOP supporting ConOut, @@ -816,6 +829,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, si->lfb_width = width; si->lfb_height = height; si->lfb_base = fb_base; + + ext_lfb_base = (u64)(unsigned long)fb_base >> 32; + if (ext_lfb_base) { + si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; + si->ext_lfb_base = ext_lfb_base; + } + si->pages = 1; setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 2d6b309c8e9a..6236b9ec4b76 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -154,7 +154,7 @@ extra_header_fields: #else .quad 0 # ImageBase #endif - .long CONFIG_PHYSICAL_ALIGN # SectionAlignment + .long 0x20 # SectionAlignment .long 0x20 # FileAlignment .word 0 # MajorOperatingSystemVersion .word 0 # MinorOperatingSystemVersion diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c index 80a0e4389c9a..bacaa13acac5 100644 --- a/arch/x86/crypto/camellia_aesni_avx_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx_glue.c @@ -554,6 +554,11 @@ static int __init camellia_aesni_init(void) { const char *feature_name; + if (!cpu_has_avx || !cpu_has_aes || !cpu_has_osxsave) { + pr_info("AVX or AES-NI instructions are not detected.\n"); + return -ENODEV; + } + if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) { pr_info("CPU feature '%s' is not supported.\n", feature_name); return -ENODEV; diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 80dcc9261ca3..a89fdbc1f0be 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -24,10 +24,19 @@ #include <asm/desc.h> #include <asm/traps.h> +#include <asm/vdso.h> +#include <asm/uaccess.h> #define CREATE_TRACE_POINTS #include <trace/events/syscalls.h> +static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) +{ + unsigned long top_of_stack = + (unsigned long)(regs + 1) + TOP_OF_KERNEL_STACK_PADDING; + return (struct thread_info *)(top_of_stack - THREAD_SIZE); +} + #ifdef CONFIG_CONTEXT_TRACKING /* Called on entry from user mode with IRQs off. */ __visible void enter_from_user_mode(void) @@ -66,13 +75,14 @@ static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch) */ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) { + struct thread_info *ti = pt_regs_to_thread_info(regs); unsigned long ret = 0; u32 work; - BUG_ON(regs != task_pt_regs(current)); + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) + BUG_ON(regs != task_pt_regs(current)); - work = ACCESS_ONCE(current_thread_info()->flags) & - _TIF_WORK_SYSCALL_ENTRY; + work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY; #ifdef CONFIG_CONTEXT_TRACKING /* @@ -154,11 +164,12 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch, unsigned long phase1_result) { + struct thread_info *ti = pt_regs_to_thread_info(regs); long ret = 0; - u32 work = ACCESS_ONCE(current_thread_info()->flags) & - _TIF_WORK_SYSCALL_ENTRY; + u32 work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY; - BUG_ON(regs != task_pt_regs(current)); + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) + BUG_ON(regs != task_pt_regs(current)); /* * If we stepped into a sysenter/syscall insn, it trapped in @@ -207,19 +218,12 @@ long syscall_trace_enter(struct pt_regs *regs) return syscall_trace_enter_phase2(regs, arch, phase1_result); } -static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) -{ - unsigned long top_of_stack = - (unsigned long)(regs + 1) + TOP_OF_KERNEL_STACK_PADDING; - return (struct thread_info *)(top_of_stack - THREAD_SIZE); -} +#define EXIT_TO_USERMODE_LOOP_FLAGS \ + (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ + _TIF_NEED_RESCHED | _TIF_USER_RETURN_NOTIFY) -/* Called with IRQs disabled. */ -__visible void prepare_exit_to_usermode(struct pt_regs *regs) +static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags) { - if (WARN_ON(!irqs_disabled())) - local_irq_disable(); - /* * In order to return to user mode, we need to have IRQs off with * none of _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_USER_RETURN_NOTIFY, @@ -229,14 +233,6 @@ __visible void prepare_exit_to_usermode(struct pt_regs *regs) * work to clear some of the flags can sleep. */ while (true) { - u32 cached_flags = - READ_ONCE(pt_regs_to_thread_info(regs)->flags); - - if (!(cached_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | - _TIF_UPROBE | _TIF_NEED_RESCHED | - _TIF_USER_RETURN_NOTIFY))) - break; - /* We have work to do. */ local_irq_enable(); @@ -260,50 +256,81 @@ __visible void prepare_exit_to_usermode(struct pt_regs *regs) /* Disable IRQs and retry */ local_irq_disable(); + + cached_flags = READ_ONCE(pt_regs_to_thread_info(regs)->flags); + + if (!(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS)) + break; + } +} + +/* Called with IRQs disabled. */ +__visible inline void prepare_exit_to_usermode(struct pt_regs *regs) +{ + u32 cached_flags; + + if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled())) + local_irq_disable(); + + lockdep_sys_exit(); + + cached_flags = + READ_ONCE(pt_regs_to_thread_info(regs)->flags); + + if (unlikely(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS)) + exit_to_usermode_loop(regs, cached_flags); user_enter(); } +#define SYSCALL_EXIT_WORK_FLAGS \ + (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ + _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT) + +static void syscall_slow_exit_work(struct pt_regs *regs, u32 cached_flags) +{ + bool step; + + audit_syscall_exit(regs); + + if (cached_flags & _TIF_SYSCALL_TRACEPOINT) + trace_sys_exit(regs, regs->ax); + + /* + * If TIF_SYSCALL_EMU is set, we only get here because of + * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). + * We already reported this syscall instruction in + * syscall_trace_enter(). + */ + step = unlikely( + (cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU)) + == _TIF_SINGLESTEP); + if (step || cached_flags & _TIF_SYSCALL_TRACE) + tracehook_report_syscall_exit(regs, step); +} + /* * Called with IRQs on and fully valid regs. Returns with IRQs off in a * state such that we can immediately switch to user mode. */ -__visible void syscall_return_slowpath(struct pt_regs *regs) +__visible inline void syscall_return_slowpath(struct pt_regs *regs) { struct thread_info *ti = pt_regs_to_thread_info(regs); u32 cached_flags = READ_ONCE(ti->flags); - bool step; CT_WARN_ON(ct_state() != CONTEXT_KERNEL); - if (WARN(irqs_disabled(), "syscall %ld left IRQs disabled", - regs->orig_ax)) + if (IS_ENABLED(CONFIG_PROVE_LOCKING) && + WARN(irqs_disabled(), "syscall %ld left IRQs disabled", regs->orig_ax)) local_irq_enable(); /* * First do one-time work. If these work items are enabled, we * want to run them exactly once per syscall exit with IRQs on. */ - if (cached_flags & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | - _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)) { - audit_syscall_exit(regs); - - if (cached_flags & _TIF_SYSCALL_TRACEPOINT) - trace_sys_exit(regs, regs->ax); - - /* - * If TIF_SYSCALL_EMU is set, we only get here because of - * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). - * We already reported this syscall instruction in - * syscall_trace_enter(). - */ - step = unlikely( - (cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU)) - == _TIF_SINGLESTEP); - if (step || cached_flags & _TIF_SYSCALL_TRACE) - tracehook_report_syscall_exit(regs, step); - } + if (unlikely(cached_flags & SYSCALL_EXIT_WORK_FLAGS)) + syscall_slow_exit_work(regs, cached_flags); #ifdef CONFIG_COMPAT /* @@ -316,3 +343,144 @@ __visible void syscall_return_slowpath(struct pt_regs *regs) local_irq_disable(); prepare_exit_to_usermode(regs); } + +#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) +/* + * Does a 32-bit syscall. Called with IRQs on and does all entry and + * exit work and returns with IRQs off. This function is extremely hot + * in workloads that use it, and it's usually called from + * do_fast_syscall_32, so forcibly inline it to improve performance. + */ +#ifdef CONFIG_X86_32 +/* 32-bit kernels use a trap gate for INT80, and the asm code calls here. */ +__visible +#else +/* 64-bit kernels use do_syscall_32_irqs_off() instead. */ +static +#endif +__always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) +{ + struct thread_info *ti = pt_regs_to_thread_info(regs); + unsigned int nr = (unsigned int)regs->orig_ax; + +#ifdef CONFIG_IA32_EMULATION + ti->status |= TS_COMPAT; +#endif + + if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY) { + /* + * Subtlety here: if ptrace pokes something larger than + * 2^32-1 into orig_ax, this truncates it. This may or + * may not be necessary, but it matches the old asm + * behavior. + */ + nr = syscall_trace_enter(regs); + } + + if (likely(nr < IA32_NR_syscalls)) { + /* + * It's possible that a 32-bit syscall implementation + * takes a 64-bit parameter but nonetheless assumes that + * the high bits are zero. Make sure we zero-extend all + * of the args. + */ + regs->ax = ia32_sys_call_table[nr]( + (unsigned int)regs->bx, (unsigned int)regs->cx, + (unsigned int)regs->dx, (unsigned int)regs->si, + (unsigned int)regs->di, (unsigned int)regs->bp); + } + + syscall_return_slowpath(regs); +} + +#ifdef CONFIG_X86_64 +/* Handles INT80 on 64-bit kernels */ +__visible void do_syscall_32_irqs_off(struct pt_regs *regs) +{ + local_irq_enable(); + do_syscall_32_irqs_on(regs); +} +#endif + +/* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */ +__visible long do_fast_syscall_32(struct pt_regs *regs) +{ + /* + * Called using the internal vDSO SYSENTER/SYSCALL32 calling + * convention. Adjust regs so it looks like we entered using int80. + */ + + unsigned long landing_pad = (unsigned long)current->mm->context.vdso + + vdso_image_32.sym_int80_landing_pad; + + /* + * SYSENTER loses EIP, and even SYSCALL32 needs us to skip forward + * so that 'regs->ip -= 2' lands back on an int $0x80 instruction. + * Fix it up. + */ + regs->ip = landing_pad; + + /* + * Fetch ECX from where the vDSO stashed it. + * + * WARNING: We are in CONTEXT_USER and RCU isn't paying attention! + */ + local_irq_enable(); + if ( +#ifdef CONFIG_X86_64 + /* + * Micro-optimization: the pointer we're following is explicitly + * 32 bits, so it can't be out of range. + */ + __get_user(*(u32 *)®s->cx, + (u32 __user __force *)(unsigned long)(u32)regs->sp) +#else + get_user(*(u32 *)®s->cx, + (u32 __user __force *)(unsigned long)(u32)regs->sp) +#endif + ) { + + /* User code screwed up. */ + local_irq_disable(); + regs->ax = -EFAULT; +#ifdef CONFIG_CONTEXT_TRACKING + enter_from_user_mode(); +#endif + prepare_exit_to_usermode(regs); + return 0; /* Keep it simple: use IRET. */ + } + + /* Now this is just like a normal syscall. */ + do_syscall_32_irqs_on(regs); + +#ifdef CONFIG_X86_64 + /* + * Opportunistic SYSRETL: if possible, try to return using SYSRETL. + * SYSRETL is available on all 64-bit CPUs, so we don't need to + * bother with SYSEXIT. + * + * Unlike 64-bit opportunistic SYSRET, we can't check that CX == IP, + * because the ECX fixup above will ensure that this is essentially + * never the case. + */ + return regs->cs == __USER32_CS && regs->ss == __USER_DS && + regs->ip == landing_pad && + (regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF)) == 0; +#else + /* + * Opportunistic SYSEXIT: if possible, try to return using SYSEXIT. + * + * Unlike 64-bit opportunistic SYSRET, we can't check that CX == IP, + * because the ECX fixup above will ensure that this is essentially + * never the case. + * + * We don't allow syscalls at all from VM86 mode, but we still + * need to check VM, because we might be returning from sys_vm86. + */ + return static_cpu_has(X86_FEATURE_SEP) && + regs->cs == __USER_CS && regs->ss == __USER_DS && + regs->ip == landing_pad && + (regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF | X86_EFLAGS_VM)) == 0; +#endif +} +#endif diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index b2909bf8cf70..3eb572ed3d7a 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -3,7 +3,7 @@ * * entry_32.S contains the system-call and low-level fault and trap handling routines. * - * Stack layout in 'syscall_exit': + * Stack layout while running C code: * ptrace needs to have all registers on the stack. * If the order here is changed, it needs to be * updated in fork.c:copy_process(), signal.c:do_signal(), @@ -153,13 +153,13 @@ #endif /* CONFIG_X86_32_LAZY_GS */ -.macro SAVE_ALL +.macro SAVE_ALL pt_regs_ax=%eax cld PUSH_GS pushl %fs pushl %es pushl %ds - pushl %eax + pushl \pt_regs_ax pushl %ebp pushl %edi pushl %esi @@ -211,7 +211,11 @@ ENTRY(ret_from_fork) popl %eax pushl $0x0202 # Reset kernel eflags popfl - jmp syscall_exit + + /* When we fork, we trace the syscall return in the child, too. */ + movl %esp, %eax + call syscall_return_slowpath + jmp restore_all END(ret_from_fork) ENTRY(ret_from_kernel_thread) @@ -224,7 +228,15 @@ ENTRY(ret_from_kernel_thread) movl PT_EBP(%esp), %eax call *PT_EBX(%esp) movl $0, PT_EAX(%esp) - jmp syscall_exit + + /* + * Kernel threads return to userspace as if returning from a syscall. + * We should check whether anything actually uses this path and, if so, + * consider switching it over to ret_from_fork. + */ + movl %esp, %eax + call syscall_return_slowpath + jmp restore_all ENDPROC(ret_from_kernel_thread) /* @@ -255,7 +267,6 @@ ret_from_intr: jb resume_kernel # not returning to v8086 or userspace ENTRY(resume_userspace) - LOCKDEP_SYS_EXIT DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF movl %esp, %eax @@ -276,76 +287,47 @@ need_resched: END(resume_kernel) #endif -/* - * SYSENTER_RETURN points to after the SYSENTER instruction - * in the vsyscall page. See vsyscall-sysentry.S, which defines - * the symbol. - */ - # SYSENTER call handler stub ENTRY(entry_SYSENTER_32) movl TSS_sysenter_sp0(%esp), %esp sysenter_past_esp: + pushl $__USER_DS /* pt_regs->ss */ + pushl %ecx /* pt_regs->cx */ + pushfl /* pt_regs->flags (except IF = 0) */ + orl $X86_EFLAGS_IF, (%esp) /* Fix IF */ + pushl $__USER_CS /* pt_regs->cs */ + pushl $0 /* pt_regs->ip = 0 (placeholder) */ + pushl %eax /* pt_regs->orig_ax */ + SAVE_ALL pt_regs_ax=$-ENOSYS /* save rest */ + /* - * Interrupts are disabled here, but we can't trace it until - * enough kernel state to call TRACE_IRQS_OFF can be called - but - * we immediately enable interrupts at that point anyway. - */ - pushl $__USER_DS - pushl %ebp - pushfl - orl $X86_EFLAGS_IF, (%esp) - pushl $__USER_CS - /* - * Push current_thread_info()->sysenter_return to the stack. - * A tiny bit of offset fixup is necessary: TI_sysenter_return - * is relative to thread_info, which is at the bottom of the - * kernel stack page. 4*4 means the 4 words pushed above; - * TOP_OF_KERNEL_STACK_PADDING takes us to the top of the stack; - * and THREAD_SIZE takes us to the bottom. + * User mode is traced as though IRQs are on, and SYSENTER + * turned them off. */ - pushl ((TI_sysenter_return) - THREAD_SIZE + TOP_OF_KERNEL_STACK_PADDING + 4*4)(%esp) - - pushl %eax - SAVE_ALL - ENABLE_INTERRUPTS(CLBR_NONE) - -/* - * Load the potential sixth argument from user stack. - * Careful about security. - */ - cmpl $__PAGE_OFFSET-3, %ebp - jae syscall_fault - ASM_STAC -1: movl (%ebp), %ebp - ASM_CLAC - movl %ebp, PT_EBP(%esp) - _ASM_EXTABLE(1b, syscall_fault) + TRACE_IRQS_OFF - GET_THREAD_INFO(%ebp) + movl %esp, %eax + call do_fast_syscall_32 + testl %eax, %eax + jz .Lsyscall_32_done - testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp) - jnz syscall_trace_entry -sysenter_do_call: - cmpl $(NR_syscalls), %eax - jae sysenter_badsys - call *sys_call_table(, %eax, 4) -sysenter_after_call: - movl %eax, PT_EAX(%esp) - LOCKDEP_SYS_EXIT - DISABLE_INTERRUPTS(CLBR_ANY) - TRACE_IRQS_OFF - movl TI_flags(%ebp), %ecx - testl $_TIF_ALLWORK_MASK, %ecx - jnz syscall_exit_work_irqs_off -sysenter_exit: -/* if something modifies registers it must also disable sysexit */ - movl PT_EIP(%esp), %edx - movl PT_OLDESP(%esp), %ecx - xorl %ebp, %ebp - TRACE_IRQS_ON +/* Opportunistic SYSEXIT */ + TRACE_IRQS_ON /* User mode traces as IRQs on. */ + movl PT_EIP(%esp), %edx /* pt_regs->ip */ + movl PT_OLDESP(%esp), %ecx /* pt_regs->sp */ 1: mov PT_FS(%esp), %fs PTGS_TO_GS + popl %ebx /* pt_regs->bx */ + addl $2*4, %esp /* skip pt_regs->cx and pt_regs->dx */ + popl %esi /* pt_regs->si */ + popl %edi /* pt_regs->di */ + popl %ebp /* pt_regs->bp */ + popl %eax /* pt_regs->ax */ + + /* + * Return back to the vDSO, which will pop ecx and edx. + * Don't bother with DS and ES (they already contain __USER_DS). + */ ENABLE_INTERRUPTS_SYSEXIT .pushsection .fixup, "ax" @@ -359,21 +341,18 @@ ENDPROC(entry_SYSENTER_32) # system call handler stub ENTRY(entry_INT80_32) ASM_CLAC - pushl %eax # save orig_eax - SAVE_ALL - GET_THREAD_INFO(%ebp) - # system call tracing in operation / emulation - testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp) - jnz syscall_trace_entry - cmpl $(NR_syscalls), %eax - jae syscall_badsys -syscall_call: - call *sys_call_table(, %eax, 4) -syscall_after_call: - movl %eax, PT_EAX(%esp) # store the return value -syscall_exit: - LOCKDEP_SYS_EXIT - jmp syscall_exit_work + pushl %eax /* pt_regs->orig_ax */ + SAVE_ALL pt_regs_ax=$-ENOSYS /* save rest */ + + /* + * User mode is traced as though IRQs are on. Unlike the 64-bit + * case, INT80 is a trap gate on 32-bit kernels, so interrupts + * are already on (unless user code is messing around with iopl). + */ + + movl %esp, %eax + call do_syscall_32_irqs_on +.Lsyscall_32_done: restore_all: TRACE_IRQS_IRET @@ -450,47 +429,6 @@ ldt_ss: #endif ENDPROC(entry_INT80_32) - # perform syscall exit tracing - ALIGN -syscall_trace_entry: - movl $-ENOSYS, PT_EAX(%esp) - movl %esp, %eax - call syscall_trace_enter - /* What it returned is what we'll actually use. */ - cmpl $(NR_syscalls), %eax - jnae syscall_call - jmp syscall_exit -END(syscall_trace_entry) - - # perform syscall exit tracing - ALIGN -syscall_exit_work_irqs_off: - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_ANY) - -syscall_exit_work: - movl %esp, %eax - call syscall_return_slowpath - jmp restore_all -END(syscall_exit_work) - -syscall_fault: - ASM_CLAC - GET_THREAD_INFO(%ebp) - movl $-EFAULT, PT_EAX(%esp) - jmp resume_userspace -END(syscall_fault) - -syscall_badsys: - movl $-ENOSYS, %eax - jmp syscall_after_call -END(syscall_badsys) - -sysenter_badsys: - movl $-ENOSYS, %eax - jmp sysenter_after_call -END(sysenter_badsys) - .macro FIXUP_ESPFIX_STACK /* * Switch back for ESPFIX stack to the normal zerobased stack diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 055a01de7c8d..53616ca03244 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -391,20 +391,16 @@ GLOBAL(stub_execveat) jmp return_from_execve END(stub_execveat) -#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION) +#if defined(CONFIG_X86_X32_ABI) .align 8 GLOBAL(stub_x32_execve) -GLOBAL(stub32_execve) call compat_sys_execve jmp return_from_execve -END(stub32_execve) END(stub_x32_execve) .align 8 GLOBAL(stub_x32_execveat) -GLOBAL(stub32_execveat) call compat_sys_execveat jmp return_from_execve -END(stub32_execveat) END(stub_x32_execveat) #endif @@ -557,7 +553,6 @@ ret_from_intr: jz retint_kernel /* Interrupt came from user space */ - LOCKDEP_SYS_EXIT_IRQ GLOBAL(retint_user) mov %rsp,%rdi call prepare_exit_to_usermode @@ -587,7 +582,7 @@ retint_kernel: * At this label, code paths which return to kernel and to user, * which come from interrupts/exception and from syscalls, merge. */ -restore_regs_and_iret: +GLOBAL(restore_regs_and_iret) RESTORE_EXTRA_REGS restore_c_regs_and_iret: RESTORE_C_REGS diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index a9360d40fb7f..c3201830a85e 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -16,16 +16,6 @@ #include <linux/linkage.h> #include <linux/err.h> -/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ -#include <linux/elf-em.h> -#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE) -#define __AUDIT_ARCH_LE 0x40000000 - -#ifndef CONFIG_AUDITSYSCALL -# define sysexit_audit ia32_ret_from_sys_call_irqs_off -# define sysretl_audit ia32_ret_from_sys_call_irqs_off -#endif - .section .entry.text, "ax" #ifdef CONFIG_PARAVIRT @@ -58,219 +48,87 @@ ENDPROC(native_usergs_sysret32) * with the int 0x80 path. */ ENTRY(entry_SYSENTER_compat) - /* - * Interrupts are off on entry. - * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, - * it is too small to ever cause noticeable irq latency. - */ + /* Interrupts are off on entry. */ SWAPGS_UNSAFE_STACK movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp - ENABLE_INTERRUPTS(CLBR_NONE) - /* Zero-extending 32-bit regs, do not remove */ - movl %ebp, %ebp + /* + * User tracing code (ptrace or signal handlers) might assume that + * the saved RAX contains a 32-bit number when we're invoking a 32-bit + * syscall. Just in case the high bits are nonzero, zero-extend + * the syscall number. (This could almost certainly be deleted + * with no ill effects.) + */ movl %eax, %eax - movl ASM_THREAD_INFO(TI_sysenter_return, %rsp, 0), %r10d - /* Construct struct pt_regs on stack */ pushq $__USER32_DS /* pt_regs->ss */ - pushq %rbp /* pt_regs->sp */ - pushfq /* pt_regs->flags */ + pushq %rcx /* pt_regs->sp */ + + /* + * Push flags. This is nasty. First, interrupts are currently + * off, but we need pt_regs->flags to have IF set. Second, even + * if TF was set when SYSENTER started, it's clear by now. We fix + * that later using TIF_SINGLESTEP. + */ + pushfq /* pt_regs->flags (except IF = 0) */ + orl $X86_EFLAGS_IF, (%rsp) /* Fix saved flags */ + ASM_CLAC /* Clear AC after saving FLAGS */ + pushq $__USER32_CS /* pt_regs->cs */ - pushq %r10 /* pt_regs->ip = thread_info->sysenter_return */ + xorq %r8,%r8 + pushq %r8 /* pt_regs->ip = 0 (placeholder) */ pushq %rax /* pt_regs->orig_ax */ pushq %rdi /* pt_regs->di */ pushq %rsi /* pt_regs->si */ pushq %rdx /* pt_regs->dx */ - pushq %rcx /* pt_regs->cx */ + pushq %rcx /* pt_regs->cx (will be overwritten) */ pushq $-ENOSYS /* pt_regs->ax */ + pushq %r8 /* pt_regs->r8 = 0 */ + pushq %r8 /* pt_regs->r9 = 0 */ + pushq %r8 /* pt_regs->r10 = 0 */ + pushq %r8 /* pt_regs->r11 = 0 */ + pushq %rbx /* pt_regs->rbx */ + pushq %rbp /* pt_regs->rbp */ + pushq %r8 /* pt_regs->r12 = 0 */ + pushq %r8 /* pt_regs->r13 = 0 */ + pushq %r8 /* pt_regs->r14 = 0 */ + pushq %r8 /* pt_regs->r15 = 0 */ cld - sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */ - - /* - * no need to do an access_ok check here because rbp has been - * 32-bit zero extended - */ - ASM_STAC -1: movl (%rbp), %ebp - _ASM_EXTABLE(1b, ia32_badarg) - ASM_CLAC /* * Sysenter doesn't filter flags, so we need to clear NT * ourselves. To save a few cycles, we can check whether * NT was set instead of doing an unconditional popfq. + * This needs to happen before enabling interrupts so that + * we don't get preempted with NT set. + * + * NB.: sysenter_fix_flags is a label with the code under it moved + * out-of-line as an optimization: NT is unlikely to be set in the + * majority of the cases and instead of polluting the I$ unnecessarily, + * we're keeping that code behind a branch which will predict as + * not-taken and therefore its instructions won't be fetched. */ testl $X86_EFLAGS_NT, EFLAGS(%rsp) jnz sysenter_fix_flags sysenter_flags_fixed: - orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz sysenter_tracesys - -sysenter_do_call: - /* 32-bit syscall -> 64-bit C ABI argument conversion */ - movl %edi, %r8d /* arg5 */ - movl %ebp, %r9d /* arg6 */ - xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */ - movl %ebx, %edi /* arg1 */ - movl %edx, %edx /* arg3 (zero extension) */ -sysenter_dispatch: - cmpq $(IA32_NR_syscalls-1), %rax - ja 1f - call *ia32_sys_call_table(, %rax, 8) - movq %rax, RAX(%rsp) -1: - DISABLE_INTERRUPTS(CLBR_NONE) - TRACE_IRQS_OFF - testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz sysexit_audit -sysexit_from_sys_call: /* - * NB: SYSEXIT is not obviously safe for 64-bit kernels -- an - * NMI between STI and SYSEXIT has poorly specified behavior, - * and and NMI followed by an IRQ with usergs is fatal. So - * we just pretend we're using SYSEXIT but we really use - * SYSRETL instead. - * - * This code path is still called 'sysexit' because it pairs - * with 'sysenter' and it uses the SYSENTER calling convention. + * User mode is traced as though IRQs are on, and SYSENTER + * turned them off. */ - andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - movl RIP(%rsp), %ecx /* User %eip */ - movq RAX(%rsp), %rax - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - xorl %edx, %edx /* Do not leak kernel information */ - xorq %r8, %r8 - xorq %r9, %r9 - xorq %r10, %r10 - movl EFLAGS(%rsp), %r11d /* User eflags */ - TRACE_IRQS_ON - - /* - * SYSRETL works even on Intel CPUs. Use it in preference to SYSEXIT, - * since it avoids a dicey window with interrupts enabled. - */ - movl RSP(%rsp), %esp - - /* - * USERGS_SYSRET32 does: - * gsbase = user's gs base - * eip = ecx - * rflags = r11 - * cs = __USER32_CS - * ss = __USER_DS - * - * The prologue set RIP(%rsp) to VDSO32_SYSENTER_RETURN, which does: - * - * pop %ebp - * pop %edx - * pop %ecx - * - * Therefore, we invoke SYSRETL with EDX and R8-R10 zeroed to - * avoid info leaks. R11 ends up with VDSO32_SYSENTER_RETURN's - * address (already known to user code), and R12-R15 are - * callee-saved and therefore don't contain any interesting - * kernel data. - */ - USERGS_SYSRET32 - -#ifdef CONFIG_AUDITSYSCALL - .macro auditsys_entry_common - /* - * At this point, registers hold syscall args in the 32-bit syscall ABI: - * EAX is syscall number, the 6 args are in EBX,ECX,EDX,ESI,EDI,EBP. - * - * We want to pass them to __audit_syscall_entry(), which is a 64-bit - * C function with 5 parameters, so shuffle them to match what - * the function expects: RDI,RSI,RDX,RCX,R8. - */ - movl %esi, %r8d /* arg5 (R8 ) <= 4th syscall arg (ESI) */ - xchg %ecx, %edx /* arg4 (RCX) <= 3rd syscall arg (EDX) */ - /* arg3 (RDX) <= 2nd syscall arg (ECX) */ - movl %ebx, %esi /* arg2 (RSI) <= 1st syscall arg (EBX) */ - movl %eax, %edi /* arg1 (RDI) <= syscall number (EAX) */ - call __audit_syscall_entry - - /* - * We are going to jump back to the syscall dispatch code. - * Prepare syscall args as required by the 64-bit C ABI. - * Registers clobbered by __audit_syscall_entry() are - * loaded from pt_regs on stack: - */ - movl ORIG_RAX(%rsp), %eax /* syscall number */ - movl %ebx, %edi /* arg1 */ - movl RCX(%rsp), %esi /* arg2 */ - movl RDX(%rsp), %edx /* arg3 */ - movl RSI(%rsp), %ecx /* arg4 */ - movl RDI(%rsp), %r8d /* arg5 */ - .endm - - .macro auditsys_exit exit - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_NONE) - testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz ia32_ret_from_sys_call - movl %eax, %esi /* second arg, syscall return value */ - cmpl $-MAX_ERRNO, %eax /* is it an error ? */ - jbe 1f - movslq %eax, %rsi /* if error sign extend to 64 bits */ -1: setbe %al /* 1 if error, 0 if not */ - movzbl %al, %edi /* zero-extend that into %edi */ - call __audit_syscall_exit - movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi - DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - testl %edi, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jz \exit - xorl %eax, %eax /* Do not leak kernel information */ - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %rax, R9(%rsp) - movq %rax, R8(%rsp) - jmp int_ret_from_sys_call_irqs_off - .endm -sysenter_auditsys: - auditsys_entry_common - movl %ebp, %r9d /* reload 6th syscall arg */ - jmp sysenter_dispatch - -sysexit_audit: - auditsys_exit sysexit_from_sys_call -#endif + movq %rsp, %rdi + call do_fast_syscall_32 + testl %eax, %eax + jz .Lsyscall_32_done + jmp sysret32_from_system_call sysenter_fix_flags: - pushq $(X86_EFLAGS_IF|X86_EFLAGS_FIXED) + pushq $X86_EFLAGS_FIXED popfq jmp sysenter_flags_fixed - -sysenter_tracesys: -#ifdef CONFIG_AUDITSYSCALL - testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jz sysenter_auditsys -#endif - SAVE_EXTRA_REGS - xorl %eax, %eax /* Do not leak kernel information */ - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %rax, R9(%rsp) - movq %rax, R8(%rsp) - movq %rsp, %rdi /* &pt_regs -> arg1 */ - call syscall_trace_enter - - /* Reload arg registers from stack. (see sysenter_tracesys) */ - movl RCX(%rsp), %ecx - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl %eax, %eax /* zero extension */ - - RESTORE_EXTRA_REGS - jmp sysenter_do_call ENDPROC(entry_SYSENTER_compat) /* @@ -298,21 +156,14 @@ ENDPROC(entry_SYSENTER_compat) * edi arg5 * esp user stack * 0(%esp) arg6 - * - * This is purely a fast path. For anything complicated we use the int 0x80 - * path below. We set up a complete hardware stack frame to share code - * with the int 0x80 path. */ ENTRY(entry_SYSCALL_compat) - /* - * Interrupts are off on entry. - * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, - * it is too small to ever cause noticeable irq latency. - */ + /* Interrupts are off on entry. */ SWAPGS_UNSAFE_STACK + + /* Stash user ESP and switch to the kernel stack. */ movl %esp, %r8d movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp - ENABLE_INTERRUPTS(CLBR_NONE) /* Zero-extending 32-bit regs, do not remove */ movl %eax, %eax @@ -327,162 +178,67 @@ ENTRY(entry_SYSCALL_compat) pushq %rdi /* pt_regs->di */ pushq %rsi /* pt_regs->si */ pushq %rdx /* pt_regs->dx */ - pushq %rbp /* pt_regs->cx */ - movl %ebp, %ecx + pushq %rcx /* pt_regs->cx (will be overwritten) */ pushq $-ENOSYS /* pt_regs->ax */ - sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */ + xorq %r8,%r8 + pushq %r8 /* pt_regs->r8 = 0 */ + pushq %r8 /* pt_regs->r9 = 0 */ + pushq %r8 /* pt_regs->r10 = 0 */ + pushq %r8 /* pt_regs->r11 = 0 */ + pushq %rbx /* pt_regs->rbx */ + pushq %rbp /* pt_regs->rbp */ + pushq %r8 /* pt_regs->r12 = 0 */ + pushq %r8 /* pt_regs->r13 = 0 */ + pushq %r8 /* pt_regs->r14 = 0 */ + pushq %r8 /* pt_regs->r15 = 0 */ /* - * No need to do an access_ok check here because r8 has been - * 32-bit zero extended: + * User mode is traced as though IRQs are on, and SYSENTER + * turned them off. */ - ASM_STAC -1: movl (%r8), %r9d - _ASM_EXTABLE(1b, ia32_badarg) - ASM_CLAC - orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz cstar_tracesys - -cstar_do_call: - /* 32-bit syscall -> 64-bit C ABI argument conversion */ - movl %edi, %r8d /* arg5 */ - /* r9 already loaded */ /* arg6 */ - xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */ - movl %ebx, %edi /* arg1 */ - movl %edx, %edx /* arg3 (zero extension) */ - -cstar_dispatch: - cmpq $(IA32_NR_syscalls-1), %rax - ja 1f - - call *ia32_sys_call_table(, %rax, 8) - movq %rax, RAX(%rsp) -1: - DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz sysretl_audit -sysretl_from_sys_call: - andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl RIP(%rsp), %ecx - movl EFLAGS(%rsp), %r11d - movq RAX(%rsp), %rax - xorq %r10, %r10 - xorq %r9, %r9 - xorq %r8, %r8 - TRACE_IRQS_ON - movl RSP(%rsp), %esp - /* - * 64-bit->32-bit SYSRET restores eip from ecx, - * eflags from r11 (but RF and VM bits are forced to 0), - * cs and ss are loaded from MSRs. - * (Note: 32-bit->32-bit SYSRET is different: since r11 - * does not exist, it merely sets eflags.IF=1). + movq %rsp, %rdi + call do_fast_syscall_32 + testl %eax, %eax + jz .Lsyscall_32_done + + /* Opportunistic SYSRET */ +sysret32_from_system_call: + TRACE_IRQS_ON /* User mode traces as IRQs on. */ + movq RBX(%rsp), %rbx /* pt_regs->rbx */ + movq RBP(%rsp), %rbp /* pt_regs->rbp */ + movq EFLAGS(%rsp), %r11 /* pt_regs->flags (in r11) */ + movq RIP(%rsp), %rcx /* pt_regs->ip (in rcx) */ + addq $RAX, %rsp /* Skip r8-r15 */ + popq %rax /* pt_regs->rax */ + popq %rdx /* Skip pt_regs->cx */ + popq %rdx /* pt_regs->dx */ + popq %rsi /* pt_regs->si */ + popq %rdi /* pt_regs->di */ + + /* + * USERGS_SYSRET32 does: + * GSBASE = user's GS base + * EIP = ECX + * RFLAGS = R11 + * CS = __USER32_CS + * SS = __USER_DS + * + * ECX will not match pt_regs->cx, but we're returning to a vDSO + * trampoline that will fix up RCX, so this is okay. * - * NB: On AMD CPUs with the X86_BUG_SYSRET_SS_ATTRS bug, the ss - * descriptor is not reinitialized. This means that we must - * avoid SYSRET with SS == NULL, which could happen if we schedule, - * exit the kernel, and re-enter using an interrupt vector. (All - * interrupt entries on x86_64 set SS to NULL.) We prevent that - * from happening by reloading SS in __switch_to. - */ - USERGS_SYSRET32 - -#ifdef CONFIG_AUDITSYSCALL -cstar_auditsys: - movl %r9d, R9(%rsp) /* register to be clobbered by call */ - auditsys_entry_common - movl R9(%rsp), %r9d /* reload 6th syscall arg */ - jmp cstar_dispatch - -sysretl_audit: - auditsys_exit sysretl_from_sys_call -#endif - -cstar_tracesys: -#ifdef CONFIG_AUDITSYSCALL - testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jz cstar_auditsys -#endif - xchgl %r9d, %ebp - SAVE_EXTRA_REGS - xorl %eax, %eax /* Do not leak kernel information */ - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %r9, R9(%rsp) - movq %rax, R8(%rsp) - movq %rsp, %rdi /* &pt_regs -> arg1 */ - call syscall_trace_enter - movl R9(%rsp), %r9d - - /* Reload arg registers from stack. (see sysenter_tracesys) */ - movl RCX(%rsp), %ecx - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl %eax, %eax /* zero extension */ - - RESTORE_EXTRA_REGS - xchgl %ebp, %r9d - jmp cstar_do_call + * R12-R15 are callee-saved, so they contain whatever was in them + * when the system call started, which is already known to user + * code. We zero R8-R10 to avoid info leaks. + */ + xorq %r8, %r8 + xorq %r9, %r9 + xorq %r10, %r10 + movq RSP-ORIG_RAX(%rsp), %rsp + USERGS_SYSRET32 END(entry_SYSCALL_compat) -ia32_badarg: - /* - * So far, we've entered kernel mode, set AC, turned on IRQs, and - * saved C regs except r8-r11. We haven't done any of the other - * standard entry work, though. We want to bail, but we shouldn't - * treat this as a syscall entry since we don't even know what the - * args are. Instead, treat this as a non-syscall entry, finish - * the entry work, and immediately exit after setting AX = -EFAULT. - * - * We're really just being polite here. Killing the task outright - * would be a reasonable action, too. Given that the only valid - * way to have gotten here is through the vDSO, and we already know - * that the stack pointer is bad, the task isn't going to survive - * for long no matter what we do. - */ - - ASM_CLAC /* undo STAC */ - movq $-EFAULT, RAX(%rsp) /* return -EFAULT if possible */ - - /* Fill in the rest of pt_regs */ - xorl %eax, %eax - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %rax, R9(%rsp) - movq %rax, R8(%rsp) - SAVE_EXTRA_REGS - - /* Turn IRQs back off. */ - DISABLE_INTERRUPTS(CLBR_NONE) - TRACE_IRQS_OFF - - /* Now finish entering normal kernel mode. */ -#ifdef CONFIG_CONTEXT_TRACKING - call enter_from_user_mode -#endif - - /* And exit again. */ - jmp retint_user - -ia32_ret_from_sys_call_irqs_off: - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_NONE) - -ia32_ret_from_sys_call: - xorl %eax, %eax /* Do not leak kernel information */ - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %rax, R9(%rsp) - movq %rax, R8(%rsp) - jmp int_ret_from_sys_call - /* * Emulated IA32 system calls via int 0x80. * @@ -507,14 +263,17 @@ ia32_ret_from_sys_call: ENTRY(entry_INT80_compat) /* * Interrupts are off on entry. - * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, - * it is too small to ever cause noticeable irq latency. */ PARAVIRT_ADJUST_EXCEPTION_FRAME SWAPGS - ENABLE_INTERRUPTS(CLBR_NONE) - /* Zero-extending 32-bit regs, do not remove */ + /* + * User tracing code (ptrace or signal handlers) might assume that + * the saved RAX contains a 32-bit number when we're invoking a 32-bit + * syscall. Just in case the high bits are nonzero, zero-extend + * the syscall number. (This could almost certainly be deleted + * with no ill effects.) + */ movl %eax, %eax /* Construct struct pt_regs on stack (iret frame is already on stack) */ @@ -524,67 +283,37 @@ ENTRY(entry_INT80_compat) pushq %rdx /* pt_regs->dx */ pushq %rcx /* pt_regs->cx */ pushq $-ENOSYS /* pt_regs->ax */ - pushq $0 /* pt_regs->r8 */ - pushq $0 /* pt_regs->r9 */ - pushq $0 /* pt_regs->r10 */ - pushq $0 /* pt_regs->r11 */ + xorq %r8,%r8 + pushq %r8 /* pt_regs->r8 = 0 */ + pushq %r8 /* pt_regs->r9 = 0 */ + pushq %r8 /* pt_regs->r10 = 0 */ + pushq %r8 /* pt_regs->r11 = 0 */ + pushq %rbx /* pt_regs->rbx */ + pushq %rbp /* pt_regs->rbp */ + pushq %r12 /* pt_regs->r12 */ + pushq %r13 /* pt_regs->r13 */ + pushq %r14 /* pt_regs->r14 */ + pushq %r15 /* pt_regs->r15 */ cld - sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */ - - orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz ia32_tracesys - -ia32_do_call: - /* 32-bit syscall -> 64-bit C ABI argument conversion */ - movl %edi, %r8d /* arg5 */ - movl %ebp, %r9d /* arg6 */ - xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */ - movl %ebx, %edi /* arg1 */ - movl %edx, %edx /* arg3 (zero extension) */ - cmpq $(IA32_NR_syscalls-1), %rax - ja 1f - call *ia32_sys_call_table(, %rax, 8) - movq %rax, RAX(%rsp) -1: - jmp int_ret_from_sys_call - -ia32_tracesys: - SAVE_EXTRA_REGS - movq %rsp, %rdi /* &pt_regs -> arg1 */ - call syscall_trace_enter /* - * Reload arg registers from stack in case ptrace changed them. - * Don't reload %eax because syscall_trace_enter() returned - * the %rax value we should see. But do truncate it to 32 bits. - * If it's -1 to make us punt the syscall, then (u32)-1 is still - * an appropriately invalid value. + * User mode is traced as though IRQs are on, and the interrupt + * gate turned them off. */ - movl RCX(%rsp), %ecx - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl %eax, %eax /* zero extension */ - RESTORE_EXTRA_REGS - jmp ia32_do_call -END(entry_INT80_compat) + TRACE_IRQS_OFF - .macro PTREGSCALL label, func - ALIGN -GLOBAL(\label) - leaq \func(%rip), %rax - jmp ia32_ptregs_common - .endm + movq %rsp, %rdi + call do_syscall_32_irqs_off +.Lsyscall_32_done: - PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn - PTREGSCALL stub32_sigreturn, sys32_sigreturn - PTREGSCALL stub32_fork, sys_fork - PTREGSCALL stub32_vfork, sys_vfork + /* Go back to user mode. */ + TRACE_IRQS_ON + SWAPGS + jmp restore_regs_and_iret +END(entry_INT80_compat) ALIGN GLOBAL(stub32_clone) - leaq sys_clone(%rip), %rax /* * The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr). * The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val). @@ -593,12 +322,4 @@ GLOBAL(stub32_clone) * so we need to swap arguments here before calling it: */ xchg %r8, %rcx - jmp ia32_ptregs_common - - ALIGN -ia32_ptregs_common: - SAVE_EXTRA_REGS 8 - call *%rax - RESTORE_EXTRA_REGS 8 - ret -END(ia32_ptregs_common) + jmp sys_clone diff --git a/arch/x86/entry/syscall_32.c b/arch/x86/entry/syscall_32.c index 8ea34f94e973..9a6649857106 100644 --- a/arch/x86/entry/syscall_32.c +++ b/arch/x86/entry/syscall_32.c @@ -4,24 +4,21 @@ #include <linux/sys.h> #include <linux/cache.h> #include <asm/asm-offsets.h> +#include <asm/syscall.h> #ifdef CONFIG_IA32_EMULATION #define SYM(sym, compat) compat #else #define SYM(sym, compat) sym -#define ia32_sys_call_table sys_call_table -#define __NR_syscall_compat_max __NR_syscall_max #endif -#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void SYM(sym, compat)(void) ; +#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage long SYM(sym, compat)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; #include <asm/syscalls_32.h> #undef __SYSCALL_I386 #define __SYSCALL_I386(nr, sym, compat) [nr] = SYM(sym, compat), -typedef asmlinkage void (*sys_call_ptr_t)(void); - -extern asmlinkage void sys_ni_syscall(void); +extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); __visible const sys_call_ptr_t ia32_sys_call_table[__NR_syscall_compat_max+1] = { /* diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c index 4ac730b37f0b..41283d22be7a 100644 --- a/arch/x86/entry/syscall_64.c +++ b/arch/x86/entry/syscall_64.c @@ -14,13 +14,13 @@ # define __SYSCALL_X32(nr, sym, compat) /* nothing */ #endif -#define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ; +#define __SYSCALL_64(nr, sym, compat) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; #include <asm/syscalls_64.h> #undef __SYSCALL_64 #define __SYSCALL_64(nr, sym, compat) [nr] = sym, -extern void sys_ni_syscall(void); +extern long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { /* diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 7663c455b9f6..caa2c712d1e7 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -8,7 +8,7 @@ # 0 i386 restart_syscall sys_restart_syscall 1 i386 exit sys_exit -2 i386 fork sys_fork stub32_fork +2 i386 fork sys_fork sys_fork 3 i386 read sys_read 4 i386 write sys_write 5 i386 open sys_open compat_sys_open @@ -17,7 +17,7 @@ 8 i386 creat sys_creat 9 i386 link sys_link 10 i386 unlink sys_unlink -11 i386 execve sys_execve stub32_execve +11 i386 execve sys_execve compat_sys_execve 12 i386 chdir sys_chdir 13 i386 time sys_time compat_sys_time 14 i386 mknod sys_mknod @@ -125,7 +125,7 @@ 116 i386 sysinfo sys_sysinfo compat_sys_sysinfo 117 i386 ipc sys_ipc compat_sys_ipc 118 i386 fsync sys_fsync -119 i386 sigreturn sys_sigreturn stub32_sigreturn +119 i386 sigreturn sys_sigreturn sys32_sigreturn 120 i386 clone sys_clone stub32_clone 121 i386 setdomainname sys_setdomainname 122 i386 uname sys_newuname @@ -179,7 +179,7 @@ 170 i386 setresgid sys_setresgid16 171 i386 getresgid sys_getresgid16 172 i386 prctl sys_prctl -173 i386 rt_sigreturn sys_rt_sigreturn stub32_rt_sigreturn +173 i386 rt_sigreturn sys_rt_sigreturn sys32_rt_sigreturn 174 i386 rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction 175 i386 rt_sigprocmask sys_rt_sigprocmask 176 i386 rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending @@ -196,7 +196,7 @@ 187 i386 sendfile sys_sendfile compat_sys_sendfile 188 i386 getpmsg 189 i386 putpmsg -190 i386 vfork sys_vfork stub32_vfork +190 i386 vfork sys_vfork sys_vfork 191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit 192 i386 mmap2 sys_mmap_pgoff 193 i386 truncate64 sys_truncate64 sys32_truncate64 @@ -364,7 +364,7 @@ 355 i386 getrandom sys_getrandom 356 i386 memfd_create sys_memfd_create 357 i386 bpf sys_bpf -358 i386 execveat sys_execveat stub32_execveat +358 i386 execveat sys_execveat compat_sys_execveat 359 i386 socket sys_socket 360 i386 socketpair sys_socketpair 361 i386 bind sys_bind diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index a3d0767a6b29..265c0ed68118 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -19,9 +19,7 @@ obj-y += vma.o # vDSO images to build vdso_img-$(VDSO64-y) += 64 vdso_img-$(VDSOX32-y) += x32 -vdso_img-$(VDSO32-y) += 32-int80 -vdso_img-$(CONFIG_IA32_EMULATION) += 32-syscall -vdso_img-$(VDSO32-y) += 32-sysenter +vdso_img-$(VDSO32-y) += 32 obj-$(VDSO32-y) += vdso32-setup.o @@ -69,7 +67,7 @@ $(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso%.so $(obj)/vdso2c FORCE CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \ -fno-omit-frame-pointer -foptimize-sibling-calls \ - -DDISABLE_BRANCH_PROFILING + -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO $(vobjs): KBUILD_CFLAGS += $(CFL) @@ -122,15 +120,6 @@ $(obj)/%.so: $(obj)/%.so.dbg $(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE $(call if_changed,vdso) -# -# Build multiple 32-bit vDSO images to choose from at boot time. -# -vdso32.so-$(VDSO32-y) += int80 -vdso32.so-$(CONFIG_IA32_EMULATION) += syscall -vdso32.so-$(VDSO32-y) += sysenter - -vdso32-images = $(vdso32.so-y:%=vdso32-%.so) - CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds) VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1 @@ -139,14 +128,12 @@ VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1 override obj-dirs = $(dir $(obj)) $(obj)/vdso32/ targets += vdso32/vdso32.lds -targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) +targets += vdso32/note.o vdso32/vclock_gettime.o vdso32/system_call.o targets += vdso32/vclock_gettime.o -$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) - -KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) -$(vdso32-images:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32) -$(vdso32-images:%=$(obj)/%.dbg): asflags-$(CONFIG_X86_64) += -m32 +KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) -DBUILD_VDSO +$(obj)/vdso32.so.dbg: KBUILD_AFLAGS = $(KBUILD_AFLAGS_32) +$(obj)/vdso32.so.dbg: asflags-$(CONFIG_X86_64) += -m32 KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32)) @@ -157,13 +144,13 @@ KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector) KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) KBUILD_CFLAGS_32 += -fno-omit-frame-pointer KBUILD_CFLAGS_32 += -DDISABLE_BRANCH_PROFILING -$(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) +$(obj)/vdso32.so.dbg: KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) -$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \ - $(obj)/vdso32/vdso32.lds \ - $(obj)/vdso32/vclock_gettime.o \ - $(obj)/vdso32/note.o \ - $(obj)/vdso32/%.o +$(obj)/vdso32.so.dbg: FORCE \ + $(obj)/vdso32/vdso32.lds \ + $(obj)/vdso32/vclock_gettime.o \ + $(obj)/vdso32/note.o \ + $(obj)/vdso32/system_call.o $(call if_changed,vdso) # @@ -206,4 +193,4 @@ $(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso FORCE PHONY += vdso_install $(vdso_img_insttargets) vdso_install: $(vdso_img_insttargets) FORCE -clean-files := vdso32-syscall* vdso32-sysenter* vdso32-int80* vdso64* vdso-image-*.c vdsox32.so* +clean-files := vdso32.so vdso32.so.dbg vdso64* vdso-image-*.c vdsox32.so* diff --git a/arch/x86/entry/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c index 8627db24a7f6..785d9922b106 100644 --- a/arch/x86/entry/vdso/vdso2c.c +++ b/arch/x86/entry/vdso/vdso2c.c @@ -98,10 +98,10 @@ struct vdso_sym required_syms[] = { "VDSO_FAKE_SECTION_TABLE_END", false }, {"VDSO32_NOTE_MASK", true}, - {"VDSO32_SYSENTER_RETURN", true}, {"__kernel_vsyscall", true}, {"__kernel_sigreturn", true}, {"__kernel_rt_sigreturn", true}, + {"int80_landing_pad", true}, }; __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) diff --git a/arch/x86/entry/vdso/vdso32-setup.c b/arch/x86/entry/vdso/vdso32-setup.c index e904c270573b..08a317a9ae4b 100644 --- a/arch/x86/entry/vdso/vdso32-setup.c +++ b/arch/x86/entry/vdso/vdso32-setup.c @@ -48,35 +48,9 @@ __setup("vdso32=", vdso32_setup); __setup_param("vdso=", vdso_setup, vdso32_setup, 0); #endif -#ifdef CONFIG_X86_64 - -#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) -#define vdso32_syscall() (boot_cpu_has(X86_FEATURE_SYSCALL32)) - -#else /* CONFIG_X86_32 */ - -#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP)) -#define vdso32_syscall() (0) - -#endif /* CONFIG_X86_64 */ - -#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT) -const struct vdso_image *selected_vdso32; -#endif - int __init sysenter_setup(void) { -#ifdef CONFIG_COMPAT - if (vdso32_syscall()) - selected_vdso32 = &vdso_image_32_syscall; - else -#endif - if (vdso32_sysenter()) - selected_vdso32 = &vdso_image_32_sysenter; - else - selected_vdso32 = &vdso_image_32_int80; - - init_vdso_image(selected_vdso32); + init_vdso_image(&vdso_image_32); return 0; } diff --git a/arch/x86/entry/vdso/vdso32/int80.S b/arch/x86/entry/vdso/vdso32/int80.S deleted file mode 100644 index b15b7c01aedb..000000000000 --- a/arch/x86/entry/vdso/vdso32/int80.S +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Code for the vDSO. This version uses the old int $0x80 method. - * - * First get the common code for the sigreturn entry points. - * This must come first. - */ -#include "sigreturn.S" - - .text - .globl __kernel_vsyscall - .type __kernel_vsyscall,@function - ALIGN -__kernel_vsyscall: -.LSTART_vsyscall: - int $0x80 - ret -.LEND_vsyscall: - .size __kernel_vsyscall,.-.LSTART_vsyscall - .previous - - .section .eh_frame,"a",@progbits -.LSTARTFRAMEDLSI: - .long .LENDCIEDLSI-.LSTARTCIEDLSI -.LSTARTCIEDLSI: - .long 0 /* CIE ID */ - .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ - .uleb128 1 /* Code alignment factor */ - .sleb128 -4 /* Data alignment factor */ - .byte 8 /* Return address register column */ - .uleb128 1 /* Augmentation value length */ - .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ - .byte 0x0c /* DW_CFA_def_cfa */ - .uleb128 4 - .uleb128 4 - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .uleb128 1 - .align 4 -.LENDCIEDLSI: - .long .LENDFDEDLSI-.LSTARTFDEDLSI /* Length FDE */ -.LSTARTFDEDLSI: - .long .LSTARTFDEDLSI-.LSTARTFRAMEDLSI /* CIE pointer */ - .long .LSTART_vsyscall-. /* PC-relative start address */ - .long .LEND_vsyscall-.LSTART_vsyscall - .uleb128 0 - .align 4 -.LENDFDEDLSI: - .previous - - /* - * Pad out the segment to match the size of the sysenter.S version. - */ -VDSO32_vsyscall_eh_frame_size = 0x40 - .section .data,"aw",@progbits - .space VDSO32_vsyscall_eh_frame_size-(.LENDFDEDLSI-.LSTARTFRAMEDLSI), 0 - .previous diff --git a/arch/x86/entry/vdso/vdso32/syscall.S b/arch/x86/entry/vdso/vdso32/syscall.S deleted file mode 100644 index 6b286bb5251c..000000000000 --- a/arch/x86/entry/vdso/vdso32/syscall.S +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Code for the vDSO. This version uses the syscall instruction. - * - * First get the common code for the sigreturn entry points. - * This must come first. - */ -#define SYSCALL_ENTER_KERNEL syscall -#include "sigreturn.S" - -#include <asm/segment.h> - - .text - .globl __kernel_vsyscall - .type __kernel_vsyscall,@function - ALIGN -__kernel_vsyscall: -.LSTART_vsyscall: - push %ebp -.Lpush_ebp: - movl %ecx, %ebp - syscall - movl %ebp, %ecx - popl %ebp -.Lpop_ebp: - ret -.LEND_vsyscall: - .size __kernel_vsyscall,.-.LSTART_vsyscall - - .section .eh_frame,"a",@progbits -.LSTARTFRAME: - .long .LENDCIE-.LSTARTCIE -.LSTARTCIE: - .long 0 /* CIE ID */ - .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ - .uleb128 1 /* Code alignment factor */ - .sleb128 -4 /* Data alignment factor */ - .byte 8 /* Return address register column */ - .uleb128 1 /* Augmentation value length */ - .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ - .byte 0x0c /* DW_CFA_def_cfa */ - .uleb128 4 - .uleb128 4 - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .uleb128 1 - .align 4 -.LENDCIE: - - .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */ -.LSTARTFDE1: - .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */ - .long .LSTART_vsyscall-. /* PC-relative start address */ - .long .LEND_vsyscall-.LSTART_vsyscall - .uleb128 0 /* Augmentation length */ - /* What follows are the instructions for the table generation. - We have to record all changes of the stack pointer. */ - .byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .uleb128 8 - .byte 0x85, 0x02 /* DW_CFA_offset %ebp -8 */ - .byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */ - .byte 0xc5 /* DW_CFA_restore %ebp */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .uleb128 4 - .align 4 -.LENDFDE1: - .previous - - /* - * Pad out the segment to match the size of the sysenter.S version. - */ -VDSO32_vsyscall_eh_frame_size = 0x40 - .section .data,"aw",@progbits - .space VDSO32_vsyscall_eh_frame_size-(.LENDFDE1-.LSTARTFRAME), 0 - .previous diff --git a/arch/x86/entry/vdso/vdso32/sysenter.S b/arch/x86/entry/vdso/vdso32/sysenter.S deleted file mode 100644 index e354bceee0e0..000000000000 --- a/arch/x86/entry/vdso/vdso32/sysenter.S +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Code for the vDSO. This version uses the sysenter instruction. - * - * First get the common code for the sigreturn entry points. - * This must come first. - */ -#include "sigreturn.S" - -/* - * The caller puts arg2 in %ecx, which gets pushed. The kernel will use - * %ecx itself for arg2. The pushing is because the sysexit instruction - * (found in entry.S) requires that we clobber %ecx with the desired %esp. - * User code might expect that %ecx is unclobbered though, as it would be - * for returning via the iret instruction, so we must push and pop. - * - * The caller puts arg3 in %edx, which the sysexit instruction requires - * for %eip. Thus, exactly as for arg2, we must push and pop. - * - * Arg6 is different. The caller puts arg6 in %ebp. Since the sysenter - * instruction clobbers %esp, the user's %esp won't even survive entry - * into the kernel. We store %esp in %ebp. Code in entry.S must fetch - * arg6 from the stack. - * - * You can not use this vsyscall for the clone() syscall because the - * three words on the parent stack do not get copied to the child. - */ - .text - .globl __kernel_vsyscall - .type __kernel_vsyscall,@function - ALIGN -__kernel_vsyscall: -.LSTART_vsyscall: - push %ecx -.Lpush_ecx: - push %edx -.Lpush_edx: - push %ebp -.Lenter_kernel: - movl %esp,%ebp - sysenter - - /* 7: align return point with nop's to make disassembly easier */ - .space 7,0x90 - - /* 14: System call restart point is here! (SYSENTER_RETURN-2) */ - int $0x80 - /* 16: System call normal return point is here! */ -VDSO32_SYSENTER_RETURN: /* Symbol used by sysenter.c via vdso32-syms.h */ - pop %ebp -.Lpop_ebp: - pop %edx -.Lpop_edx: - pop %ecx -.Lpop_ecx: - ret -.LEND_vsyscall: - .size __kernel_vsyscall,.-.LSTART_vsyscall - .previous - - .section .eh_frame,"a",@progbits -.LSTARTFRAMEDLSI: - .long .LENDCIEDLSI-.LSTARTCIEDLSI -.LSTARTCIEDLSI: - .long 0 /* CIE ID */ - .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ - .uleb128 1 /* Code alignment factor */ - .sleb128 -4 /* Data alignment factor */ - .byte 8 /* Return address register column */ - .uleb128 1 /* Augmentation value length */ - .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ - .byte 0x0c /* DW_CFA_def_cfa */ - .uleb128 4 - .uleb128 4 - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .uleb128 1 - .align 4 -.LENDCIEDLSI: - .long .LENDFDEDLSI-.LSTARTFDEDLSI /* Length FDE */ -.LSTARTFDEDLSI: - .long .LSTARTFDEDLSI-.LSTARTFRAMEDLSI /* CIE pointer */ - .long .LSTART_vsyscall-. /* PC-relative start address */ - .long .LEND_vsyscall-.LSTART_vsyscall - .uleb128 0 - /* What follows are the instructions for the table generation. - We have to record all changes of the stack pointer. */ - .byte 0x40 + (.Lpush_ecx-.LSTART_vsyscall) /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .byte 0x08 /* RA at offset 8 now */ - .byte 0x40 + (.Lpush_edx-.Lpush_ecx) /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .byte 0x0c /* RA at offset 12 now */ - .byte 0x40 + (.Lenter_kernel-.Lpush_edx) /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .byte 0x10 /* RA at offset 16 now */ - .byte 0x85, 0x04 /* DW_CFA_offset %ebp -16 */ - /* Finally the epilogue. */ - .byte 0x40 + (.Lpop_ebp-.Lenter_kernel) /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .byte 0x0c /* RA at offset 12 now */ - .byte 0xc5 /* DW_CFA_restore %ebp */ - .byte 0x40 + (.Lpop_edx-.Lpop_ebp) /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .byte 0x08 /* RA at offset 8 now */ - .byte 0x40 + (.Lpop_ecx-.Lpop_edx) /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .byte 0x04 /* RA at offset 4 now */ - .align 4 -.LENDFDEDLSI: - .previous - - /* - * Emit a symbol with the size of this .eh_frame data, - * to verify it matches the other versions. - */ -VDSO32_vsyscall_eh_frame_size = (.LENDFDEDLSI-.LSTARTFRAMEDLSI) diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S new file mode 100644 index 000000000000..93bd8452383f --- /dev/null +++ b/arch/x86/entry/vdso/vdso32/system_call.S @@ -0,0 +1,57 @@ +/* + * Code for the vDSO. This version uses the old int $0x80 method. +*/ + +#include <asm/dwarf2.h> +#include <asm/cpufeature.h> +#include <asm/alternative-asm.h> + +/* + * First get the common code for the sigreturn entry points. + * This must come first. + */ +#include "sigreturn.S" + + .text + .globl __kernel_vsyscall + .type __kernel_vsyscall,@function + ALIGN +__kernel_vsyscall: + CFI_STARTPROC + /* + * Reshuffle regs so that all of any of the entry instructions + * will preserve enough state. + */ + pushl %edx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET edx, 0 + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx, 0 + movl %esp, %ecx + +#ifdef CONFIG_X86_64 + /* If SYSENTER (Intel) or SYSCALL32 (AMD) is available, use it. */ + ALTERNATIVE_2 "", "sysenter", X86_FEATURE_SYSENTER32, \ + "syscall", X86_FEATURE_SYSCALL32 +#else + ALTERNATIVE "", "sysenter", X86_FEATURE_SEP +#endif + + /* Enter using int $0x80 */ + movl (%esp), %ecx + int $0x80 +GLOBAL(int80_landing_pad) + + /* Restore ECX and EDX in case they were clobbered. */ + popl %ecx + CFI_RESTORE ecx + CFI_ADJUST_CFA_OFFSET -4 + popl %edx + CFI_RESTORE edx + CFI_ADJUST_CFA_OFFSET -4 + ret + CFI_ENDPROC + + .size __kernel_vsyscall,.-__kernel_vsyscall + .previous diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index 434543145d78..64df47148160 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -180,21 +180,10 @@ up_fail: #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) static int load_vdso32(void) { - int ret; - if (vdso32_enabled != 1) /* Other values all mean "disabled" */ return 0; - ret = map_vdso(selected_vdso32, false); - if (ret) - return ret; - - if (selected_vdso32->sym_VDSO32_SYSENTER_RETURN) - current_thread_info()->sysenter_return = - current->mm->context.vdso + - selected_vdso32->sym_VDSO32_SYSENTER_RETURN; - - return 0; + return map_vdso(&vdso_image_32, false); } #endif diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index b160c0c6baed..174c2549939d 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -38,7 +38,14 @@ #define CREATE_TRACE_POINTS #include "vsyscall_trace.h" -static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE; +static enum { EMULATE, NATIVE, NONE } vsyscall_mode = +#if defined(CONFIG_LEGACY_VSYSCALL_NATIVE) + NATIVE; +#elif defined(CONFIG_LEGACY_VSYSCALL_NONE) + NONE; +#else + EMULATE; +#endif static int __init vsyscall_setup(char *str) { diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index a0a19b7ba22d..e6a5c275cd3f 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -289,7 +289,7 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, /* Return stub is in 32bit vsyscall page */ if (current->mm->context.vdso) restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_sigreturn; + vdso_image_32.sym___kernel_sigreturn; else restorer = &frame->retcode; } @@ -368,7 +368,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, restorer = ksig->ka.sa.sa_restorer; else restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_rt_sigreturn; + vdso_image_32.sym___kernel_rt_sigreturn; put_user_ex(ptr_to_compat(restorer), &frame->pretcode); /* diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 3a45668f6dc3..94c18ebfd68c 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -32,6 +32,10 @@ #include <asm/mpspec.h> #include <asm/realmode.h> +#ifdef CONFIG_ACPI_APEI +# include <asm/pgtable_types.h> +#endif + #ifdef CONFIG_ACPI extern int acpi_lapic; extern int acpi_ioapic; @@ -147,4 +151,23 @@ extern int x86_acpi_numa_init(void); #define acpi_unlazy_tlb(x) leave_mm(x) +#ifdef CONFIG_ACPI_APEI +static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr) +{ + /* + * We currently have no way to look up the EFI memory map + * attributes for a region in a consistent way, because the + * memmap is discarded after efi_free_boot_services(). So if + * you call efi_mem_attributes() during boot and at runtime, + * you could theoretically see different attributes. + * + * Since we are yet to see any x86 platforms that require + * anything other than PAGE_KERNEL (some arm64 platforms + * require the equivalent of PAGE_KERNEL_NOCACHE), return that + * until we know differently. + */ + return PAGE_KERNEL; +} +#endif + #endif /* _ASM_X86_ACPI_H */ diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index 1a5da2e63aee..3c56ef1ae068 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -81,7 +81,7 @@ static inline struct amd_northbridge *node_to_amd_nb(int node) return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL; } -static inline u16 amd_get_node_id(struct pci_dev *pdev) +static inline u16 amd_pci_dev_to_node_id(struct pci_dev *pdev) { struct pci_dev *misc; int i; diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index ebf6d5e5668c..a30316bf801a 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -115,6 +115,59 @@ static inline bool apic_is_x2apic_enabled(void) return msr & X2APIC_ENABLE; } +extern void enable_IR_x2apic(void); + +extern int get_physical_broadcast(void); + +extern int lapic_get_maxlvt(void); +extern void clear_local_APIC(void); +extern void disconnect_bsp_APIC(int virt_wire_setup); +extern void disable_local_APIC(void); +extern void lapic_shutdown(void); +extern void sync_Arb_IDs(void); +extern void init_bsp_APIC(void); +extern void setup_local_APIC(void); +extern void init_apic_mappings(void); +void register_lapic_address(unsigned long address); +extern void setup_boot_APIC_clock(void); +extern void setup_secondary_APIC_clock(void); +extern int APIC_init_uniprocessor(void); + +#ifdef CONFIG_X86_64 +static inline int apic_force_enable(unsigned long addr) +{ + return -1; +} +#else +extern int apic_force_enable(unsigned long addr); +#endif + +extern int apic_bsp_setup(bool upmode); +extern void apic_ap_setup(void); + +/* + * On 32bit this is mach-xxx local + */ +#ifdef CONFIG_X86_64 +extern int apic_is_clustered_box(void); +#else +static inline int apic_is_clustered_box(void) +{ + return 0; +} +#endif + +extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask); + +#else /* !CONFIG_X86_LOCAL_APIC */ +static inline void lapic_shutdown(void) { } +#define local_apic_timer_c2_ok 1 +static inline void init_apic_mappings(void) { } +static inline void disable_local_APIC(void) { } +# define setup_boot_APIC_clock x86_init_noop +# define setup_secondary_APIC_clock x86_init_noop +#endif /* !CONFIG_X86_LOCAL_APIC */ + #ifdef CONFIG_X86_X2APIC /* * Make previous memory operations globally visible before @@ -186,67 +239,14 @@ static inline int x2apic_enabled(void) } #define x2apic_supported() (cpu_has_x2apic) -#else +#else /* !CONFIG_X86_X2APIC */ static inline void check_x2apic(void) { } static inline void x2apic_setup(void) { } static inline int x2apic_enabled(void) { return 0; } #define x2apic_mode (0) #define x2apic_supported() (0) -#endif - -extern void enable_IR_x2apic(void); - -extern int get_physical_broadcast(void); - -extern int lapic_get_maxlvt(void); -extern void clear_local_APIC(void); -extern void disconnect_bsp_APIC(int virt_wire_setup); -extern void disable_local_APIC(void); -extern void lapic_shutdown(void); -extern void sync_Arb_IDs(void); -extern void init_bsp_APIC(void); -extern void setup_local_APIC(void); -extern void init_apic_mappings(void); -void register_lapic_address(unsigned long address); -extern void setup_boot_APIC_clock(void); -extern void setup_secondary_APIC_clock(void); -extern int APIC_init_uniprocessor(void); - -#ifdef CONFIG_X86_64 -static inline int apic_force_enable(unsigned long addr) -{ - return -1; -} -#else -extern int apic_force_enable(unsigned long addr); -#endif - -extern int apic_bsp_setup(bool upmode); -extern void apic_ap_setup(void); - -/* - * On 32bit this is mach-xxx local - */ -#ifdef CONFIG_X86_64 -extern int apic_is_clustered_box(void); -#else -static inline int apic_is_clustered_box(void) -{ - return 0; -} -#endif - -extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask); - -#else /* !CONFIG_X86_LOCAL_APIC */ -static inline void lapic_shutdown(void) { } -#define local_apic_timer_c2_ok 1 -static inline void init_apic_mappings(void) { } -static inline void disable_local_APIC(void) { } -# define setup_boot_APIC_clock x86_init_noop -# define setup_secondary_APIC_clock x86_init_noop -#endif /* !CONFIG_X86_LOCAL_APIC */ +#endif /* !CONFIG_X86_X2APIC */ #ifdef CONFIG_X86_64 #define SET_APIC_ID(x) (apic->set_apic_id(x)) diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index fb52aa644aab..ae5fb83e6d91 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -24,7 +24,7 @@ */ static __always_inline int atomic_read(const atomic_t *v) { - return ACCESS_ONCE((v)->counter); + return READ_ONCE((v)->counter); } /** @@ -36,7 +36,7 @@ static __always_inline int atomic_read(const atomic_t *v) */ static __always_inline void atomic_set(atomic_t *v, int i) { - v->counter = i; + WRITE_ONCE(v->counter, i); } /** diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 50e33eff58de..037351022f54 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -18,7 +18,7 @@ */ static inline long atomic64_read(const atomic64_t *v) { - return ACCESS_ONCE((v)->counter); + return READ_ONCE((v)->counter); } /** @@ -30,7 +30,7 @@ static inline long atomic64_read(const atomic64_t *v) */ static inline void atomic64_set(atomic64_t *v, long i) { - v->counter = i; + WRITE_ONCE(v->counter, i); } /** diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h new file mode 100644 index 000000000000..b7a1ab865d68 --- /dev/null +++ b/arch/x86/include/asm/dwarf2.h @@ -0,0 +1,84 @@ +#ifndef _ASM_X86_DWARF2_H +#define _ASM_X86_DWARF2_H + +#ifndef __ASSEMBLY__ +#warning "asm/dwarf2.h should be only included in pure assembly files" +#endif + +/* + * Macros for dwarf2 CFI unwind table entries. + * See "as.info" for details on these pseudo ops. Unfortunately + * they are only supported in very new binutils, so define them + * away for older version. + */ + +#ifdef CONFIG_AS_CFI + +#define CFI_STARTPROC .cfi_startproc +#define CFI_ENDPROC .cfi_endproc +#define CFI_DEF_CFA .cfi_def_cfa +#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register +#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset +#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset +#define CFI_OFFSET .cfi_offset +#define CFI_REL_OFFSET .cfi_rel_offset +#define CFI_REGISTER .cfi_register +#define CFI_RESTORE .cfi_restore +#define CFI_REMEMBER_STATE .cfi_remember_state +#define CFI_RESTORE_STATE .cfi_restore_state +#define CFI_UNDEFINED .cfi_undefined +#define CFI_ESCAPE .cfi_escape + +#ifdef CONFIG_AS_CFI_SIGNAL_FRAME +#define CFI_SIGNAL_FRAME .cfi_signal_frame +#else +#define CFI_SIGNAL_FRAME +#endif + +#if defined(CONFIG_AS_CFI_SECTIONS) && defined(__ASSEMBLY__) +#ifndef BUILD_VDSO + /* + * Emit CFI data in .debug_frame sections, not .eh_frame sections. + * The latter we currently just discard since we don't do DWARF + * unwinding at runtime. So only the offline DWARF information is + * useful to anyone. Note we should not use this directive if + * vmlinux.lds.S gets changed so it doesn't discard .eh_frame. + */ + .cfi_sections .debug_frame +#else + /* + * For the vDSO, emit both runtime unwind information and debug + * symbols for the .dbg file. + */ + .cfi_sections .eh_frame, .debug_frame +#endif +#endif + +#else + +/* + * Due to the structure of pre-exisiting code, don't use assembler line + * comment character # to ignore the arguments. Instead, use a dummy macro. + */ +.macro cfi_ignore a=0, b=0, c=0, d=0 +.endm + +#define CFI_STARTPROC cfi_ignore +#define CFI_ENDPROC cfi_ignore +#define CFI_DEF_CFA cfi_ignore +#define CFI_DEF_CFA_REGISTER cfi_ignore +#define CFI_DEF_CFA_OFFSET cfi_ignore +#define CFI_ADJUST_CFA_OFFSET cfi_ignore +#define CFI_OFFSET cfi_ignore +#define CFI_REL_OFFSET cfi_ignore +#define CFI_REGISTER cfi_ignore +#define CFI_RESTORE cfi_ignore +#define CFI_REMEMBER_STATE cfi_ignore +#define CFI_RESTORE_STATE cfi_ignore +#define CFI_UNDEFINED cfi_ignore +#define CFI_ESCAPE cfi_ignore +#define CFI_SIGNAL_FRAME cfi_ignore + +#endif + +#endif /* _ASM_X86_DWARF2_H */ diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index ae68be92f755..0010c78c4998 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -105,6 +105,7 @@ extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); extern int __init efi_memblock_x86_reserve_range(void); extern pgd_t * __init efi_call_phys_prolog(void); extern void __init efi_call_phys_epilog(pgd_t *save_pgd); +extern void __init efi_print_memmap(void); extern void __init efi_unmap_memmap(void); extern void __init efi_memory_uc(u64 addr, unsigned long size); extern void __init efi_map_region(efi_memory_desc_t *md); diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 141c561f4664..1514753fd435 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -171,11 +171,11 @@ do { \ static inline void elf_common_init(struct thread_struct *t, struct pt_regs *regs, const u16 ds) { - /* Commented-out registers are cleared in stub_execve */ - /*regs->ax = regs->bx =*/ regs->cx = regs->dx = 0; - regs->si = regs->di /*= regs->bp*/ = 0; + /* ax gets execve's return value. */ + /*regs->ax = */ regs->bx = regs->cx = regs->dx = 0; + regs->si = regs->di = regs->bp = 0; regs->r8 = regs->r9 = regs->r10 = regs->r11 = 0; - /*regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;*/ + regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0; t->fs = t->gs = 0; t->fsindex = t->gsindex = 0; t->ds = t->es = ds; @@ -328,7 +328,7 @@ else \ #define VDSO_ENTRY \ ((unsigned long)current->mm->context.vdso + \ - selected_vdso32->sym___kernel_vsyscall) + vdso_image_32.sym___kernel_vsyscall) struct linux_binprm; diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index 5fa9fb0f8809..cc285ec4b2c1 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h @@ -63,10 +63,10 @@ /* hpet memory map physical address */ extern unsigned long hpet_address; extern unsigned long force_hpet_address; -extern int boot_hpet_disable; +extern bool boot_hpet_disable; extern u8 hpet_blockid; -extern int hpet_force_user; -extern u8 hpet_msi_disable; +extern bool hpet_force_user; +extern bool hpet_msi_disable; extern int is_hpet_enabled(void); extern int hpet_enable(void); extern void hpet_disable(void); diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 2beee0382088..3a36ee704c30 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1226,10 +1226,8 @@ void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err); int kvm_is_in_guest(void); -int __x86_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem); -int x86_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem); +int __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size); +int x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size); bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu); bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu); diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 2dbc0bf2b9f3..2ea4527e462f 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -123,19 +123,27 @@ struct mca_config { }; struct mce_vendor_flags { - /* - * overflow recovery cpuid bit indicates that overflow - * conditions are not fatal - */ - __u64 overflow_recov : 1, - - /* - * SUCCOR stands for S/W UnCorrectable error COntainment - * and Recovery. It indicates support for data poisoning - * in HW and deferred error interrupts. - */ - succor : 1, - __reserved_0 : 62; + /* + * Indicates that overflow conditions are not fatal, when set. + */ + __u64 overflow_recov : 1, + + /* + * (AMD) SUCCOR stands for S/W UnCorrectable error COntainment and + * Recovery. It indicates support for data poisoning in HW and deferred + * error interrupts. + */ + succor : 1, + + /* + * (AMD) SMCA: This bit indicates support for Scalable MCA which expands + * the register space for each MCA bank and also increases number of + * banks. Also, to accommodate the new banks and registers, the MCA + * register space is moved to a new MSR range. + */ + smca : 1, + + __reserved_0 : 61; }; extern struct mce_vendor_flags mce_flags; diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 9e6278c7140e..34e62b1dcfce 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -27,7 +27,6 @@ struct cpu_signature { struct device; enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; -extern bool dis_ucode_ldr; struct microcode_ops { enum ucode_state (*request_microcode_user) (int cpu, @@ -55,6 +54,12 @@ struct ucode_cpu_info { }; extern struct ucode_cpu_info ucode_cpu_info[]; +#ifdef CONFIG_MICROCODE +int __init microcode_init(void); +#else +static inline int __init microcode_init(void) { return 0; }; +#endif + #ifdef CONFIG_MICROCODE_INTEL extern struct microcode_ops * __init init_intel_microcode(void); #else @@ -75,7 +80,6 @@ static inline struct microcode_ops * __init init_amd_microcode(void) static inline void __exit exit_amd_microcode(void) {} #endif -#ifdef CONFIG_MICROCODE_EARLY #define MAX_UCODE_COUNT 128 #define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24)) @@ -150,22 +154,18 @@ static inline unsigned int x86_model(unsigned int sig) return model; } +#ifdef CONFIG_MICROCODE extern void __init load_ucode_bsp(void); extern void load_ucode_ap(void); extern int __init save_microcode_in_initrd(void); void reload_early_microcode(void); extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); #else -static inline void __init load_ucode_bsp(void) {} -static inline void load_ucode_ap(void) {} -static inline int __init save_microcode_in_initrd(void) -{ - return 0; -} -static inline void reload_early_microcode(void) {} -static inline bool get_builtin_firmware(struct cpio_data *cd, const char *name) -{ - return false; -} +static inline void __init load_ucode_bsp(void) { } +static inline void load_ucode_ap(void) { } +static inline int __init save_microcode_in_initrd(void) { return 0; } +static inline void reload_early_microcode(void) { } +static inline bool +get_builtin_firmware(struct cpio_data *cd, const char *name) { return false; } #endif #endif /* _ASM_X86_MICROCODE_H */ diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index ac6d328977a6..adfc847a395e 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -64,7 +64,7 @@ extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, s #define PATCH_MAX_SIZE PAGE_SIZE extern u8 amd_ucode_patch[PATCH_MAX_SIZE]; -#ifdef CONFIG_MICROCODE_AMD_EARLY +#ifdef CONFIG_MICROCODE_AMD extern void __init load_ucode_amd_bsp(unsigned int family); extern void load_ucode_amd_ap(void); extern int __init save_microcode_in_initrd_amd(void); @@ -76,4 +76,5 @@ static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; } void reload_ucode_amd(void) {} #endif +extern bool check_current_patch_level(u32 *rev, bool early); #endif /* _ASM_X86_MICROCODE_AMD_H */ diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h index 7991c606125d..8559b0102ea1 100644 --- a/arch/x86/include/asm/microcode_intel.h +++ b/arch/x86/include/asm/microcode_intel.h @@ -57,7 +57,7 @@ extern int has_newer_microcode(void *mc, unsigned int csig, int cpf, int rev); extern int microcode_sanity_check(void *mc, int print_err); extern int find_matching_signature(void *mc, unsigned int csig, int cpf); -#ifdef CONFIG_MICROCODE_INTEL_EARLY +#ifdef CONFIG_MICROCODE_INTEL extern void __init load_ucode_intel_bsp(void); extern void load_ucode_intel_ap(void); extern void show_ucode_info_early(void); @@ -71,13 +71,9 @@ static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; static inline void reload_ucode_intel(void) {} #endif -#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU) +#ifdef CONFIG_HOTPLUG_CPU extern int save_mc_for_early(u8 *mc); #else -static inline int save_mc_for_early(u8 *mc) -{ - return 0; -} +static inline int save_mc_for_early(u8 *mc) { return 0; } #endif - #endif /* _ASM_X86_MICROCODE_INTEL_H */ diff --git a/arch/x86/include/asm/numachip/numachip.h b/arch/x86/include/asm/numachip/numachip.h index 1c6f7f6212c1..c64373a2d731 100644 --- a/arch/x86/include/asm/numachip/numachip.h +++ b/arch/x86/include/asm/numachip/numachip.h @@ -14,6 +14,7 @@ #ifndef _ASM_X86_NUMACHIP_NUMACHIP_H #define _ASM_X86_NUMACHIP_NUMACHIP_H +extern u8 numachip_system; extern int __init pci_numachip_init(void); #endif /* _ASM_X86_NUMACHIP_NUMACHIP_H */ diff --git a/arch/x86/include/asm/numachip/numachip_csr.h b/arch/x86/include/asm/numachip/numachip_csr.h index 660f843df928..29719eecdc2e 100644 --- a/arch/x86/include/asm/numachip/numachip_csr.h +++ b/arch/x86/include/asm/numachip/numachip_csr.h @@ -14,12 +14,8 @@ #ifndef _ASM_X86_NUMACHIP_NUMACHIP_CSR_H #define _ASM_X86_NUMACHIP_NUMACHIP_CSR_H -#include <linux/numa.h> -#include <linux/percpu.h> +#include <linux/smp.h> #include <linux/io.h> -#include <linux/swab.h> -#include <asm/types.h> -#include <asm/processor.h> #define CSR_NODE_SHIFT 16 #define CSR_NODE_BITS(p) (((unsigned long)(p)) << CSR_NODE_SHIFT) @@ -27,11 +23,8 @@ /* 32K CSR space, b15 indicates geo/non-geo */ #define CSR_OFFSET_MASK 0x7fffUL - -/* Global CSR space covers all 4K possible nodes with 64K CSR space per node */ -#define NUMACHIP_GCSR_BASE 0x3fff00000000ULL -#define NUMACHIP_GCSR_LIM 0x3fff0fffffffULL -#define NUMACHIP_GCSR_SIZE (NUMACHIP_GCSR_LIM - NUMACHIP_GCSR_BASE + 1) +#define CSR_G0_NODE_IDS (0x008 + (0 << 12)) +#define CSR_G3_EXT_IRQ_GEN (0x030 + (3 << 12)) /* * Local CSR space starts in global CSR space with "nodeid" = 0xfff0, however @@ -41,12 +34,7 @@ #define NUMACHIP_LCSR_BASE 0x3ffffe000000ULL #define NUMACHIP_LCSR_LIM 0x3fffffffffffULL #define NUMACHIP_LCSR_SIZE (NUMACHIP_LCSR_LIM - NUMACHIP_LCSR_BASE + 1) - -static inline void *gcsr_address(int node, unsigned long offset) -{ - return __va(NUMACHIP_GCSR_BASE | (1UL << 15) | - CSR_NODE_BITS(node & CSR_NODE_MASK) | (offset & CSR_OFFSET_MASK)); -} +#define NUMACHIP_LAPIC_BITS 8 static inline void *lcsr_address(unsigned long offset) { @@ -54,114 +42,57 @@ static inline void *lcsr_address(unsigned long offset) CSR_NODE_BITS(0xfff0) | (offset & CSR_OFFSET_MASK)); } -static inline unsigned int read_gcsr(int node, unsigned long offset) +static inline unsigned int read_lcsr(unsigned long offset) { - return swab32(readl(gcsr_address(node, offset))); + return swab32(readl(lcsr_address(offset))); } -static inline void write_gcsr(int node, unsigned long offset, unsigned int val) +static inline void write_lcsr(unsigned long offset, unsigned int val) { - writel(swab32(val), gcsr_address(node, offset)); + writel(swab32(val), lcsr_address(offset)); } -static inline unsigned int read_lcsr(unsigned long offset) +/* + * On NumaChip2, local CSR space is 16MB and starts at fixed offset below 4G + */ + +#define NUMACHIP2_LCSR_BASE 0xf0000000UL +#define NUMACHIP2_LCSR_SIZE 0x1000000UL +#define NUMACHIP2_APIC_ICR 0x100000 +#define NUMACHIP2_TIMER_DEADLINE 0x200000 +#define NUMACHIP2_TIMER_INT 0x200008 +#define NUMACHIP2_TIMER_NOW 0x200018 +#define NUMACHIP2_TIMER_RESET 0x200020 + +static inline void __iomem *numachip2_lcsr_address(unsigned long offset) { - return swab32(readl(lcsr_address(offset))); + return (void __iomem *)__va(NUMACHIP2_LCSR_BASE | + (offset & (NUMACHIP2_LCSR_SIZE - 1))); } -static inline void write_lcsr(unsigned long offset, unsigned int val) +static inline u32 numachip2_read32_lcsr(unsigned long offset) { - writel(swab32(val), lcsr_address(offset)); + return readl(numachip2_lcsr_address(offset)); } -/* ========================================================================= */ -/* CSR_G0_STATE_CLEAR */ -/* ========================================================================= */ - -#define CSR_G0_STATE_CLEAR (0x000 + (0 << 12)) -union numachip_csr_g0_state_clear { - unsigned int v; - struct numachip_csr_g0_state_clear_s { - unsigned int _state:2; - unsigned int _rsvd_2_6:5; - unsigned int _lost:1; - unsigned int _rsvd_8_31:24; - } s; -}; - -/* ========================================================================= */ -/* CSR_G0_NODE_IDS */ -/* ========================================================================= */ +static inline u64 numachip2_read64_lcsr(unsigned long offset) +{ + return readq(numachip2_lcsr_address(offset)); +} -#define CSR_G0_NODE_IDS (0x008 + (0 << 12)) -union numachip_csr_g0_node_ids { - unsigned int v; - struct numachip_csr_g0_node_ids_s { - unsigned int _initialid:16; - unsigned int _nodeid:12; - unsigned int _rsvd_28_31:4; - } s; -}; - -/* ========================================================================= */ -/* CSR_G3_EXT_IRQ_GEN */ -/* ========================================================================= */ +static inline void numachip2_write32_lcsr(unsigned long offset, u32 val) +{ + writel(val, numachip2_lcsr_address(offset)); +} -#define CSR_G3_EXT_IRQ_GEN (0x030 + (3 << 12)) -union numachip_csr_g3_ext_irq_gen { - unsigned int v; - struct numachip_csr_g3_ext_irq_gen_s { - unsigned int _vector:8; - unsigned int _msgtype:3; - unsigned int _index:5; - unsigned int _destination_apic_id:16; - } s; -}; - -/* ========================================================================= */ -/* CSR_G3_EXT_IRQ_STATUS */ -/* ========================================================================= */ - -#define CSR_G3_EXT_IRQ_STATUS (0x034 + (3 << 12)) -union numachip_csr_g3_ext_irq_status { - unsigned int v; - struct numachip_csr_g3_ext_irq_status_s { - unsigned int _result:32; - } s; -}; - -/* ========================================================================= */ -/* CSR_G3_EXT_IRQ_DEST */ -/* ========================================================================= */ - -#define CSR_G3_EXT_IRQ_DEST (0x038 + (3 << 12)) -union numachip_csr_g3_ext_irq_dest { - unsigned int v; - struct numachip_csr_g3_ext_irq_dest_s { - unsigned int _irq:8; - unsigned int _rsvd_8_31:24; - } s; -}; - -/* ========================================================================= */ -/* CSR_G3_NC_ATT_MAP_SELECT */ -/* ========================================================================= */ - -#define CSR_G3_NC_ATT_MAP_SELECT (0x7fc + (3 << 12)) -union numachip_csr_g3_nc_att_map_select { - unsigned int v; - struct numachip_csr_g3_nc_att_map_select_s { - unsigned int _upper_address_bits:4; - unsigned int _select_ram:4; - unsigned int _rsvd_8_31:24; - } s; -}; - -/* ========================================================================= */ -/* CSR_G3_NC_ATT_MAP_SELECT_0-255 */ -/* ========================================================================= */ - -#define CSR_G3_NC_ATT_MAP_SELECT_0 (0x800 + (3 << 12)) +static inline void numachip2_write64_lcsr(unsigned long offset, u64 val) +{ + writeq(val, numachip2_lcsr_address(offset)); +} -#endif /* _ASM_X86_NUMACHIP_NUMACHIP_CSR_H */ +static inline unsigned int numachip2_timer(void) +{ + return (smp_processor_id() % 48) << 6; +} +#endif /* _ASM_X86_NUMACHIP_NUMACHIP_CSR_H */ diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index b12f81022a6b..01bcde84d3e4 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h @@ -30,12 +30,9 @@ static __always_inline void preempt_count_set(int pc) /* * must be macros to avoid header recursion hell */ -#define init_task_preempt_count(p) do { \ - task_thread_info(p)->saved_preempt_count = PREEMPT_DISABLED; \ -} while (0) +#define init_task_preempt_count(p) do { } while (0) #define init_idle_preempt_count(p, cpu) do { \ - task_thread_info(p)->saved_preempt_count = PREEMPT_ENABLED; \ per_cpu(__preempt_count, (cpu)) = PREEMPT_ENABLED; \ } while (0) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 19577dd325fa..b55f30960554 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -556,12 +556,12 @@ static inline unsigned int cpuid_edx(unsigned int op) } /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ -static inline void rep_nop(void) +static __always_inline void rep_nop(void) { asm volatile("rep; nop" ::: "memory"); } -static inline void cpu_relax(void) +static __always_inline void cpu_relax(void) { rep_nop(); } diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h index e4661196994e..ff8b9a17dc4b 100644 --- a/arch/x86/include/asm/string_64.h +++ b/arch/x86/include/asm/string_64.h @@ -27,12 +27,11 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t function. */ #define __HAVE_ARCH_MEMCPY 1 +extern void *memcpy(void *to, const void *from, size_t len); extern void *__memcpy(void *to, const void *from, size_t len); #ifndef CONFIG_KMEMCHECK -#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 -extern void *memcpy(void *to, const void *from, size_t len); -#else +#if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || __GNUC__ < 4 #define memcpy(dst, src, len) \ ({ \ size_t __len = (len); \ diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index d7f3b3b78ac3..751bf4b7bf11 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -79,12 +79,12 @@ do { \ #else /* CONFIG_X86_32 */ /* frame pointer must be last for get_wchan */ -#define SAVE_CONTEXT "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t" -#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t" +#define SAVE_CONTEXT "pushq %%rbp ; movq %%rsi,%%rbp\n\t" +#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\t" #define __EXTRA_CLOBBER \ , "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \ - "r12", "r13", "r14", "r15" + "r12", "r13", "r14", "r15", "flags" #ifdef CONFIG_CC_STACKPROTECTOR #define __switch_canary \ @@ -100,7 +100,11 @@ do { \ #define __switch_canary_iparam #endif /* CC_STACKPROTECTOR */ -/* Save restore flags to clear handle leaking NT */ +/* + * There is no need to save or restore flags, because flags are always + * clean in kernel mode, with the possible exception of IOPL. Kernel IOPL + * has no effect. + */ #define switch_to(prev, next, last) \ asm volatile(SAVE_CONTEXT \ "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \ diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index d6a756ae04c8..999b7cd2e78c 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -20,9 +20,21 @@ #include <asm/thread_info.h> /* for TS_COMPAT */ #include <asm/unistd.h> -typedef void (*sys_call_ptr_t)(void); +typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long, + unsigned long, unsigned long, + unsigned long, unsigned long); extern const sys_call_ptr_t sys_call_table[]; +#if defined(CONFIG_X86_32) +#define ia32_sys_call_table sys_call_table +#define __NR_syscall_compat_max __NR_syscall_max +#define IA32_NR_syscalls NR_syscalls +#endif + +#if defined(CONFIG_IA32_EMULATION) +extern const sys_call_ptr_t ia32_sys_call_table[]; +#endif + /* * Only the low 32 bits of orig_ax are meaningful, so we return int. * This importantly ignores the high bits on 64-bit, so comparisons diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 8afdc3e44247..c7b551028740 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -57,9 +57,7 @@ struct thread_info { __u32 flags; /* low level flags */ __u32 status; /* thread synchronous flags */ __u32 cpu; /* current CPU */ - int saved_preempt_count; mm_segment_t addr_limit; - void __user *sysenter_return; unsigned int sig_on_uaccess_error:1; unsigned int uaccess_err:1; /* uaccess failed */ }; @@ -69,7 +67,6 @@ struct thread_info { .task = &tsk, \ .flags = 0, \ .cpu = 0, \ - .saved_preempt_count = INIT_PREEMPT_COUNT, \ .addr_limit = KERNEL_DS, \ } diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index a8df874f3e88..09b1b0ab94b7 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -51,13 +51,13 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un * limit, not add it to the address). */ if (__builtin_constant_p(size)) - return addr > limit - size; + return unlikely(addr > limit - size); /* Arbitrary sizes? Be careful about overflow */ addr += size; - if (addr < size) + if (unlikely(addr < size)) return true; - return addr > limit; + return unlikely(addr > limit); } #define __range_not_ok(addr, size, limit) \ @@ -182,7 +182,7 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) : "=a" (__ret_gu), "=r" (__val_gu) \ : "0" (ptr), "i" (sizeof(*(ptr)))); \ (x) = (__force __typeof__(*(ptr))) __val_gu; \ - __ret_gu; \ + __builtin_expect(__ret_gu, 0); \ }) #define __put_user_x(size, x, ptr, __ret_pu) \ @@ -278,7 +278,7 @@ extern void __put_user_8(void); __put_user_x(X, __pu_val, ptr, __ret_pu); \ break; \ } \ - __ret_pu; \ + __builtin_expect(__ret_pu, 0); \ }) #define __put_user_size(x, ptr, size, retval, errret) \ @@ -401,7 +401,7 @@ do { \ ({ \ int __pu_err; \ __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ - __pu_err; \ + __builtin_expect(__pu_err, 0); \ }) #define __get_user_nocheck(x, ptr, size) \ @@ -410,7 +410,7 @@ do { \ unsigned long __gu_val; \ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ - __gu_err; \ + __builtin_expect(__gu_err, 0); \ }) /* FIXME: this hack is definitely wrong -AK */ diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h index 8021bd28c0f1..756de9190aec 100644 --- a/arch/x86/include/asm/vdso.h +++ b/arch/x86/include/asm/vdso.h @@ -26,7 +26,7 @@ struct vdso_image { long sym___kernel_sigreturn; long sym___kernel_rt_sigreturn; long sym___kernel_vsyscall; - long sym_VDSO32_SYSENTER_RETURN; + long sym_int80_landing_pad; }; #ifdef CONFIG_X86_64 @@ -38,13 +38,7 @@ extern const struct vdso_image vdso_image_x32; #endif #if defined CONFIG_X86_32 || defined CONFIG_COMPAT -extern const struct vdso_image vdso_image_32_int80; -#ifdef CONFIG_COMPAT -extern const struct vdso_image vdso_image_32_syscall; -#endif -extern const struct vdso_image vdso_image_32_sysenter; - -extern const struct vdso_image *selected_vdso32; +extern const struct vdso_image vdso_image_32; #endif extern void __init init_vdso_image(const struct vdso_image *image); diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h index 76880ede9a35..03429da2fa80 100644 --- a/arch/x86/include/uapi/asm/mce.h +++ b/arch/x86/include/uapi/asm/mce.h @@ -2,7 +2,7 @@ #define _UAPI_ASM_X86_MCE_H #include <linux/types.h> -#include <asm/ioctls.h> +#include <linux/ioctl.h> /* Fields are zero when not available */ struct mce { diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 24e94ce454e2..2f69e3b184f6 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1431,7 +1431,7 @@ enum { }; static int x2apic_state; -static inline void __x2apic_disable(void) +static void __x2apic_disable(void) { u64 msr; @@ -1447,7 +1447,7 @@ static inline void __x2apic_disable(void) printk_once(KERN_INFO "x2apic disabled\n"); } -static inline void __x2apic_enable(void) +static void __x2apic_enable(void) { u64 msr; @@ -1807,7 +1807,7 @@ int apic_version[MAX_LOCAL_APIC]; /* * This interrupt should _never_ happen with our APIC/SMP architecture */ -static inline void __smp_spurious_interrupt(u8 vector) +static void __smp_spurious_interrupt(u8 vector) { u32 v; @@ -1848,7 +1848,7 @@ __visible void smp_trace_spurious_interrupt(struct pt_regs *regs) /* * This interrupt should never happen with our APIC/SMP architecture */ -static inline void __smp_error_interrupt(struct pt_regs *regs) +static void __smp_error_interrupt(struct pt_regs *regs) { u32 v; u32 i = 0; diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index b548fd3b764b..38dd5efdd04c 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -11,30 +11,21 @@ * */ -#include <linux/errno.h> -#include <linux/threads.h> -#include <linux/cpumask.h> -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/ctype.h> #include <linux/init.h> -#include <linux/hardirq.h> -#include <linux/delay.h> #include <asm/numachip/numachip.h> #include <asm/numachip/numachip_csr.h> -#include <asm/smp.h> -#include <asm/apic.h> #include <asm/ipi.h> #include <asm/apic_flat_64.h> #include <asm/pgtable.h> +#include <asm/pci_x86.h> -static int numachip_system __read_mostly; +u8 numachip_system __read_mostly; +static const struct apic apic_numachip1; +static const struct apic apic_numachip2; +static void (*numachip_apic_icr_write)(int apicid, unsigned int val) __read_mostly; -static const struct apic apic_numachip; - -static unsigned int get_apic_id(unsigned long x) +static unsigned int numachip1_get_apic_id(unsigned long x) { unsigned long value; unsigned int id = (x >> 24) & 0xff; @@ -47,7 +38,7 @@ static unsigned int get_apic_id(unsigned long x) return id; } -static unsigned long set_apic_id(unsigned int id) +static unsigned long numachip1_set_apic_id(unsigned int id) { unsigned long x; @@ -55,9 +46,17 @@ static unsigned long set_apic_id(unsigned int id) return x; } -static unsigned int read_xapic_id(void) +static unsigned int numachip2_get_apic_id(unsigned long x) +{ + u64 mcfg; + + rdmsrl(MSR_FAM10H_MMIO_CONF_BASE, mcfg); + return ((mcfg >> (28 - 8)) & 0xfff00) | (x >> 24); +} + +static unsigned long numachip2_set_apic_id(unsigned int id) { - return get_apic_id(apic_read(APIC_ID)); + return id << 24; } static int numachip_apic_id_valid(int apicid) @@ -68,7 +67,7 @@ static int numachip_apic_id_valid(int apicid) static int numachip_apic_id_registered(void) { - return physid_isset(read_xapic_id(), phys_cpu_present_map); + return 1; } static int numachip_phys_pkg_id(int initial_apic_id, int index_msb) @@ -76,36 +75,48 @@ static int numachip_phys_pkg_id(int initial_apic_id, int index_msb) return initial_apic_id >> index_msb; } -static int numachip_wakeup_secondary(int phys_apicid, unsigned long start_rip) +static void numachip1_apic_icr_write(int apicid, unsigned int val) { - union numachip_csr_g3_ext_irq_gen int_gen; - - int_gen.s._destination_apic_id = phys_apicid; - int_gen.s._vector = 0; - int_gen.s._msgtype = APIC_DM_INIT >> 8; - int_gen.s._index = 0; - - write_lcsr(CSR_G3_EXT_IRQ_GEN, int_gen.v); + write_lcsr(CSR_G3_EXT_IRQ_GEN, (apicid << 16) | val); +} - int_gen.s._msgtype = APIC_DM_STARTUP >> 8; - int_gen.s._vector = start_rip >> 12; +static void numachip2_apic_icr_write(int apicid, unsigned int val) +{ + numachip2_write32_lcsr(NUMACHIP2_APIC_ICR, (apicid << 12) | val); +} - write_lcsr(CSR_G3_EXT_IRQ_GEN, int_gen.v); +static int numachip_wakeup_secondary(int phys_apicid, unsigned long start_rip) +{ + numachip_apic_icr_write(phys_apicid, APIC_DM_INIT); + numachip_apic_icr_write(phys_apicid, APIC_DM_STARTUP | + (start_rip >> 12)); return 0; } static void numachip_send_IPI_one(int cpu, int vector) { - union numachip_csr_g3_ext_irq_gen int_gen; - int apicid = per_cpu(x86_cpu_to_apicid, cpu); - - int_gen.s._destination_apic_id = apicid; - int_gen.s._vector = vector; - int_gen.s._msgtype = (vector == NMI_VECTOR ? APIC_DM_NMI : APIC_DM_FIXED) >> 8; - int_gen.s._index = 0; + int local_apicid, apicid = per_cpu(x86_cpu_to_apicid, cpu); + unsigned int dmode; + + preempt_disable(); + local_apicid = __this_cpu_read(x86_cpu_to_apicid); + + /* Send via local APIC where non-local part matches */ + if (!((apicid ^ local_apicid) >> NUMACHIP_LAPIC_BITS)) { + unsigned long flags; + + local_irq_save(flags); + __default_send_IPI_dest_field(apicid, vector, + APIC_DEST_PHYSICAL); + local_irq_restore(flags); + preempt_enable(); + return; + } + preempt_enable(); - write_lcsr(CSR_G3_EXT_IRQ_GEN, int_gen.v); + dmode = (vector == NMI_VECTOR) ? APIC_DM_NMI : APIC_DM_FIXED; + numachip_apic_icr_write(apicid, dmode | vector); } static void numachip_send_IPI_mask(const struct cpumask *mask, int vector) @@ -149,9 +160,14 @@ static void numachip_send_IPI_self(int vector) apic_write(APIC_SELF_IPI, vector); } -static int __init numachip_probe(void) +static int __init numachip1_probe(void) { - return apic == &apic_numachip; + return apic == &apic_numachip1; +} + +static int __init numachip2_probe(void) +{ + return apic == &apic_numachip2; } static void fixup_cpu_id(struct cpuinfo_x86 *c, int node) @@ -172,34 +188,118 @@ static void fixup_cpu_id(struct cpuinfo_x86 *c, int node) static int __init numachip_system_init(void) { - if (!numachip_system) + /* Map the LCSR area and set up the apic_icr_write function */ + switch (numachip_system) { + case 1: + init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE); + numachip_apic_icr_write = numachip1_apic_icr_write; + x86_init.pci.arch_init = pci_numachip_init; + break; + case 2: + init_extra_mapping_uc(NUMACHIP2_LCSR_BASE, NUMACHIP2_LCSR_SIZE); + numachip_apic_icr_write = numachip2_apic_icr_write; + + /* Use MCFG config cycles rather than locked CF8 cycles */ + raw_pci_ops = &pci_mmcfg; + break; + default: return 0; - - init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE); - init_extra_mapping_uc(NUMACHIP_GCSR_BASE, NUMACHIP_GCSR_SIZE); + } x86_cpuinit.fixup_cpu_id = fixup_cpu_id; - x86_init.pci.arch_init = pci_numachip_init; return 0; } early_initcall(numachip_system_init); -static int numachip_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +static int numachip1_acpi_madt_oem_check(char *oem_id, char *oem_table_id) { - if (!strncmp(oem_id, "NUMASC", 6)) { - numachip_system = 1; - return 1; - } + if ((strncmp(oem_id, "NUMASC", 6) != 0) || + (strncmp(oem_table_id, "NCONNECT", 8) != 0)) + return 0; - return 0; + numachip_system = 1; + + return 1; +} + +static int numachip2_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + if ((strncmp(oem_id, "NUMASC", 6) != 0) || + (strncmp(oem_table_id, "NCONECT2", 8) != 0)) + return 0; + + numachip_system = 2; + + return 1; +} + +/* APIC IPIs are queued */ +static void numachip_apic_wait_icr_idle(void) +{ } -static const struct apic apic_numachip __refconst = { +/* APIC NMI IPIs are queued */ +static u32 numachip_safe_apic_wait_icr_idle(void) +{ + return 0; +} +static const struct apic apic_numachip1 __refconst = { .name = "NumaConnect system", - .probe = numachip_probe, - .acpi_madt_oem_check = numachip_acpi_madt_oem_check, + .probe = numachip1_probe, + .acpi_madt_oem_check = numachip1_acpi_madt_oem_check, + .apic_id_valid = numachip_apic_id_valid, + .apic_id_registered = numachip_apic_id_registered, + + .irq_delivery_mode = dest_Fixed, + .irq_dest_mode = 0, /* physical */ + + .target_cpus = online_target_cpus, + .disable_esr = 0, + .dest_logical = 0, + .check_apicid_used = NULL, + + .vector_allocation_domain = default_vector_allocation_domain, + .init_apic_ldr = flat_init_apic_ldr, + + .ioapic_phys_id_map = NULL, + .setup_apic_routing = NULL, + .cpu_present_to_apicid = default_cpu_present_to_apicid, + .apicid_to_cpu_present = NULL, + .check_phys_apicid_present = default_check_phys_apicid_present, + .phys_pkg_id = numachip_phys_pkg_id, + + .get_apic_id = numachip1_get_apic_id, + .set_apic_id = numachip1_set_apic_id, + .apic_id_mask = 0xffU << 24, + + .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, + + .send_IPI_mask = numachip_send_IPI_mask, + .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself, + .send_IPI_allbutself = numachip_send_IPI_allbutself, + .send_IPI_all = numachip_send_IPI_all, + .send_IPI_self = numachip_send_IPI_self, + + .wakeup_secondary_cpu = numachip_wakeup_secondary, + .inquire_remote_apic = NULL, /* REMRD not supported */ + + .read = native_apic_mem_read, + .write = native_apic_mem_write, + .eoi_write = native_apic_mem_write, + .icr_read = native_apic_icr_read, + .icr_write = native_apic_icr_write, + .wait_icr_idle = numachip_apic_wait_icr_idle, + .safe_wait_icr_idle = numachip_safe_apic_wait_icr_idle, +}; + +apic_driver(apic_numachip1); + +static const struct apic apic_numachip2 __refconst = { + .name = "NumaConnect2 system", + .probe = numachip2_probe, + .acpi_madt_oem_check = numachip2_acpi_madt_oem_check, .apic_id_valid = numachip_apic_id_valid, .apic_id_registered = numachip_apic_id_registered, @@ -221,8 +321,8 @@ static const struct apic apic_numachip __refconst = { .check_phys_apicid_present = default_check_phys_apicid_present, .phys_pkg_id = numachip_phys_pkg_id, - .get_apic_id = get_apic_id, - .set_apic_id = set_apic_id, + .get_apic_id = numachip2_get_apic_id, + .set_apic_id = numachip2_set_apic_id, .apic_id_mask = 0xffU << 24, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, @@ -241,8 +341,8 @@ static const struct apic apic_numachip __refconst = { .eoi_write = native_apic_mem_write, .icr_read = native_apic_icr_read, .icr_write = native_apic_icr_write, - .wait_icr_idle = native_apic_wait_icr_idle, - .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, + .wait_icr_idle = numachip_apic_wait_icr_idle, + .safe_wait_icr_idle = numachip_safe_apic_wait_icr_idle, }; -apic_driver(apic_numachip); +apic_driver(apic_numachip2); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 5c60bb162622..f25321894ad2 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -529,7 +529,7 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector) } } -void eoi_ioapic_pin(int vector, struct mp_chip_data *data) +static void eoi_ioapic_pin(int vector, struct mp_chip_data *data) { unsigned long flags; struct irq_pin_list *entry; @@ -2547,7 +2547,9 @@ void __init setup_ioapic_dest(void) mask = apic->target_cpus(); chip = irq_data_get_irq_chip(idata); - chip->irq_set_affinity(idata, mask, false); + /* Might be lapic_chip for irq 0 */ + if (chip->irq_set_affinity) + chip->irq_set_affinity(idata, mask, false); } } #endif @@ -2907,6 +2909,7 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, struct irq_data *irq_data; struct mp_chip_data *data; struct irq_alloc_info *info = arg; + unsigned long flags; if (!info || nr_irqs > 1) return -EINVAL; @@ -2939,11 +2942,14 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, cfg = irqd_cfg(irq_data); add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin); + + local_irq_save(flags); if (info->ioapic_entry) mp_setup_entry(cfg, data, info->ioapic_entry); mp_register_handler(virq, data->trigger); if (virq < nr_legacy_irqs()) legacy_pic->mask(virq); + local_irq_restore(flags); apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n", diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 8e3d22a1af94..95a18e25d5bf 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -54,9 +54,6 @@ void common(void) { OFFSET(IA32_SIGCONTEXT_ip, sigcontext_ia32, ip); BLANK(); - OFFSET(TI_sysenter_return, thread_info, sysenter_return); - - BLANK(); OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext); #endif diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 4eb065c6bed2..58031303e304 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_rapl.o perf_event_intel_cqm.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_pt.o perf_event_intel_bts.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_cstate.o obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += perf_event_intel_uncore.o \ perf_event_intel_uncore_snb.o \ diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index be4febc58b94..e38d338a6447 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -157,7 +157,7 @@ struct _cpuid4_info_regs { struct amd_northbridge *nb; }; -unsigned short num_cache_leaves; +static unsigned short num_cache_leaves; /* AMD doesn't have CPUID4. Emulate it here to report the same information to the user. This makes some assumptions about the machine: @@ -326,7 +326,7 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb) * * @returns: the disabled index if used or negative value if slot free. */ -int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot) +static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot) { unsigned int reg = 0; @@ -403,8 +403,8 @@ static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu, * * @return: 0 on success, error status on failure */ -int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot, - unsigned long index) +static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, + unsigned slot, unsigned long index) { int ret = 0; diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 9d014b82a124..c5b0d562dbf5 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1586,6 +1586,8 @@ static int __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) winchip_mcheck_init(c); return 1; break; + default: + return 0; } return 0; @@ -1605,6 +1607,8 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) mce_amd_feature_init(c); mce_flags.overflow_recov = !!(ebx & BIT(0)); mce_flags.succor = !!(ebx & BIT(1)); + mce_flags.smca = !!(ebx & BIT(3)); + break; } @@ -2042,7 +2046,7 @@ int __init mcheck_init(void) * Disable machine checks on suspend and shutdown. We can't really handle * them later. */ -static int mce_disable_error_reporting(void) +static void mce_disable_error_reporting(void) { int i; @@ -2052,17 +2056,32 @@ static int mce_disable_error_reporting(void) if (b->init) wrmsrl(MSR_IA32_MCx_CTL(i), 0); } - return 0; + return; +} + +static void vendor_disable_error_reporting(void) +{ + /* + * Don't clear on Intel CPUs. Some of these MSRs are socket-wide. + * Disabling them for just a single offlined CPU is bad, since it will + * inhibit reporting for all shared resources on the socket like the + * last level cache (LLC), the integrated memory controller (iMC), etc. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + return; + + mce_disable_error_reporting(); } static int mce_syscore_suspend(void) { - return mce_disable_error_reporting(); + vendor_disable_error_reporting(); + return 0; } static void mce_syscore_shutdown(void) { - mce_disable_error_reporting(); + vendor_disable_error_reporting(); } /* @@ -2342,19 +2361,14 @@ static void mce_device_remove(unsigned int cpu) static void mce_disable_cpu(void *h) { unsigned long action = *(unsigned long *)h; - int i; if (!mce_available(raw_cpu_ptr(&cpu_info))) return; if (!(action & CPU_TASKS_FROZEN)) cmci_clear(); - for (i = 0; i < mca_cfg.banks; i++) { - struct mce_bank *b = &mce_banks[i]; - if (b->init) - wrmsrl(MSR_IA32_MCx_CTL(i), 0); - } + vendor_disable_error_reporting(); } static void mce_reenable_cpu(void *h) diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 1af51b1586d7..2c5aaf8c2e2f 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -503,14 +503,6 @@ void intel_init_thermal(struct cpuinfo_x86 *c) return; } - /* Check whether a vector already exists */ - if (h & APIC_VECTOR_MASK) { - printk(KERN_DEBUG - "CPU%d: Thermal LVT vector (%#x) already installed\n", - cpu, (h & APIC_VECTOR_MASK)); - return; - } - /* early Pentium M models use different method for enabling TM2 */ if (cpu_has(c, X86_FEATURE_TM2)) { if (c->x86 == 6 && (c->x86_model == 9 || c->x86_model == 13)) { diff --git a/arch/x86/kernel/cpu/microcode/Makefile b/arch/x86/kernel/cpu/microcode/Makefile index 285c85427c32..220b1a508513 100644 --- a/arch/x86/kernel/cpu/microcode/Makefile +++ b/arch/x86/kernel/cpu/microcode/Makefile @@ -2,6 +2,3 @@ microcode-y := core.o obj-$(CONFIG_MICROCODE) += microcode.o microcode-$(CONFIG_MICROCODE_INTEL) += intel.o intel_lib.o microcode-$(CONFIG_MICROCODE_AMD) += amd.o -obj-$(CONFIG_MICROCODE_EARLY) += core_early.o -obj-$(CONFIG_MICROCODE_INTEL_EARLY) += intel_early.o -obj-$(CONFIG_MICROCODE_AMD_EARLY) += amd_early.o diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 12829c3ced3c..2233f8a76615 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -1,5 +1,9 @@ /* * AMD CPU Microcode Update Driver for Linux + * + * This driver allows to upgrade microcode on F10h AMD + * CPUs and later. + * * Copyright (C) 2008-2011 Advanced Micro Devices Inc. * * Author: Peter Oruba <peter.oruba@amd.com> @@ -7,34 +11,31 @@ * Based on work by: * Tigran Aivazian <tigran@aivazian.fsnet.co.uk> * - * Maintainers: - * Andreas Herrmann <herrmann.der.user@googlemail.com> - * Borislav Petkov <bp@alien8.de> + * early loader: + * Copyright (C) 2013 Advanced Micro Devices, Inc. * - * This driver allows to upgrade microcode on F10h AMD - * CPUs and later. + * Author: Jacob Shin <jacob.shin@amd.com> + * Fixes: Borislav Petkov <bp@suse.de> * * Licensed under the terms of the GNU General Public * License version 2. See file COPYING for details. */ +#define pr_fmt(fmt) "microcode: " fmt -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include <linux/earlycpio.h> #include <linux/firmware.h> #include <linux/uaccess.h> #include <linux/vmalloc.h> +#include <linux/initrd.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/pci.h> +#include <asm/microcode_amd.h> #include <asm/microcode.h> #include <asm/processor.h> +#include <asm/setup.h> +#include <asm/cpu.h> #include <asm/msr.h> -#include <asm/microcode_amd.h> - -MODULE_DESCRIPTION("AMD Microcode Update Driver"); -MODULE_AUTHOR("Peter Oruba"); -MODULE_LICENSE("GPL v2"); static struct equiv_cpu_entry *equiv_cpu_table; @@ -47,6 +48,432 @@ struct ucode_patch { static LIST_HEAD(pcache); +/* + * This points to the current valid container of microcode patches which we will + * save from the initrd before jettisoning its contents. + */ +static u8 *container; +static size_t container_size; + +static u32 ucode_new_rev; +u8 amd_ucode_patch[PATCH_MAX_SIZE]; +static u16 this_equiv_id; + +static struct cpio_data ucode_cpio; + +/* + * Microcode patch container file is prepended to the initrd in cpio format. + * See Documentation/x86/early-microcode.txt + */ +static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin"; + +static struct cpio_data __init find_ucode_in_initrd(void) +{ + long offset = 0; + char *path; + void *start; + size_t size; + +#ifdef CONFIG_X86_32 + struct boot_params *p; + + /* + * On 32-bit, early load occurs before paging is turned on so we need + * to use physical addresses. + */ + p = (struct boot_params *)__pa_nodebug(&boot_params); + path = (char *)__pa_nodebug(ucode_path); + start = (void *)p->hdr.ramdisk_image; + size = p->hdr.ramdisk_size; +#else + path = ucode_path; + start = (void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET); + size = boot_params.hdr.ramdisk_size; +#endif + + return find_cpio_data(path, start, size, &offset); +} + +static size_t compute_container_size(u8 *data, u32 total_size) +{ + size_t size = 0; + u32 *header = (u32 *)data; + + if (header[0] != UCODE_MAGIC || + header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */ + header[2] == 0) /* size */ + return size; + + size = header[2] + CONTAINER_HDR_SZ; + total_size -= size; + data += size; + + while (total_size) { + u16 patch_size; + + header = (u32 *)data; + + if (header[0] != UCODE_UCODE_TYPE) + break; + + /* + * Sanity-check patch size. + */ + patch_size = header[1]; + if (patch_size > PATCH_MAX_SIZE) + break; + + size += patch_size + SECTION_HDR_SIZE; + data += patch_size + SECTION_HDR_SIZE; + total_size -= patch_size + SECTION_HDR_SIZE; + } + + return size; +} + +/* + * Early load occurs before we can vmalloc(). So we look for the microcode + * patch container file in initrd, traverse equivalent cpu table, look for a + * matching microcode patch, and update, all in initrd memory in place. + * When vmalloc() is available for use later -- on 64-bit during first AP load, + * and on 32-bit during save_microcode_in_initrd_amd() -- we can call + * load_microcode_amd() to save equivalent cpu table and microcode patches in + * kernel heap memory. + */ +static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) +{ + struct equiv_cpu_entry *eq; + size_t *cont_sz; + u32 *header; + u8 *data, **cont; + u8 (*patch)[PATCH_MAX_SIZE]; + u16 eq_id = 0; + int offset, left; + u32 rev, eax, ebx, ecx, edx; + u32 *new_rev; + +#ifdef CONFIG_X86_32 + new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); + cont_sz = (size_t *)__pa_nodebug(&container_size); + cont = (u8 **)__pa_nodebug(&container); + patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); +#else + new_rev = &ucode_new_rev; + cont_sz = &container_size; + cont = &container; + patch = &amd_ucode_patch; +#endif + + data = ucode; + left = size; + header = (u32 *)data; + + /* find equiv cpu table */ + if (header[0] != UCODE_MAGIC || + header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */ + header[2] == 0) /* size */ + return; + + eax = 0x00000001; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + + while (left > 0) { + eq = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ); + + *cont = data; + + /* Advance past the container header */ + offset = header[2] + CONTAINER_HDR_SZ; + data += offset; + left -= offset; + + eq_id = find_equiv_id(eq, eax); + if (eq_id) { + this_equiv_id = eq_id; + *cont_sz = compute_container_size(*cont, left + offset); + + /* + * truncate how much we need to iterate over in the + * ucode update loop below + */ + left = *cont_sz - offset; + break; + } + + /* + * support multiple container files appended together. if this + * one does not have a matching equivalent cpu entry, we fast + * forward to the next container file. + */ + while (left > 0) { + header = (u32 *)data; + if (header[0] == UCODE_MAGIC && + header[1] == UCODE_EQUIV_CPU_TABLE_TYPE) + break; + + offset = header[1] + SECTION_HDR_SIZE; + data += offset; + left -= offset; + } + + /* mark where the next microcode container file starts */ + offset = data - (u8 *)ucode; + ucode = data; + } + + if (!eq_id) { + *cont = NULL; + *cont_sz = 0; + return; + } + + if (check_current_patch_level(&rev, true)) + return; + + while (left > 0) { + struct microcode_amd *mc; + + header = (u32 *)data; + if (header[0] != UCODE_UCODE_TYPE || /* type */ + header[1] == 0) /* size */ + break; + + mc = (struct microcode_amd *)(data + SECTION_HDR_SIZE); + + if (eq_id == mc->hdr.processor_rev_id && rev < mc->hdr.patch_id) { + + if (!__apply_microcode_amd(mc)) { + rev = mc->hdr.patch_id; + *new_rev = rev; + + if (save_patch) + memcpy(patch, mc, + min_t(u32, header[1], PATCH_MAX_SIZE)); + } + } + + offset = header[1] + SECTION_HDR_SIZE; + data += offset; + left -= offset; + } +} + +static bool __init load_builtin_amd_microcode(struct cpio_data *cp, + unsigned int family) +{ +#ifdef CONFIG_X86_64 + char fw_name[36] = "amd-ucode/microcode_amd.bin"; + + if (family >= 0x15) + snprintf(fw_name, sizeof(fw_name), + "amd-ucode/microcode_amd_fam%.2xh.bin", family); + + return get_builtin_firmware(cp, fw_name); +#else + return false; +#endif +} + +void __init load_ucode_amd_bsp(unsigned int family) +{ + struct cpio_data cp; + void **data; + size_t *size; + +#ifdef CONFIG_X86_32 + data = (void **)__pa_nodebug(&ucode_cpio.data); + size = (size_t *)__pa_nodebug(&ucode_cpio.size); +#else + data = &ucode_cpio.data; + size = &ucode_cpio.size; +#endif + + cp = find_ucode_in_initrd(); + if (!cp.data) { + if (!load_builtin_amd_microcode(&cp, family)) + return; + } + + *data = cp.data; + *size = cp.size; + + apply_ucode_in_initrd(cp.data, cp.size, true); +} + +#ifdef CONFIG_X86_32 +/* + * On 32-bit, since AP's early load occurs before paging is turned on, we + * cannot traverse cpu_equiv_table and pcache in kernel heap memory. So during + * cold boot, AP will apply_ucode_in_initrd() just like the BSP. During + * save_microcode_in_initrd_amd() BSP's patch is copied to amd_ucode_patch, + * which is used upon resume from suspend. + */ +void load_ucode_amd_ap(void) +{ + struct microcode_amd *mc; + size_t *usize; + void **ucode; + + mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch); + if (mc->hdr.patch_id && mc->hdr.processor_rev_id) { + __apply_microcode_amd(mc); + return; + } + + ucode = (void *)__pa_nodebug(&container); + usize = (size_t *)__pa_nodebug(&container_size); + + if (!*ucode || !*usize) + return; + + apply_ucode_in_initrd(*ucode, *usize, false); +} + +static void __init collect_cpu_sig_on_bsp(void *arg) +{ + unsigned int cpu = smp_processor_id(); + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + + 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) +{ + unsigned int cpu = smp_processor_id(); + struct equiv_cpu_entry *eq; + struct microcode_amd *mc; + u32 rev, eax; + u16 eq_id; + + /* Exit if called on the BSP. */ + if (!cpu) + return; + + if (!container) + return; + + /* + * 64-bit runs with paging enabled, thus early==false. + */ + if (check_current_patch_level(&rev, false)) + return; + + eax = cpuid_eax(0x00000001); + eq = (struct equiv_cpu_entry *)(container + CONTAINER_HDR_SZ); + + eq_id = find_equiv_id(eq, eax); + if (!eq_id) + return; + + if (eq_id == this_equiv_id) { + mc = (struct microcode_amd *)amd_ucode_patch; + + if (mc && rev < mc->hdr.patch_id) { + if (!__apply_microcode_amd(mc)) + ucode_new_rev = mc->hdr.patch_id; + } + + } else { + if (!ucode_cpio.data) + return; + + /* + * AP has a different equivalence ID than BSP, looks like + * mixed-steppings silicon so go through the ucode blob anew. + */ + apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size, false); + } +} +#endif + +int __init save_microcode_in_initrd_amd(void) +{ + unsigned long cont; + int retval = 0; + enum ucode_state ret; + u8 *cont_va; + u32 eax; + + if (!container) + return -EINVAL; + +#ifdef CONFIG_X86_32 + get_bsp_sig(); + cont = (unsigned long)container; + cont_va = __va(container); +#else + /* + * We need the physical address of the container for both bitness since + * boot_params.hdr.ramdisk_image is a physical address. + */ + cont = __pa(container); + cont_va = 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)); + else + container = cont_va; + + if (ucode_new_rev) + pr_info("microcode: updated early to new patch_level=0x%08x\n", + ucode_new_rev); + + eax = cpuid_eax(0x00000001); + eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); + + ret = load_microcode_amd(smp_processor_id(), eax, container, container_size); + if (ret != UCODE_OK) + retval = -EINVAL; + + /* + * This will be freed any msec now, stash patches for the current + * family and switch to patch cache for cpu hotplug, etc later. + */ + container = NULL; + container_size = 0; + + return retval; +} + +void reload_ucode_amd(void) +{ + struct microcode_amd *mc; + u32 rev; + + /* + * early==false because this is a syscore ->resume path and by + * that time paging is long enabled. + */ + if (check_current_patch_level(&rev, false)) + return; + + mc = (struct microcode_amd *)amd_ucode_patch; + + if (mc && rev < mc->hdr.patch_id) { + if (!__apply_microcode_amd(mc)) { + ucode_new_rev = mc->hdr.patch_id; + pr_info("microcode: reload patch_level=0x%08x\n", + ucode_new_rev); + } + } +} static u16 __find_equiv_id(unsigned int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; @@ -177,6 +604,53 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, return patch_size; } +/* + * Those patch levels cannot be updated to newer ones and thus should be final. + */ +static u32 final_levels[] = { + 0x01000098, + 0x0100009f, + 0x010000af, + 0, /* T-101 terminator */ +}; + +/* + * Check the current patch level on this CPU. + * + * @rev: Use it to return the patch level. It is set to 0 in the case of + * error. + * + * Returns: + * - true: if update should stop + * - false: otherwise + */ +bool check_current_patch_level(u32 *rev, bool early) +{ + u32 lvl, dummy, i; + bool ret = false; + u32 *levels; + + native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); + + if (IS_ENABLED(CONFIG_X86_32) && early) + levels = (u32 *)__pa_nodebug(&final_levels); + else + levels = final_levels; + + for (i = 0; levels[i]; i++) { + if (lvl == levels[i]) { + lvl = 0; + ret = true; + break; + } + } + + if (rev) + *rev = lvl; + + return ret; +} + int __apply_microcode_amd(struct microcode_amd *mc_amd) { u32 rev, dummy; @@ -197,7 +671,7 @@ int apply_microcode_amd(int cpu) struct microcode_amd *mc_amd; struct ucode_cpu_info *uci; struct ucode_patch *p; - u32 rev, dummy; + u32 rev; BUG_ON(raw_smp_processor_id() != cpu); @@ -210,7 +684,8 @@ int apply_microcode_amd(int cpu) mc_amd = p->data; uci->mc = p->data; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + if (check_current_patch_level(&rev, false)) + return -1; /* need to apply patch? */ if (rev >= mc_amd->hdr.patch_id) { @@ -387,7 +862,7 @@ enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t s if (ret != UCODE_OK) cleanup(); -#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32) +#ifdef CONFIG_X86_32 /* save BSP's matching patch for early load */ if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) { struct ucode_patch *p = find_patch(cpu); @@ -475,7 +950,7 @@ static struct microcode_ops microcode_amd_ops = { struct microcode_ops * __init init_amd_microcode(void) { - struct cpuinfo_x86 *c = &cpu_data(0); + struct cpuinfo_x86 *c = &boot_cpu_data; if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { pr_warning("AMD CPU family 0x%x not supported\n", c->x86); diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c deleted file mode 100644 index e8a215a9a345..000000000000 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2013 Advanced Micro Devices, Inc. - * - * Author: Jacob Shin <jacob.shin@amd.com> - * Fixes: Borislav Petkov <bp@suse.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/earlycpio.h> -#include <linux/initrd.h> - -#include <asm/cpu.h> -#include <asm/setup.h> -#include <asm/microcode_amd.h> - -/* - * This points to the current valid container of microcode patches which we will - * save from the initrd before jettisoning its contents. - */ -static u8 *container; -static size_t container_size; - -static u32 ucode_new_rev; -u8 amd_ucode_patch[PATCH_MAX_SIZE]; -static u16 this_equiv_id; - -static struct cpio_data ucode_cpio; - -/* - * Microcode patch container file is prepended to the initrd in cpio format. - * See Documentation/x86/early-microcode.txt - */ -static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin"; - -static struct cpio_data __init find_ucode_in_initrd(void) -{ - long offset = 0; - char *path; - void *start; - size_t size; - -#ifdef CONFIG_X86_32 - struct boot_params *p; - - /* - * On 32-bit, early load occurs before paging is turned on so we need - * to use physical addresses. - */ - p = (struct boot_params *)__pa_nodebug(&boot_params); - path = (char *)__pa_nodebug(ucode_path); - start = (void *)p->hdr.ramdisk_image; - size = p->hdr.ramdisk_size; -#else - path = ucode_path; - start = (void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET); - size = boot_params.hdr.ramdisk_size; -#endif - - return find_cpio_data(path, start, size, &offset); -} - -static size_t compute_container_size(u8 *data, u32 total_size) -{ - size_t size = 0; - u32 *header = (u32 *)data; - - if (header[0] != UCODE_MAGIC || - header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */ - header[2] == 0) /* size */ - return size; - - size = header[2] + CONTAINER_HDR_SZ; - total_size -= size; - data += size; - - while (total_size) { - u16 patch_size; - - header = (u32 *)data; - - if (header[0] != UCODE_UCODE_TYPE) - break; - - /* - * Sanity-check patch size. - */ - patch_size = header[1]; - if (patch_size > PATCH_MAX_SIZE) - break; - - size += patch_size + SECTION_HDR_SIZE; - data += patch_size + SECTION_HDR_SIZE; - total_size -= patch_size + SECTION_HDR_SIZE; - } - - return size; -} - -/* - * Early load occurs before we can vmalloc(). So we look for the microcode - * patch container file in initrd, traverse equivalent cpu table, look for a - * matching microcode patch, and update, all in initrd memory in place. - * When vmalloc() is available for use later -- on 64-bit during first AP load, - * and on 32-bit during save_microcode_in_initrd_amd() -- we can call - * load_microcode_amd() to save equivalent cpu table and microcode patches in - * kernel heap memory. - */ -static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) -{ - struct equiv_cpu_entry *eq; - size_t *cont_sz; - u32 *header; - u8 *data, **cont; - u8 (*patch)[PATCH_MAX_SIZE]; - u16 eq_id = 0; - int offset, left; - u32 rev, eax, ebx, ecx, edx; - u32 *new_rev; - -#ifdef CONFIG_X86_32 - new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); - cont_sz = (size_t *)__pa_nodebug(&container_size); - cont = (u8 **)__pa_nodebug(&container); - patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); -#else - new_rev = &ucode_new_rev; - cont_sz = &container_size; - cont = &container; - patch = &amd_ucode_patch; -#endif - - data = ucode; - left = size; - header = (u32 *)data; - - /* find equiv cpu table */ - if (header[0] != UCODE_MAGIC || - header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */ - header[2] == 0) /* size */ - return; - - eax = 0x00000001; - ecx = 0; - native_cpuid(&eax, &ebx, &ecx, &edx); - - while (left > 0) { - eq = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ); - - *cont = data; - - /* Advance past the container header */ - offset = header[2] + CONTAINER_HDR_SZ; - data += offset; - left -= offset; - - eq_id = find_equiv_id(eq, eax); - if (eq_id) { - this_equiv_id = eq_id; - *cont_sz = compute_container_size(*cont, left + offset); - - /* - * truncate how much we need to iterate over in the - * ucode update loop below - */ - left = *cont_sz - offset; - break; - } - - /* - * support multiple container files appended together. if this - * one does not have a matching equivalent cpu entry, we fast - * forward to the next container file. - */ - while (left > 0) { - header = (u32 *)data; - if (header[0] == UCODE_MAGIC && - header[1] == UCODE_EQUIV_CPU_TABLE_TYPE) - break; - - offset = header[1] + SECTION_HDR_SIZE; - data += offset; - left -= offset; - } - - /* mark where the next microcode container file starts */ - offset = data - (u8 *)ucode; - ucode = data; - } - - if (!eq_id) { - *cont = NULL; - *cont_sz = 0; - return; - } - - /* find ucode and update if needed */ - - native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); - - while (left > 0) { - struct microcode_amd *mc; - - header = (u32 *)data; - if (header[0] != UCODE_UCODE_TYPE || /* type */ - header[1] == 0) /* size */ - break; - - mc = (struct microcode_amd *)(data + SECTION_HDR_SIZE); - - if (eq_id == mc->hdr.processor_rev_id && rev < mc->hdr.patch_id) { - - if (!__apply_microcode_amd(mc)) { - rev = mc->hdr.patch_id; - *new_rev = rev; - - if (save_patch) - memcpy(patch, mc, - min_t(u32, header[1], PATCH_MAX_SIZE)); - } - } - - offset = header[1] + SECTION_HDR_SIZE; - data += offset; - left -= offset; - } -} - -static bool __init load_builtin_amd_microcode(struct cpio_data *cp, - unsigned int family) -{ -#ifdef CONFIG_X86_64 - char fw_name[36] = "amd-ucode/microcode_amd.bin"; - - if (family >= 0x15) - snprintf(fw_name, sizeof(fw_name), - "amd-ucode/microcode_amd_fam%.2xh.bin", family); - - return get_builtin_firmware(cp, fw_name); -#else - return false; -#endif -} - -void __init load_ucode_amd_bsp(unsigned int family) -{ - struct cpio_data cp; - void **data; - size_t *size; - -#ifdef CONFIG_X86_32 - data = (void **)__pa_nodebug(&ucode_cpio.data); - size = (size_t *)__pa_nodebug(&ucode_cpio.size); -#else - data = &ucode_cpio.data; - size = &ucode_cpio.size; -#endif - - cp = find_ucode_in_initrd(); - if (!cp.data) { - if (!load_builtin_amd_microcode(&cp, family)) - return; - } - - *data = cp.data; - *size = cp.size; - - apply_ucode_in_initrd(cp.data, cp.size, true); -} - -#ifdef CONFIG_X86_32 -/* - * On 32-bit, since AP's early load occurs before paging is turned on, we - * cannot traverse cpu_equiv_table and pcache in kernel heap memory. So during - * cold boot, AP will apply_ucode_in_initrd() just like the BSP. During - * save_microcode_in_initrd_amd() BSP's patch is copied to amd_ucode_patch, - * which is used upon resume from suspend. - */ -void load_ucode_amd_ap(void) -{ - struct microcode_amd *mc; - size_t *usize; - void **ucode; - - mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch); - if (mc->hdr.patch_id && mc->hdr.processor_rev_id) { - __apply_microcode_amd(mc); - return; - } - - ucode = (void *)__pa_nodebug(&container); - usize = (size_t *)__pa_nodebug(&container_size); - - if (!*ucode || !*usize) - return; - - apply_ucode_in_initrd(*ucode, *usize, false); -} - -static void __init collect_cpu_sig_on_bsp(void *arg) -{ - unsigned int cpu = smp_processor_id(); - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - - 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) -{ - unsigned int cpu = smp_processor_id(); - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - struct equiv_cpu_entry *eq; - struct microcode_amd *mc; - u32 rev, eax; - u16 eq_id; - - /* Exit if called on the BSP. */ - if (!cpu) - return; - - if (!container) - return; - - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); - - uci->cpu_sig.rev = rev; - uci->cpu_sig.sig = eax; - - eax = cpuid_eax(0x00000001); - eq = (struct equiv_cpu_entry *)(container + CONTAINER_HDR_SZ); - - eq_id = find_equiv_id(eq, eax); - if (!eq_id) - return; - - if (eq_id == this_equiv_id) { - mc = (struct microcode_amd *)amd_ucode_patch; - - if (mc && rev < mc->hdr.patch_id) { - if (!__apply_microcode_amd(mc)) - ucode_new_rev = mc->hdr.patch_id; - } - - } else { - if (!ucode_cpio.data) - return; - - /* - * AP has a different equivalence ID than BSP, looks like - * mixed-steppings silicon so go through the ucode blob anew. - */ - apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size, false); - } -} -#endif - -int __init save_microcode_in_initrd_amd(void) -{ - unsigned long cont; - int retval = 0; - enum ucode_state ret; - u8 *cont_va; - u32 eax; - - if (!container) - return -EINVAL; - -#ifdef CONFIG_X86_32 - get_bsp_sig(); - cont = (unsigned long)container; - cont_va = __va(container); -#else - /* - * We need the physical address of the container for both bitness since - * boot_params.hdr.ramdisk_image is a physical address. - */ - cont = __pa(container); - cont_va = 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)); - else - container = cont_va; - - if (ucode_new_rev) - pr_info("microcode: updated early to new patch_level=0x%08x\n", - ucode_new_rev); - - eax = cpuid_eax(0x00000001); - eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); - - ret = load_microcode_amd(smp_processor_id(), eax, container, container_size); - if (ret != UCODE_OK) - retval = -EINVAL; - - /* - * This will be freed any msec now, stash patches for the current - * family and switch to patch cache for cpu hotplug, etc later. - */ - container = NULL; - container_size = 0; - - return retval; -} - -void reload_ucode_amd(void) -{ - struct microcode_amd *mc; - u32 rev, eax; - - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); - - mc = (struct microcode_amd *)amd_ucode_patch; - - if (mc && rev < mc->hdr.patch_id) { - if (!__apply_microcode_amd(mc)) { - ucode_new_rev = mc->hdr.patch_id; - pr_info("microcode: reload patch_level=0x%08x\n", - ucode_new_rev); - } - } -} diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 9e3f3c7dd5d7..7fc27f1cca58 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -5,6 +5,12 @@ * 2006 Shaohua Li <shaohua.li@intel.com> * 2013-2015 Borislav Petkov <bp@alien8.de> * + * X86 CPU microcode early update for Linux: + * + * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> + * H Peter Anvin" <hpa@zytor.com> + * (C) 2015 Borislav Petkov <bp@alien8.de> + * * This driver allows to upgrade microcode on x86 processors. * * This program is free software; you can redistribute it and/or @@ -13,34 +19,39 @@ * 2 of the License, or (at your option) any later version. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define pr_fmt(fmt) "microcode: " fmt #include <linux/platform_device.h> +#include <linux/syscore_ops.h> #include <linux/miscdevice.h> #include <linux/capability.h> +#include <linux/firmware.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/mutex.h> #include <linux/cpu.h> #include <linux/fs.h> #include <linux/mm.h> -#include <linux/syscore_ops.h> -#include <asm/microcode.h> -#include <asm/processor.h> +#include <asm/microcode_intel.h> #include <asm/cpu_device_id.h> +#include <asm/microcode_amd.h> #include <asm/perf_event.h> +#include <asm/microcode.h> +#include <asm/processor.h> +#include <asm/cmdline.h> -MODULE_DESCRIPTION("Microcode Update Driver"); -MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); -MODULE_LICENSE("GPL"); - -#define MICROCODE_VERSION "2.00" +#define MICROCODE_VERSION "2.01" static struct microcode_ops *microcode_ops; -bool dis_ucode_ldr; -module_param(dis_ucode_ldr, bool, 0); +static bool dis_ucode_ldr; + +static int __init disable_loader(char *str) +{ + dis_ucode_ldr = true; + return 1; +} +__setup("dis_ucode_ldr", disable_loader); /* * Synchronization. @@ -68,6 +79,150 @@ struct cpu_info_ctx { int err; }; +static bool __init check_loader_disabled_bsp(void) +{ +#ifdef CONFIG_X86_32 + const char *cmdline = (const char *)__pa_nodebug(boot_command_line); + const char *opt = "dis_ucode_ldr"; + const char *option = (const char *)__pa_nodebug(opt); + bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr); + +#else /* CONFIG_X86_64 */ + const char *cmdline = boot_command_line; + const char *option = "dis_ucode_ldr"; + bool *res = &dis_ucode_ldr; +#endif + + if (cmdline_find_option_bool(cmdline, option)) + *res = true; + + return *res; +} + +extern struct builtin_fw __start_builtin_fw[]; +extern struct builtin_fw __end_builtin_fw[]; + +bool get_builtin_firmware(struct cpio_data *cd, const char *name) +{ +#ifdef CONFIG_FW_LOADER + struct builtin_fw *b_fw; + + for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { + if (!strcmp(name, b_fw->name)) { + cd->size = b_fw->size; + cd->data = b_fw->data; + return true; + } + } +#endif + return false; +} + +void __init load_ucode_bsp(void) +{ + int vendor; + unsigned int family; + + if (check_loader_disabled_bsp()) + return; + + if (!have_cpuid_p()) + return; + + vendor = x86_vendor(); + family = x86_family(); + + switch (vendor) { + case X86_VENDOR_INTEL: + if (family >= 6) + load_ucode_intel_bsp(); + break; + case X86_VENDOR_AMD: + if (family >= 0x10) + load_ucode_amd_bsp(family); + break; + default: + break; + } +} + +static bool check_loader_disabled_ap(void) +{ +#ifdef CONFIG_X86_32 + return *((bool *)__pa_nodebug(&dis_ucode_ldr)); +#else + return dis_ucode_ldr; +#endif +} + +void load_ucode_ap(void) +{ + int vendor, family; + + if (check_loader_disabled_ap()) + return; + + if (!have_cpuid_p()) + return; + + vendor = x86_vendor(); + family = x86_family(); + + switch (vendor) { + case X86_VENDOR_INTEL: + if (family >= 6) + load_ucode_intel_ap(); + break; + case X86_VENDOR_AMD: + if (family >= 0x10) + load_ucode_amd_ap(); + break; + default: + break; + } +} + +int __init save_microcode_in_initrd(void) +{ + struct cpuinfo_x86 *c = &boot_cpu_data; + + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + if (c->x86 >= 6) + save_microcode_in_initrd_intel(); + break; + case X86_VENDOR_AMD: + if (c->x86 >= 0x10) + save_microcode_in_initrd_amd(); + break; + default: + break; + } + + return 0; +} + +void reload_early_microcode(void) +{ + int vendor, family; + + vendor = x86_vendor(); + family = x86_family(); + + switch (vendor) { + case X86_VENDOR_INTEL: + if (family >= 6) + reload_ucode_intel(); + break; + case X86_VENDOR_AMD: + if (family >= 0x10) + reload_ucode_amd(); + break; + default: + break; + } +} + static void collect_cpu_info_local(void *arg) { struct cpu_info_ctx *ctx = arg; @@ -210,9 +365,6 @@ static void __exit microcode_dev_exit(void) { misc_deregister(µcode_dev); } - -MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); -MODULE_ALIAS("devname:cpu/microcode"); #else #define microcode_dev_init() 0 #define microcode_dev_exit() do { } while (0) @@ -463,20 +615,6 @@ static struct notifier_block mc_cpu_notifier = { .notifier_call = mc_cpu_callback, }; -#ifdef MODULE -/* Autoload on Intel and AMD systems */ -static const struct x86_cpu_id __initconst microcode_id[] = { -#ifdef CONFIG_MICROCODE_INTEL - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, }, -#endif -#ifdef CONFIG_MICROCODE_AMD - { X86_VENDOR_AMD, X86_FAMILY_ANY, X86_MODEL_ANY, }, -#endif - {} -}; -MODULE_DEVICE_TABLE(x86cpu, microcode_id); -#endif - static struct attribute *cpu_root_microcode_attrs[] = { &dev_attr_reload.attr, NULL @@ -487,9 +625,9 @@ static struct attribute_group cpu_root_microcode_group = { .attrs = cpu_root_microcode_attrs, }; -static int __init microcode_init(void) +int __init microcode_init(void) { - struct cpuinfo_x86 *c = &cpu_data(0); + struct cpuinfo_x86 *c = &boot_cpu_data; int error; if (paravirt_enabled() || dis_ucode_ldr) @@ -560,35 +698,3 @@ static int __init microcode_init(void) return error; } -module_init(microcode_init); - -static void __exit microcode_exit(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - microcode_dev_exit(); - - unregister_hotcpu_notifier(&mc_cpu_notifier); - unregister_syscore_ops(&mc_syscore_ops); - - sysfs_remove_group(&cpu_subsys.dev_root->kobj, - &cpu_root_microcode_group); - - get_online_cpus(); - mutex_lock(µcode_mutex); - - subsys_interface_unregister(&mc_cpu_interface); - - mutex_unlock(µcode_mutex); - put_online_cpus(); - - platform_device_unregister(microcode_pdev); - - microcode_ops = NULL; - - if (c->x86_vendor == X86_VENDOR_AMD) - exit_amd_microcode(); - - pr_info("Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); -} -module_exit(microcode_exit); diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c deleted file mode 100644 index 8ebc421d6299..000000000000 --- a/arch/x86/kernel/cpu/microcode/core_early.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * X86 CPU microcode early update for Linux - * - * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> - * H Peter Anvin" <hpa@zytor.com> - * (C) 2015 Borislav Petkov <bp@alien8.de> - * - * This driver allows to early upgrade microcode on Intel processors - * belonging to IA-32 family - PentiumPro, Pentium II, - * Pentium III, Xeon, Pentium 4, etc. - * - * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture - * Software Developer's Manual. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/module.h> -#include <linux/firmware.h> -#include <asm/microcode.h> -#include <asm/microcode_intel.h> -#include <asm/microcode_amd.h> -#include <asm/processor.h> -#include <asm/cmdline.h> - -static bool __init check_loader_disabled_bsp(void) -{ -#ifdef CONFIG_X86_32 - const char *cmdline = (const char *)__pa_nodebug(boot_command_line); - const char *opt = "dis_ucode_ldr"; - const char *option = (const char *)__pa_nodebug(opt); - bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr); - -#else /* CONFIG_X86_64 */ - const char *cmdline = boot_command_line; - const char *option = "dis_ucode_ldr"; - bool *res = &dis_ucode_ldr; -#endif - - if (cmdline_find_option_bool(cmdline, option)) - *res = true; - - return *res; -} - -extern struct builtin_fw __start_builtin_fw[]; -extern struct builtin_fw __end_builtin_fw[]; - -bool get_builtin_firmware(struct cpio_data *cd, const char *name) -{ -#ifdef CONFIG_FW_LOADER - struct builtin_fw *b_fw; - - for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { - if (!strcmp(name, b_fw->name)) { - cd->size = b_fw->size; - cd->data = b_fw->data; - return true; - } - } -#endif - return false; -} - -void __init load_ucode_bsp(void) -{ - int vendor; - unsigned int family; - - if (check_loader_disabled_bsp()) - return; - - if (!have_cpuid_p()) - return; - - vendor = x86_vendor(); - family = x86_family(); - - switch (vendor) { - case X86_VENDOR_INTEL: - if (family >= 6) - load_ucode_intel_bsp(); - break; - case X86_VENDOR_AMD: - if (family >= 0x10) - load_ucode_amd_bsp(family); - break; - default: - break; - } -} - -static bool check_loader_disabled_ap(void) -{ -#ifdef CONFIG_X86_32 - return *((bool *)__pa_nodebug(&dis_ucode_ldr)); -#else - return dis_ucode_ldr; -#endif -} - -void load_ucode_ap(void) -{ - int vendor, family; - - if (check_loader_disabled_ap()) - return; - - if (!have_cpuid_p()) - return; - - vendor = x86_vendor(); - family = x86_family(); - - switch (vendor) { - case X86_VENDOR_INTEL: - if (family >= 6) - load_ucode_intel_ap(); - break; - case X86_VENDOR_AMD: - if (family >= 0x10) - load_ucode_amd_ap(); - break; - default: - break; - } -} - -int __init save_microcode_in_initrd(void) -{ - struct cpuinfo_x86 *c = &boot_cpu_data; - - switch (c->x86_vendor) { - case X86_VENDOR_INTEL: - if (c->x86 >= 6) - save_microcode_in_initrd_intel(); - break; - case X86_VENDOR_AMD: - if (c->x86 >= 0x10) - save_microcode_in_initrd_amd(); - break; - default: - break; - } - - return 0; -} - -void reload_early_microcode(void) -{ - int vendor, family; - - vendor = x86_vendor(); - family = x86_family(); - - switch (vendor) { - case X86_VENDOR_INTEL: - if (family >= 6) - reload_ucode_intel(); - break; - case X86_VENDOR_AMD: - if (family >= 0x10) - reload_ucode_amd(); - break; - default: - break; - } -} diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 969dc17eb1b4..ce47402eb2f9 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -4,27 +4,804 @@ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk> * 2006 Shaohua Li <shaohua.li@intel.com> * + * Intel CPU microcode early update for Linux + * + * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> + * H Peter Anvin" <hpa@zytor.com> + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* + * This needs to be before all headers so that pr_debug in printk.h doesn't turn + * printk calls into no_printk(). + * + *#define DEBUG + */ +#define pr_fmt(fmt) "microcode: " fmt +#include <linux/earlycpio.h> #include <linux/firmware.h> #include <linux/uaccess.h> -#include <linux/kernel.h> -#include <linux/module.h> #include <linux/vmalloc.h> +#include <linux/initrd.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/cpu.h> +#include <linux/mm.h> #include <asm/microcode_intel.h> #include <asm/processor.h> +#include <asm/tlbflush.h> +#include <asm/setup.h> #include <asm/msr.h> -MODULE_DESCRIPTION("Microcode Update Driver"); -MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); -MODULE_LICENSE("GPL"); +static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; +static struct mc_saved_data { + unsigned int mc_saved_count; + struct microcode_intel **mc_saved; +} mc_saved_data; + +static enum ucode_state +load_microcode_early(struct microcode_intel **saved, + unsigned int num_saved, struct ucode_cpu_info *uci) +{ + struct microcode_intel *ucode_ptr, *new_mc = NULL; + struct microcode_header_intel *mc_hdr; + int new_rev, ret, i; + + new_rev = uci->cpu_sig.rev; + + for (i = 0; i < num_saved; i++) { + ucode_ptr = saved[i]; + mc_hdr = (struct microcode_header_intel *)ucode_ptr; + + ret = has_newer_microcode(ucode_ptr, + uci->cpu_sig.sig, + uci->cpu_sig.pf, + new_rev); + if (!ret) + continue; + + new_rev = mc_hdr->rev; + new_mc = ucode_ptr; + } + + if (!new_mc) + return UCODE_NFOUND; + + uci->mc = (struct microcode_intel *)new_mc; + return UCODE_OK; +} + +static inline void +copy_initrd_ptrs(struct microcode_intel **mc_saved, unsigned long *initrd, + unsigned long off, int num_saved) +{ + int i; + + for (i = 0; i < num_saved; i++) + mc_saved[i] = (struct microcode_intel *)(initrd[i] + off); +} + +#ifdef CONFIG_X86_32 +static void +microcode_phys(struct microcode_intel **mc_saved_tmp, + struct mc_saved_data *mc_saved_data) +{ + int i; + struct microcode_intel ***mc_saved; + + mc_saved = (struct microcode_intel ***) + __pa_nodebug(&mc_saved_data->mc_saved); + for (i = 0; i < mc_saved_data->mc_saved_count; i++) { + struct microcode_intel *p; + + p = *(struct microcode_intel **) + __pa_nodebug(mc_saved_data->mc_saved + i); + mc_saved_tmp[i] = (struct microcode_intel *)__pa_nodebug(p); + } +} +#endif + +static enum ucode_state +load_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd, + unsigned long initrd_start, struct ucode_cpu_info *uci) +{ + struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; + unsigned int count = mc_saved_data->mc_saved_count; + + if (!mc_saved_data->mc_saved) { + copy_initrd_ptrs(mc_saved_tmp, initrd, initrd_start, count); + + return load_microcode_early(mc_saved_tmp, count, uci); + } else { +#ifdef CONFIG_X86_32 + microcode_phys(mc_saved_tmp, mc_saved_data); + return load_microcode_early(mc_saved_tmp, count, uci); +#else + return load_microcode_early(mc_saved_data->mc_saved, + count, uci); +#endif + } +} + +/* + * Given CPU signature and a microcode patch, this function finds if the + * microcode patch has matching family and model with the CPU. + */ +static enum ucode_state +matching_model_microcode(struct microcode_header_intel *mc_header, + unsigned long sig) +{ + unsigned int fam, model; + unsigned int fam_ucode, model_ucode; + struct extended_sigtable *ext_header; + unsigned long total_size = get_totalsize(mc_header); + unsigned long data_size = get_datasize(mc_header); + int ext_sigcount, i; + struct extended_signature *ext_sig; + + fam = __x86_family(sig); + model = x86_model(sig); + + fam_ucode = __x86_family(mc_header->sig); + model_ucode = x86_model(mc_header->sig); + + if (fam == fam_ucode && model == model_ucode) + return UCODE_OK; + + /* Look for ext. headers: */ + if (total_size <= data_size + MC_HEADER_SIZE) + return UCODE_NFOUND; + + ext_header = (void *) mc_header + data_size + MC_HEADER_SIZE; + ext_sig = (void *)ext_header + EXT_HEADER_SIZE; + ext_sigcount = ext_header->count; + + for (i = 0; i < ext_sigcount; i++) { + fam_ucode = __x86_family(ext_sig->sig); + model_ucode = x86_model(ext_sig->sig); + + if (fam == fam_ucode && model == model_ucode) + return UCODE_OK; + + ext_sig++; + } + return UCODE_NFOUND; +} + +static int +save_microcode(struct mc_saved_data *mc_saved_data, + struct microcode_intel **mc_saved_src, + unsigned int mc_saved_count) +{ + int i, j; + struct microcode_intel **saved_ptr; + int ret; + + if (!mc_saved_count) + return -EINVAL; + + /* + * Copy new microcode data. + */ + saved_ptr = kcalloc(mc_saved_count, sizeof(struct microcode_intel *), GFP_KERNEL); + if (!saved_ptr) + return -ENOMEM; + + for (i = 0; i < mc_saved_count; i++) { + struct microcode_header_intel *mc_hdr; + struct microcode_intel *mc; + unsigned long size; + + if (!mc_saved_src[i]) { + ret = -EINVAL; + goto err; + } + + mc = mc_saved_src[i]; + mc_hdr = &mc->hdr; + size = get_totalsize(mc_hdr); + + saved_ptr[i] = kmalloc(size, GFP_KERNEL); + if (!saved_ptr[i]) { + ret = -ENOMEM; + goto err; + } + + memcpy(saved_ptr[i], mc, size); + } + + /* + * Point to newly saved microcode. + */ + mc_saved_data->mc_saved = saved_ptr; + mc_saved_data->mc_saved_count = mc_saved_count; + + return 0; + +err: + for (j = 0; j <= i; j++) + kfree(saved_ptr[j]); + kfree(saved_ptr); + + return ret; +} + +/* + * A microcode patch in ucode_ptr is saved into mc_saved + * - if it has matching signature and newer revision compared to an existing + * patch mc_saved. + * - or if it is a newly discovered microcode patch. + * + * The microcode patch should have matching model with CPU. + * + * Returns: The updated number @num_saved of saved microcode patches. + */ +static unsigned int _save_mc(struct microcode_intel **mc_saved, + u8 *ucode_ptr, unsigned int num_saved) +{ + struct microcode_header_intel *mc_hdr, *mc_saved_hdr; + unsigned int sig, pf; + int found = 0, i; + + mc_hdr = (struct microcode_header_intel *)ucode_ptr; + + for (i = 0; i < num_saved; i++) { + mc_saved_hdr = (struct microcode_header_intel *)mc_saved[i]; + sig = mc_saved_hdr->sig; + pf = mc_saved_hdr->pf; + + if (!find_matching_signature(ucode_ptr, sig, pf)) + continue; + + found = 1; + + if (mc_hdr->rev <= mc_saved_hdr->rev) + continue; + + /* + * Found an older ucode saved earlier. Replace it with + * this newer one. + */ + mc_saved[i] = (struct microcode_intel *)ucode_ptr; + break; + } + + /* Newly detected microcode, save it to memory. */ + if (i >= num_saved && !found) + mc_saved[num_saved++] = (struct microcode_intel *)ucode_ptr; + + return num_saved; +} + +/* + * Get microcode matching with BSP's model. Only CPUs with the same model as + * BSP can stay in the platform. + */ +static enum ucode_state __init +get_matching_model_microcode(int cpu, unsigned long start, + void *data, size_t size, + struct mc_saved_data *mc_saved_data, + unsigned long *mc_saved_in_initrd, + struct ucode_cpu_info *uci) +{ + u8 *ucode_ptr = data; + unsigned int leftover = size; + enum ucode_state state = UCODE_OK; + unsigned int mc_size; + struct microcode_header_intel *mc_header; + struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; + unsigned int mc_saved_count = mc_saved_data->mc_saved_count; + int i; + + while (leftover && mc_saved_count < ARRAY_SIZE(mc_saved_tmp)) { + + if (leftover < sizeof(mc_header)) + break; + + mc_header = (struct microcode_header_intel *)ucode_ptr; + + mc_size = get_totalsize(mc_header); + if (!mc_size || mc_size > leftover || + microcode_sanity_check(ucode_ptr, 0) < 0) + break; + + leftover -= mc_size; + + /* + * Since APs with same family and model as the BSP may boot in + * the platform, we need to find and save microcode patches + * with the same family and model as the BSP. + */ + if (matching_model_microcode(mc_header, uci->cpu_sig.sig) != + UCODE_OK) { + ucode_ptr += mc_size; + continue; + } + + mc_saved_count = _save_mc(mc_saved_tmp, ucode_ptr, mc_saved_count); + + ucode_ptr += mc_size; + } + + if (leftover) { + state = UCODE_ERROR; + goto out; + } + + if (mc_saved_count == 0) { + state = UCODE_NFOUND; + goto out; + } + + for (i = 0; i < mc_saved_count; i++) + mc_saved_in_initrd[i] = (unsigned long)mc_saved_tmp[i] - start; + + mc_saved_data->mc_saved_count = mc_saved_count; +out: + return state; +} + +static int collect_cpu_info_early(struct ucode_cpu_info *uci) +{ + unsigned int val[2]; + unsigned int family, model; + struct cpu_signature csig; + unsigned int eax, ebx, ecx, edx; + + csig.sig = 0; + csig.pf = 0; + csig.rev = 0; + + memset(uci, 0, sizeof(*uci)); + + eax = 0x00000001; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + csig.sig = eax; + + family = __x86_family(csig.sig); + model = x86_model(csig.sig); + + if ((model >= 5) || (family > 6)) { + /* get processor flags from MSR 0x17 */ + native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); + csig.pf = 1 << ((val[1] >> 18) & 7); + } + native_wrmsr(MSR_IA32_UCODE_REV, 0, 0); + + /* As documented in the SDM: Do a CPUID 1 here */ + sync_core(); + + /* get the current revision from MSR 0x8B */ + native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); + + csig.rev = val[1]; + + uci->cpu_sig = csig; + uci->valid = 1; + + return 0; +} + +static void show_saved_mc(void) +{ +#ifdef DEBUG + int i, j; + unsigned int sig, pf, rev, total_size, data_size, date; + struct ucode_cpu_info uci; + + if (mc_saved_data.mc_saved_count == 0) { + pr_debug("no microcode data saved.\n"); + return; + } + pr_debug("Total microcode saved: %d\n", mc_saved_data.mc_saved_count); + + collect_cpu_info_early(&uci); + + sig = uci.cpu_sig.sig; + pf = uci.cpu_sig.pf; + rev = uci.cpu_sig.rev; + pr_debug("CPU: sig=0x%x, pf=0x%x, rev=0x%x\n", sig, pf, rev); + + for (i = 0; i < mc_saved_data.mc_saved_count; i++) { + struct microcode_header_intel *mc_saved_header; + struct extended_sigtable *ext_header; + int ext_sigcount; + struct extended_signature *ext_sig; + + mc_saved_header = (struct microcode_header_intel *) + mc_saved_data.mc_saved[i]; + sig = mc_saved_header->sig; + pf = mc_saved_header->pf; + rev = mc_saved_header->rev; + total_size = get_totalsize(mc_saved_header); + data_size = get_datasize(mc_saved_header); + date = mc_saved_header->date; + + pr_debug("mc_saved[%d]: sig=0x%x, pf=0x%x, rev=0x%x, toal size=0x%x, date = %04x-%02x-%02x\n", + i, sig, pf, rev, total_size, + date & 0xffff, + date >> 24, + (date >> 16) & 0xff); + + /* Look for ext. headers: */ + if (total_size <= data_size + MC_HEADER_SIZE) + continue; + + ext_header = (void *) mc_saved_header + data_size + MC_HEADER_SIZE; + ext_sigcount = ext_header->count; + ext_sig = (void *)ext_header + EXT_HEADER_SIZE; + + for (j = 0; j < ext_sigcount; j++) { + sig = ext_sig->sig; + pf = ext_sig->pf; + + pr_debug("\tExtended[%d]: sig=0x%x, pf=0x%x\n", + j, sig, pf); + + ext_sig++; + } + + } +#endif +} + +#ifdef CONFIG_HOTPLUG_CPU +static DEFINE_MUTEX(x86_cpu_microcode_mutex); +/* + * Save this mc into mc_saved_data. So it will be loaded early when a CPU is + * hot added or resumes. + * + * Please make sure this mc should be a valid microcode patch before calling + * this function. + */ +int save_mc_for_early(u8 *mc) +{ + struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; + unsigned int mc_saved_count_init; + unsigned int mc_saved_count; + struct microcode_intel **mc_saved; + int ret = 0; + int i; + + /* + * Hold hotplug lock so mc_saved_data is not accessed by a CPU in + * hotplug. + */ + mutex_lock(&x86_cpu_microcode_mutex); + + mc_saved_count_init = mc_saved_data.mc_saved_count; + mc_saved_count = mc_saved_data.mc_saved_count; + mc_saved = mc_saved_data.mc_saved; + + if (mc_saved && mc_saved_count) + memcpy(mc_saved_tmp, mc_saved, + mc_saved_count * sizeof(struct microcode_intel *)); + /* + * Save the microcode patch mc in mc_save_tmp structure if it's a newer + * version. + */ + mc_saved_count = _save_mc(mc_saved_tmp, mc, mc_saved_count); + + /* + * Save the mc_save_tmp in global mc_saved_data. + */ + ret = save_microcode(&mc_saved_data, mc_saved_tmp, mc_saved_count); + if (ret) { + pr_err("Cannot save microcode patch.\n"); + goto out; + } + + show_saved_mc(); + + /* + * Free old saved microcode data. + */ + if (mc_saved) { + for (i = 0; i < mc_saved_count_init; i++) + kfree(mc_saved[i]); + kfree(mc_saved); + } + +out: + mutex_unlock(&x86_cpu_microcode_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(save_mc_for_early); +#endif + +static bool __init load_builtin_intel_microcode(struct cpio_data *cp) +{ +#ifdef CONFIG_X86_64 + unsigned int eax = 0x00000001, ebx, ecx = 0, edx; + unsigned int family, model, stepping; + char name[30]; + + native_cpuid(&eax, &ebx, &ecx, &edx); + + family = __x86_family(eax); + model = x86_model(eax); + stepping = eax & 0xf; + + sprintf(name, "intel-ucode/%02x-%02x-%02x", family, model, stepping); + + return get_builtin_firmware(cp, name); +#else + return false; +#endif +} + +static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; +static __init enum ucode_state +scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd, + unsigned long start, unsigned long size, + struct ucode_cpu_info *uci) +{ + struct cpio_data cd; + long offset = 0; +#ifdef CONFIG_X86_32 + char *p = (char *)__pa_nodebug(ucode_name); +#else + char *p = ucode_name; +#endif + + cd.data = NULL; + cd.size = 0; + + cd = find_cpio_data(p, (void *)start, size, &offset); + if (!cd.data) { + if (!load_builtin_intel_microcode(&cd)) + return UCODE_ERROR; + } + + return get_matching_model_microcode(0, start, cd.data, cd.size, + mc_saved_data, initrd, uci); +} + +/* + * Print ucode update info. + */ +static void +print_ucode_info(struct ucode_cpu_info *uci, unsigned int date) +{ + int cpu = smp_processor_id(); + + pr_info("CPU%d microcode updated early to revision 0x%x, date = %04x-%02x-%02x\n", + cpu, + uci->cpu_sig.rev, + date & 0xffff, + date >> 24, + (date >> 16) & 0xff); +} + +#ifdef CONFIG_X86_32 + +static int delay_ucode_info; +static int current_mc_date; + +/* + * Print early updated ucode info after printk works. This is delayed info dump. + */ +void show_ucode_info_early(void) +{ + struct ucode_cpu_info uci; + + if (delay_ucode_info) { + collect_cpu_info_early(&uci); + print_ucode_info(&uci, current_mc_date); + delay_ucode_info = 0; + } +} + +/* + * At this point, we can not call printk() yet. Keep microcode patch number in + * mc_saved_data.mc_saved and delay printing microcode info in + * show_ucode_info_early() until printk() works. + */ +static void print_ucode(struct ucode_cpu_info *uci) +{ + struct microcode_intel *mc_intel; + int *delay_ucode_info_p; + int *current_mc_date_p; + + mc_intel = uci->mc; + if (mc_intel == NULL) + return; + + delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info); + current_mc_date_p = (int *)__pa_nodebug(¤t_mc_date); + + *delay_ucode_info_p = 1; + *current_mc_date_p = mc_intel->hdr.date; +} +#else + +/* + * Flush global tlb. We only do this in x86_64 where paging has been enabled + * already and PGE should be enabled as well. + */ +static inline void flush_tlb_early(void) +{ + __native_flush_tlb_global_irq_disabled(); +} + +static inline void print_ucode(struct ucode_cpu_info *uci) +{ + struct microcode_intel *mc_intel; + + mc_intel = uci->mc; + if (mc_intel == NULL) + return; + + print_ucode_info(uci, mc_intel->hdr.date); +} +#endif + +static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) +{ + struct microcode_intel *mc_intel; + unsigned int val[2]; + + mc_intel = uci->mc; + if (mc_intel == NULL) + return 0; + + /* write microcode via MSR 0x79 */ + native_wrmsr(MSR_IA32_UCODE_WRITE, + (unsigned long) mc_intel->bits, + (unsigned long) mc_intel->bits >> 16 >> 16); + native_wrmsr(MSR_IA32_UCODE_REV, 0, 0); + + /* As documented in the SDM: Do a CPUID 1 here */ + sync_core(); + + /* get the current revision from MSR 0x8B */ + native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); + if (val[1] != mc_intel->hdr.rev) + return -1; + +#ifdef CONFIG_X86_64 + /* Flush global tlb. This is precaution. */ + flush_tlb_early(); +#endif + uci->cpu_sig.rev = val[1]; + + if (early) + print_ucode(uci); + else + print_ucode_info(uci, mc_intel->hdr.date); + + return 0; +} + +/* + * This function converts microcode patch offsets previously stored in + * mc_saved_in_initrd to pointers and stores the pointers in mc_saved_data. + */ +int __init save_microcode_in_initrd_intel(void) +{ + unsigned int count = mc_saved_data.mc_saved_count; + struct microcode_intel *mc_saved[MAX_UCODE_COUNT]; + int ret = 0; + + if (count == 0) + return ret; + + copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, initrd_start, count); + ret = save_microcode(&mc_saved_data, mc_saved, count); + if (ret) + pr_err("Cannot save microcode patches from initrd.\n"); + + show_saved_mc(); + + return ret; +} + +static void __init +_load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data, + unsigned long *initrd, + unsigned long start, unsigned long size) +{ + struct ucode_cpu_info uci; + enum ucode_state ret; + + collect_cpu_info_early(&uci); + + ret = scan_microcode(mc_saved_data, initrd, start, size, &uci); + if (ret != UCODE_OK) + return; + + ret = load_microcode(mc_saved_data, initrd, start, &uci); + if (ret != UCODE_OK) + return; + + apply_microcode_early(&uci, true); +} + +void __init load_ucode_intel_bsp(void) +{ + u64 start, size; +#ifdef CONFIG_X86_32 + struct boot_params *p; + + p = (struct boot_params *)__pa_nodebug(&boot_params); + start = p->hdr.ramdisk_image; + size = p->hdr.ramdisk_size; + + _load_ucode_intel_bsp( + (struct mc_saved_data *)__pa_nodebug(&mc_saved_data), + (unsigned long *)__pa_nodebug(&mc_saved_in_initrd), + start, size); +#else + start = boot_params.hdr.ramdisk_image + PAGE_OFFSET; + size = boot_params.hdr.ramdisk_size; + + _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, start, size); +#endif +} + +void load_ucode_intel_ap(void) +{ + struct mc_saved_data *mc_saved_data_p; + struct ucode_cpu_info uci; + unsigned long *mc_saved_in_initrd_p; + unsigned long initrd_start_addr; + enum ucode_state ret; +#ifdef CONFIG_X86_32 + unsigned long *initrd_start_p; + + mc_saved_in_initrd_p = + (unsigned long *)__pa_nodebug(mc_saved_in_initrd); + mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); + initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start); + initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p); +#else + mc_saved_data_p = &mc_saved_data; + mc_saved_in_initrd_p = mc_saved_in_initrd; + initrd_start_addr = initrd_start; +#endif + + /* + * If there is no valid ucode previously saved in memory, no need to + * update ucode on this AP. + */ + if (mc_saved_data_p->mc_saved_count == 0) + return; + + collect_cpu_info_early(&uci); + ret = load_microcode(mc_saved_data_p, mc_saved_in_initrd_p, + initrd_start_addr, &uci); + + if (ret != UCODE_OK) + return; + + apply_microcode_early(&uci, true); +} + +void reload_ucode_intel(void) +{ + struct ucode_cpu_info uci; + enum ucode_state ret; + + if (!mc_saved_data.mc_saved_count) + return; + + collect_cpu_info_early(&uci); + + ret = load_microcode_early(mc_saved_data.mc_saved, + mc_saved_data.mc_saved_count, &uci); + if (ret != UCODE_OK) + return; + + apply_microcode_early(&uci, false); +} static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) { @@ -264,7 +1041,7 @@ static struct microcode_ops microcode_intel_ops = { struct microcode_ops * __init init_intel_microcode(void) { - struct cpuinfo_x86 *c = &cpu_data(0); + struct cpuinfo_x86 *c = &boot_cpu_data; if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || cpu_has(c, X86_FEATURE_IA64)) { diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c deleted file mode 100644 index 37ea89c11520..000000000000 --- a/arch/x86/kernel/cpu/microcode/intel_early.c +++ /dev/null @@ -1,808 +0,0 @@ -/* - * Intel CPU microcode early update for Linux - * - * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> - * H Peter Anvin" <hpa@zytor.com> - * - * This allows to early upgrade microcode on Intel processors - * belonging to IA-32 family - PentiumPro, Pentium II, - * Pentium III, Xeon, Pentium 4, etc. - * - * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture - * Software Developer's Manual. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * This needs to be before all headers so that pr_debug in printk.h doesn't turn - * printk calls into no_printk(). - * - *#define DEBUG - */ - -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/earlycpio.h> -#include <linux/initrd.h> -#include <linux/cpu.h> -#include <asm/msr.h> -#include <asm/microcode_intel.h> -#include <asm/processor.h> -#include <asm/tlbflush.h> -#include <asm/setup.h> - -#undef pr_fmt -#define pr_fmt(fmt) "microcode: " fmt - -static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; -static struct mc_saved_data { - unsigned int mc_saved_count; - struct microcode_intel **mc_saved; -} mc_saved_data; - -static enum ucode_state -load_microcode_early(struct microcode_intel **saved, - unsigned int num_saved, struct ucode_cpu_info *uci) -{ - struct microcode_intel *ucode_ptr, *new_mc = NULL; - struct microcode_header_intel *mc_hdr; - int new_rev, ret, i; - - new_rev = uci->cpu_sig.rev; - - for (i = 0; i < num_saved; i++) { - ucode_ptr = saved[i]; - mc_hdr = (struct microcode_header_intel *)ucode_ptr; - - ret = has_newer_microcode(ucode_ptr, - uci->cpu_sig.sig, - uci->cpu_sig.pf, - new_rev); - if (!ret) - continue; - - new_rev = mc_hdr->rev; - new_mc = ucode_ptr; - } - - if (!new_mc) - return UCODE_NFOUND; - - uci->mc = (struct microcode_intel *)new_mc; - return UCODE_OK; -} - -static inline void -copy_initrd_ptrs(struct microcode_intel **mc_saved, unsigned long *initrd, - unsigned long off, int num_saved) -{ - int i; - - for (i = 0; i < num_saved; i++) - mc_saved[i] = (struct microcode_intel *)(initrd[i] + off); -} - -#ifdef CONFIG_X86_32 -static void -microcode_phys(struct microcode_intel **mc_saved_tmp, - struct mc_saved_data *mc_saved_data) -{ - int i; - struct microcode_intel ***mc_saved; - - mc_saved = (struct microcode_intel ***) - __pa_nodebug(&mc_saved_data->mc_saved); - for (i = 0; i < mc_saved_data->mc_saved_count; i++) { - struct microcode_intel *p; - - p = *(struct microcode_intel **) - __pa_nodebug(mc_saved_data->mc_saved + i); - mc_saved_tmp[i] = (struct microcode_intel *)__pa_nodebug(p); - } -} -#endif - -static enum ucode_state -load_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd, - unsigned long initrd_start, struct ucode_cpu_info *uci) -{ - struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; - unsigned int count = mc_saved_data->mc_saved_count; - - if (!mc_saved_data->mc_saved) { - copy_initrd_ptrs(mc_saved_tmp, initrd, initrd_start, count); - - return load_microcode_early(mc_saved_tmp, count, uci); - } else { -#ifdef CONFIG_X86_32 - microcode_phys(mc_saved_tmp, mc_saved_data); - return load_microcode_early(mc_saved_tmp, count, uci); -#else - return load_microcode_early(mc_saved_data->mc_saved, - count, uci); -#endif - } -} - -/* - * Given CPU signature and a microcode patch, this function finds if the - * microcode patch has matching family and model with the CPU. - */ -static enum ucode_state -matching_model_microcode(struct microcode_header_intel *mc_header, - unsigned long sig) -{ - unsigned int fam, model; - unsigned int fam_ucode, model_ucode; - struct extended_sigtable *ext_header; - unsigned long total_size = get_totalsize(mc_header); - unsigned long data_size = get_datasize(mc_header); - int ext_sigcount, i; - struct extended_signature *ext_sig; - - fam = __x86_family(sig); - model = x86_model(sig); - - fam_ucode = __x86_family(mc_header->sig); - model_ucode = x86_model(mc_header->sig); - - if (fam == fam_ucode && model == model_ucode) - return UCODE_OK; - - /* Look for ext. headers: */ - if (total_size <= data_size + MC_HEADER_SIZE) - return UCODE_NFOUND; - - ext_header = (void *) mc_header + data_size + MC_HEADER_SIZE; - ext_sig = (void *)ext_header + EXT_HEADER_SIZE; - ext_sigcount = ext_header->count; - - for (i = 0; i < ext_sigcount; i++) { - fam_ucode = __x86_family(ext_sig->sig); - model_ucode = x86_model(ext_sig->sig); - - if (fam == fam_ucode && model == model_ucode) - return UCODE_OK; - - ext_sig++; - } - return UCODE_NFOUND; -} - -static int -save_microcode(struct mc_saved_data *mc_saved_data, - struct microcode_intel **mc_saved_src, - unsigned int mc_saved_count) -{ - int i, j; - struct microcode_intel **saved_ptr; - int ret; - - if (!mc_saved_count) - return -EINVAL; - - /* - * Copy new microcode data. - */ - saved_ptr = kcalloc(mc_saved_count, sizeof(struct microcode_intel *), GFP_KERNEL); - if (!saved_ptr) - return -ENOMEM; - - for (i = 0; i < mc_saved_count; i++) { - struct microcode_header_intel *mc_hdr; - struct microcode_intel *mc; - unsigned long size; - - if (!mc_saved_src[i]) { - ret = -EINVAL; - goto err; - } - - mc = mc_saved_src[i]; - mc_hdr = &mc->hdr; - size = get_totalsize(mc_hdr); - - saved_ptr[i] = kmalloc(size, GFP_KERNEL); - if (!saved_ptr[i]) { - ret = -ENOMEM; - goto err; - } - - memcpy(saved_ptr[i], mc, size); - } - - /* - * Point to newly saved microcode. - */ - mc_saved_data->mc_saved = saved_ptr; - mc_saved_data->mc_saved_count = mc_saved_count; - - return 0; - -err: - for (j = 0; j <= i; j++) - kfree(saved_ptr[j]); - kfree(saved_ptr); - - return ret; -} - -/* - * A microcode patch in ucode_ptr is saved into mc_saved - * - if it has matching signature and newer revision compared to an existing - * patch mc_saved. - * - or if it is a newly discovered microcode patch. - * - * The microcode patch should have matching model with CPU. - * - * Returns: The updated number @num_saved of saved microcode patches. - */ -static unsigned int _save_mc(struct microcode_intel **mc_saved, - u8 *ucode_ptr, unsigned int num_saved) -{ - struct microcode_header_intel *mc_hdr, *mc_saved_hdr; - unsigned int sig, pf; - int found = 0, i; - - mc_hdr = (struct microcode_header_intel *)ucode_ptr; - - for (i = 0; i < num_saved; i++) { - mc_saved_hdr = (struct microcode_header_intel *)mc_saved[i]; - sig = mc_saved_hdr->sig; - pf = mc_saved_hdr->pf; - - if (!find_matching_signature(ucode_ptr, sig, pf)) - continue; - - found = 1; - - if (mc_hdr->rev <= mc_saved_hdr->rev) - continue; - - /* - * Found an older ucode saved earlier. Replace it with - * this newer one. - */ - mc_saved[i] = (struct microcode_intel *)ucode_ptr; - break; - } - - /* Newly detected microcode, save it to memory. */ - if (i >= num_saved && !found) - mc_saved[num_saved++] = (struct microcode_intel *)ucode_ptr; - - return num_saved; -} - -/* - * Get microcode matching with BSP's model. Only CPUs with the same model as - * BSP can stay in the platform. - */ -static enum ucode_state __init -get_matching_model_microcode(int cpu, unsigned long start, - void *data, size_t size, - struct mc_saved_data *mc_saved_data, - unsigned long *mc_saved_in_initrd, - struct ucode_cpu_info *uci) -{ - u8 *ucode_ptr = data; - unsigned int leftover = size; - enum ucode_state state = UCODE_OK; - unsigned int mc_size; - struct microcode_header_intel *mc_header; - struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; - unsigned int mc_saved_count = mc_saved_data->mc_saved_count; - int i; - - while (leftover && mc_saved_count < ARRAY_SIZE(mc_saved_tmp)) { - - if (leftover < sizeof(mc_header)) - break; - - mc_header = (struct microcode_header_intel *)ucode_ptr; - - mc_size = get_totalsize(mc_header); - if (!mc_size || mc_size > leftover || - microcode_sanity_check(ucode_ptr, 0) < 0) - break; - - leftover -= mc_size; - - /* - * Since APs with same family and model as the BSP may boot in - * the platform, we need to find and save microcode patches - * with the same family and model as the BSP. - */ - if (matching_model_microcode(mc_header, uci->cpu_sig.sig) != - UCODE_OK) { - ucode_ptr += mc_size; - continue; - } - - mc_saved_count = _save_mc(mc_saved_tmp, ucode_ptr, mc_saved_count); - - ucode_ptr += mc_size; - } - - if (leftover) { - state = UCODE_ERROR; - goto out; - } - - if (mc_saved_count == 0) { - state = UCODE_NFOUND; - goto out; - } - - for (i = 0; i < mc_saved_count; i++) - mc_saved_in_initrd[i] = (unsigned long)mc_saved_tmp[i] - start; - - mc_saved_data->mc_saved_count = mc_saved_count; -out: - return state; -} - -static int collect_cpu_info_early(struct ucode_cpu_info *uci) -{ - unsigned int val[2]; - unsigned int family, model; - struct cpu_signature csig; - unsigned int eax, ebx, ecx, edx; - - csig.sig = 0; - csig.pf = 0; - csig.rev = 0; - - memset(uci, 0, sizeof(*uci)); - - eax = 0x00000001; - ecx = 0; - native_cpuid(&eax, &ebx, &ecx, &edx); - csig.sig = eax; - - family = __x86_family(csig.sig); - model = x86_model(csig.sig); - - if ((model >= 5) || (family > 6)) { - /* get processor flags from MSR 0x17 */ - native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); - csig.pf = 1 << ((val[1] >> 18) & 7); - } - native_wrmsr(MSR_IA32_UCODE_REV, 0, 0); - - /* As documented in the SDM: Do a CPUID 1 here */ - sync_core(); - - /* get the current revision from MSR 0x8B */ - native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); - - csig.rev = val[1]; - - uci->cpu_sig = csig; - uci->valid = 1; - - return 0; -} - -#ifdef DEBUG -static void show_saved_mc(void) -{ - int i, j; - unsigned int sig, pf, rev, total_size, data_size, date; - struct ucode_cpu_info uci; - - if (mc_saved_data.mc_saved_count == 0) { - pr_debug("no microcode data saved.\n"); - return; - } - pr_debug("Total microcode saved: %d\n", mc_saved_data.mc_saved_count); - - collect_cpu_info_early(&uci); - - sig = uci.cpu_sig.sig; - pf = uci.cpu_sig.pf; - rev = uci.cpu_sig.rev; - pr_debug("CPU: sig=0x%x, pf=0x%x, rev=0x%x\n", sig, pf, rev); - - for (i = 0; i < mc_saved_data.mc_saved_count; i++) { - struct microcode_header_intel *mc_saved_header; - struct extended_sigtable *ext_header; - int ext_sigcount; - struct extended_signature *ext_sig; - - mc_saved_header = (struct microcode_header_intel *) - mc_saved_data.mc_saved[i]; - sig = mc_saved_header->sig; - pf = mc_saved_header->pf; - rev = mc_saved_header->rev; - total_size = get_totalsize(mc_saved_header); - data_size = get_datasize(mc_saved_header); - date = mc_saved_header->date; - - pr_debug("mc_saved[%d]: sig=0x%x, pf=0x%x, rev=0x%x, toal size=0x%x, date = %04x-%02x-%02x\n", - i, sig, pf, rev, total_size, - date & 0xffff, - date >> 24, - (date >> 16) & 0xff); - - /* Look for ext. headers: */ - if (total_size <= data_size + MC_HEADER_SIZE) - continue; - - ext_header = (void *) mc_saved_header + data_size + MC_HEADER_SIZE; - ext_sigcount = ext_header->count; - ext_sig = (void *)ext_header + EXT_HEADER_SIZE; - - for (j = 0; j < ext_sigcount; j++) { - sig = ext_sig->sig; - pf = ext_sig->pf; - - pr_debug("\tExtended[%d]: sig=0x%x, pf=0x%x\n", - j, sig, pf); - - ext_sig++; - } - - } -} -#else -static inline void show_saved_mc(void) -{ -} -#endif - -#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU) -static DEFINE_MUTEX(x86_cpu_microcode_mutex); -/* - * Save this mc into mc_saved_data. So it will be loaded early when a CPU is - * hot added or resumes. - * - * Please make sure this mc should be a valid microcode patch before calling - * this function. - */ -int save_mc_for_early(u8 *mc) -{ - struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; - unsigned int mc_saved_count_init; - unsigned int mc_saved_count; - struct microcode_intel **mc_saved; - int ret = 0; - int i; - - /* - * Hold hotplug lock so mc_saved_data is not accessed by a CPU in - * hotplug. - */ - mutex_lock(&x86_cpu_microcode_mutex); - - mc_saved_count_init = mc_saved_data.mc_saved_count; - mc_saved_count = mc_saved_data.mc_saved_count; - mc_saved = mc_saved_data.mc_saved; - - if (mc_saved && mc_saved_count) - memcpy(mc_saved_tmp, mc_saved, - mc_saved_count * sizeof(struct microcode_intel *)); - /* - * Save the microcode patch mc in mc_save_tmp structure if it's a newer - * version. - */ - mc_saved_count = _save_mc(mc_saved_tmp, mc, mc_saved_count); - - /* - * Save the mc_save_tmp in global mc_saved_data. - */ - ret = save_microcode(&mc_saved_data, mc_saved_tmp, mc_saved_count); - if (ret) { - pr_err("Cannot save microcode patch.\n"); - goto out; - } - - show_saved_mc(); - - /* - * Free old saved microcode data. - */ - if (mc_saved) { - for (i = 0; i < mc_saved_count_init; i++) - kfree(mc_saved[i]); - kfree(mc_saved); - } - -out: - mutex_unlock(&x86_cpu_microcode_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(save_mc_for_early); -#endif - -static bool __init load_builtin_intel_microcode(struct cpio_data *cp) -{ -#ifdef CONFIG_X86_64 - unsigned int eax = 0x00000001, ebx, ecx = 0, edx; - unsigned int family, model, stepping; - char name[30]; - - native_cpuid(&eax, &ebx, &ecx, &edx); - - family = __x86_family(eax); - model = x86_model(eax); - stepping = eax & 0xf; - - sprintf(name, "intel-ucode/%02x-%02x-%02x", family, model, stepping); - - return get_builtin_firmware(cp, name); -#else - return false; -#endif -} - -static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; -static __init enum ucode_state -scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd, - unsigned long start, unsigned long size, - struct ucode_cpu_info *uci) -{ - struct cpio_data cd; - long offset = 0; -#ifdef CONFIG_X86_32 - char *p = (char *)__pa_nodebug(ucode_name); -#else - char *p = ucode_name; -#endif - - cd.data = NULL; - cd.size = 0; - - cd = find_cpio_data(p, (void *)start, size, &offset); - if (!cd.data) { - if (!load_builtin_intel_microcode(&cd)) - return UCODE_ERROR; - } - - return get_matching_model_microcode(0, start, cd.data, cd.size, - mc_saved_data, initrd, uci); -} - -/* - * Print ucode update info. - */ -static void -print_ucode_info(struct ucode_cpu_info *uci, unsigned int date) -{ - int cpu = smp_processor_id(); - - pr_info("CPU%d microcode updated early to revision 0x%x, date = %04x-%02x-%02x\n", - cpu, - uci->cpu_sig.rev, - date & 0xffff, - date >> 24, - (date >> 16) & 0xff); -} - -#ifdef CONFIG_X86_32 - -static int delay_ucode_info; -static int current_mc_date; - -/* - * Print early updated ucode info after printk works. This is delayed info dump. - */ -void show_ucode_info_early(void) -{ - struct ucode_cpu_info uci; - - if (delay_ucode_info) { - collect_cpu_info_early(&uci); - print_ucode_info(&uci, current_mc_date); - delay_ucode_info = 0; - } -} - -/* - * At this point, we can not call printk() yet. Keep microcode patch number in - * mc_saved_data.mc_saved and delay printing microcode info in - * show_ucode_info_early() until printk() works. - */ -static void print_ucode(struct ucode_cpu_info *uci) -{ - struct microcode_intel *mc_intel; - int *delay_ucode_info_p; - int *current_mc_date_p; - - mc_intel = uci->mc; - if (mc_intel == NULL) - return; - - delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info); - current_mc_date_p = (int *)__pa_nodebug(¤t_mc_date); - - *delay_ucode_info_p = 1; - *current_mc_date_p = mc_intel->hdr.date; -} -#else - -/* - * Flush global tlb. We only do this in x86_64 where paging has been enabled - * already and PGE should be enabled as well. - */ -static inline void flush_tlb_early(void) -{ - __native_flush_tlb_global_irq_disabled(); -} - -static inline void print_ucode(struct ucode_cpu_info *uci) -{ - struct microcode_intel *mc_intel; - - mc_intel = uci->mc; - if (mc_intel == NULL) - return; - - print_ucode_info(uci, mc_intel->hdr.date); -} -#endif - -static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) -{ - struct microcode_intel *mc_intel; - unsigned int val[2]; - - mc_intel = uci->mc; - if (mc_intel == NULL) - return 0; - - /* write microcode via MSR 0x79 */ - native_wrmsr(MSR_IA32_UCODE_WRITE, - (unsigned long) mc_intel->bits, - (unsigned long) mc_intel->bits >> 16 >> 16); - native_wrmsr(MSR_IA32_UCODE_REV, 0, 0); - - /* As documented in the SDM: Do a CPUID 1 here */ - sync_core(); - - /* get the current revision from MSR 0x8B */ - native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); - if (val[1] != mc_intel->hdr.rev) - return -1; - -#ifdef CONFIG_X86_64 - /* Flush global tlb. This is precaution. */ - flush_tlb_early(); -#endif - uci->cpu_sig.rev = val[1]; - - if (early) - print_ucode(uci); - else - print_ucode_info(uci, mc_intel->hdr.date); - - return 0; -} - -/* - * This function converts microcode patch offsets previously stored in - * mc_saved_in_initrd to pointers and stores the pointers in mc_saved_data. - */ -int __init save_microcode_in_initrd_intel(void) -{ - unsigned int count = mc_saved_data.mc_saved_count; - struct microcode_intel *mc_saved[MAX_UCODE_COUNT]; - int ret = 0; - - if (count == 0) - return ret; - - copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, initrd_start, count); - ret = save_microcode(&mc_saved_data, mc_saved, count); - if (ret) - pr_err("Cannot save microcode patches from initrd.\n"); - - show_saved_mc(); - - return ret; -} - -static void __init -_load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data, - unsigned long *initrd, - unsigned long start, unsigned long size) -{ - struct ucode_cpu_info uci; - enum ucode_state ret; - - collect_cpu_info_early(&uci); - - ret = scan_microcode(mc_saved_data, initrd, start, size, &uci); - if (ret != UCODE_OK) - return; - - ret = load_microcode(mc_saved_data, initrd, start, &uci); - if (ret != UCODE_OK) - return; - - apply_microcode_early(&uci, true); -} - -void __init load_ucode_intel_bsp(void) -{ - u64 start, size; -#ifdef CONFIG_X86_32 - struct boot_params *p; - - p = (struct boot_params *)__pa_nodebug(&boot_params); - start = p->hdr.ramdisk_image; - size = p->hdr.ramdisk_size; - - _load_ucode_intel_bsp( - (struct mc_saved_data *)__pa_nodebug(&mc_saved_data), - (unsigned long *)__pa_nodebug(&mc_saved_in_initrd), - start, size); -#else - start = boot_params.hdr.ramdisk_image + PAGE_OFFSET; - size = boot_params.hdr.ramdisk_size; - - _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, start, size); -#endif -} - -void load_ucode_intel_ap(void) -{ - struct mc_saved_data *mc_saved_data_p; - struct ucode_cpu_info uci; - unsigned long *mc_saved_in_initrd_p; - unsigned long initrd_start_addr; - enum ucode_state ret; -#ifdef CONFIG_X86_32 - unsigned long *initrd_start_p; - - mc_saved_in_initrd_p = - (unsigned long *)__pa_nodebug(mc_saved_in_initrd); - mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); - initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start); - initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p); -#else - mc_saved_data_p = &mc_saved_data; - mc_saved_in_initrd_p = mc_saved_in_initrd; - initrd_start_addr = initrd_start; -#endif - - /* - * If there is no valid ucode previously saved in memory, no need to - * update ucode on this AP. - */ - if (mc_saved_data_p->mc_saved_count == 0) - return; - - collect_cpu_info_early(&uci); - ret = load_microcode(mc_saved_data_p, mc_saved_in_initrd_p, - initrd_start_addr, &uci); - - if (ret != UCODE_OK) - return; - - apply_microcode_early(&uci, true); -} - -void reload_ucode_intel(void) -{ - struct ucode_cpu_info uci; - enum ucode_state ret; - - if (!mc_saved_data.mc_saved_count) - return; - - collect_cpu_info_early(&uci); - - ret = load_microcode_early(mc_saved_data.mc_saved, - mc_saved_data.mc_saved_count, &uci); - if (ret != UCODE_OK) - return; - - apply_microcode_early(&uci, false); -} diff --git a/arch/x86/kernel/cpu/microcode/intel_lib.c b/arch/x86/kernel/cpu/microcode/intel_lib.c index 1883d252ff7d..b96896bcbdaf 100644 --- a/arch/x86/kernel/cpu/microcode/intel_lib.c +++ b/arch/x86/kernel/cpu/microcode/intel_lib.c @@ -25,7 +25,6 @@ #include <linux/firmware.h> #include <linux/uaccess.h> #include <linux/kernel.h> -#include <linux/module.h> #include <asm/microcode_intel.h> #include <asm/processor.h> diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 66dd3fe99b82..4562cf070c27 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1175,7 +1175,7 @@ static int x86_pmu_add(struct perf_event *event, int flags) * skip the schedulability test here, it will be performed * at commit time (->commit_txn) as a whole. */ - if (cpuc->group_flag & PERF_EVENT_TXN) + if (cpuc->txn_flags & PERF_PMU_TXN_ADD) goto done_collect; ret = x86_pmu.schedule_events(cpuc, n, assign); @@ -1326,7 +1326,7 @@ static void x86_pmu_del(struct perf_event *event, int flags) * XXX assumes any ->del() called during a TXN will only be on * an event added during that same TXN. */ - if (cpuc->group_flag & PERF_EVENT_TXN) + if (cpuc->txn_flags & PERF_PMU_TXN_ADD) return; /* @@ -1748,11 +1748,22 @@ static inline void x86_pmu_read(struct perf_event *event) * Start group events scheduling transaction * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time + * + * We only support PERF_PMU_TXN_ADD transactions. Save the + * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD + * transactions. */ -static void x86_pmu_start_txn(struct pmu *pmu) +static void x86_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + WARN_ON_ONCE(cpuc->txn_flags); /* txn already in flight */ + + cpuc->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); - __this_cpu_or(cpu_hw_events.group_flag, PERF_EVENT_TXN); __this_cpu_write(cpu_hw_events.n_txn, 0); } @@ -1763,7 +1774,16 @@ static void x86_pmu_start_txn(struct pmu *pmu) */ static void x86_pmu_cancel_txn(struct pmu *pmu) { - __this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN); + unsigned int txn_flags; + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + WARN_ON_ONCE(!cpuc->txn_flags); /* no txn in flight */ + + txn_flags = cpuc->txn_flags; + cpuc->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + /* * Truncate collected array by the number of events added in this * transaction. See x86_pmu_add() and x86_pmu_*_txn(). @@ -1786,6 +1806,13 @@ static int x86_pmu_commit_txn(struct pmu *pmu) int assign[X86_PMC_IDX_MAX]; int n, ret; + WARN_ON_ONCE(!cpuc->txn_flags); /* no txn in flight */ + + if (cpuc->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuc->txn_flags = 0; + return 0; + } + n = cpuc->n_events; if (!x86_pmu_initialized()) @@ -1801,7 +1828,7 @@ static int x86_pmu_commit_txn(struct pmu *pmu) */ memcpy(cpuc->assign, assign, n*sizeof(int)); - cpuc->group_flag &= ~PERF_EVENT_TXN; + cpuc->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 165be83a7fa4..499f533dd3cc 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -196,7 +196,7 @@ struct cpu_hw_events { int n_excl; /* the number of exclusive events */ - unsigned int group_flag; + unsigned int txn_flags; int is_fake; /* diff --git a/arch/x86/kernel/cpu/perf_event_intel_bts.c b/arch/x86/kernel/cpu/perf_event_intel_bts.c index d1c0f254afbe..2cad71d1b14c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_bts.c +++ b/arch/x86/kernel/cpu/perf_event_intel_bts.c @@ -495,6 +495,19 @@ static int bts_event_init(struct perf_event *event) if (x86_add_exclusive(x86_lbr_exclusive_bts)) return -EBUSY; + /* + * BTS leaks kernel addresses even when CPL0 tracing is + * disabled, so disallow intel_bts driver for unprivileged + * users on paranoid systems since it provides trace data + * to the user in a zero-copy fashion. + * + * Note that the default paranoia setting permits unprivileged + * users to profile the kernel. + */ + if (event->attr.exclude_kernel && perf_paranoid_kernel() && + !capable(CAP_SYS_ADMIN)) + return -EACCES; + ret = x86_reserve_hardware(); if (ret) { x86_del_exclusive(x86_lbr_exclusive_bts); diff --git a/arch/x86/kernel/cpu/perf_event_intel_cstate.c b/arch/x86/kernel/cpu/perf_event_intel_cstate.c new file mode 100644 index 000000000000..75a38b5a2e26 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_cstate.c @@ -0,0 +1,694 @@ +/* + * perf_event_intel_cstate.c: support cstate residency counters + * + * Copyright (C) 2015, Intel Corp. + * Author: Kan Liang (kan.liang@intel.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + */ + +/* + * This file export cstate related free running (read-only) counters + * for perf. These counters may be use simultaneously by other tools, + * such as turbostat. However, it still make sense to implement them + * in perf. Because we can conveniently collect them together with + * other events, and allow to use them from tools without special MSR + * access code. + * + * The events only support system-wide mode counting. There is no + * sampling support because it is not supported by the hardware. + * + * According to counters' scope and category, two PMUs are registered + * with the perf_event core subsystem. + * - 'cstate_core': The counter is available for each physical core. + * The counters include CORE_C*_RESIDENCY. + * - 'cstate_pkg': The counter is available for each physical package. + * The counters include PKG_C*_RESIDENCY. + * + * All of these counters are specified in the Intel® 64 and IA-32 + * Architectures Software Developer.s Manual Vol3b. + * + * Model specific counters: + * MSR_CORE_C1_RES: CORE C1 Residency Counter + * perf code: 0x00 + * Available model: SLM,AMT + * Scope: Core (each processor core has a MSR) + * MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter + * perf code: 0x01 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Core + * MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter + * perf code: 0x02 + * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Core + * MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter + * perf code: 0x03 + * Available model: SNB,IVB,HSW,BDW,SKL + * Scope: Core + * MSR_PKG_C2_RESIDENCY: Package C2 Residency Counter. + * perf code: 0x00 + * Available model: SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C3_RESIDENCY: Package C3 Residency Counter. + * perf code: 0x01 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C6_RESIDENCY: Package C6 Residency Counter. + * perf code: 0x02 + * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter. + * perf code: 0x03 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C8_RESIDENCY: Package C8 Residency Counter. + * perf code: 0x04 + * Available model: HSW ULT only + * Scope: Package (physical package) + * MSR_PKG_C9_RESIDENCY: Package C9 Residency Counter. + * perf code: 0x05 + * Available model: HSW ULT only + * Scope: Package (physical package) + * MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter. + * perf code: 0x06 + * Available model: HSW ULT only + * Scope: Package (physical package) + * + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/perf_event.h> +#include <asm/cpu_device_id.h> +#include "perf_event.h" + +#define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format) \ +static ssize_t __cstate_##_var##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *page) \ +{ \ + BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ + return sprintf(page, _format "\n"); \ +} \ +static struct kobj_attribute format_attr_##_var = \ + __ATTR(_name, 0444, __cstate_##_var##_show, NULL) + +static ssize_t cstate_get_attr_cpumask(struct device *dev, + struct device_attribute *attr, + char *buf); + +struct perf_cstate_msr { + u64 msr; + struct perf_pmu_events_attr *attr; + bool (*test)(int idx); +}; + + +/* cstate_core PMU */ + +static struct pmu cstate_core_pmu; +static bool has_cstate_core; + +enum perf_cstate_core_id { + /* + * cstate_core events + */ + PERF_CSTATE_CORE_C1_RES = 0, + PERF_CSTATE_CORE_C3_RES, + PERF_CSTATE_CORE_C6_RES, + PERF_CSTATE_CORE_C7_RES, + + PERF_CSTATE_CORE_EVENT_MAX, +}; + +bool test_core(int idx) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || + boot_cpu_data.x86 != 6) + return false; + + switch (boot_cpu_data.x86_model) { + case 30: /* 45nm Nehalem */ + case 26: /* 45nm Nehalem-EP */ + case 46: /* 45nm Nehalem-EX */ + + case 37: /* 32nm Westmere */ + case 44: /* 32nm Westmere-EP */ + case 47: /* 32nm Westmere-EX */ + if (idx == PERF_CSTATE_CORE_C3_RES || + idx == PERF_CSTATE_CORE_C6_RES) + return true; + break; + case 42: /* 32nm SandyBridge */ + case 45: /* 32nm SandyBridge-E/EN/EP */ + + case 58: /* 22nm IvyBridge */ + case 62: /* 22nm IvyBridge-EP/EX */ + + case 60: /* 22nm Haswell Core */ + case 63: /* 22nm Haswell Server */ + case 69: /* 22nm Haswell ULT */ + case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ + + case 61: /* 14nm Broadwell Core-M */ + case 86: /* 14nm Broadwell Xeon D */ + case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ + case 79: /* 14nm Broadwell Server */ + + case 78: /* 14nm Skylake Mobile */ + case 94: /* 14nm Skylake Desktop */ + if (idx == PERF_CSTATE_CORE_C3_RES || + idx == PERF_CSTATE_CORE_C6_RES || + idx == PERF_CSTATE_CORE_C7_RES) + return true; + break; + case 55: /* 22nm Atom "Silvermont" */ + case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ + case 76: /* 14nm Atom "Airmont" */ + if (idx == PERF_CSTATE_CORE_C1_RES || + idx == PERF_CSTATE_CORE_C6_RES) + return true; + break; + } + + return false; +} + +PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00"); +PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01"); +PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02"); +PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03"); + +static struct perf_cstate_msr core_msr[] = { + [PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1, test_core, }, + [PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3, test_core, }, + [PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6, test_core, }, + [PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7, test_core, }, +}; + +static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = { + NULL, +}; + +static struct attribute_group core_events_attr_group = { + .name = "events", + .attrs = core_events_attrs, +}; + +DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63"); +static struct attribute *core_format_attrs[] = { + &format_attr_core_event.attr, + NULL, +}; + +static struct attribute_group core_format_attr_group = { + .name = "format", + .attrs = core_format_attrs, +}; + +static cpumask_t cstate_core_cpu_mask; +static DEVICE_ATTR(cpumask, S_IRUGO, cstate_get_attr_cpumask, NULL); + +static struct attribute *cstate_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static struct attribute_group cpumask_attr_group = { + .attrs = cstate_cpumask_attrs, +}; + +static const struct attribute_group *core_attr_groups[] = { + &core_events_attr_group, + &core_format_attr_group, + &cpumask_attr_group, + NULL, +}; + +/* cstate_core PMU end */ + + +/* cstate_pkg PMU */ + +static struct pmu cstate_pkg_pmu; +static bool has_cstate_pkg; + +enum perf_cstate_pkg_id { + /* + * cstate_pkg events + */ + PERF_CSTATE_PKG_C2_RES = 0, + PERF_CSTATE_PKG_C3_RES, + PERF_CSTATE_PKG_C6_RES, + PERF_CSTATE_PKG_C7_RES, + PERF_CSTATE_PKG_C8_RES, + PERF_CSTATE_PKG_C9_RES, + PERF_CSTATE_PKG_C10_RES, + + PERF_CSTATE_PKG_EVENT_MAX, +}; + +bool test_pkg(int idx) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || + boot_cpu_data.x86 != 6) + return false; + + switch (boot_cpu_data.x86_model) { + case 30: /* 45nm Nehalem */ + case 26: /* 45nm Nehalem-EP */ + case 46: /* 45nm Nehalem-EX */ + + case 37: /* 32nm Westmere */ + case 44: /* 32nm Westmere-EP */ + case 47: /* 32nm Westmere-EX */ + if (idx == PERF_CSTATE_CORE_C3_RES || + idx == PERF_CSTATE_CORE_C6_RES || + idx == PERF_CSTATE_CORE_C7_RES) + return true; + break; + case 42: /* 32nm SandyBridge */ + case 45: /* 32nm SandyBridge-E/EN/EP */ + + case 58: /* 22nm IvyBridge */ + case 62: /* 22nm IvyBridge-EP/EX */ + + case 60: /* 22nm Haswell Core */ + case 63: /* 22nm Haswell Server */ + case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ + + case 61: /* 14nm Broadwell Core-M */ + case 86: /* 14nm Broadwell Xeon D */ + case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ + case 79: /* 14nm Broadwell Server */ + + case 78: /* 14nm Skylake Mobile */ + case 94: /* 14nm Skylake Desktop */ + if (idx == PERF_CSTATE_PKG_C2_RES || + idx == PERF_CSTATE_PKG_C3_RES || + idx == PERF_CSTATE_PKG_C6_RES || + idx == PERF_CSTATE_PKG_C7_RES) + return true; + break; + case 55: /* 22nm Atom "Silvermont" */ + case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ + case 76: /* 14nm Atom "Airmont" */ + if (idx == PERF_CSTATE_CORE_C6_RES) + return true; + break; + case 69: /* 22nm Haswell ULT */ + if (idx == PERF_CSTATE_PKG_C2_RES || + idx == PERF_CSTATE_PKG_C3_RES || + idx == PERF_CSTATE_PKG_C6_RES || + idx == PERF_CSTATE_PKG_C7_RES || + idx == PERF_CSTATE_PKG_C8_RES || + idx == PERF_CSTATE_PKG_C9_RES || + idx == PERF_CSTATE_PKG_C10_RES) + return true; + break; + } + + return false; +} + +PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00"); +PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01"); +PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02"); +PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_pkg_c7, "event=0x03"); +PMU_EVENT_ATTR_STRING(c8-residency, evattr_cstate_pkg_c8, "event=0x04"); +PMU_EVENT_ATTR_STRING(c9-residency, evattr_cstate_pkg_c9, "event=0x05"); +PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06"); + +static struct perf_cstate_msr pkg_msr[] = { + [PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2, test_pkg, }, + [PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3, test_pkg, }, + [PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6, test_pkg, }, + [PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7, test_pkg, }, + [PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8, test_pkg, }, + [PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9, test_pkg, }, + [PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10, test_pkg, }, +}; + +static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = { + NULL, +}; + +static struct attribute_group pkg_events_attr_group = { + .name = "events", + .attrs = pkg_events_attrs, +}; + +DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63"); +static struct attribute *pkg_format_attrs[] = { + &format_attr_pkg_event.attr, + NULL, +}; +static struct attribute_group pkg_format_attr_group = { + .name = "format", + .attrs = pkg_format_attrs, +}; + +static cpumask_t cstate_pkg_cpu_mask; + +static const struct attribute_group *pkg_attr_groups[] = { + &pkg_events_attr_group, + &pkg_format_attr_group, + &cpumask_attr_group, + NULL, +}; + +/* cstate_pkg PMU end*/ + +static ssize_t cstate_get_attr_cpumask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pmu *pmu = dev_get_drvdata(dev); + + if (pmu == &cstate_core_pmu) + return cpumap_print_to_pagebuf(true, buf, &cstate_core_cpu_mask); + else if (pmu == &cstate_pkg_pmu) + return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask); + else + return 0; +} + +static int cstate_pmu_event_init(struct perf_event *event) +{ + u64 cfg = event->attr.config; + int ret = 0; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + /* unsupported modes and filters */ + if (event->attr.exclude_user || + event->attr.exclude_kernel || + event->attr.exclude_hv || + event->attr.exclude_idle || + event->attr.exclude_host || + event->attr.exclude_guest || + event->attr.sample_period) /* no sampling */ + return -EINVAL; + + if (event->pmu == &cstate_core_pmu) { + if (cfg >= PERF_CSTATE_CORE_EVENT_MAX) + return -EINVAL; + if (!core_msr[cfg].attr) + return -EINVAL; + event->hw.event_base = core_msr[cfg].msr; + } else if (event->pmu == &cstate_pkg_pmu) { + if (cfg >= PERF_CSTATE_PKG_EVENT_MAX) + return -EINVAL; + if (!pkg_msr[cfg].attr) + return -EINVAL; + event->hw.event_base = pkg_msr[cfg].msr; + } else + return -ENOENT; + + /* must be done before validate_group */ + event->hw.config = cfg; + event->hw.idx = -1; + + return ret; +} + +static inline u64 cstate_pmu_read_counter(struct perf_event *event) +{ + u64 val; + + rdmsrl(event->hw.event_base, val); + return val; +} + +static void cstate_pmu_event_update(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + u64 prev_raw_count, new_raw_count; + +again: + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = cstate_pmu_read_counter(event); + + if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count) + goto again; + + local64_add(new_raw_count - prev_raw_count, &event->count); +} + +static void cstate_pmu_event_start(struct perf_event *event, int mode) +{ + local64_set(&event->hw.prev_count, cstate_pmu_read_counter(event)); +} + +static void cstate_pmu_event_stop(struct perf_event *event, int mode) +{ + cstate_pmu_event_update(event); +} + +static void cstate_pmu_event_del(struct perf_event *event, int mode) +{ + cstate_pmu_event_stop(event, PERF_EF_UPDATE); +} + +static int cstate_pmu_event_add(struct perf_event *event, int mode) +{ + if (mode & PERF_EF_START) + cstate_pmu_event_start(event, mode); + + return 0; +} + +static void cstate_cpu_exit(int cpu) +{ + int i, id, target; + + /* cpu exit for cstate core */ + if (has_cstate_core) { + id = topology_core_id(cpu); + target = -1; + + for_each_online_cpu(i) { + if (i == cpu) + continue; + if (id == topology_core_id(i)) { + target = i; + break; + } + } + if (cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask) && target >= 0) + cpumask_set_cpu(target, &cstate_core_cpu_mask); + WARN_ON(cpumask_empty(&cstate_core_cpu_mask)); + if (target >= 0) + perf_pmu_migrate_context(&cstate_core_pmu, cpu, target); + } + + /* cpu exit for cstate pkg */ + if (has_cstate_pkg) { + id = topology_physical_package_id(cpu); + target = -1; + + for_each_online_cpu(i) { + if (i == cpu) + continue; + if (id == topology_physical_package_id(i)) { + target = i; + break; + } + } + if (cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask) && target >= 0) + cpumask_set_cpu(target, &cstate_pkg_cpu_mask); + WARN_ON(cpumask_empty(&cstate_pkg_cpu_mask)); + if (target >= 0) + perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target); + } +} + +static void cstate_cpu_init(int cpu) +{ + int i, id; + + /* cpu init for cstate core */ + if (has_cstate_core) { + id = topology_core_id(cpu); + for_each_cpu(i, &cstate_core_cpu_mask) { + if (id == topology_core_id(i)) + break; + } + if (i >= nr_cpu_ids) + cpumask_set_cpu(cpu, &cstate_core_cpu_mask); + } + + /* cpu init for cstate pkg */ + if (has_cstate_pkg) { + id = topology_physical_package_id(cpu); + for_each_cpu(i, &cstate_pkg_cpu_mask) { + if (id == topology_physical_package_id(i)) + break; + } + if (i >= nr_cpu_ids) + cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask); + } +} + +static int cstate_cpu_notifier(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_UP_PREPARE: + break; + case CPU_STARTING: + cstate_cpu_init(cpu); + break; + case CPU_UP_CANCELED: + case CPU_DYING: + break; + case CPU_ONLINE: + case CPU_DEAD: + break; + case CPU_DOWN_PREPARE: + cstate_cpu_exit(cpu); + break; + default: + break; + } + + return NOTIFY_OK; +} + +/* + * Probe the cstate events and insert the available one into sysfs attrs + * Return false if there is no available events. + */ +static bool cstate_probe_msr(struct perf_cstate_msr *msr, + struct attribute **events_attrs, + int max_event_nr) +{ + int i, j = 0; + u64 val; + + /* Probe the cstate events. */ + for (i = 0; i < max_event_nr; i++) { + if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val)) + msr[i].attr = NULL; + } + + /* List remaining events in the sysfs attrs. */ + for (i = 0; i < max_event_nr; i++) { + if (msr[i].attr) + events_attrs[j++] = &msr[i].attr->attr.attr; + } + events_attrs[j] = NULL; + + return (j > 0) ? true : false; +} + +static int __init cstate_init(void) +{ + /* SLM has different MSR for PKG C6 */ + switch (boot_cpu_data.x86_model) { + case 55: + case 76: + case 77: + pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY; + } + + if (cstate_probe_msr(core_msr, core_events_attrs, PERF_CSTATE_CORE_EVENT_MAX)) + has_cstate_core = true; + + if (cstate_probe_msr(pkg_msr, pkg_events_attrs, PERF_CSTATE_PKG_EVENT_MAX)) + has_cstate_pkg = true; + + return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV; +} + +static void __init cstate_cpumask_init(void) +{ + int cpu; + + cpu_notifier_register_begin(); + + for_each_online_cpu(cpu) + cstate_cpu_init(cpu); + + __perf_cpu_notifier(cstate_cpu_notifier); + + cpu_notifier_register_done(); +} + +static struct pmu cstate_core_pmu = { + .attr_groups = core_attr_groups, + .name = "cstate_core", + .task_ctx_nr = perf_invalid_context, + .event_init = cstate_pmu_event_init, + .add = cstate_pmu_event_add, /* must have */ + .del = cstate_pmu_event_del, /* must have */ + .start = cstate_pmu_event_start, + .stop = cstate_pmu_event_stop, + .read = cstate_pmu_event_update, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT, +}; + +static struct pmu cstate_pkg_pmu = { + .attr_groups = pkg_attr_groups, + .name = "cstate_pkg", + .task_ctx_nr = perf_invalid_context, + .event_init = cstate_pmu_event_init, + .add = cstate_pmu_event_add, /* must have */ + .del = cstate_pmu_event_del, /* must have */ + .start = cstate_pmu_event_start, + .stop = cstate_pmu_event_stop, + .read = cstate_pmu_event_update, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT, +}; + +static void __init cstate_pmus_register(void) +{ + int err; + + if (has_cstate_core) { + err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1); + if (WARN_ON(err)) + pr_info("Failed to register PMU %s error %d\n", + cstate_core_pmu.name, err); + } + + if (has_cstate_pkg) { + err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, -1); + if (WARN_ON(err)) + pr_info("Failed to register PMU %s error %d\n", + cstate_pkg_pmu.name, err); + } +} + +static int __init cstate_pmu_init(void) +{ + int err; + + if (cpu_has_hypervisor) + return -ENODEV; + + err = cstate_init(); + if (err) + return err; + + cstate_cpumask_init(); + + cstate_pmus_register(); + + return 0; +} + +device_initcall(cstate_pmu_init); diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 84f236ab96b0..5db1c7755548 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -510,10 +510,11 @@ int intel_pmu_drain_bts_buffer(void) u64 flags; }; struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS]; - struct bts_record *at, *top; + struct bts_record *at, *base, *top; struct perf_output_handle handle; struct perf_event_header header; struct perf_sample_data data; + unsigned long skip = 0; struct pt_regs regs; if (!event) @@ -522,10 +523,10 @@ int intel_pmu_drain_bts_buffer(void) if (!x86_pmu.bts_active) return 0; - at = (struct bts_record *)(unsigned long)ds->bts_buffer_base; - top = (struct bts_record *)(unsigned long)ds->bts_index; + base = (struct bts_record *)(unsigned long)ds->bts_buffer_base; + top = (struct bts_record *)(unsigned long)ds->bts_index; - if (top <= at) + if (top <= base) return 0; memset(®s, 0, sizeof(regs)); @@ -535,16 +536,43 @@ int intel_pmu_drain_bts_buffer(void) perf_sample_data_init(&data, 0, event->hw.last_period); /* + * BTS leaks kernel addresses in branches across the cpl boundary, + * such as traps or system calls, so unless the user is asking for + * kernel tracing (and right now it's not possible), we'd need to + * filter them out. But first we need to count how many of those we + * have in the current batch. This is an extra O(n) pass, however, + * it's much faster than the other one especially considering that + * n <= 2560 (BTS_BUFFER_SIZE / BTS_RECORD_SIZE * 15/16; see the + * alloc_bts_buffer()). + */ + for (at = base; at < top; at++) { + /* + * Note that right now *this* BTS code only works if + * attr::exclude_kernel is set, but let's keep this extra + * check here in case that changes. + */ + if (event->attr.exclude_kernel && + (kernel_ip(at->from) || kernel_ip(at->to))) + skip++; + } + + /* * Prepare a generic sample, i.e. fill in the invariant fields. * We will overwrite the from and to address before we output * the sample. */ perf_prepare_sample(&header, &data, event, ®s); - if (perf_output_begin(&handle, event, header.size * (top - at))) + if (perf_output_begin(&handle, event, header.size * + (top - base - skip))) return 1; - for (; at < top; at++) { + for (at = base; at < top; at++) { + /* Filter out any records that contain kernel addresses. */ + if (event->attr.exclude_kernel && + (kernel_ip(at->from) || kernel_ip(at->to))) + continue; + data.ip = at->from; data.addr = at->to; diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index b2c9475b7ff2..bfd0b717e944 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -151,10 +151,10 @@ static void __intel_pmu_lbr_enable(bool pmi) * No need to reprogram LBR_SELECT in a PMI, as it * did not change. */ - if (cpuc->lbr_sel && !pmi) { + if (cpuc->lbr_sel) lbr_select = cpuc->lbr_sel->config; + if (!pmi) wrmsrl(MSR_LBR_SELECT, lbr_select); - } rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); orig_debugctl = debugctl; @@ -555,6 +555,8 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) if (br_type & PERF_SAMPLE_BRANCH_IND_JUMP) mask |= X86_BR_IND_JMP; + if (br_type & PERF_SAMPLE_BRANCH_CALL) + mask |= X86_BR_CALL | X86_BR_ZERO_CALL; /* * stash actual user request into reg, it may * be used by fixup code for some CPU @@ -890,6 +892,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL, [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, + [PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_REL_CALL, }; static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { @@ -905,6 +908,7 @@ static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] = LBR_REL_CALL | LBR_IND_CALL | LBR_RETURN | LBR_CALL_STACK, [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, + [PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_REL_CALL, }; /* core */ diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c index 42169283448b..868e1194337f 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_pt.c +++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c @@ -139,9 +139,6 @@ static int __init pt_pmu_hw_init(void) long i; attrs = NULL; - ret = -ENODEV; - if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT)) - goto fail; for (i = 0; i < PT_CPUID_LEAVES; i++) { cpuid_count(20, i, @@ -1130,6 +1127,10 @@ static __init int pt_init(void) int ret, cpu, prior_warn = 0; BUILD_BUG_ON(sizeof(struct topa) > PAGE_SIZE); + + if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT)) + return -ENODEV; + get_online_cpus(); for_each_online_cpu(cpu) { u64 ctl; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 560e5255b15e..61215a69b03d 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -7,7 +7,8 @@ struct intel_uncore_type **uncore_pci_uncores = empty_uncore; static bool pcidrv_registered; struct pci_driver *uncore_pci_driver; /* pci bus to socket mapping */ -int uncore_pcibus_to_physid[256] = { [0 ... 255] = -1, }; +DEFINE_RAW_SPINLOCK(pci2phy_map_lock); +struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head); struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; static DEFINE_RAW_SPINLOCK(uncore_box_lock); @@ -20,6 +21,59 @@ static struct event_constraint uncore_constraint_fixed = struct event_constraint uncore_constraint_empty = EVENT_CONSTRAINT(0, 0, 0); +int uncore_pcibus_to_physid(struct pci_bus *bus) +{ + struct pci2phy_map *map; + int phys_id = -1; + + raw_spin_lock(&pci2phy_map_lock); + list_for_each_entry(map, &pci2phy_map_head, list) { + if (map->segment == pci_domain_nr(bus)) { + phys_id = map->pbus_to_physid[bus->number]; + break; + } + } + raw_spin_unlock(&pci2phy_map_lock); + + return phys_id; +} + +struct pci2phy_map *__find_pci2phy_map(int segment) +{ + struct pci2phy_map *map, *alloc = NULL; + int i; + + lockdep_assert_held(&pci2phy_map_lock); + +lookup: + list_for_each_entry(map, &pci2phy_map_head, list) { + if (map->segment == segment) + goto end; + } + + if (!alloc) { + raw_spin_unlock(&pci2phy_map_lock); + alloc = kmalloc(sizeof(struct pci2phy_map), GFP_KERNEL); + raw_spin_lock(&pci2phy_map_lock); + + if (!alloc) + return NULL; + + goto lookup; + } + + map = alloc; + alloc = NULL; + map->segment = segment; + for (i = 0; i < 256; i++) + map->pbus_to_physid[i] = -1; + list_add_tail(&map->list, &pci2phy_map_head); + +end: + kfree(alloc); + return map; +} + ssize_t uncore_event_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -809,7 +863,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id int phys_id; bool first_box = false; - phys_id = uncore_pcibus_to_physid[pdev->bus->number]; + phys_id = uncore_pcibus_to_physid(pdev->bus); if (phys_id < 0) return -ENODEV; @@ -856,9 +910,10 @@ static void uncore_pci_remove(struct pci_dev *pdev) { struct intel_uncore_box *box = pci_get_drvdata(pdev); struct intel_uncore_pmu *pmu; - int i, cpu, phys_id = uncore_pcibus_to_physid[pdev->bus->number]; + int i, cpu, phys_id; bool last_box = false; + phys_id = uncore_pcibus_to_physid(pdev->bus); box = pci_get_drvdata(pdev); if (!box) { for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) { diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 72c54c2e5b1a..2f0a4a98e16b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -117,6 +117,15 @@ struct uncore_event_desc { const char *config; }; +struct pci2phy_map { + struct list_head list; + int segment; + int pbus_to_physid[256]; +}; + +int uncore_pcibus_to_physid(struct pci_bus *bus); +struct pci2phy_map *__find_pci2phy_map(int segment); + ssize_t uncore_event_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -317,7 +326,8 @@ u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx); extern struct intel_uncore_type **uncore_msr_uncores; extern struct intel_uncore_type **uncore_pci_uncores; extern struct pci_driver *uncore_pci_driver; -extern int uncore_pcibus_to_physid[256]; +extern raw_spinlock_t pci2phy_map_lock; +extern struct list_head pci2phy_map_head; extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; extern struct event_constraint uncore_constraint_empty; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c index f78574b3cb55..845256158a10 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c @@ -420,15 +420,25 @@ static void snb_uncore_imc_event_del(struct perf_event *event, int flags) static int snb_pci2phy_map_init(int devid) { struct pci_dev *dev = NULL; - int bus; + struct pci2phy_map *map; + int bus, segment; dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev); if (!dev) return -ENOTTY; bus = dev->bus->number; - - uncore_pcibus_to_physid[bus] = 0; + segment = pci_domain_nr(dev->bus); + + raw_spin_lock(&pci2phy_map_lock); + map = __find_pci2phy_map(segment); + if (!map) { + raw_spin_unlock(&pci2phy_map_lock); + pci_dev_put(dev); + return -ENOMEM; + } + map->pbus_to_physid[bus] = 0; + raw_spin_unlock(&pci2phy_map_lock); pci_dev_put(dev); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index 694510a887dc..f0f4fcba252e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -1087,7 +1087,8 @@ static struct pci_driver snbep_uncore_pci_driver = { static int snbep_pci2phy_map_init(int devid) { struct pci_dev *ubox_dev = NULL; - int i, bus, nodeid; + int i, bus, nodeid, segment; + struct pci2phy_map *map; int err = 0; u32 config = 0; @@ -1106,16 +1107,27 @@ static int snbep_pci2phy_map_init(int devid) err = pci_read_config_dword(ubox_dev, 0x54, &config); if (err) break; + + segment = pci_domain_nr(ubox_dev->bus); + raw_spin_lock(&pci2phy_map_lock); + map = __find_pci2phy_map(segment); + if (!map) { + raw_spin_unlock(&pci2phy_map_lock); + err = -ENOMEM; + break; + } + /* * every three bits in the Node ID mapping register maps * to a particular node. */ for (i = 0; i < 8; i++) { if (nodeid == ((config >> (3 * i)) & 0x7)) { - uncore_pcibus_to_physid[bus] = i; + map->pbus_to_physid[bus] = i; break; } } + raw_spin_unlock(&pci2phy_map_lock); } if (!err) { @@ -1123,13 +1135,17 @@ static int snbep_pci2phy_map_init(int devid) * For PCI bus with no UBOX device, find the next bus * that has UBOX device and use its mapping. */ - i = -1; - for (bus = 255; bus >= 0; bus--) { - if (uncore_pcibus_to_physid[bus] >= 0) - i = uncore_pcibus_to_physid[bus]; - else - uncore_pcibus_to_physid[bus] = i; + raw_spin_lock(&pci2phy_map_lock); + list_for_each_entry(map, &pci2phy_map_head, list) { + i = -1; + for (bus = 255; bus >= 0; bus--) { + if (map->pbus_to_physid[bus] >= 0) + i = map->pbus_to_physid[bus]; + else + map->pbus_to_physid[bus] = i; + } } + raw_spin_unlock(&pci2phy_map_lock); } pci_dev_put(ubox_dev); @@ -2444,7 +2460,7 @@ static struct intel_uncore_type *bdx_pci_uncores[] = { NULL, }; -static DEFINE_PCI_DEVICE_TABLE(bdx_uncore_pci_ids) = { +static const struct pci_device_id bdx_uncore_pci_ids[] = { { /* Home Agent 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f30), .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 0), diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 9f9cc682e561..db9a675e751b 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -584,7 +584,7 @@ static void __init intel_graphics_stolen(int num, int slot, int func) static void __init force_disable_hpet(int num, int slot, int func) { #ifdef CONFIG_HPET_TIMER - boot_hpet_disable = 1; + boot_hpet_disable = true; pr_info("x86/hpet: Will disable the HPET for this platform because it's not reliable\n"); #endif } diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 0e2d96ffd158..6bc9ae24b6d2 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -152,7 +152,7 @@ ENTRY(startup_32) movl %eax, pa(olpc_ofw_pgd) #endif -#ifdef CONFIG_MICROCODE_EARLY +#ifdef CONFIG_MICROCODE /* Early load ucode on BSP. */ call load_ucode_bsp #endif @@ -311,12 +311,11 @@ ENTRY(startup_32_smp) movl %eax,%ss leal -__PAGE_OFFSET(%ecx),%esp -#ifdef CONFIG_MICROCODE_EARLY +#ifdef CONFIG_MICROCODE /* Early load ucode on AP. */ call load_ucode_ap #endif - default_entry: #define CR0_STATE (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \ X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \ diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 88b4da373081..b8e6ff5cd5d0 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -37,10 +37,10 @@ */ unsigned long hpet_address; u8 hpet_blockid; /* OS timer block num */ -u8 hpet_msi_disable; +bool hpet_msi_disable; #ifdef CONFIG_PCI_MSI -static unsigned long hpet_num_timers; +static unsigned int hpet_num_timers; #endif static void __iomem *hpet_virt_address; @@ -86,9 +86,9 @@ static inline void hpet_clear_mapping(void) /* * HPET command line enable / disable */ -int boot_hpet_disable; -int hpet_force_user; -static int hpet_verbose; +bool boot_hpet_disable; +bool hpet_force_user; +static bool hpet_verbose; static int __init hpet_setup(char *str) { @@ -98,11 +98,11 @@ static int __init hpet_setup(char *str) if (next) *next++ = 0; if (!strncmp("disable", str, 7)) - boot_hpet_disable = 1; + boot_hpet_disable = true; if (!strncmp("force", str, 5)) - hpet_force_user = 1; + hpet_force_user = true; if (!strncmp("verbose", str, 7)) - hpet_verbose = 1; + hpet_verbose = true; str = next; } return 1; @@ -111,7 +111,7 @@ __setup("hpet=", hpet_setup); static int __init disable_hpet(char *str) { - boot_hpet_disable = 1; + boot_hpet_disable = true; return 1; } __setup("nohpet", disable_hpet); @@ -124,7 +124,7 @@ static inline int is_hpet_capable(void) /* * HPET timer interrupt enable / disable */ -static int hpet_legacy_int_enabled; +static bool hpet_legacy_int_enabled; /** * is_hpet_enabled - check whether the hpet timer interrupt is enabled @@ -230,7 +230,7 @@ static struct clock_event_device hpet_clockevent; static void hpet_stop_counter(void) { - unsigned long cfg = hpet_readl(HPET_CFG); + u32 cfg = hpet_readl(HPET_CFG); cfg &= ~HPET_CFG_ENABLE; hpet_writel(cfg, HPET_CFG); } @@ -272,7 +272,7 @@ static void hpet_enable_legacy_int(void) cfg |= HPET_CFG_LEGACY; hpet_writel(cfg, HPET_CFG); - hpet_legacy_int_enabled = 1; + hpet_legacy_int_enabled = true; } static void hpet_legacy_clockevent_register(void) @@ -983,7 +983,7 @@ void hpet_disable(void) cfg = *hpet_boot_cfg; else if (hpet_legacy_int_enabled) { cfg &= ~HPET_CFG_LEGACY; - hpet_legacy_int_enabled = 0; + hpet_legacy_int_enabled = false; } cfg &= ~HPET_CFG_ENABLE; hpet_writel(cfg, HPET_CFG); @@ -1121,8 +1121,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_timer_init); static void hpet_disable_rtc_channel(void) { - unsigned long cfg; - cfg = hpet_readl(HPET_T1_CFG); + u32 cfg = hpet_readl(HPET_T1_CFG); cfg &= ~HPET_TN_ENABLE; hpet_writel(cfg, HPET_T1_CFG); } diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index c767cf2bc80a..206d0b90a3ab 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -72,7 +72,7 @@ bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) { stack_overflow_check(regs); - if (unlikely(IS_ERR_OR_NULL(desc))) + if (IS_ERR_OR_NULL(desc)) return false; generic_handle_irq_desc(desc); diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 1b55de1267cf..cd99433b8ba1 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -131,11 +131,12 @@ void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr, bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp) { + if (!*dev) + *dev = &x86_dma_fallback_dev; + *gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); *gfp = dma_alloc_coherent_gfp_flags(*dev, *gfp); - if (!*dev) - *dev = &x86_dma_fallback_dev; if (!is_device_dma_capable(*dev)) return false; return true; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 39e585a554b7..9f7c21c22477 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -84,6 +84,9 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister); int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { memcpy(dst, src, arch_task_struct_size); +#ifdef CONFIG_VM86 + dst->thread.vm86 = NULL; +#endif return fpu__copy(&dst->thread.fpu, &src->thread.fpu); } @@ -550,14 +553,14 @@ unsigned long get_wchan(struct task_struct *p) if (sp < bottom || sp > top) return 0; - fp = READ_ONCE(*(unsigned long *)sp); + fp = READ_ONCE_NOCHECK(*(unsigned long *)sp); do { if (fp < bottom || fp > top) return 0; - ip = READ_ONCE(*(unsigned long *)(fp + sizeof(unsigned long))); + ip = READ_ONCE_NOCHECK(*(unsigned long *)(fp + sizeof(unsigned long))); if (!in_sched_functions(ip)) return ip; - fp = READ_ONCE(*(unsigned long *)fp); + fp = READ_ONCE_NOCHECK(*(unsigned long *)fp); } while (count++ < 16 && p->state != TASK_RUNNING); return 0; } diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 737527b40e5b..9f950917528b 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -280,14 +280,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) set_iopl_mask(next->iopl); /* - * If it were not for PREEMPT_ACTIVE we could guarantee that the - * preempt_count of all tasks was equal here and this would not be - * needed. - */ - task_thread_info(prev_p)->saved_preempt_count = this_cpu_read(__preempt_count); - this_cpu_write(__preempt_count, task_thread_info(next_p)->saved_preempt_count); - - /* * Now maybe handle debug registers and/or IO bitmaps */ if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV || diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index b35921a670b2..e835d263a33b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -332,7 +332,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) /* * Switch FS and GS. * - * These are even more complicated than FS and GS: they have + * These are even more complicated than DS and ES: they have * 64-bit bases are that controlled by arch_prctl. Those bases * only differ from the values in the GDT or LDT if the selector * is 0. @@ -401,14 +401,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) */ this_cpu_write(current_task, next_p); - /* - * If it were not for PREEMPT_ACTIVE we could guarantee that the - * preempt_count of all tasks was equal here and this would not be - * needed. - */ - task_thread_info(prev_p)->saved_preempt_count = this_cpu_read(__preempt_count); - this_cpu_write(__preempt_count, task_thread_info(next_p)->saved_preempt_count); - /* Reload esp0 and ss1. This changes current_thread_info(). */ load_sp0(tss, next); diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 176a0f99d4da..cc457ff818ad 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -524,7 +524,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E6XX_CU, */ static void force_disable_hpet_msi(struct pci_dev *unused) { - hpet_msi_disable = 1; + hpet_msi_disable = true; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index fdb7f2a2d328..a1e4da98c8f0 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -111,6 +111,7 @@ #include <asm/mce.h> #include <asm/alternative.h> #include <asm/prom.h> +#include <asm/microcode.h> /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB @@ -480,34 +481,34 @@ static void __init memblock_x86_reserve_range_setup_data(void) #ifdef CONFIG_KEXEC_CORE +/* 16M alignment for crash kernel regions */ +#define CRASH_ALIGN (16 << 20) + /* * Keep the crash kernel below this limit. On 32 bits earlier kernels * would limit the kernel to the low 512 MiB due to mapping restrictions. * On 64bit, old kexec-tools need to under 896MiB. */ #ifdef CONFIG_X86_32 -# define CRASH_KERNEL_ADDR_LOW_MAX (512 << 20) -# define CRASH_KERNEL_ADDR_HIGH_MAX (512 << 20) +# define CRASH_ADDR_LOW_MAX (512 << 20) +# define CRASH_ADDR_HIGH_MAX (512 << 20) #else -# define CRASH_KERNEL_ADDR_LOW_MAX (896UL<<20) -# define CRASH_KERNEL_ADDR_HIGH_MAX MAXMEM +# define CRASH_ADDR_LOW_MAX (896UL << 20) +# define CRASH_ADDR_HIGH_MAX MAXMEM #endif -static void __init reserve_crashkernel_low(void) +static int __init reserve_crashkernel_low(void) { #ifdef CONFIG_X86_64 - const unsigned long long alignment = 16<<20; /* 16M */ - unsigned long long low_base = 0, low_size = 0; + unsigned long long base, low_base = 0, low_size = 0; unsigned long total_low_mem; - unsigned long long base; - bool auto_set = false; int ret; - total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT)); + total_low_mem = memblock_mem_size(1UL << (32 - PAGE_SHIFT)); + /* crashkernel=Y,low */ - ret = parse_crashkernel_low(boot_command_line, total_low_mem, - &low_size, &base); - if (ret != 0) { + ret = parse_crashkernel_low(boot_command_line, total_low_mem, &low_size, &base); + if (ret) { /* * two parts from lib/swiotlb.c: * -swiotlb size: user-specified with swiotlb= or default. @@ -517,52 +518,52 @@ static void __init reserve_crashkernel_low(void) * make sure we allocate enough extra low memory so that we * don't run out of DMA buffers for 32-bit devices. */ - low_size = max(swiotlb_size_or_default() + (8UL<<20), 256UL<<20); - auto_set = true; + low_size = max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20); } else { /* passed with crashkernel=0,low ? */ if (!low_size) - return; + return 0; } - low_base = memblock_find_in_range(low_size, (1ULL<<32), - low_size, alignment); - + low_base = memblock_find_in_range(low_size, 1ULL << 32, low_size, CRASH_ALIGN); if (!low_base) { - if (!auto_set) - pr_info("crashkernel low reservation failed - No suitable area found.\n"); + pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n", + (unsigned long)(low_size >> 20)); + return -ENOMEM; + } - return; + ret = memblock_reserve(low_base, low_size); + if (ret) { + pr_err("%s: Error reserving crashkernel low memblock.\n", __func__); + return ret; } - memblock_reserve(low_base, low_size); pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (System low RAM: %ldMB)\n", - (unsigned long)(low_size >> 20), - (unsigned long)(low_base >> 20), - (unsigned long)(total_low_mem >> 20)); + (unsigned long)(low_size >> 20), + (unsigned long)(low_base >> 20), + (unsigned long)(total_low_mem >> 20)); + crashk_low_res.start = low_base; crashk_low_res.end = low_base + low_size - 1; insert_resource(&iomem_resource, &crashk_low_res); #endif + return 0; } static void __init reserve_crashkernel(void) { - const unsigned long long alignment = 16<<20; /* 16M */ - unsigned long long total_mem; - unsigned long long crash_size, crash_base; + unsigned long long crash_size, crash_base, total_mem; bool high = false; int ret; total_mem = memblock_phys_mem_size(); /* crashkernel=XM */ - ret = parse_crashkernel(boot_command_line, total_mem, - &crash_size, &crash_base); + ret = parse_crashkernel(boot_command_line, total_mem, &crash_size, &crash_base); if (ret != 0 || crash_size <= 0) { /* crashkernel=X,high */ ret = parse_crashkernel_high(boot_command_line, total_mem, - &crash_size, &crash_base); + &crash_size, &crash_base); if (ret != 0 || crash_size <= 0) return; high = true; @@ -573,11 +574,10 @@ static void __init reserve_crashkernel(void) /* * kexec want bzImage is below CRASH_KERNEL_ADDR_MAX */ - crash_base = memblock_find_in_range(alignment, - high ? CRASH_KERNEL_ADDR_HIGH_MAX : - CRASH_KERNEL_ADDR_LOW_MAX, - crash_size, alignment); - + crash_base = memblock_find_in_range(CRASH_ALIGN, + high ? CRASH_ADDR_HIGH_MAX + : CRASH_ADDR_LOW_MAX, + crash_size, CRASH_ALIGN); if (!crash_base) { pr_info("crashkernel reservation failed - No suitable area found.\n"); return; @@ -587,26 +587,32 @@ static void __init reserve_crashkernel(void) unsigned long long start; start = memblock_find_in_range(crash_base, - crash_base + crash_size, crash_size, 1<<20); + crash_base + crash_size, + crash_size, 1 << 20); if (start != crash_base) { pr_info("crashkernel reservation failed - memory is in use.\n"); return; } } - memblock_reserve(crash_base, crash_size); + ret = memblock_reserve(crash_base, crash_size); + if (ret) { + pr_err("%s: Error reserving crashkernel memblock.\n", __func__); + return; + } - printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " - "for crashkernel (System RAM: %ldMB)\n", - (unsigned long)(crash_size >> 20), - (unsigned long)(crash_base >> 20), - (unsigned long)(total_mem >> 20)); + if (crash_base >= (1ULL << 32) && reserve_crashkernel_low()) { + memblock_free(crash_base, crash_size); + return; + } + + pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n", + (unsigned long)(crash_size >> 20), + (unsigned long)(crash_base >> 20), + (unsigned long)(total_mem >> 20)); crashk_res.start = crash_base; crashk_res.end = crash_base + crash_size - 1; insert_resource(&iomem_resource, &crashk_res); - - if (crash_base >= (1ULL<<32)) - reserve_crashkernel_low(); } #else static void __init reserve_crashkernel(void) @@ -1079,8 +1085,10 @@ void __init setup_arch(char **cmdline_p) memblock_set_current_limit(ISA_END_ADDRESS); memblock_x86_fill(); - if (efi_enabled(EFI_BOOT)) + if (efi_enabled(EFI_BOOT)) { + efi_fake_memmap(); efi_find_mirror(); + } /* * The EFI specification says that boot service code won't be called @@ -1173,6 +1181,14 @@ void __init setup_arch(char **cmdline_p) clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, swapper_pg_dir + KERNEL_PGD_BOUNDARY, KERNEL_PGD_PTRS); + + /* + * sync back low identity map too. It is used for example + * in the 32-bit EFI stub. + */ + clone_pgd_range(initial_page_table, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); #endif tboot_probe(); @@ -1234,6 +1250,8 @@ void __init setup_arch(char **cmdline_p) if (efi_enabled(EFI_BOOT)) efi_apply_memmap_quirks(); #endif + + microcode_init(); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index da52e6bb5c7f..d87ce92d3404 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -299,7 +299,7 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set, if (current->mm->context.vdso) restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_sigreturn; + vdso_image_32.sym___kernel_sigreturn; else restorer = &frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) @@ -363,7 +363,7 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, /* Set up to return from userspace. */ restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_rt_sigreturn; + vdso_image_32.sym___kernel_rt_sigreturn; if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; put_user_ex(restorer, &frame->pretcode); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index e0c198e5f920..892ee2e5ecbc 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -509,7 +509,7 @@ void __inquire_remote_apic(int apicid) */ #define UDELAY_10MS_DEFAULT 10000 -static unsigned int init_udelay = UDELAY_10MS_DEFAULT; +static unsigned int init_udelay = INT_MAX; static int __init cpu_init_udelay(char *str) { @@ -522,13 +522,16 @@ early_param("cpu_init_udelay", cpu_init_udelay); static void __init smp_quirk_init_udelay(void) { /* if cmdline changed it from default, leave it alone */ - if (init_udelay != UDELAY_10MS_DEFAULT) + if (init_udelay != INT_MAX) return; /* if modern processor, use no delay */ if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) || ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) init_udelay = 0; + + /* else, use legacy delay */ + init_udelay = UDELAY_10MS_DEFAULT; } /* @@ -657,7 +660,9 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip) /* * Give the other CPU some time to accept the IPI. */ - if (init_udelay) + if (init_udelay == 0) + udelay(10); + else udelay(300); pr_debug("Startup point 1\n"); @@ -668,7 +673,9 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip) /* * Give the other CPU some time to accept the IPI. */ - if (init_udelay) + if (init_udelay == 0) + udelay(10); + else udelay(200); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index c3f7602cd038..c7c4d9c51e99 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -168,21 +168,20 @@ static void cyc2ns_write_end(int cpu, struct cyc2ns_data *data) * ns = cycles * cyc2ns_scale / SC * * And since SC is a constant power of two, we can convert the div - * into a shift. + * into a shift. The larger SC is, the more accurate the conversion, but + * cyc2ns_scale needs to be a 32-bit value so that 32-bit multiplication + * (64-bit result) can be used. * - * We can use khz divisor instead of mhz to keep a better precision, since - * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. + * We can use khz divisor instead of mhz to keep a better precision. * (mathieu.desnoyers@polymtl.ca) * * -johnstul@us.ibm.com "math is hard, lets go shopping!" */ -#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ - static void cyc2ns_data_init(struct cyc2ns_data *data) { data->cyc2ns_mul = 0; - data->cyc2ns_shift = CYC2NS_SCALE_FACTOR; + data->cyc2ns_shift = 0; data->cyc2ns_offset = 0; data->__count = 0; } @@ -216,14 +215,14 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) if (likely(data == tail)) { ns = data->cyc2ns_offset; - ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, CYC2NS_SCALE_FACTOR); + ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, data->cyc2ns_shift); } else { data->__count++; barrier(); ns = data->cyc2ns_offset; - ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, CYC2NS_SCALE_FACTOR); + ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, data->cyc2ns_shift); barrier(); @@ -257,12 +256,22 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) * time function is continuous; see the comment near struct * cyc2ns_data. */ - data->cyc2ns_mul = - DIV_ROUND_CLOSEST(NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR, - cpu_khz); - data->cyc2ns_shift = CYC2NS_SCALE_FACTOR; + clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, cpu_khz, + NSEC_PER_MSEC, 0); + + /* + * cyc2ns_shift is exported via arch_perf_update_userpage() where it is + * not expected to be greater than 31 due to the original published + * conversion algorithm shifting a 32-bit value (now specifies a 64-bit + * value) - refer perf_event_mmap_page documentation in perf_event.h. + */ + if (data->cyc2ns_shift == 32) { + data->cyc2ns_shift = 31; + data->cyc2ns_mul >>= 1; + } + data->cyc2ns_offset = ns_now - - mul_u64_u32_shr(tsc_now, data->cyc2ns_mul, CYC2NS_SCALE_FACTOR); + mul_u64_u32_shr(tsc_now, data->cyc2ns_mul, data->cyc2ns_shift); cyc2ns_write_end(cpu, data); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index b372a7557c16..9da95b9daf8d 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2418,7 +2418,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) u64 val, cr0, cr4; u32 base3; u16 selector; - int i; + int i, r; for (i = 0; i < 16; i++) *reg_write(ctxt, i) = GET_SMSTATE(u64, smbase, 0x7ff8 - i * 8); @@ -2460,13 +2460,17 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) dt.address = GET_SMSTATE(u64, smbase, 0x7e68); ctxt->ops->set_gdt(ctxt, &dt); + r = rsm_enter_protected_mode(ctxt, cr0, cr4); + if (r != X86EMUL_CONTINUE) + return r; + for (i = 0; i < 6; i++) { - int r = rsm_load_seg_64(ctxt, smbase, i); + r = rsm_load_seg_64(ctxt, smbase, i); if (r != X86EMUL_CONTINUE) return r; } - return rsm_enter_protected_mode(ctxt, cr0, cr4); + return X86EMUL_CONTINUE; } static int em_rsm(struct x86_emulate_ctxt *ctxt) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 06ef4908ba61..6a8bc64566ab 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -4105,17 +4105,13 @@ static void seg_setup(int seg) static int alloc_apic_access_page(struct kvm *kvm) { struct page *page; - struct kvm_userspace_memory_region kvm_userspace_mem; int r = 0; mutex_lock(&kvm->slots_lock); if (kvm->arch.apic_access_page_done) goto out; - kvm_userspace_mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT; - kvm_userspace_mem.flags = 0; - kvm_userspace_mem.guest_phys_addr = APIC_DEFAULT_PHYS_BASE; - kvm_userspace_mem.memory_size = PAGE_SIZE; - r = __x86_set_memory_region(kvm, &kvm_userspace_mem); + r = __x86_set_memory_region(kvm, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, + APIC_DEFAULT_PHYS_BASE, PAGE_SIZE); if (r) goto out; @@ -4140,17 +4136,12 @@ static int alloc_identity_pagetable(struct kvm *kvm) { /* Called with kvm->slots_lock held. */ - struct kvm_userspace_memory_region kvm_userspace_mem; int r = 0; BUG_ON(kvm->arch.ept_identity_pagetable_done); - kvm_userspace_mem.slot = IDENTITY_PAGETABLE_PRIVATE_MEMSLOT; - kvm_userspace_mem.flags = 0; - kvm_userspace_mem.guest_phys_addr = - kvm->arch.ept_identity_map_addr; - kvm_userspace_mem.memory_size = PAGE_SIZE; - r = __x86_set_memory_region(kvm, &kvm_userspace_mem); + r = __x86_set_memory_region(kvm, IDENTITY_PAGETABLE_PRIVATE_MEMSLOT, + kvm->arch.ept_identity_map_addr, PAGE_SIZE); return r; } @@ -4949,14 +4940,9 @@ static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr) { int ret; - struct kvm_userspace_memory_region tss_mem = { - .slot = TSS_PRIVATE_MEMSLOT, - .guest_phys_addr = addr, - .memory_size = PAGE_SIZE * 3, - .flags = 0, - }; - ret = x86_set_memory_region(kvm, &tss_mem); + ret = x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, addr, + PAGE_SIZE * 3); if (ret) return ret; kvm->arch.tss_addr = addr; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 92511d4b7236..9a9a19830321 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6453,6 +6453,12 @@ static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu) return 1; } +static inline bool kvm_vcpu_running(struct kvm_vcpu *vcpu) +{ + return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && + !vcpu->arch.apf.halted); +} + static int vcpu_run(struct kvm_vcpu *vcpu) { int r; @@ -6461,8 +6467,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu) vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); for (;;) { - if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && - !vcpu->arch.apf.halted) + if (kvm_vcpu_running(vcpu)) r = vcpu_enter_guest(vcpu); else r = vcpu_block(kvm, vcpu); @@ -7474,34 +7479,66 @@ void kvm_arch_sync_events(struct kvm *kvm) kvm_free_pit(kvm); } -int __x86_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem) +int __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size) { int i, r; + unsigned long hva; + struct kvm_memslots *slots = kvm_memslots(kvm); + struct kvm_memory_slot *slot, old; /* Called with kvm->slots_lock held. */ - BUG_ON(mem->slot >= KVM_MEM_SLOTS_NUM); + if (WARN_ON(id >= KVM_MEM_SLOTS_NUM)) + return -EINVAL; + + slot = id_to_memslot(slots, id); + if (size) { + if (WARN_ON(slot->npages)) + return -EEXIST; + + /* + * MAP_SHARED to prevent internal slot pages from being moved + * by fork()/COW. + */ + hva = vm_mmap(NULL, 0, size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, 0); + if (IS_ERR((void *)hva)) + return PTR_ERR((void *)hva); + } else { + if (!slot->npages) + return 0; + hva = 0; + } + + old = *slot; for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { - struct kvm_userspace_memory_region m = *mem; + struct kvm_userspace_memory_region m; - m.slot |= i << 16; + m.slot = id | (i << 16); + m.flags = 0; + m.guest_phys_addr = gpa; + m.userspace_addr = hva; + m.memory_size = size; r = __kvm_set_memory_region(kvm, &m); if (r < 0) return r; } + if (!size) { + r = vm_munmap(old.userspace_addr, old.npages * PAGE_SIZE); + WARN_ON(r < 0); + } + return 0; } EXPORT_SYMBOL_GPL(__x86_set_memory_region); -int x86_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem) +int x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size) { int r; mutex_lock(&kvm->slots_lock); - r = __x86_set_memory_region(kvm, mem); + r = __x86_set_memory_region(kvm, id, gpa, size); mutex_unlock(&kvm->slots_lock); return r; @@ -7516,16 +7553,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm) * unless the the memory map has changed due to process exit * or fd copying. */ - struct kvm_userspace_memory_region mem; - memset(&mem, 0, sizeof(mem)); - mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT; - x86_set_memory_region(kvm, &mem); - - mem.slot = IDENTITY_PAGETABLE_PRIVATE_MEMSLOT; - x86_set_memory_region(kvm, &mem); - - mem.slot = TSS_PRIVATE_MEMSLOT; - x86_set_memory_region(kvm, &mem); + x86_set_memory_region(kvm, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, 0, 0); + x86_set_memory_region(kvm, IDENTITY_PAGETABLE_PRIVATE_MEMSLOT, 0, 0); + x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, 0, 0); } kvm_iommu_unmap_guest(kvm); kfree(kvm->arch.vpic); @@ -7628,27 +7658,6 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_userspace_memory_region *mem, enum kvm_mr_change change) { - /* - * Only private memory slots need to be mapped here since - * KVM_SET_MEMORY_REGION ioctl is no longer supported. - */ - if ((memslot->id >= KVM_USER_MEM_SLOTS) && (change == KVM_MR_CREATE)) { - unsigned long userspace_addr; - - /* - * MAP_SHARED to prevent internal slot pages from being moved - * by fork()/COW. - */ - userspace_addr = vm_mmap(NULL, 0, memslot->npages * PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, 0); - - if (IS_ERR((void *)userspace_addr)) - return PTR_ERR((void *)userspace_addr); - - memslot->userspace_addr = userspace_addr; - } - return 0; } @@ -7710,17 +7719,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, { int nr_mmu_pages = 0; - if (change == KVM_MR_DELETE && old->id >= KVM_USER_MEM_SLOTS) { - int ret; - - ret = vm_munmap(old->userspace_addr, - old->npages * PAGE_SIZE); - if (ret < 0) - printk(KERN_WARNING - "kvm_vm_ioctl_set_memory_region: " - "failed to munmap memory\n"); - } - if (!kvm->arch.n_requested_mmu_pages) nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm); @@ -7769,19 +7767,36 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm, kvm_mmu_invalidate_zap_all_pages(kvm); } +static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) +{ + if (!list_empty_careful(&vcpu->async_pf.done)) + return true; + + if (kvm_apic_has_events(vcpu)) + return true; + + if (vcpu->arch.pv.pv_unhalted) + return true; + + if (atomic_read(&vcpu->arch.nmi_queued)) + return true; + + if (test_bit(KVM_REQ_SMI, &vcpu->requests)) + return true; + + if (kvm_arch_interrupt_allowed(vcpu) && + kvm_cpu_has_interrupt(vcpu)) + return true; + + return false; +} + int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) { if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) kvm_x86_ops->check_nested_events(vcpu, false); - return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && - !vcpu->arch.apf.halted) - || !list_empty_careful(&vcpu->async_pf.done) - || kvm_apic_has_events(vcpu) - || vcpu->arch.pv.pv_unhalted - || atomic_read(&vcpu->arch.nmi_queued) || - (kvm_arch_interrupt_allowed(vcpu) && - kvm_cpu_has_interrupt(vcpu)); + return kvm_vcpu_running(vcpu) || kvm_vcpu_has_events(vcpu); } int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 816488c0b97e..d388de72eaca 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -353,8 +353,12 @@ AVXcode: 1 17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) 18: Grp16 (1A) 19: -1a: BNDCL Ev,Gv | BNDCU Ev,Gv | BNDMOV Gv,Ev | BNDLDX Gv,Ev,Gv -1b: BNDCN Ev,Gv | BNDMOV Ev,Gv | BNDMK Gv,Ev | BNDSTX Ev,GV,Gv +# Intel SDM opcode map does not list MPX instructions. For now using Gv for +# bnd registers and Ev for everything else is OK because the instruction +# decoder does not use the information except as an indication that there is +# a ModR/M byte. +1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev +1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv 1c: 1d: 1e: @@ -732,6 +736,12 @@ bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) # 0x0f 0x38 0xc0-0xff +c8: sha1nexte Vdq,Wdq +c9: sha1msg1 Vdq,Wdq +ca: sha1msg2 Vdq,Wdq +cb: sha256rnds2 Vdq,Wdq +cc: sha256msg1 Vdq,Wdq +cd: sha256msg2 Vdq,Wdq db: VAESIMC Vdq,Wdq (66),(v1) dc: VAESENC Vdq,Hdq,Wdq (66),(v1) dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) @@ -790,6 +800,7 @@ AVXcode: 3 61: vpcmpestri Vdq,Wdq,Ib (66),(v1) 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) 63: vpcmpistri Vdq,Wdq,Ib (66),(v1) +cc: sha1rnds4 Vdq,Wdq,Ib df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) f0: RORX Gy,Ey,Ib (F2),(v) EndTable @@ -874,7 +885,7 @@ GrpTable: Grp7 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) 3: LIDT Ms 4: SMSW Mw/Rv -5: +5: rdpkru (110),(11B) | wrpkru (111),(11B) 6: LMSW Ew 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) EndTable @@ -888,6 +899,9 @@ EndTable GrpTable: Grp9 1: CMPXCHG8B/16B Mq/Mdq +3: xrstors +4: xsavec +5: xsaves 6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) 7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) EndTable @@ -932,8 +946,8 @@ GrpTable: Grp15 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) 4: XSAVE 5: XRSTOR | lfence (11B) -6: XSAVEOPT | mfence (11B) -7: clflush | sfence (11B) +6: XSAVEOPT | clwb (66) | mfence (11B) +7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B) EndTable GrpTable: Grp16 diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 1d8a83df153a..1f37cb2b56a9 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -693,14 +693,12 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void __init free_initrd_mem(unsigned long start, unsigned long end) { -#ifdef CONFIG_MICROCODE_EARLY /* * Remember, initrd memory may contain microcode or other useful things. * Before we lose initrd mem, we need to find a place to hold them * now that normal virtual memory is enabled. */ save_microcode_in_initrd(); -#endif /* * end could be not aligned, and We can not align that, diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 2c44c0792301..050a092b8d9a 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -647,9 +647,12 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc) set_pte(&pbase[i], pfn_pte(pfn, canon_pgprot(ref_prot))); - if (pfn_range_is_mapped(PFN_DOWN(__pa(address)), - PFN_DOWN(__pa(address)) + 1)) - split_page_count(level); + if (virt_addr_valid(address)) { + unsigned long pfn = PFN_DOWN(__pa(address)); + + if (pfn_range_is_mapped(pfn, pfn + 1)) + split_page_count(level); + } /* * Install the new, split up pagetable. diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index d7f997f7c26d..ea48449b2e63 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c @@ -50,11 +50,16 @@ void __init efi_bgrt_init(void) bgrt_tab->version); return; } - if (bgrt_tab->status != 1) { - pr_err("Ignoring BGRT: invalid status %u (expected 1)\n", + if (bgrt_tab->status & 0xfe) { + pr_err("Ignoring BGRT: reserved status bits are non-zero %u\n", bgrt_tab->status); return; } + if (bgrt_tab->status != 1) { + pr_debug("Ignoring BGRT: invalid status %u (expected 1)\n", + bgrt_tab->status); + return; + } if (bgrt_tab->image_type != 0) { pr_err("Ignoring BGRT: invalid image type %u (expected 0)\n", bgrt_tab->image_type); diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 6a28ded74211..ad285404ea7f 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -194,7 +194,7 @@ static void __init do_add_efi_memmap(void) int __init efi_memblock_x86_reserve_range(void) { struct efi_info *e = &boot_params.efi_info; - unsigned long pmap; + phys_addr_t pmap; if (efi_enabled(EFI_PARAVIRT)) return 0; @@ -209,7 +209,7 @@ int __init efi_memblock_x86_reserve_range(void) #else pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32)); #endif - memmap.phys_map = (void *)pmap; + memmap.phys_map = pmap; memmap.nr_map = e->efi_memmap_size / e->efi_memdesc_size; memmap.desc_size = e->efi_memdesc_size; @@ -222,7 +222,7 @@ int __init efi_memblock_x86_reserve_range(void) return 0; } -static void __init print_efi_memmap(void) +void __init efi_print_memmap(void) { #ifdef EFI_DEBUG efi_memory_desc_t *md; @@ -524,7 +524,7 @@ void __init efi_init(void) return; if (efi_enabled(EFI_DBG)) - print_efi_memmap(); + efi_print_memmap(); efi_esrt_init(); } @@ -1017,24 +1017,6 @@ u32 efi_mem_type(unsigned long phys_addr) return 0; } -u64 efi_mem_attributes(unsigned long phys_addr) -{ - efi_memory_desc_t *md; - void *p; - - if (!efi_enabled(EFI_MEMMAP)) - return 0; - - for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { - md = p; - if ((md->phys_addr <= phys_addr) && - (phys_addr < (md->phys_addr + - (md->num_pages << EFI_PAGE_SHIFT)))) - return md->attribute; - } - return 0; -} - static int __init arch_parse_efi_cmdline(char *str) { if (!str) { @@ -1044,8 +1026,6 @@ static int __init arch_parse_efi_cmdline(char *str) if (parse_option_str(str, "old_map")) set_bit(EFI_OLD_MEMMAP, &efi.flags); - if (parse_option_str(str, "debug")) - set_bit(EFI_DBG, &efi.flags); return 0; } diff --git a/arch/x86/ras/Kconfig b/arch/x86/ras/Kconfig index 10fea5fc821e..df280da34825 100644 --- a/arch/x86/ras/Kconfig +++ b/arch/x86/ras/Kconfig @@ -1,11 +1,9 @@ config AMD_MCE_INJ tristate "Simple MCE injection interface for AMD processors" - depends on RAS && EDAC_DECODE_MCE && DEBUG_FS + depends on RAS && EDAC_DECODE_MCE && DEBUG_FS && AMD_NB default n help This is a simple debugfs interface to inject MCEs and test different aspects of the MCE handling code. WARNING: Do not even assume this interface is staying stable! - - diff --git a/arch/x86/ras/mce_amd_inj.c b/arch/x86/ras/mce_amd_inj.c index 17e35b5bf779..55d38cfa46c2 100644 --- a/arch/x86/ras/mce_amd_inj.c +++ b/arch/x86/ras/mce_amd_inj.c @@ -17,7 +17,11 @@ #include <linux/cpu.h> #include <linux/string.h> #include <linux/uaccess.h> +#include <linux/pci.h> + #include <asm/mce.h> +#include <asm/amd_nb.h> +#include <asm/irq_vectors.h> #include "../kernel/cpu/mcheck/mce-internal.h" @@ -30,16 +34,21 @@ static struct dentry *dfs_inj; static u8 n_banks; #define MAX_FLAG_OPT_SIZE 3 +#define NBCFG 0x44 enum injection_type { SW_INJ = 0, /* SW injection, simply decode the error */ HW_INJ, /* Trigger a #MC */ + DFR_INT_INJ, /* Trigger Deferred error interrupt */ + THR_INT_INJ, /* Trigger threshold interrupt */ N_INJ_TYPES, }; static const char * const flags_options[] = { [SW_INJ] = "sw", [HW_INJ] = "hw", + [DFR_INT_INJ] = "df", + [THR_INT_INJ] = "th", NULL }; @@ -129,12 +138,9 @@ static ssize_t flags_write(struct file *filp, const char __user *ubuf, { char buf[MAX_FLAG_OPT_SIZE], *__buf; int err; - size_t ret; if (cnt > MAX_FLAG_OPT_SIZE) - cnt = MAX_FLAG_OPT_SIZE; - - ret = cnt; + return -EINVAL; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; @@ -150,9 +156,9 @@ static ssize_t flags_write(struct file *filp, const char __user *ubuf, return err; } - *ppos += ret; + *ppos += cnt; - return ret; + return cnt; } static const struct file_operations flags_fops = { @@ -185,6 +191,55 @@ static void trigger_mce(void *info) asm volatile("int $18"); } +static void trigger_dfr_int(void *info) +{ + asm volatile("int %0" :: "i" (DEFERRED_ERROR_VECTOR)); +} + +static void trigger_thr_int(void *info) +{ + asm volatile("int %0" :: "i" (THRESHOLD_APIC_VECTOR)); +} + +static u32 get_nbc_for_node(int node_id) +{ + struct cpuinfo_x86 *c = &boot_cpu_data; + u32 cores_per_node; + + cores_per_node = c->x86_max_cores / amd_get_nodes_per_socket(); + + return cores_per_node * node_id; +} + +static void toggle_nb_mca_mst_cpu(u16 nid) +{ + struct pci_dev *F3 = node_to_amd_nb(nid)->misc; + u32 val; + int err; + + if (!F3) + return; + + err = pci_read_config_dword(F3, NBCFG, &val); + if (err) { + pr_err("%s: Error reading F%dx%03x.\n", + __func__, PCI_FUNC(F3->devfn), NBCFG); + return; + } + + if (val & BIT(27)) + return; + + pr_err("%s: Set D18F3x44[NbMcaToMstCpuEn] which BIOS hasn't done.\n", + __func__); + + val |= BIT(27); + err = pci_write_config_dword(F3, NBCFG, val); + if (err) + pr_err("%s: Error writing F%dx%03x.\n", + __func__, PCI_FUNC(F3->devfn), NBCFG); +} + static void do_inject(void) { u64 mcg_status = 0; @@ -205,6 +260,26 @@ static void do_inject(void) if (!(i_mce.status & MCI_STATUS_PCC)) mcg_status |= MCG_STATUS_RIPV; + /* + * Ensure necessary status bits for deferred errors: + * - MCx_STATUS[Deferred]: make sure it is a deferred error + * - MCx_STATUS[UC] cleared: deferred errors are _not_ UC + */ + if (inj_type == DFR_INT_INJ) { + i_mce.status |= MCI_STATUS_DEFERRED; + i_mce.status |= (i_mce.status & ~MCI_STATUS_UC); + } + + /* + * For multi node CPUs, logging and reporting of bank 4 errors happens + * only on the node base core. Refer to D18F3x44[NbMcaToMstCpuEn] for + * Fam10h and later BKDGs. + */ + if (static_cpu_has(X86_FEATURE_AMD_DCM) && b == 4) { + toggle_nb_mca_mst_cpu(amd_get_nb_id(cpu)); + cpu = get_nbc_for_node(amd_get_nb_id(cpu)); + } + get_online_cpus(); if (!cpu_online(cpu)) goto err; @@ -225,7 +300,16 @@ static void do_inject(void) toggle_hw_mce_inject(cpu, false); - smp_call_function_single(cpu, trigger_mce, NULL, 0); + switch (inj_type) { + case DFR_INT_INJ: + smp_call_function_single(cpu, trigger_dfr_int, NULL, 0); + break; + case THR_INT_INJ: + smp_call_function_single(cpu, trigger_thr_int, NULL, 0); + break; + default: + smp_call_function_single(cpu, trigger_mce, NULL, 0); + } err: put_online_cpus(); @@ -290,6 +374,11 @@ static const char readme_msg[] = "\t handle the error. Be warned: might cause system panic if MCi_STATUS[PCC] \n" "\t is set. Therefore, consider setting (debugfs_mountpoint)/mce/fake_panic \n" "\t before injecting.\n" +"\t - \"df\": Trigger APIC interrupt for Deferred error. Causes deferred \n" +"\t error APIC interrupt handler to handle the error if the feature is \n" +"\t is present in hardware. \n" +"\t - \"th\": Trigger APIC interrupt for Threshold errors. Causes threshold \n" +"\t APIC interrupt handler to handle the error. \n" "\n"; static ssize_t diff --git a/arch/x86/um/asm/syscall.h b/arch/x86/um/asm/syscall.h index 9fe77b7b5a0e..81d6562ce01d 100644 --- a/arch/x86/um/asm/syscall.h +++ b/arch/x86/um/asm/syscall.h @@ -3,6 +3,10 @@ #include <uapi/linux/audit.h> +typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long, + unsigned long, unsigned long, + unsigned long, unsigned long); + static inline int syscall_get_arch(void) { #ifdef CONFIG_X86_32 diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c index 9701a4fd7bf2..836a1eb5df43 100644 --- a/arch/x86/um/ldt.c +++ b/arch/x86/um/ldt.c @@ -12,7 +12,10 @@ #include <skas.h> #include <sysdep/tls.h> -extern int modify_ldt(int func, void *ptr, unsigned long bytecount); +static inline int modify_ldt (int func, void *ptr, unsigned long bytecount) +{ + return syscall(__NR_modify_ldt, func, ptr, bytecount); +} static long write_ldt_entry(struct mm_id *mm_idp, int func, struct user_desc *desc, void **addr, int done) diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c index bd16d6c370ec..439c0994b696 100644 --- a/arch/x86/um/sys_call_table_32.c +++ b/arch/x86/um/sys_call_table_32.c @@ -7,6 +7,7 @@ #include <linux/sys.h> #include <linux/cache.h> #include <generated/user_constants.h> +#include <asm/syscall.h> #define __NO_STUBS @@ -24,15 +25,13 @@ #define old_mmap sys_old_mmap -#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ; +#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; #include <asm/syscalls_32.h> #undef __SYSCALL_I386 #define __SYSCALL_I386(nr, sym, compat) [ nr ] = sym, -typedef asmlinkage void (*sys_call_ptr_t)(void); - -extern asmlinkage void sys_ni_syscall(void); +extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = { /* diff --git a/arch/x86/um/sys_call_table_64.c b/arch/x86/um/sys_call_table_64.c index a75d8700472a..b74ea6c2c0e7 100644 --- a/arch/x86/um/sys_call_table_64.c +++ b/arch/x86/um/sys_call_table_64.c @@ -7,6 +7,7 @@ #include <linux/sys.h> #include <linux/cache.h> #include <generated/user_constants.h> +#include <asm/syscall.h> #define __NO_STUBS @@ -37,15 +38,13 @@ #define __SYSCALL_COMMON(nr, sym, compat) __SYSCALL_64(nr, sym, compat) #define __SYSCALL_X32(nr, sym, compat) /* Not supported */ -#define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ; +#define __SYSCALL_64(nr, sym, compat) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; #include <asm/syscalls_64.h> #undef __SYSCALL_64 #define __SYSCALL_64(nr, sym, compat) [ nr ] = sym, -typedef void (*sys_call_ptr_t)(void); - -extern void sys_ni_syscall(void); +extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = { /* diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 1c30e4ab1022..63320b6d35bc 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -965,17 +965,8 @@ char * __init xen_auto_xlated_memory_setup(void) static void __init fiddle_vdso(void) { #ifdef CONFIG_X86_32 - /* - * This could be called before selected_vdso32 is initialized, so - * just fiddle with both possible images. vdso_image_32_syscall - * can't be selected, since it only exists on 64-bit systems. - */ - u32 *mask; - mask = vdso_image_32_int80.data + - vdso_image_32_int80.sym_VDSO32_NOTE_MASK; - *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; - mask = vdso_image_32_sysenter.data + - vdso_image_32_sysenter.sym_VDSO32_NOTE_MASK; + u32 *mask = vdso_image_32.data + + vdso_image_32.sym_VDSO32_NOTE_MASK; *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; #endif } diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index 93795d047303..fd8017ce298a 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -47,7 +47,7 @@ * * Atomically reads the value of @v. */ -#define atomic_read(v) ACCESS_ONCE((v)->counter) +#define atomic_read(v) READ_ONCE((v)->counter) /** * atomic_set - set atomic variable @@ -56,7 +56,7 @@ * * Atomically sets the value of @v to @i. */ -#define atomic_set(v,i) ((v)->counter = (i)) +#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) #if XCHAL_HAVE_S32C1I #define ATOMIC_OP(op) \ |