mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 09:44:18 +08:00
Three simple fixes:
- the first one is fixing a non-critical bug in the gpmi driver - the second one is fixing a bug in the 'automatic NAND timings selection' feature introduced in 4.9-rc1 - the last one is fixing a false positive uninitialized-var warning -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJYEwsOAAoJEGXtNgF+CLcAef0P/jEfwHzg9PM+4Nb9z1W42Cug llY//idJZJvQd/ui8jLrjpvKIbaYUKquEnADX/ZIAqglAOnKPgT4tkrffHTMq4UC d2bND6dG6V3WcBlOgb1+ejOOlKbSEf5sIIvSa/IRLiSjQPBY9IoZqZFEWjzk9B/6 8x7MwWKkFMnol/xBAI9QXQcausVIyf2KdbzUFLlypo98KelOfFWwn1efK2SgqgmH BbLi0Fxo/X+AXOq3ymWvXqQkEh4OJnlA0I3b8v9rofmOFxfZEAkbuBPVj0r8kDLX cID6/QcnkHP2rrVmMjD/hllkYRdKXj4EgdbOVWtoYju6EhaTcSAEM2z7wD1syEHt Ks82NQo+H/LlyuizgPntll1dM+dVYYLN452kP3fKMGImNJxk+ZPqVSQIlio5mLxi 6mPb8arx+V6zxtjMmkkkcouctg14ffH2SuGhfdm03jFuc/Kwz6JfB88c029t3Ejh 1qdlsuPo7rw0SasbBYYrydwafkZ1w1zlBWCoq+xu4ZZXAUXQrZYJCw+gY++mgZBk JVpo+dG6wcB3A5vz7ntX/Ri6rtc3VgzXvTUacw9jkjlBGn3cTdNDPZY2l+pqn4RM hjGGIUe0W3qQfHtOe1uamdKfLy9LgKe40hcfFDAKMl8eJqcnCPKdiZzoF7scDiEN qID3AFfmhPomDloCXOTx =75Gw -----END PGP SIGNATURE----- Merge tag 'nand/fixes-for-4.9-rc3' of github.com:linux-nand/linux From Boris: """ Three simple fixes: - the first one is fixing a non-critical bug in the gpmi driver - the second one is fixing a bug in the 'automatic NAND timings selection' feature introduced in 4.9-rc1 - the last one is fixing a false positive uninitialized-var warning """ Acked-by: Marek Vasut <marex@denx.de>
This commit is contained in:
commit
0e2ce9d3fc
@ -220,8 +220,11 @@ What: /sys/class/cxl/<card>/reset
|
||||
Date: October 2014
|
||||
Contact: linuxppc-dev@lists.ozlabs.org
|
||||
Description: write only
|
||||
Writing 1 will issue a PERST to card which may cause the card
|
||||
to reload the FPGA depending on load_image_on_perst.
|
||||
Writing 1 will issue a PERST to card provided there are no
|
||||
contexts active on any one of the card AFUs. This may cause
|
||||
the card to reload the FPGA depending on load_image_on_perst.
|
||||
Writing -1 will do a force PERST irrespective of any active
|
||||
contexts on the card AFUs.
|
||||
Users: https://github.com/ibm-capi/libcxl
|
||||
|
||||
What: /sys/class/cxl/<card>/perst_reloads_same_image (not in a guest)
|
||||
|
@ -0,0 +1,23 @@
|
||||
* Aspeed BT (Block Transfer) IPMI interface
|
||||
|
||||
The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
|
||||
(BaseBoard Management Controllers) and the BT interface can be used to
|
||||
perform in-band IPMI communication with their host.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "aspeed,ast2400-bt-bmc"
|
||||
- reg: physical address and size of the registers
|
||||
|
||||
Optional properties:
|
||||
|
||||
- interrupts: interrupt generated by the BT interface. without an
|
||||
interrupt, the driver will operate in poll mode.
|
||||
|
||||
Example:
|
||||
|
||||
ibt@1e789140 {
|
||||
compatible = "aspeed,ast2400-bt-bmc";
|
||||
reg = <0x1e789140 0x18>;
|
||||
interrupts = <8>;
|
||||
};
|
@ -43,7 +43,9 @@ aspeed,ast2500-pinctrl, aspeed,g5-pinctrl:
|
||||
|
||||
GPID0 GPID2 GPIE0 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8
|
||||
I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7
|
||||
RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8
|
||||
RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 SPI1DEBUG SPI1PASSTHRU TIMER4 TIMER5 TIMER6
|
||||
TIMER7 TIMER8 VGABIOSROM
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
24
Documentation/devicetree/bindings/timer/jcore,pit.txt
Normal file
24
Documentation/devicetree/bindings/timer/jcore,pit.txt
Normal file
@ -0,0 +1,24 @@
|
||||
J-Core Programmable Interval Timer and Clocksource
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "jcore,pit".
|
||||
|
||||
- reg: Memory region(s) for timer/clocksource registers. For SMP,
|
||||
there should be one region per cpu, indexed by the sequential,
|
||||
zero-based hardware cpu number.
|
||||
|
||||
- interrupts: An interrupt to assign for the timer. The actual pit
|
||||
core is integrated with the aic and allows the timer interrupt
|
||||
assignment to be programmed by software, but this property is
|
||||
required in order to reserve an interrupt number that doesn't
|
||||
conflict with other devices.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
timer@200 {
|
||||
compatible = "jcore,pit";
|
||||
reg = < 0x200 0x30 0x500 0x30 >;
|
||||
interrupts = < 0x48 >;
|
||||
};
|
@ -395,32 +395,6 @@ is not associated with a file:
|
||||
|
||||
or if empty, the mapping is anonymous.
|
||||
|
||||
The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
|
||||
of the individual tasks of a process. In this file you will see a mapping marked
|
||||
as [stack] if that task sees it as a stack. Hence, for the example above, the
|
||||
task-level map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
|
||||
|
||||
08048000-08049000 r-xp 00000000 03:00 8312 /opt/test
|
||||
08049000-0804a000 rw-p 00001000 03:00 8312 /opt/test
|
||||
0804a000-0806b000 rw-p 00000000 00:00 0 [heap]
|
||||
a7cb1000-a7cb2000 ---p 00000000 00:00 0
|
||||
a7cb2000-a7eb2000 rw-p 00000000 00:00 0
|
||||
a7eb2000-a7eb3000 ---p 00000000 00:00 0
|
||||
a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack]
|
||||
a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6
|
||||
a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6
|
||||
a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6
|
||||
a800b000-a800e000 rw-p 00000000 00:00 0
|
||||
a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0
|
||||
a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0
|
||||
a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0
|
||||
a8024000-a8027000 rw-p 00000000 00:00 0
|
||||
a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2
|
||||
a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2
|
||||
a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2
|
||||
aff35000-aff4a000 rw-p 00000000 00:00 0
|
||||
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
|
||||
|
||||
The /proc/PID/smaps is an extension based on maps, showing the memory
|
||||
consumption for each of the process's mappings. For each of mappings there
|
||||
is a series of lines such as the following:
|
||||
|
@ -4620,8 +4620,9 @@ F: sound/usb/misc/ua101.c
|
||||
|
||||
EXTENSIBLE FIRMWARE INTERFACE (EFI)
|
||||
M: Matt Fleming <matt@codeblueprint.co.uk>
|
||||
M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
|
||||
L: linux-efi@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
|
||||
S: Maintained
|
||||
F: Documentation/efi-stub.txt
|
||||
F: arch/ia64/kernel/efi.c
|
||||
@ -8216,7 +8217,7 @@ F: include/linux/mfd/
|
||||
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
|
||||
M: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
T: git git://git.linaro.org/people/ulf.hansson/mmc.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mmc/
|
||||
F: drivers/mmc/
|
||||
@ -9303,7 +9304,7 @@ S: Maintained
|
||||
F: drivers/pci/host/*designware*
|
||||
|
||||
PCI DRIVER FOR SYNOPSYS PROTOTYPING DEVICE
|
||||
M: Joao Pinto <jpinto@synopsys.com>
|
||||
M: Jose Abreu <Jose.Abreu@synopsys.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/pci/designware-pcie.txt
|
||||
|
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 9
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc1
|
||||
EXTRAVERSION = -rc2
|
||||
NAME = Psychotic Stoned Sheep
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -157,14 +157,16 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
|
||||
static inline int
|
||||
read_int(struct task_struct *task, unsigned long addr, int * data)
|
||||
{
|
||||
int copied = access_process_vm(task, addr, data, sizeof(int), 0);
|
||||
int copied = access_process_vm(task, addr, data, sizeof(int),
|
||||
FOLL_FORCE);
|
||||
return (copied == sizeof(int)) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static inline int
|
||||
write_int(struct task_struct *task, unsigned long addr, int data)
|
||||
{
|
||||
int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
|
||||
int copied = access_process_vm(task, addr, &data, sizeof(int),
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
return (copied == sizeof(int)) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
@ -281,7 +283,8 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
/* When I and D space are separate, these will need to be fixed. */
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA:
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp),
|
||||
FOLL_FORCE);
|
||||
ret = -EIO;
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
|
@ -1312,6 +1312,13 @@ static int init_hyp_mode(void)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = create_hyp_mappings(kvm_ksym_ref(__bss_start),
|
||||
kvm_ksym_ref(__bss_stop), PAGE_HYP_RO);
|
||||
if (err) {
|
||||
kvm_err("Cannot map bss section\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the Hyp stack pages
|
||||
*/
|
||||
|
@ -915,7 +915,7 @@ config RANDOMIZE_BASE
|
||||
|
||||
config RANDOMIZE_MODULE_REGION_FULL
|
||||
bool "Randomize the module region independently from the core kernel"
|
||||
depends on RANDOMIZE_BASE
|
||||
depends on RANDOMIZE_BASE && !DYNAMIC_FTRACE
|
||||
default y
|
||||
help
|
||||
Randomizes the location of the module region without considering the
|
||||
|
@ -15,7 +15,7 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
GZFLAGS :=-9
|
||||
|
||||
ifneq ($(CONFIG_RELOCATABLE),)
|
||||
LDFLAGS_vmlinux += -pie -Bsymbolic
|
||||
LDFLAGS_vmlinux += -pie -shared -Bsymbolic
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
|
||||
|
@ -94,7 +94,7 @@ struct arm64_cpu_capabilities {
|
||||
u16 capability;
|
||||
int def_scope; /* default scope */
|
||||
bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
|
||||
void (*enable)(void *); /* Called on all active CPUs */
|
||||
int (*enable)(void *); /* Called on all active CPUs */
|
||||
union {
|
||||
struct { /* To be used for erratum handling only */
|
||||
u32 midr_model;
|
||||
|
@ -18,6 +18,9 @@
|
||||
#ifndef __ASM_EXEC_H
|
||||
#define __ASM_EXEC_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
extern unsigned long arch_align_stack(unsigned long sp);
|
||||
void uao_thread_switch(struct task_struct *next);
|
||||
|
||||
#endif /* __ASM_EXEC_H */
|
||||
|
@ -178,11 +178,6 @@ static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV);
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR);
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE);
|
||||
@ -203,6 +198,12 @@ static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) ||
|
||||
kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define __ASM_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
#include <asm/memory.h>
|
||||
|
||||
#define MODULE_ARCH_VERMAGIC "aarch64"
|
||||
|
||||
@ -32,6 +33,10 @@ u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
|
||||
Elf64_Sym *sym);
|
||||
|
||||
#ifdef CONFIG_RANDOMIZE_BASE
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
#define ARCH_RELOCATES_KCRCTAB
|
||||
#define reloc_start (kimage_vaddr - KIMAGE_VADDR)
|
||||
#endif
|
||||
extern u64 module_alloc_base;
|
||||
#else
|
||||
#define module_alloc_base ((u64)_etext - MODULES_VSIZE)
|
||||
|
@ -44,48 +44,44 @@ static inline unsigned long __percpu_##op(void *ptr, \
|
||||
\
|
||||
switch (size) { \
|
||||
case 1: \
|
||||
do { \
|
||||
asm ("//__per_cpu_" #op "_1\n" \
|
||||
"ldxrb %w[ret], %[ptr]\n" \
|
||||
asm ("//__per_cpu_" #op "_1\n" \
|
||||
"1: ldxrb %w[ret], %[ptr]\n" \
|
||||
#asm_op " %w[ret], %w[ret], %w[val]\n" \
|
||||
"stxrb %w[loop], %w[ret], %[ptr]\n" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u8 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
} while (loop); \
|
||||
" stxrb %w[loop], %w[ret], %[ptr]\n" \
|
||||
" cbnz %w[loop], 1b" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u8 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
break; \
|
||||
case 2: \
|
||||
do { \
|
||||
asm ("//__per_cpu_" #op "_2\n" \
|
||||
"ldxrh %w[ret], %[ptr]\n" \
|
||||
asm ("//__per_cpu_" #op "_2\n" \
|
||||
"1: ldxrh %w[ret], %[ptr]\n" \
|
||||
#asm_op " %w[ret], %w[ret], %w[val]\n" \
|
||||
"stxrh %w[loop], %w[ret], %[ptr]\n" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u16 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
} while (loop); \
|
||||
" stxrh %w[loop], %w[ret], %[ptr]\n" \
|
||||
" cbnz %w[loop], 1b" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u16 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
break; \
|
||||
case 4: \
|
||||
do { \
|
||||
asm ("//__per_cpu_" #op "_4\n" \
|
||||
"ldxr %w[ret], %[ptr]\n" \
|
||||
asm ("//__per_cpu_" #op "_4\n" \
|
||||
"1: ldxr %w[ret], %[ptr]\n" \
|
||||
#asm_op " %w[ret], %w[ret], %w[val]\n" \
|
||||
"stxr %w[loop], %w[ret], %[ptr]\n" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u32 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
} while (loop); \
|
||||
" stxr %w[loop], %w[ret], %[ptr]\n" \
|
||||
" cbnz %w[loop], 1b" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u32 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
break; \
|
||||
case 8: \
|
||||
do { \
|
||||
asm ("//__per_cpu_" #op "_8\n" \
|
||||
"ldxr %[ret], %[ptr]\n" \
|
||||
asm ("//__per_cpu_" #op "_8\n" \
|
||||
"1: ldxr %[ret], %[ptr]\n" \
|
||||
#asm_op " %[ret], %[ret], %[val]\n" \
|
||||
"stxr %w[loop], %[ret], %[ptr]\n" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u64 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
} while (loop); \
|
||||
" stxr %w[loop], %[ret], %[ptr]\n" \
|
||||
" cbnz %w[loop], 1b" \
|
||||
: [loop] "=&r" (loop), [ret] "=&r" (ret), \
|
||||
[ptr] "+Q"(*(u64 *)ptr) \
|
||||
: [val] "Ir" (val)); \
|
||||
break; \
|
||||
default: \
|
||||
BUILD_BUG(); \
|
||||
@ -150,44 +146,40 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
do {
|
||||
asm ("//__percpu_xchg_1\n"
|
||||
"ldxrb %w[ret], %[ptr]\n"
|
||||
"stxrb %w[loop], %w[val], %[ptr]\n"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u8 *)ptr)
|
||||
: [val] "r" (val));
|
||||
} while (loop);
|
||||
asm ("//__percpu_xchg_1\n"
|
||||
"1: ldxrb %w[ret], %[ptr]\n"
|
||||
" stxrb %w[loop], %w[val], %[ptr]\n"
|
||||
" cbnz %w[loop], 1b"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u8 *)ptr)
|
||||
: [val] "r" (val));
|
||||
break;
|
||||
case 2:
|
||||
do {
|
||||
asm ("//__percpu_xchg_2\n"
|
||||
"ldxrh %w[ret], %[ptr]\n"
|
||||
"stxrh %w[loop], %w[val], %[ptr]\n"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u16 *)ptr)
|
||||
: [val] "r" (val));
|
||||
} while (loop);
|
||||
asm ("//__percpu_xchg_2\n"
|
||||
"1: ldxrh %w[ret], %[ptr]\n"
|
||||
" stxrh %w[loop], %w[val], %[ptr]\n"
|
||||
" cbnz %w[loop], 1b"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u16 *)ptr)
|
||||
: [val] "r" (val));
|
||||
break;
|
||||
case 4:
|
||||
do {
|
||||
asm ("//__percpu_xchg_4\n"
|
||||
"ldxr %w[ret], %[ptr]\n"
|
||||
"stxr %w[loop], %w[val], %[ptr]\n"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u32 *)ptr)
|
||||
: [val] "r" (val));
|
||||
} while (loop);
|
||||
asm ("//__percpu_xchg_4\n"
|
||||
"1: ldxr %w[ret], %[ptr]\n"
|
||||
" stxr %w[loop], %w[val], %[ptr]\n"
|
||||
" cbnz %w[loop], 1b"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u32 *)ptr)
|
||||
: [val] "r" (val));
|
||||
break;
|
||||
case 8:
|
||||
do {
|
||||
asm ("//__percpu_xchg_8\n"
|
||||
"ldxr %[ret], %[ptr]\n"
|
||||
"stxr %w[loop], %[val], %[ptr]\n"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u64 *)ptr)
|
||||
: [val] "r" (val));
|
||||
} while (loop);
|
||||
asm ("//__percpu_xchg_8\n"
|
||||
"1: ldxr %[ret], %[ptr]\n"
|
||||
" stxr %w[loop], %[val], %[ptr]\n"
|
||||
" cbnz %w[loop], 1b"
|
||||
: [loop] "=&r"(loop), [ret] "=&r"(ret),
|
||||
[ptr] "+Q"(*(u64 *)ptr)
|
||||
: [val] "r" (val));
|
||||
break;
|
||||
default:
|
||||
BUILD_BUG();
|
||||
|
@ -188,8 +188,8 @@ static inline void spin_lock_prefetch(const void *ptr)
|
||||
|
||||
#endif
|
||||
|
||||
void cpu_enable_pan(void *__unused);
|
||||
void cpu_enable_uao(void *__unused);
|
||||
void cpu_enable_cache_maint_trap(void *__unused);
|
||||
int cpu_enable_pan(void *__unused);
|
||||
int cpu_enable_uao(void *__unused);
|
||||
int cpu_enable_cache_maint_trap(void *__unused);
|
||||
|
||||
#endif /* __ASM_PROCESSOR_H */
|
||||
|
@ -286,7 +286,7 @@ asm(
|
||||
|
||||
#define write_sysreg_s(v, r) do { \
|
||||
u64 __val = (u64)v; \
|
||||
asm volatile("msr_s " __stringify(r) ", %0" : : "rZ" (__val)); \
|
||||
asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \
|
||||
} while (0)
|
||||
|
||||
static inline void config_sctlr_el1(u32 clear, u32 set)
|
||||
|
@ -21,6 +21,7 @@
|
||||
/*
|
||||
* User space memory access functions
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kasan-checks.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/thread_info.h>
|
||||
@ -102,6 +103,13 @@ static inline void set_fs(mm_segment_t fs)
|
||||
flag; \
|
||||
})
|
||||
|
||||
/*
|
||||
* When dealing with data aborts or instruction traps we may end up with
|
||||
* a tagged userland pointer. Clear the tag to get a sane pointer to pass
|
||||
* on to access_ok(), for instance.
|
||||
*/
|
||||
#define untagged_addr(addr) sign_extend64(addr, 55)
|
||||
|
||||
#define access_ok(type, addr, size) __range_ok(addr, size)
|
||||
#define user_addr_max get_fs
|
||||
|
||||
|
@ -280,35 +280,43 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
|
||||
/*
|
||||
* Error-checking SWP macros implemented using ldxr{b}/stxr{b}
|
||||
*/
|
||||
#define __user_swpX_asm(data, addr, res, temp, B) \
|
||||
|
||||
/* Arbitrary constant to ensure forward-progress of the LL/SC loop */
|
||||
#define __SWP_LL_SC_LOOPS 4
|
||||
|
||||
#define __user_swpX_asm(data, addr, res, temp, temp2, B) \
|
||||
__asm__ __volatile__( \
|
||||
" mov %w3, %w7\n" \
|
||||
ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \
|
||||
CONFIG_ARM64_PAN) \
|
||||
"0: ldxr"B" %w2, [%3]\n" \
|
||||
"1: stxr"B" %w0, %w1, [%3]\n" \
|
||||
"0: ldxr"B" %w2, [%4]\n" \
|
||||
"1: stxr"B" %w0, %w1, [%4]\n" \
|
||||
" cbz %w0, 2f\n" \
|
||||
" mov %w0, %w4\n" \
|
||||
" sub %w3, %w3, #1\n" \
|
||||
" cbnz %w3, 0b\n" \
|
||||
" mov %w0, %w5\n" \
|
||||
" b 3f\n" \
|
||||
"2:\n" \
|
||||
" mov %w1, %w2\n" \
|
||||
"3:\n" \
|
||||
" .pushsection .fixup,\"ax\"\n" \
|
||||
" .align 2\n" \
|
||||
"4: mov %w0, %w5\n" \
|
||||
"4: mov %w0, %w6\n" \
|
||||
" b 3b\n" \
|
||||
" .popsection" \
|
||||
_ASM_EXTABLE(0b, 4b) \
|
||||
_ASM_EXTABLE(1b, 4b) \
|
||||
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
|
||||
CONFIG_ARM64_PAN) \
|
||||
: "=&r" (res), "+r" (data), "=&r" (temp) \
|
||||
: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \
|
||||
: "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
|
||||
: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT), \
|
||||
"i" (__SWP_LL_SC_LOOPS) \
|
||||
: "memory")
|
||||
|
||||
#define __user_swp_asm(data, addr, res, temp) \
|
||||
__user_swpX_asm(data, addr, res, temp, "")
|
||||
#define __user_swpb_asm(data, addr, res, temp) \
|
||||
__user_swpX_asm(data, addr, res, temp, "b")
|
||||
#define __user_swp_asm(data, addr, res, temp, temp2) \
|
||||
__user_swpX_asm(data, addr, res, temp, temp2, "")
|
||||
#define __user_swpb_asm(data, addr, res, temp, temp2) \
|
||||
__user_swpX_asm(data, addr, res, temp, temp2, "b")
|
||||
|
||||
/*
|
||||
* Bit 22 of the instruction encoding distinguishes between
|
||||
@ -328,12 +336,12 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
|
||||
}
|
||||
|
||||
while (1) {
|
||||
unsigned long temp;
|
||||
unsigned long temp, temp2;
|
||||
|
||||
if (type == TYPE_SWPB)
|
||||
__user_swpb_asm(*data, address, res, temp);
|
||||
__user_swpb_asm(*data, address, res, temp, temp2);
|
||||
else
|
||||
__user_swp_asm(*data, address, res, temp);
|
||||
__user_swp_asm(*data, address, res, temp, temp2);
|
||||
|
||||
if (likely(res != -EAGAIN) || signal_pending(current))
|
||||
break;
|
||||
|
@ -39,10 +39,11 @@ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
|
||||
(arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask);
|
||||
}
|
||||
|
||||
static void cpu_enable_trap_ctr_access(void *__unused)
|
||||
static int cpu_enable_trap_ctr_access(void *__unused)
|
||||
{
|
||||
/* Clear SCTLR_EL1.UCT */
|
||||
config_sctlr_el1(SCTLR_EL1_UCT, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MIDR_RANGE(model, min, max) \
|
||||
|
@ -19,7 +19,9 @@
|
||||
#define pr_fmt(fmt) "CPU features: " fmt
|
||||
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/stop_machine.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpufeature.h>
|
||||
@ -941,7 +943,13 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
|
||||
{
|
||||
for (; caps->matches; caps++)
|
||||
if (caps->enable && cpus_have_cap(caps->capability))
|
||||
on_each_cpu(caps->enable, NULL, true);
|
||||
/*
|
||||
* Use stop_machine() as it schedules the work allowing
|
||||
* us to modify PSTATE, instead of on_each_cpu() which
|
||||
* uses an IPI, giving us a PSTATE that disappears when
|
||||
* we return.
|
||||
*/
|
||||
stop_machine(caps->enable, NULL, cpu_online_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -586,8 +586,9 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems
|
||||
b.lt 4f // Skip if no PMU present
|
||||
mrs x0, pmcr_el0 // Disable debug access traps
|
||||
ubfx x0, x0, #11, #5 // to EL2 and allow access to
|
||||
msr mdcr_el2, x0 // all PMU counters from EL1
|
||||
4:
|
||||
csel x0, xzr, x0, lt // all PMU counters from EL1
|
||||
msr mdcr_el2, x0 // (if they exist)
|
||||
|
||||
/* Stage-2 translation */
|
||||
msr vttbr_el2, xzr
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/compat.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/exec.h>
|
||||
#include <asm/fpsimd.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/processor.h>
|
||||
@ -186,10 +187,19 @@ void __show_regs(struct pt_regs *regs)
|
||||
printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
|
||||
regs->pc, lr, regs->pstate);
|
||||
printk("sp : %016llx\n", sp);
|
||||
for (i = top_reg; i >= 0; i--) {
|
||||
|
||||
i = top_reg;
|
||||
|
||||
while (i >= 0) {
|
||||
printk("x%-2d: %016llx ", i, regs->regs[i]);
|
||||
if (i % 2 == 0)
|
||||
printk("\n");
|
||||
i--;
|
||||
|
||||
if (i % 2 == 0) {
|
||||
pr_cont("x%-2d: %016llx ", i, regs->regs[i]);
|
||||
i--;
|
||||
}
|
||||
|
||||
pr_cont("\n");
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
@ -301,7 +311,7 @@ static void tls_thread_switch(struct task_struct *next)
|
||||
}
|
||||
|
||||
/* Restore the UAO state depending on next's addr_limit */
|
||||
static void uao_thread_switch(struct task_struct *next)
|
||||
void uao_thread_switch(struct task_struct *next)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM64_UAO)) {
|
||||
if (task_thread_info(next)->addr_limit == KERNEL_DS)
|
||||
|
@ -135,7 +135,7 @@ ENTRY(_cpu_resume)
|
||||
|
||||
#ifdef CONFIG_KASAN
|
||||
mov x0, sp
|
||||
bl kasan_unpoison_remaining_stack
|
||||
bl kasan_unpoison_task_stack_below
|
||||
#endif
|
||||
|
||||
ldp x19, x20, [x29, #16]
|
||||
|
@ -544,6 +544,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
|
||||
return;
|
||||
}
|
||||
bootcpu_valid = true;
|
||||
early_map_cpu_to_node(0, acpi_numa_get_nid(0, hwid));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <asm/exec.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/mmu_context.h>
|
||||
@ -49,6 +52,14 @@ void notrace __cpu_suspend_exit(void)
|
||||
*/
|
||||
set_my_cpu_offset(per_cpu_offset(cpu));
|
||||
|
||||
/*
|
||||
* PSTATE was not saved over suspend/resume, re-enable any detected
|
||||
* features that might not have been set correctly.
|
||||
*/
|
||||
asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,
|
||||
CONFIG_ARM64_PAN));
|
||||
uao_thread_switch(current);
|
||||
|
||||
/*
|
||||
* Restore HW breakpoint registers to sane values
|
||||
* before debug exceptions are possibly reenabled
|
||||
|
@ -428,24 +428,28 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||||
force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
|
||||
}
|
||||
|
||||
void cpu_enable_cache_maint_trap(void *__unused)
|
||||
int cpu_enable_cache_maint_trap(void *__unused)
|
||||
{
|
||||
config_sctlr_el1(SCTLR_EL1_UCI, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define __user_cache_maint(insn, address, res) \
|
||||
asm volatile ( \
|
||||
"1: " insn ", %1\n" \
|
||||
" mov %w0, #0\n" \
|
||||
"2:\n" \
|
||||
" .pushsection .fixup,\"ax\"\n" \
|
||||
" .align 2\n" \
|
||||
"3: mov %w0, %w2\n" \
|
||||
" b 2b\n" \
|
||||
" .popsection\n" \
|
||||
_ASM_EXTABLE(1b, 3b) \
|
||||
: "=r" (res) \
|
||||
: "r" (address), "i" (-EFAULT) )
|
||||
if (untagged_addr(address) >= user_addr_max()) \
|
||||
res = -EFAULT; \
|
||||
else \
|
||||
asm volatile ( \
|
||||
"1: " insn ", %1\n" \
|
||||
" mov %w0, #0\n" \
|
||||
"2:\n" \
|
||||
" .pushsection .fixup,\"ax\"\n" \
|
||||
" .align 2\n" \
|
||||
"3: mov %w0, %w2\n" \
|
||||
" b 2b\n" \
|
||||
" .popsection\n" \
|
||||
_ASM_EXTABLE(1b, 3b) \
|
||||
: "=r" (res) \
|
||||
: "r" (address), "i" (-EFAULT) )
|
||||
|
||||
static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
|
||||
{
|
||||
|
@ -29,7 +29,9 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/preempt.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
@ -670,9 +672,17 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
|
||||
NOKPROBE_SYMBOL(do_debug_exception);
|
||||
|
||||
#ifdef CONFIG_ARM64_PAN
|
||||
void cpu_enable_pan(void *__unused)
|
||||
int cpu_enable_pan(void *__unused)
|
||||
{
|
||||
/*
|
||||
* We modify PSTATE. This won't work from irq context as the PSTATE
|
||||
* is discarded once we return from the exception.
|
||||
*/
|
||||
WARN_ON_ONCE(in_interrupt());
|
||||
|
||||
config_sctlr_el1(SCTLR_EL1_SPAN, 0);
|
||||
asm(SET_PSTATE_PAN(1));
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ARM64_PAN */
|
||||
|
||||
@ -683,8 +693,9 @@ void cpu_enable_pan(void *__unused)
|
||||
* We need to enable the feature at runtime (instead of adding it to
|
||||
* PSR_MODE_EL1h) as the feature may not be implemented by the cpu.
|
||||
*/
|
||||
void cpu_enable_uao(void *__unused)
|
||||
int cpu_enable_uao(void *__unused)
|
||||
{
|
||||
asm(SET_PSTATE_UAO(1));
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ARM64_UAO */
|
||||
|
@ -421,35 +421,35 @@ void __init mem_init(void)
|
||||
|
||||
pr_notice("Virtual kernel memory layout:\n");
|
||||
#ifdef CONFIG_KASAN
|
||||
pr_cont(" kasan : 0x%16lx - 0x%16lx (%6ld GB)\n",
|
||||
pr_notice(" kasan : 0x%16lx - 0x%16lx (%6ld GB)\n",
|
||||
MLG(KASAN_SHADOW_START, KASAN_SHADOW_END));
|
||||
#endif
|
||||
pr_cont(" modules : 0x%16lx - 0x%16lx (%6ld MB)\n",
|
||||
pr_notice(" modules : 0x%16lx - 0x%16lx (%6ld MB)\n",
|
||||
MLM(MODULES_VADDR, MODULES_END));
|
||||
pr_cont(" vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n",
|
||||
pr_notice(" vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n",
|
||||
MLG(VMALLOC_START, VMALLOC_END));
|
||||
pr_cont(" .text : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
pr_notice(" .text : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
MLK_ROUNDUP(_text, _etext));
|
||||
pr_cont(" .rodata : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
pr_notice(" .rodata : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
MLK_ROUNDUP(__start_rodata, __init_begin));
|
||||
pr_cont(" .init : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
pr_notice(" .init : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
MLK_ROUNDUP(__init_begin, __init_end));
|
||||
pr_cont(" .data : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
pr_notice(" .data : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
MLK_ROUNDUP(_sdata, _edata));
|
||||
pr_cont(" .bss : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
pr_notice(" .bss : 0x%p" " - 0x%p" " (%6ld KB)\n",
|
||||
MLK_ROUNDUP(__bss_start, __bss_stop));
|
||||
pr_cont(" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n",
|
||||
pr_notice(" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n",
|
||||
MLK(FIXADDR_START, FIXADDR_TOP));
|
||||
pr_cont(" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n",
|
||||
pr_notice(" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n",
|
||||
MLM(PCI_IO_START, PCI_IO_END));
|
||||
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
||||
pr_cont(" vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n",
|
||||
pr_notice(" vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n",
|
||||
MLG(VMEMMAP_START, VMEMMAP_START + VMEMMAP_SIZE));
|
||||
pr_cont(" 0x%16lx - 0x%16lx (%6ld MB actual)\n",
|
||||
pr_notice(" 0x%16lx - 0x%16lx (%6ld MB actual)\n",
|
||||
MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()),
|
||||
(unsigned long)virt_to_page(high_memory)));
|
||||
#endif
|
||||
pr_cont(" memory : 0x%16lx - 0x%16lx (%6ld MB)\n",
|
||||
pr_notice(" memory : 0x%16lx - 0x%16lx (%6ld MB)\n",
|
||||
MLM(__phys_to_virt(memblock_start_of_DRAM()),
|
||||
(unsigned long)high_memory));
|
||||
|
||||
|
@ -271,7 +271,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
case BFIN_MEM_ACCESS_CORE:
|
||||
case BFIN_MEM_ACCESS_CORE_ONLY:
|
||||
copied = access_process_vm(child, addr, &tmp,
|
||||
to_copy, 0);
|
||||
to_copy, FOLL_FORCE);
|
||||
if (copied)
|
||||
break;
|
||||
|
||||
@ -324,7 +324,8 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
case BFIN_MEM_ACCESS_CORE:
|
||||
case BFIN_MEM_ACCESS_CORE_ONLY:
|
||||
copied = access_process_vm(child, addr, &data,
|
||||
to_copy, 1);
|
||||
to_copy,
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
break;
|
||||
case BFIN_MEM_ACCESS_DMA:
|
||||
if (safe_dma_memcpy(paddr, &data, to_copy))
|
||||
|
@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
|
||||
err = get_user_pages((unsigned long int)(oper.indata + prev_ix),
|
||||
noinpages,
|
||||
0, /* read access only for in data */
|
||||
0, /* no force */
|
||||
inpages,
|
||||
NULL);
|
||||
|
||||
@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
|
||||
if (oper.do_cipher){
|
||||
err = get_user_pages((unsigned long int)oper.cipher_outdata,
|
||||
nooutpages,
|
||||
1, /* write access for out data */
|
||||
0, /* no force */
|
||||
FOLL_WRITE, /* write access for out data */
|
||||
outpages,
|
||||
NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
|
@ -147,7 +147,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
/* The trampoline page is globally mapped, no page table to traverse.*/
|
||||
tmp = *(unsigned long*)addr;
|
||||
} else {
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE);
|
||||
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
@ -279,7 +279,7 @@ static int insn_size(struct task_struct *child, unsigned long pc)
|
||||
int opsize = 0;
|
||||
|
||||
/* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */
|
||||
copied = access_process_vm(child, pc, &opcode, sizeof(opcode), 0);
|
||||
copied = access_process_vm(child, pc, &opcode, sizeof(opcode), FOLL_FORCE);
|
||||
if (copied != sizeof(opcode))
|
||||
return 0;
|
||||
|
||||
|
@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
|
||||
u64 virt_addr=simple_strtoull(buf, NULL, 16);
|
||||
int ret;
|
||||
|
||||
ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL);
|
||||
ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL);
|
||||
if (ret<=0) {
|
||||
#ifdef ERR_INJ_DEBUG
|
||||
printk("Virtual address %lx is not existing.\n",virt_addr);
|
||||
|
@ -453,7 +453,7 @@ ia64_peek (struct task_struct *child, struct switch_stack *child_stack,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
copied = access_process_vm(child, addr, &ret, sizeof(ret), 0);
|
||||
copied = access_process_vm(child, addr, &ret, sizeof(ret), FOLL_FORCE);
|
||||
if (copied != sizeof(ret))
|
||||
return -EIO;
|
||||
*val = ret;
|
||||
@ -489,7 +489,8 @@ ia64_poke (struct task_struct *child, struct switch_stack *child_stack,
|
||||
*ia64_rse_skip_regs(krbs, regnum) = val;
|
||||
}
|
||||
}
|
||||
} else if (access_process_vm(child, addr, &val, sizeof(val), 1)
|
||||
} else if (access_process_vm(child, addr, &val, sizeof(val),
|
||||
FOLL_FORCE | FOLL_WRITE)
|
||||
!= sizeof(val))
|
||||
return -EIO;
|
||||
return 0;
|
||||
@ -543,7 +544,8 @@ ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw,
|
||||
ret = ia64_peek(child, sw, user_rbs_end, addr, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (access_process_vm(child, addr, &val, sizeof(val), 1)
|
||||
if (access_process_vm(child, addr, &val, sizeof(val),
|
||||
FOLL_FORCE | FOLL_WRITE)
|
||||
!= sizeof(val))
|
||||
return -EIO;
|
||||
}
|
||||
@ -559,7 +561,8 @@ ia64_sync_kernel_rbs (struct task_struct *child, struct switch_stack *sw,
|
||||
|
||||
/* now copy word for word from user rbs to kernel rbs: */
|
||||
for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) {
|
||||
if (access_process_vm(child, addr, &val, sizeof(val), 0)
|
||||
if (access_process_vm(child, addr, &val, sizeof(val),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(val))
|
||||
return -EIO;
|
||||
|
||||
@ -1156,7 +1159,8 @@ arch_ptrace (struct task_struct *child, long request,
|
||||
case PTRACE_PEEKTEXT:
|
||||
case PTRACE_PEEKDATA:
|
||||
/* read word at location addr */
|
||||
if (access_process_vm(child, addr, &data, sizeof(data), 0)
|
||||
if (access_process_vm(child, addr, &data, sizeof(data),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(data))
|
||||
return -EIO;
|
||||
/* ensure return value is not mistaken for error code */
|
||||
|
@ -493,7 +493,8 @@ unregister_all_debug_traps(struct task_struct *child)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < p->nr_trap; i++)
|
||||
access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1);
|
||||
access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]),
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
p->nr_trap = 0;
|
||||
}
|
||||
|
||||
@ -537,7 +538,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc)
|
||||
unsigned long next_insn, code;
|
||||
unsigned long addr = next_pc & ~3;
|
||||
|
||||
if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0)
|
||||
if (access_process_vm(child, addr, &next_insn, sizeof(next_insn),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(next_insn)) {
|
||||
return -1; /* error */
|
||||
}
|
||||
@ -546,7 +548,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc)
|
||||
if (register_debug_trap(child, next_pc, next_insn, &code)) {
|
||||
return -1; /* error */
|
||||
}
|
||||
if (access_process_vm(child, addr, &code, sizeof(code), 1)
|
||||
if (access_process_vm(child, addr, &code, sizeof(code),
|
||||
FOLL_FORCE | FOLL_WRITE)
|
||||
!= sizeof(code)) {
|
||||
return -1; /* error */
|
||||
}
|
||||
@ -562,7 +565,8 @@ withdraw_debug_trap(struct pt_regs *regs)
|
||||
addr = (regs->bpc - 2) & ~3;
|
||||
regs->bpc -= 2;
|
||||
if (unregister_debug_trap(current, addr, &code)) {
|
||||
access_process_vm(current, addr, &code, sizeof(code), 1);
|
||||
access_process_vm(current, addr, &code, sizeof(code),
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
invalidate_cache();
|
||||
}
|
||||
}
|
||||
@ -589,7 +593,8 @@ void user_enable_single_step(struct task_struct *child)
|
||||
/* Compute next pc. */
|
||||
pc = get_stack_long(child, PT_BPC);
|
||||
|
||||
if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
|
||||
if (access_process_vm(child, pc&~3, &insn, sizeof(insn),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(insn))
|
||||
return;
|
||||
|
||||
|
@ -70,7 +70,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
break;
|
||||
|
||||
copied = access_process_vm(child, (u64)addrOthers, &tmp,
|
||||
sizeof(tmp), 0);
|
||||
sizeof(tmp), FOLL_FORCE);
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp, (u32 __user *) (unsigned long) data);
|
||||
@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
break;
|
||||
ret = 0;
|
||||
if (access_process_vm(child, (u64)addrOthers, &data,
|
||||
sizeof(data), 1) == sizeof(data))
|
||||
sizeof(data),
|
||||
FOLL_FORCE | FOLL_WRITE) == sizeof(data))
|
||||
break;
|
||||
ret = -EIO;
|
||||
break;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/bootmem.h>
|
||||
|
@ -287,7 +287,7 @@ slow_irqon:
|
||||
pages += nr;
|
||||
|
||||
ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT,
|
||||
write, 0, pages);
|
||||
pages, write ? FOLL_WRITE : 0);
|
||||
|
||||
/* Have to be a bit careful with return values */
|
||||
if (nr > 0) {
|
||||
|
@ -32,9 +32,16 @@ static struct addr_range prep_kernel(void)
|
||||
void *addr = 0;
|
||||
struct elf_info ei;
|
||||
long len;
|
||||
int uncompressed_image = 0;
|
||||
|
||||
partial_decompress(vmlinuz_addr, vmlinuz_size,
|
||||
len = partial_decompress(vmlinuz_addr, vmlinuz_size,
|
||||
elfheader, sizeof(elfheader), 0);
|
||||
/* assume uncompressed data if -1 is returned */
|
||||
if (len == -1) {
|
||||
uncompressed_image = 1;
|
||||
memcpy(elfheader, vmlinuz_addr, sizeof(elfheader));
|
||||
printf("No valid compressed data found, assume uncompressed data\n\r");
|
||||
}
|
||||
|
||||
if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
|
||||
fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
|
||||
@ -67,6 +74,13 @@ static struct addr_range prep_kernel(void)
|
||||
"device tree\n\r");
|
||||
}
|
||||
|
||||
if (uncompressed_image) {
|
||||
memcpy(addr, vmlinuz_addr + ei.elfoffset, ei.loadsize);
|
||||
printf("0x%lx bytes of uncompressed data copied\n\r",
|
||||
ei.loadsize);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Finally, decompress the kernel */
|
||||
printf("Decompressing (0x%p <- 0x%p:0x%p)...\n\r", addr,
|
||||
vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
|
||||
@ -82,7 +96,7 @@ static struct addr_range prep_kernel(void)
|
||||
len, ei.loadsize);
|
||||
|
||||
printf("Done! Decompressed 0x%lx bytes\n\r", len);
|
||||
|
||||
out:
|
||||
flush_cache(addr, ei.loadsize);
|
||||
|
||||
return (struct addr_range){addr, ei.memsize};
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
#define __NR__exit __NR_exit
|
||||
|
||||
#define __IGNORE_pkey_mprotect
|
||||
#define __IGNORE_pkey_alloc
|
||||
#define __IGNORE_pkey_free
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
@ -74,7 +74,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
break;
|
||||
|
||||
copied = access_process_vm(child, (u64)addrOthers, &tmp,
|
||||
sizeof(tmp), 0);
|
||||
sizeof(tmp), FOLL_FORCE);
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp, (u32 __user *)data);
|
||||
@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
break;
|
||||
ret = 0;
|
||||
if (access_process_vm(child, (u64)addrOthers, &tmp,
|
||||
sizeof(tmp), 1) == sizeof(tmp))
|
||||
sizeof(tmp),
|
||||
FOLL_FORCE | FOLL_WRITE) == sizeof(tmp))
|
||||
break;
|
||||
ret = -EIO;
|
||||
break;
|
||||
|
@ -106,6 +106,8 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
|
||||
switch (REGION_ID(ea)) {
|
||||
case USER_REGION_ID:
|
||||
pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
|
||||
if (mm == NULL)
|
||||
return 1;
|
||||
psize = get_slice_psize(mm, ea);
|
||||
ssize = user_segment_size(ea);
|
||||
vsid = get_vsid(mm->context.id, ea, ssize);
|
||||
|
@ -845,7 +845,7 @@ void __init dump_numa_cpu_topology(void)
|
||||
return;
|
||||
|
||||
for_each_online_node(node) {
|
||||
printk(KERN_DEBUG "Node %d CPUs:", node);
|
||||
pr_info("Node %d CPUs:", node);
|
||||
|
||||
count = 0;
|
||||
/*
|
||||
@ -856,52 +856,18 @@ void __init dump_numa_cpu_topology(void)
|
||||
if (cpumask_test_cpu(cpu,
|
||||
node_to_cpumask_map[node])) {
|
||||
if (count == 0)
|
||||
printk(" %u", cpu);
|
||||
pr_cont(" %u", cpu);
|
||||
++count;
|
||||
} else {
|
||||
if (count > 1)
|
||||
printk("-%u", cpu - 1);
|
||||
pr_cont("-%u", cpu - 1);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
printk("-%u", nr_cpu_ids - 1);
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void __init dump_numa_memory_topology(void)
|
||||
{
|
||||
unsigned int node;
|
||||
unsigned int count;
|
||||
|
||||
if (min_common_depth == -1 || !numa_enabled)
|
||||
return;
|
||||
|
||||
for_each_online_node(node) {
|
||||
unsigned long i;
|
||||
|
||||
printk(KERN_DEBUG "Node %d Memory:", node);
|
||||
|
||||
count = 0;
|
||||
|
||||
for (i = 0; i < memblock_end_of_DRAM();
|
||||
i += (1 << SECTION_SIZE_BITS)) {
|
||||
if (early_pfn_to_nid(i >> PAGE_SHIFT) == node) {
|
||||
if (count == 0)
|
||||
printk(" 0x%lx", i);
|
||||
++count;
|
||||
} else {
|
||||
if (count > 0)
|
||||
printk("-0x%lx", i);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
printk("-0x%lx", i);
|
||||
printk("\n");
|
||||
pr_cont("-%u", nr_cpu_ids - 1);
|
||||
pr_cont("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,8 +913,6 @@ void __init initmem_init(void)
|
||||
|
||||
if (parse_numa_properties())
|
||||
setup_nonnuma();
|
||||
else
|
||||
dump_numa_memory_topology();
|
||||
|
||||
memblock_dump_all();
|
||||
|
||||
|
@ -119,8 +119,13 @@ static int handle_validity(struct kvm_vcpu *vcpu)
|
||||
|
||||
vcpu->stat.exit_validity++;
|
||||
trace_kvm_s390_intercept_validity(vcpu, viwhy);
|
||||
WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy);
|
||||
return -EOPNOTSUPP;
|
||||
KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy,
|
||||
current->pid, vcpu->kvm);
|
||||
|
||||
/* do not warn on invalid runtime instrumentation mode */
|
||||
WARN_ONCE(viwhy != 0x44, "kvm: unhandled validity intercept 0x%x\n",
|
||||
viwhy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int handle_instruction(struct kvm_vcpu *vcpu)
|
||||
|
@ -266,7 +266,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
|
||||
/* Try to get the remaining pages with get_user_pages */
|
||||
start += nr << PAGE_SHIFT;
|
||||
pages += nr;
|
||||
ret = get_user_pages_unlocked(start, nr_pages - nr, write, 0, pages);
|
||||
ret = get_user_pages_unlocked(start, nr_pages - nr, pages,
|
||||
write ? FOLL_WRITE : 0);
|
||||
/* Have to be a bit careful with return values */
|
||||
if (nr > 0)
|
||||
ret = (ret < 0) ? nr : ret + nr;
|
||||
|
@ -131,7 +131,7 @@ read_tsk_long(struct task_struct *child,
|
||||
{
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, res, sizeof(*res), 0);
|
||||
copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE);
|
||||
|
||||
return copied != sizeof(*res) ? -EIO : 0;
|
||||
}
|
||||
@ -142,7 +142,7 @@ read_tsk_short(struct task_struct *child,
|
||||
{
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, res, sizeof(*res), 0);
|
||||
copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE);
|
||||
|
||||
return copied != sizeof(*res) ? -EIO : 0;
|
||||
}
|
||||
@ -153,7 +153,8 @@ write_tsk_short(struct task_struct *child,
|
||||
{
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, &val, sizeof(val), 1);
|
||||
copied = access_process_vm(child, addr, &val, sizeof(val),
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
|
||||
return copied != sizeof(val) ? -EIO : 0;
|
||||
}
|
||||
@ -164,7 +165,8 @@ write_tsk_long(struct task_struct *child,
|
||||
{
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, &val, sizeof(val), 1);
|
||||
copied = access_process_vm(child, addr, &val, sizeof(val),
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
|
||||
return copied != sizeof(val) ? -EIO : 0;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ isa-y := $(isa-y)-up
|
||||
endif
|
||||
|
||||
cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,)
|
||||
cflags-$(CONFIG_CPU_J2) := $(call cc-option,-mj2,)
|
||||
cflags-$(CONFIG_CPU_J2) += $(call cc-option,-mj2,)
|
||||
cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \
|
||||
$(call cc-option,-m2a-nofpu,) \
|
||||
$(call cc-option,-m4-nofpu,)
|
||||
|
@ -22,6 +22,16 @@ config SH_DEVICE_TREE
|
||||
have sufficient driver coverage to use this option; do not
|
||||
select it if you are using original SuperH hardware.
|
||||
|
||||
config SH_JCORE_SOC
|
||||
bool "J-Core SoC"
|
||||
depends on SH_DEVICE_TREE && (CPU_SH2 || CPU_J2)
|
||||
select CLKSRC_JCORE_PIT
|
||||
select JCORE_AIC
|
||||
default y if CPU_J2
|
||||
help
|
||||
Select this option to include drivers core components of the
|
||||
J-Core SoC, including interrupt controllers and timers.
|
||||
|
||||
config SH_SOLUTION_ENGINE
|
||||
bool "SolutionEngine"
|
||||
select SOLUTION_ENGINE
|
||||
|
@ -8,6 +8,7 @@ CONFIG_MEMORY_START=0x10000000
|
||||
CONFIG_MEMORY_SIZE=0x04000000
|
||||
CONFIG_CPU_BIG_ENDIAN=y
|
||||
CONFIG_SH_DEVICE_TREE=y
|
||||
CONFIG_SH_JCORE_SOC=y
|
||||
CONFIG_HZ_100=y
|
||||
CONFIG_CMDLINE_OVERWRITE=y
|
||||
CONFIG_CMDLINE="console=ttyUL0 earlycon"
|
||||
@ -20,6 +21,7 @@ CONFIG_INET=y
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_SERIAL_EARLYCON=y
|
||||
CONFIG_SERIAL_UARTLITE=y
|
||||
CONFIG_SERIAL_UARTLITE_CONSOLE=y
|
||||
CONFIG_I2C=y
|
||||
|
@ -258,7 +258,8 @@ slow_irqon:
|
||||
pages += nr;
|
||||
|
||||
ret = get_user_pages_unlocked(start,
|
||||
(end - start) >> PAGE_SHIFT, write, 0, pages);
|
||||
(end - start) >> PAGE_SHIFT, pages,
|
||||
write ? FOLL_WRITE : 0);
|
||||
|
||||
/* Have to be a bit careful with return values */
|
||||
if (nr > 0) {
|
||||
|
@ -127,7 +127,8 @@ static int get_from_target(struct task_struct *target, unsigned long uaddr,
|
||||
if (copy_from_user(kbuf, (void __user *) uaddr, len))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
int len2 = access_process_vm(target, uaddr, kbuf, len, 0);
|
||||
int len2 = access_process_vm(target, uaddr, kbuf, len,
|
||||
FOLL_FORCE);
|
||||
if (len2 != len)
|
||||
return -EFAULT;
|
||||
}
|
||||
@ -141,7 +142,8 @@ static int set_to_target(struct task_struct *target, unsigned long uaddr,
|
||||
if (copy_to_user((void __user *) uaddr, kbuf, len))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
int len2 = access_process_vm(target, uaddr, kbuf, len, 1);
|
||||
int len2 = access_process_vm(target, uaddr, kbuf, len,
|
||||
FOLL_FORCE | FOLL_WRITE);
|
||||
if (len2 != len)
|
||||
return -EFAULT;
|
||||
}
|
||||
@ -505,7 +507,8 @@ static int genregs32_get(struct task_struct *target,
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_window[pos],
|
||||
k, sizeof(*k), 0)
|
||||
k, sizeof(*k),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(*k))
|
||||
return -EFAULT;
|
||||
k++;
|
||||
@ -531,12 +534,14 @@ static int genregs32_get(struct task_struct *target,
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_window[pos],
|
||||
®, sizeof(reg), 0)
|
||||
®, sizeof(reg),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(reg))
|
||||
return -EFAULT;
|
||||
if (access_process_vm(target,
|
||||
(unsigned long) u,
|
||||
®, sizeof(reg), 1)
|
||||
®, sizeof(reg),
|
||||
FOLL_FORCE | FOLL_WRITE)
|
||||
!= sizeof(reg))
|
||||
return -EFAULT;
|
||||
pos++;
|
||||
@ -615,7 +620,8 @@ static int genregs32_set(struct task_struct *target,
|
||||
(unsigned long)
|
||||
®_window[pos],
|
||||
(void *) k,
|
||||
sizeof(*k), 1)
|
||||
sizeof(*k),
|
||||
FOLL_FORCE | FOLL_WRITE)
|
||||
!= sizeof(*k))
|
||||
return -EFAULT;
|
||||
k++;
|
||||
@ -642,13 +648,15 @@ static int genregs32_set(struct task_struct *target,
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
u,
|
||||
®, sizeof(reg), 0)
|
||||
®, sizeof(reg),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(reg))
|
||||
return -EFAULT;
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_window[pos],
|
||||
®, sizeof(reg), 1)
|
||||
®, sizeof(reg),
|
||||
FOLL_FORCE | FOLL_WRITE)
|
||||
!= sizeof(reg))
|
||||
return -EFAULT;
|
||||
pos++;
|
||||
|
@ -238,7 +238,8 @@ slow:
|
||||
pages += nr;
|
||||
|
||||
ret = get_user_pages_unlocked(start,
|
||||
(end - start) >> PAGE_SHIFT, write, 0, pages);
|
||||
(end - start) >> PAGE_SHIFT, pages,
|
||||
write ? FOLL_WRITE : 0);
|
||||
|
||||
/* Have to be a bit careful with return values */
|
||||
if (nr > 0) {
|
||||
|
@ -389,5 +389,3 @@
|
||||
380 i386 pkey_mprotect sys_pkey_mprotect
|
||||
381 i386 pkey_alloc sys_pkey_alloc
|
||||
382 i386 pkey_free sys_pkey_free
|
||||
#383 i386 pkey_get sys_pkey_get
|
||||
#384 i386 pkey_set sys_pkey_set
|
||||
|
@ -338,8 +338,6 @@
|
||||
329 common pkey_mprotect sys_pkey_mprotect
|
||||
330 common pkey_alloc sys_pkey_alloc
|
||||
331 common pkey_free sys_pkey_free
|
||||
#332 common pkey_get sys_pkey_get
|
||||
#333 common pkey_set sys_pkey_set
|
||||
|
||||
#
|
||||
# x32-specific system call numbers start at 512 to avoid cache impact
|
||||
|
@ -3898,6 +3898,7 @@ __init int intel_pmu_init(void)
|
||||
break;
|
||||
|
||||
case INTEL_FAM6_XEON_PHI_KNL:
|
||||
case INTEL_FAM6_XEON_PHI_KNM:
|
||||
memcpy(hw_cache_event_ids,
|
||||
slm_hw_cache_event_ids, sizeof(hw_cache_event_ids));
|
||||
memcpy(hw_cache_extra_regs,
|
||||
@ -3912,7 +3913,7 @@ __init int intel_pmu_init(void)
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
||||
|
||||
pr_cont("Knights Landing events, ");
|
||||
pr_cont("Knights Landing/Mill events, ");
|
||||
break;
|
||||
|
||||
case INTEL_FAM6_SKYLAKE_MOBILE:
|
||||
|
@ -458,8 +458,8 @@ void intel_pmu_lbr_del(struct perf_event *event)
|
||||
if (!x86_pmu.lbr_nr)
|
||||
return;
|
||||
|
||||
if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
|
||||
event->ctx->task_ctx_data) {
|
||||
if (branch_user_callstack(cpuc->br_sel) &&
|
||||
event->ctx->task_ctx_data) {
|
||||
task_ctx = event->ctx->task_ctx_data;
|
||||
task_ctx->lbr_callstack_users--;
|
||||
}
|
||||
|
@ -763,6 +763,7 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = {
|
||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsw_rapl_init),
|
||||
|
||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init),
|
||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_rapl_init),
|
||||
|
||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_rapl_init),
|
||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init),
|
||||
|
@ -1349,6 +1349,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, bdx_uncore_init),
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, bdx_uncore_init),
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_uncore_init),
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_uncore_init),
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init),
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_uncore_init),
|
||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, skx_uncore_init),
|
||||
|
@ -194,6 +194,8 @@
|
||||
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
|
||||
|
||||
#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */
|
||||
#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
|
||||
#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
|
||||
|
||||
/* Virtualization flags: Linux defined, word 8 */
|
||||
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */
|
||||
|
@ -64,5 +64,6 @@
|
||||
/* Xeon Phi */
|
||||
|
||||
#define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */
|
||||
#define INTEL_FAM6_XEON_PHI_KNM 0x85 /* Knights Mill */
|
||||
|
||||
#endif /* _ASM_X86_INTEL_FAMILY_H */
|
||||
|
@ -88,7 +88,6 @@
|
||||
|
||||
#define MSR_IA32_RTIT_CTL 0x00000570
|
||||
#define MSR_IA32_RTIT_STATUS 0x00000571
|
||||
#define MSR_IA32_RTIT_STATUS 0x00000571
|
||||
#define MSR_IA32_RTIT_ADDR0_A 0x00000580
|
||||
#define MSR_IA32_RTIT_ADDR0_B 0x00000581
|
||||
#define MSR_IA32_RTIT_ADDR1_A 0x00000582
|
||||
|
@ -103,8 +103,10 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
|
||||
({ \
|
||||
long tmp; \
|
||||
struct rw_semaphore* ret; \
|
||||
register void *__sp asm(_ASM_SP); \
|
||||
\
|
||||
asm volatile("# beginning down_write\n\t" \
|
||||
LOCK_PREFIX " xadd %1,(%3)\n\t" \
|
||||
LOCK_PREFIX " xadd %1,(%4)\n\t" \
|
||||
/* adds 0xffff0001, returns the old value */ \
|
||||
" test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
|
||||
/* was the active mask 0 before? */\
|
||||
@ -112,7 +114,7 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
|
||||
" call " slow_path "\n" \
|
||||
"1:\n" \
|
||||
"# ending down_write" \
|
||||
: "+m" (sem->count), "=d" (tmp), "=a" (ret) \
|
||||
: "+m" (sem->count), "=d" (tmp), "=a" (ret), "+r" (__sp) \
|
||||
: "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
|
||||
: "memory", "cc"); \
|
||||
ret; \
|
||||
|
@ -52,6 +52,15 @@ struct task_struct;
|
||||
#include <asm/cpufeature.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
struct thread_info {
|
||||
unsigned long flags; /* low level flags */
|
||||
};
|
||||
|
||||
#define INIT_THREAD_INFO(tsk) \
|
||||
{ \
|
||||
.flags = 0, \
|
||||
}
|
||||
|
||||
#define init_stack (init_thread_union.stack)
|
||||
|
||||
#else /* !__ASSEMBLY__ */
|
||||
|
@ -32,6 +32,8 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
|
||||
|
||||
static const struct cpuid_bit cpuid_bits[] = {
|
||||
{ X86_FEATURE_INTEL_PT, CR_EBX,25, 0x00000007, 0 },
|
||||
{ X86_FEATURE_AVX512_4VNNIW, CR_EDX, 2, 0x00000007, 0 },
|
||||
{ X86_FEATURE_AVX512_4FMAPS, CR_EDX, 3, 0x00000007, 0 },
|
||||
{ X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
|
||||
{ X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
|
||||
{ X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 },
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <asm/div64.h>
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/apic.h>
|
||||
|
||||
#define CPUID_VMWARE_INFO_LEAF 0x40000000
|
||||
@ -94,6 +95,10 @@ static void __init vmware_platform_setup(void)
|
||||
} else {
|
||||
pr_warn("Failed to get TSC freq from the hypervisor\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
no_timer_check = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -350,7 +350,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
|
||||
* continue building up new bios map based on this
|
||||
* information
|
||||
*/
|
||||
if (current_type != last_type) {
|
||||
if (current_type != last_type || current_type == E820_PRAM) {
|
||||
if (last_type != 0) {
|
||||
new_bios[new_bios_entry].size =
|
||||
change_point[chgidx]->addr - last_addr;
|
||||
|
@ -74,6 +74,8 @@ void fpu__xstate_clear_all_cpu_caps(void)
|
||||
setup_clear_cpu_cap(X86_FEATURE_MPX);
|
||||
setup_clear_cpu_cap(X86_FEATURE_XGETBV1);
|
||||
setup_clear_cpu_cap(X86_FEATURE_PKU);
|
||||
setup_clear_cpu_cap(X86_FEATURE_AVX512_4VNNIW);
|
||||
setup_clear_cpu_cap(X86_FEATURE_AVX512_4FMAPS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/frame.h>
|
||||
#include <linux/kasan.h>
|
||||
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@ -1057,9 +1058,10 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
* tailcall optimization. So, to be absolutely safe
|
||||
* we also save and restore enough stack bytes to cover
|
||||
* the argument area.
|
||||
* Use __memcpy() to avoid KASAN stack out-of-bounds reports as we copy
|
||||
* raw stack chunk with redzones:
|
||||
*/
|
||||
memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
|
||||
MIN_STACK_SIZE(addr));
|
||||
__memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, MIN_STACK_SIZE(addr));
|
||||
regs->flags &= ~X86_EFLAGS_IF;
|
||||
trace_hardirqs_off();
|
||||
regs->ip = (unsigned long)(jp->entry);
|
||||
@ -1080,6 +1082,9 @@ void jprobe_return(void)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
/* Unpoison stack redzones in the frames we are going to jump over. */
|
||||
kasan_unpoison_stack_above_sp_to(kcb->jprobe_saved_sp);
|
||||
|
||||
asm volatile (
|
||||
#ifdef CONFIG_X86_64
|
||||
" xchg %%rbx,%%rsp \n"
|
||||
@ -1118,7 +1123,7 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||
/* It's OK to start function graph tracing again */
|
||||
unpause_graph_tracing();
|
||||
*regs = kcb->jprobe_saved_regs;
|
||||
memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp));
|
||||
__memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp));
|
||||
preempt_enable_no_resched();
|
||||
return 1;
|
||||
}
|
||||
|
@ -105,9 +105,6 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
|
||||
/* Don't let flags to be set from userspace */
|
||||
act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
|
||||
|
||||
if (user_64bit_mode(current_pt_regs()))
|
||||
return;
|
||||
|
||||
if (in_ia32_syscall())
|
||||
act->sa.sa_flags |= SA_IA32_ABI;
|
||||
if (in_x32_syscall())
|
||||
|
@ -261,8 +261,10 @@ static inline void __smp_reschedule_interrupt(void)
|
||||
|
||||
__visible void smp_reschedule_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
irq_enter();
|
||||
ack_APIC_irq();
|
||||
__smp_reschedule_interrupt();
|
||||
irq_exit();
|
||||
/*
|
||||
* KVM uses this interrupt to force a cpu out of guest mode
|
||||
*/
|
||||
|
@ -1409,15 +1409,17 @@ __init void prefill_possible_map(void)
|
||||
|
||||
/* No boot processor was found in mptable or ACPI MADT */
|
||||
if (!num_processors) {
|
||||
int apicid = boot_cpu_physical_apicid;
|
||||
int cpu = hard_smp_processor_id();
|
||||
if (boot_cpu_has(X86_FEATURE_APIC)) {
|
||||
int apicid = boot_cpu_physical_apicid;
|
||||
int cpu = hard_smp_processor_id();
|
||||
|
||||
pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu);
|
||||
pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu);
|
||||
|
||||
/* Make sure boot cpu is enumerated */
|
||||
if (apic->cpu_present_to_apicid(0) == BAD_APICID &&
|
||||
apic->apic_id_valid(apicid))
|
||||
generic_processor_info(apicid, boot_cpu_apic_version);
|
||||
/* Make sure boot cpu is enumerated */
|
||||
if (apic->cpu_present_to_apicid(0) == BAD_APICID &&
|
||||
apic->apic_id_valid(apicid))
|
||||
generic_processor_info(apicid, boot_cpu_apic_version);
|
||||
}
|
||||
|
||||
if (!num_processors)
|
||||
num_processors = 1;
|
||||
|
@ -57,7 +57,8 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
|
||||
unsigned char opcode[15];
|
||||
unsigned long addr = convert_ip_to_linear(child, regs);
|
||||
|
||||
copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
|
||||
copied = access_process_vm(child, addr, opcode, sizeof(opcode),
|
||||
FOLL_FORCE);
|
||||
for (i = 0; i < copied; i++) {
|
||||
switch (opcode[i]) {
|
||||
/* popf and iret */
|
||||
|
@ -594,7 +594,7 @@ static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
|
||||
ioapic->irr = 0;
|
||||
ioapic->irr_delivered = 0;
|
||||
ioapic->id = 0;
|
||||
memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS);
|
||||
memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi));
|
||||
rtc_irq_eoi_tracking_reset(ioapic);
|
||||
}
|
||||
|
||||
|
@ -5733,13 +5733,13 @@ static int kvmclock_cpu_online(unsigned int cpu)
|
||||
|
||||
static void kvm_timer_init(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
max_tsc_khz = tsc_khz;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
struct cpufreq_policy policy;
|
||||
int cpu;
|
||||
|
||||
memset(&policy, 0, sizeof(policy));
|
||||
cpu = get_cpu();
|
||||
cpufreq_get_policy(&policy, cpu);
|
||||
|
@ -435,7 +435,7 @@ slow_irqon:
|
||||
|
||||
ret = get_user_pages_unlocked(start,
|
||||
(end - start) >> PAGE_SHIFT,
|
||||
write, 0, pages);
|
||||
pages, write ? FOLL_WRITE : 0);
|
||||
|
||||
/* Have to be a bit careful with return values */
|
||||
if (nr > 0) {
|
||||
|
@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int write)
|
||||
{
|
||||
long gup_ret;
|
||||
int nr_pages = 1;
|
||||
int force = 0;
|
||||
|
||||
gup_ret = get_user_pages((unsigned long)addr, nr_pages, write,
|
||||
force, NULL, NULL);
|
||||
gup_ret = get_user_pages((unsigned long)addr, nr_pages,
|
||||
write ? FOLL_WRITE : 0, NULL, NULL);
|
||||
/*
|
||||
* get_user_pages() returns number of pages gotten.
|
||||
* 0 means we failed to fault in and get anything,
|
||||
|
@ -40,7 +40,15 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
|
||||
*/
|
||||
return BIOS_STATUS_UNIMPLEMENTED;
|
||||
|
||||
ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
|
||||
/*
|
||||
* If EFI_OLD_MEMMAP is set, we need to fall back to using our old EFI
|
||||
* callback method, which uses efi_call() directly, with the kernel page tables:
|
||||
*/
|
||||
if (unlikely(test_bit(EFI_OLD_MEMMAP, &efi.flags)))
|
||||
ret = efi_call((void *)__va(tab->function), (u64)which, a1, a2, a3, a4, a5);
|
||||
else
|
||||
ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uv_bios_call);
|
||||
|
@ -36,7 +36,8 @@ int is_syscall(unsigned long addr)
|
||||
* slow, but that doesn't matter, since it will be called only
|
||||
* in case of singlestepping, if copy_from_user failed.
|
||||
*/
|
||||
n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
|
||||
n = access_process_vm(current, addr, &instr, sizeof(instr),
|
||||
FOLL_FORCE);
|
||||
if (n != sizeof(instr)) {
|
||||
printk(KERN_ERR "is_syscall : failed to read "
|
||||
"instruction from 0x%lx\n", addr);
|
||||
|
@ -212,7 +212,8 @@ int is_syscall(unsigned long addr)
|
||||
* slow, but that doesn't matter, since it will be called only
|
||||
* in case of singlestepping, if copy_from_user failed.
|
||||
*/
|
||||
n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
|
||||
n = access_process_vm(current, addr, &instr, sizeof(instr),
|
||||
FOLL_FORCE);
|
||||
if (n != sizeof(instr)) {
|
||||
printk("is_syscall : failed to read instruction from "
|
||||
"0x%lx\n", addr);
|
||||
|
@ -354,7 +354,8 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
|
||||
* current range. Earlier ranges could also overlap,
|
||||
* but only this one can overlap the end of the range.
|
||||
*/
|
||||
if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) {
|
||||
if ((BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) &&
|
||||
(BB_OFFSET(p[lo]) < target)) {
|
||||
/* Partial overlap, leave the tail of this range */
|
||||
int ack = BB_ACK(p[lo]);
|
||||
sector_t a = BB_OFFSET(p[lo]);
|
||||
@ -377,7 +378,8 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
|
||||
lo--;
|
||||
}
|
||||
while (lo >= 0 &&
|
||||
BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
|
||||
(BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) &&
|
||||
(BB_OFFSET(p[lo]) < target)) {
|
||||
/* This range does overlap */
|
||||
if (BB_OFFSET(p[lo]) < s) {
|
||||
/* Keep the early parts of this range. */
|
||||
|
@ -21,7 +21,7 @@ obj-y += video/
|
||||
obj-y += idle/
|
||||
|
||||
# IPMI must come before ACPI in order to provide IPMI opregion support
|
||||
obj-$(CONFIG_IPMI_HANDLER) += char/ipmi/
|
||||
obj-y += char/ipmi/
|
||||
|
||||
obj-$(CONFIG_ACPI) += acpi/
|
||||
obj-$(CONFIG_SFI) += sfi/
|
||||
|
@ -415,15 +415,15 @@ struct rbd_device {
|
||||
};
|
||||
|
||||
/*
|
||||
* Flag bits for rbd_dev->flags. If atomicity is required,
|
||||
* rbd_dev->lock is used to protect access.
|
||||
*
|
||||
* Currently, only the "removing" flag (which is coupled with the
|
||||
* "open_count" field) requires atomic access.
|
||||
* Flag bits for rbd_dev->flags:
|
||||
* - REMOVING (which is coupled with rbd_dev->open_count) is protected
|
||||
* by rbd_dev->lock
|
||||
* - BLACKLISTED is protected by rbd_dev->lock_rwsem
|
||||
*/
|
||||
enum rbd_dev_flags {
|
||||
RBD_DEV_FLAG_EXISTS, /* mapped snapshot has not been deleted */
|
||||
RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */
|
||||
RBD_DEV_FLAG_BLACKLISTED, /* our ceph_client is blacklisted */
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(client_mutex); /* Serialize client creation */
|
||||
@ -3926,6 +3926,7 @@ static void rbd_reregister_watch(struct work_struct *work)
|
||||
struct rbd_device *rbd_dev = container_of(to_delayed_work(work),
|
||||
struct rbd_device, watch_dwork);
|
||||
bool was_lock_owner = false;
|
||||
bool need_to_wake = false;
|
||||
int ret;
|
||||
|
||||
dout("%s rbd_dev %p\n", __func__, rbd_dev);
|
||||
@ -3935,19 +3936,27 @@ static void rbd_reregister_watch(struct work_struct *work)
|
||||
was_lock_owner = rbd_release_lock(rbd_dev);
|
||||
|
||||
mutex_lock(&rbd_dev->watch_mutex);
|
||||
if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR)
|
||||
goto fail_unlock;
|
||||
if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) {
|
||||
mutex_unlock(&rbd_dev->watch_mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = __rbd_register_watch(rbd_dev);
|
||||
if (ret) {
|
||||
rbd_warn(rbd_dev, "failed to reregister watch: %d", ret);
|
||||
if (ret != -EBLACKLISTED)
|
||||
if (ret == -EBLACKLISTED || ret == -ENOENT) {
|
||||
set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags);
|
||||
need_to_wake = true;
|
||||
} else {
|
||||
queue_delayed_work(rbd_dev->task_wq,
|
||||
&rbd_dev->watch_dwork,
|
||||
RBD_RETRY_DELAY);
|
||||
goto fail_unlock;
|
||||
}
|
||||
mutex_unlock(&rbd_dev->watch_mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
need_to_wake = true;
|
||||
rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED;
|
||||
rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id;
|
||||
mutex_unlock(&rbd_dev->watch_mutex);
|
||||
@ -3963,13 +3972,10 @@ static void rbd_reregister_watch(struct work_struct *work)
|
||||
ret);
|
||||
}
|
||||
|
||||
out:
|
||||
up_write(&rbd_dev->lock_rwsem);
|
||||
wake_requests(rbd_dev, true);
|
||||
return;
|
||||
|
||||
fail_unlock:
|
||||
mutex_unlock(&rbd_dev->watch_mutex);
|
||||
up_write(&rbd_dev->lock_rwsem);
|
||||
if (need_to_wake)
|
||||
wake_requests(rbd_dev, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4074,7 +4080,9 @@ static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
|
||||
up_read(&rbd_dev->lock_rwsem);
|
||||
schedule();
|
||||
down_read(&rbd_dev->lock_rwsem);
|
||||
} while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
|
||||
} while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED &&
|
||||
!test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags));
|
||||
|
||||
finish_wait(&rbd_dev->lock_waitq, &wait);
|
||||
}
|
||||
|
||||
@ -4166,8 +4174,16 @@ static void rbd_queue_workfn(struct work_struct *work)
|
||||
|
||||
if (must_be_locked) {
|
||||
down_read(&rbd_dev->lock_rwsem);
|
||||
if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED)
|
||||
if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED &&
|
||||
!test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags))
|
||||
rbd_wait_state_locked(rbd_dev);
|
||||
|
||||
WARN_ON((rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) ^
|
||||
!test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags));
|
||||
if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
|
||||
result = -EBLACKLISTED;
|
||||
goto err_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
img_request = rbd_img_request_create(rbd_dev, offset, length, op_type,
|
||||
|
@ -76,3 +76,11 @@ config IPMI_POWEROFF
|
||||
the IPMI management controller is capable of this.
|
||||
|
||||
endif # IPMI_HANDLER
|
||||
|
||||
config ASPEED_BT_IPMI_BMC
|
||||
depends on ARCH_ASPEED
|
||||
tristate "BT IPMI bmc driver"
|
||||
help
|
||||
Provides a driver for the BT (Block Transfer) IPMI interface
|
||||
found on Aspeed SOCs (AST2400 and AST2500). The driver
|
||||
implements the BMC side of the BT interface.
|
||||
|
@ -11,3 +11,4 @@ obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
|
||||
obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
|
||||
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
|
||||
obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
|
||||
obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
|
||||
|
505
drivers/char/ipmi/bt-bmc.c
Normal file
505
drivers/char/ipmi/bt-bmc.c
Normal file
@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016, IBM Corporation.
|
||||
*
|
||||
* 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/atomic.h>
|
||||
#include <linux/bt-bmc.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
/*
|
||||
* This is a BMC device used to communicate to the host
|
||||
*/
|
||||
#define DEVICE_NAME "ipmi-bt-host"
|
||||
|
||||
#define BT_IO_BASE 0xe4
|
||||
#define BT_IRQ 10
|
||||
|
||||
#define BT_CR0 0x0
|
||||
#define BT_CR0_IO_BASE 16
|
||||
#define BT_CR0_IRQ 12
|
||||
#define BT_CR0_EN_CLR_SLV_RDP 0x8
|
||||
#define BT_CR0_EN_CLR_SLV_WRP 0x4
|
||||
#define BT_CR0_ENABLE_IBT 0x1
|
||||
#define BT_CR1 0x4
|
||||
#define BT_CR1_IRQ_H2B 0x01
|
||||
#define BT_CR1_IRQ_HBUSY 0x40
|
||||
#define BT_CR2 0x8
|
||||
#define BT_CR2_IRQ_H2B 0x01
|
||||
#define BT_CR2_IRQ_HBUSY 0x40
|
||||
#define BT_CR3 0xc
|
||||
#define BT_CTRL 0x10
|
||||
#define BT_CTRL_B_BUSY 0x80
|
||||
#define BT_CTRL_H_BUSY 0x40
|
||||
#define BT_CTRL_OEM0 0x20
|
||||
#define BT_CTRL_SMS_ATN 0x10
|
||||
#define BT_CTRL_B2H_ATN 0x08
|
||||
#define BT_CTRL_H2B_ATN 0x04
|
||||
#define BT_CTRL_CLR_RD_PTR 0x02
|
||||
#define BT_CTRL_CLR_WR_PTR 0x01
|
||||
#define BT_BMC2HOST 0x14
|
||||
#define BT_INTMASK 0x18
|
||||
#define BT_INTMASK_B2H_IRQEN 0x01
|
||||
#define BT_INTMASK_B2H_IRQ 0x02
|
||||
#define BT_INTMASK_BMC_HWRST 0x80
|
||||
|
||||
#define BT_BMC_BUFFER_SIZE 256
|
||||
|
||||
struct bt_bmc {
|
||||
struct device dev;
|
||||
struct miscdevice miscdev;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
wait_queue_head_t queue;
|
||||
struct timer_list poll_timer;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static atomic_t open_count = ATOMIC_INIT(0);
|
||||
|
||||
static u8 bt_inb(struct bt_bmc *bt_bmc, int reg)
|
||||
{
|
||||
return ioread8(bt_bmc->base + reg);
|
||||
}
|
||||
|
||||
static void bt_outb(struct bt_bmc *bt_bmc, u8 data, int reg)
|
||||
{
|
||||
iowrite8(data, bt_bmc->base + reg);
|
||||
}
|
||||
|
||||
static void clr_rd_ptr(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
bt_outb(bt_bmc, BT_CTRL_CLR_RD_PTR, BT_CTRL);
|
||||
}
|
||||
|
||||
static void clr_wr_ptr(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
bt_outb(bt_bmc, BT_CTRL_CLR_WR_PTR, BT_CTRL);
|
||||
}
|
||||
|
||||
static void clr_h2b_atn(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
bt_outb(bt_bmc, BT_CTRL_H2B_ATN, BT_CTRL);
|
||||
}
|
||||
|
||||
static void set_b_busy(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
if (!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_B_BUSY))
|
||||
bt_outb(bt_bmc, BT_CTRL_B_BUSY, BT_CTRL);
|
||||
}
|
||||
|
||||
static void clr_b_busy(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
if (bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_B_BUSY)
|
||||
bt_outb(bt_bmc, BT_CTRL_B_BUSY, BT_CTRL);
|
||||
}
|
||||
|
||||
static void set_b2h_atn(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
bt_outb(bt_bmc, BT_CTRL_B2H_ATN, BT_CTRL);
|
||||
}
|
||||
|
||||
static u8 bt_read(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
return bt_inb(bt_bmc, BT_BMC2HOST);
|
||||
}
|
||||
|
||||
static ssize_t bt_readn(struct bt_bmc *bt_bmc, u8 *buf, size_t n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
buf[i] = bt_read(bt_bmc);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void bt_write(struct bt_bmc *bt_bmc, u8 c)
|
||||
{
|
||||
bt_outb(bt_bmc, c, BT_BMC2HOST);
|
||||
}
|
||||
|
||||
static ssize_t bt_writen(struct bt_bmc *bt_bmc, u8 *buf, size_t n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
bt_write(bt_bmc, buf[i]);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void set_sms_atn(struct bt_bmc *bt_bmc)
|
||||
{
|
||||
bt_outb(bt_bmc, BT_CTRL_SMS_ATN, BT_CTRL);
|
||||
}
|
||||
|
||||
static struct bt_bmc *file_bt_bmc(struct file *file)
|
||||
{
|
||||
return container_of(file->private_data, struct bt_bmc, miscdev);
|
||||
}
|
||||
|
||||
static int bt_bmc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = file_bt_bmc(file);
|
||||
|
||||
if (atomic_inc_return(&open_count) == 1) {
|
||||
clr_b_busy(bt_bmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
atomic_dec(&open_count);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* The BT (Block Transfer) interface means that entire messages are
|
||||
* buffered by the host before a notification is sent to the BMC that
|
||||
* there is data to be read. The first byte is the length and the
|
||||
* message data follows. The read operation just tries to capture the
|
||||
* whole before returning it to userspace.
|
||||
*
|
||||
* BT Message format :
|
||||
*
|
||||
* Byte 1 Byte 2 Byte 3 Byte 4 Byte 5:N
|
||||
* Length NetFn/LUN Seq Cmd Data
|
||||
*
|
||||
*/
|
||||
static ssize_t bt_bmc_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = file_bt_bmc(file);
|
||||
u8 len;
|
||||
int len_byte = 1;
|
||||
u8 kbuffer[BT_BMC_BUFFER_SIZE];
|
||||
ssize_t ret = 0;
|
||||
ssize_t nread;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
WARN_ON(*ppos);
|
||||
|
||||
if (wait_event_interruptible(bt_bmc->queue,
|
||||
bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
mutex_lock(&bt_bmc->mutex);
|
||||
|
||||
if (unlikely(!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))) {
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
set_b_busy(bt_bmc);
|
||||
clr_h2b_atn(bt_bmc);
|
||||
clr_rd_ptr(bt_bmc);
|
||||
|
||||
/*
|
||||
* The BT frames start with the message length, which does not
|
||||
* include the length byte.
|
||||
*/
|
||||
kbuffer[0] = bt_read(bt_bmc);
|
||||
len = kbuffer[0];
|
||||
|
||||
/* We pass the length back to userspace as well */
|
||||
if (len + 1 > count)
|
||||
len = count - 1;
|
||||
|
||||
while (len) {
|
||||
nread = min_t(ssize_t, len, sizeof(kbuffer) - len_byte);
|
||||
|
||||
bt_readn(bt_bmc, kbuffer + len_byte, nread);
|
||||
|
||||
if (copy_to_user(buf, kbuffer, nread + len_byte)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
len -= nread;
|
||||
buf += nread + len_byte;
|
||||
ret += nread + len_byte;
|
||||
len_byte = 0;
|
||||
}
|
||||
|
||||
clr_b_busy(bt_bmc);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&bt_bmc->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* BT Message response format :
|
||||
*
|
||||
* Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6:N
|
||||
* Length NetFn/LUN Seq Cmd Code Data
|
||||
*/
|
||||
static ssize_t bt_bmc_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = file_bt_bmc(file);
|
||||
u8 kbuffer[BT_BMC_BUFFER_SIZE];
|
||||
ssize_t ret = 0;
|
||||
ssize_t nwritten;
|
||||
|
||||
/*
|
||||
* send a minimum response size
|
||||
*/
|
||||
if (count < 5)
|
||||
return -EINVAL;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
WARN_ON(*ppos);
|
||||
|
||||
/*
|
||||
* There's no interrupt for clearing bmc busy so we have to
|
||||
* poll
|
||||
*/
|
||||
if (wait_event_interruptible(bt_bmc->queue,
|
||||
!(bt_inb(bt_bmc, BT_CTRL) &
|
||||
(BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
mutex_lock(&bt_bmc->mutex);
|
||||
|
||||
if (unlikely(bt_inb(bt_bmc, BT_CTRL) &
|
||||
(BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) {
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
clr_wr_ptr(bt_bmc);
|
||||
|
||||
while (count) {
|
||||
nwritten = min_t(ssize_t, count, sizeof(kbuffer));
|
||||
if (copy_from_user(&kbuffer, buf, nwritten)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
bt_writen(bt_bmc, kbuffer, nwritten);
|
||||
|
||||
count -= nwritten;
|
||||
buf += nwritten;
|
||||
ret += nwritten;
|
||||
}
|
||||
|
||||
set_b2h_atn(bt_bmc);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&bt_bmc->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long bt_bmc_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long param)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = file_bt_bmc(file);
|
||||
|
||||
switch (cmd) {
|
||||
case BT_BMC_IOCTL_SMS_ATN:
|
||||
set_sms_atn(bt_bmc);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bt_bmc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = file_bt_bmc(file);
|
||||
|
||||
atomic_dec(&open_count);
|
||||
set_b_busy(bt_bmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int bt_bmc_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = file_bt_bmc(file);
|
||||
unsigned int mask = 0;
|
||||
u8 ctrl;
|
||||
|
||||
poll_wait(file, &bt_bmc->queue, wait);
|
||||
|
||||
ctrl = bt_inb(bt_bmc, BT_CTRL);
|
||||
|
||||
if (ctrl & BT_CTRL_H2B_ATN)
|
||||
mask |= POLLIN;
|
||||
|
||||
if (!(ctrl & (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN)))
|
||||
mask |= POLLOUT;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static const struct file_operations bt_bmc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = bt_bmc_open,
|
||||
.read = bt_bmc_read,
|
||||
.write = bt_bmc_write,
|
||||
.release = bt_bmc_release,
|
||||
.poll = bt_bmc_poll,
|
||||
.unlocked_ioctl = bt_bmc_ioctl,
|
||||
};
|
||||
|
||||
static void poll_timer(unsigned long data)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = (void *)data;
|
||||
|
||||
bt_bmc->poll_timer.expires += msecs_to_jiffies(500);
|
||||
wake_up(&bt_bmc->queue);
|
||||
add_timer(&bt_bmc->poll_timer);
|
||||
}
|
||||
|
||||
static irqreturn_t bt_bmc_irq(int irq, void *arg)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = arg;
|
||||
u32 reg;
|
||||
|
||||
reg = ioread32(bt_bmc->base + BT_CR2);
|
||||
reg &= BT_CR2_IRQ_H2B | BT_CR2_IRQ_HBUSY;
|
||||
if (!reg)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* ack pending IRQs */
|
||||
iowrite32(reg, bt_bmc->base + BT_CR2);
|
||||
|
||||
wake_up(&bt_bmc->queue);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
u32 reg;
|
||||
int rc;
|
||||
|
||||
bt_bmc->irq = platform_get_irq(pdev, 0);
|
||||
if (!bt_bmc->irq)
|
||||
return -ENODEV;
|
||||
|
||||
rc = devm_request_irq(dev, bt_bmc->irq, bt_bmc_irq, IRQF_SHARED,
|
||||
DEVICE_NAME, bt_bmc);
|
||||
if (rc < 0) {
|
||||
dev_warn(dev, "Unable to request IRQ %d\n", bt_bmc->irq);
|
||||
bt_bmc->irq = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure IRQs on the bmc clearing the H2B and HBUSY bits;
|
||||
* H2B will be asserted when the bmc has data for us; HBUSY
|
||||
* will be cleared (along with B2H) when we can write the next
|
||||
* message to the BT buffer
|
||||
*/
|
||||
reg = ioread32(bt_bmc->base + BT_CR1);
|
||||
reg |= BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY;
|
||||
iowrite32(reg, bt_bmc->base + BT_CR1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt_bmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bt_bmc *bt_bmc;
|
||||
struct device *dev;
|
||||
struct resource *res;
|
||||
int rc;
|
||||
|
||||
if (!pdev || !pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
dev = &pdev->dev;
|
||||
dev_info(dev, "Found bt bmc device\n");
|
||||
|
||||
bt_bmc = devm_kzalloc(dev, sizeof(*bt_bmc), GFP_KERNEL);
|
||||
if (!bt_bmc)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, bt_bmc);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
bt_bmc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(bt_bmc->base))
|
||||
return PTR_ERR(bt_bmc->base);
|
||||
|
||||
mutex_init(&bt_bmc->mutex);
|
||||
init_waitqueue_head(&bt_bmc->queue);
|
||||
|
||||
bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR,
|
||||
bt_bmc->miscdev.name = DEVICE_NAME,
|
||||
bt_bmc->miscdev.fops = &bt_bmc_fops,
|
||||
bt_bmc->miscdev.parent = dev;
|
||||
rc = misc_register(&bt_bmc->miscdev);
|
||||
if (rc) {
|
||||
dev_err(dev, "Unable to register misc device\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
bt_bmc_config_irq(bt_bmc, pdev);
|
||||
|
||||
if (bt_bmc->irq) {
|
||||
dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
|
||||
} else {
|
||||
dev_info(dev, "No IRQ; using timer\n");
|
||||
setup_timer(&bt_bmc->poll_timer, poll_timer,
|
||||
(unsigned long)bt_bmc);
|
||||
bt_bmc->poll_timer.expires = jiffies + msecs_to_jiffies(10);
|
||||
add_timer(&bt_bmc->poll_timer);
|
||||
}
|
||||
|
||||
iowrite32((BT_IO_BASE << BT_CR0_IO_BASE) |
|
||||
(BT_IRQ << BT_CR0_IRQ) |
|
||||
BT_CR0_EN_CLR_SLV_RDP |
|
||||
BT_CR0_EN_CLR_SLV_WRP |
|
||||
BT_CR0_ENABLE_IBT,
|
||||
bt_bmc->base + BT_CR0);
|
||||
|
||||
clr_b_busy(bt_bmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt_bmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
misc_deregister(&bt_bmc->miscdev);
|
||||
if (!bt_bmc->irq)
|
||||
del_timer_sync(&bt_bmc->poll_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bt_bmc_match[] = {
|
||||
{ .compatible = "aspeed,ast2400-bt-bmc" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver bt_bmc_driver = {
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.of_match_table = bt_bmc_match,
|
||||
},
|
||||
.probe = bt_bmc_probe,
|
||||
.remove = bt_bmc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(bt_bmc_driver);
|
||||
|
||||
MODULE_DEVICE_TABLE(of, bt_bmc_match);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alistair Popple <alistair@popple.id.au>");
|
||||
MODULE_DESCRIPTION("Linux device interface to the BT interface");
|
@ -2891,11 +2891,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||
intf->curr_channel = IPMI_MAX_CHANNELS;
|
||||
}
|
||||
|
||||
rv = ipmi_bmc_register(intf, i);
|
||||
|
||||
if (rv == 0)
|
||||
rv = add_proc_entries(intf, i);
|
||||
|
||||
rv = ipmi_bmc_register(intf, i);
|
||||
|
||||
out:
|
||||
if (rv) {
|
||||
if (intf->proc_dir)
|
||||
@ -2982,8 +2982,6 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
|
||||
int intf_num = intf->intf_num;
|
||||
ipmi_user_t user;
|
||||
|
||||
ipmi_bmc_unregister(intf);
|
||||
|
||||
mutex_lock(&smi_watchers_mutex);
|
||||
mutex_lock(&ipmi_interfaces_mutex);
|
||||
intf->intf_num = -1;
|
||||
@ -3007,6 +3005,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
|
||||
mutex_unlock(&ipmi_interfaces_mutex);
|
||||
|
||||
remove_proc_entries(intf);
|
||||
ipmi_bmc_unregister(intf);
|
||||
|
||||
/*
|
||||
* Call all the watcher interfaces to tell them that
|
||||
|
@ -417,6 +417,16 @@ config SYS_SUPPORTS_SH_TMU
|
||||
config SYS_SUPPORTS_EM_STI
|
||||
bool
|
||||
|
||||
config CLKSRC_JCORE_PIT
|
||||
bool "J-Core PIT timer driver" if COMPILE_TEST
|
||||
depends on OF
|
||||
depends on GENERIC_CLOCKEVENTS
|
||||
depends on HAS_IOMEM
|
||||
select CLKSRC_MMIO
|
||||
help
|
||||
This enables build of clocksource and clockevent driver for
|
||||
the integrated PIT in the J-Core synthesizable, open source SoC.
|
||||
|
||||
config SH_TIMER_CMT
|
||||
bool "Renesas CMT timer driver" if COMPILE_TEST
|
||||
depends on GENERIC_CLOCKEVENTS
|
||||
|
@ -5,6 +5,7 @@ obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
|
||||
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
|
||||
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
|
||||
obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o
|
||||
obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o
|
||||
obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o
|
||||
obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o
|
||||
obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
|
||||
|
249
drivers/clocksource/jcore-pit.c
Normal file
249
drivers/clocksource/jcore-pit.c
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* J-Core SoC PIT/clocksource driver
|
||||
*
|
||||
* Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#define PIT_IRQ_SHIFT 12
|
||||
#define PIT_PRIO_SHIFT 20
|
||||
#define PIT_ENABLE_SHIFT 26
|
||||
#define PIT_PRIO_MASK 0xf
|
||||
|
||||
#define REG_PITEN 0x00
|
||||
#define REG_THROT 0x10
|
||||
#define REG_COUNT 0x14
|
||||
#define REG_BUSPD 0x18
|
||||
#define REG_SECHI 0x20
|
||||
#define REG_SECLO 0x24
|
||||
#define REG_NSEC 0x28
|
||||
|
||||
struct jcore_pit {
|
||||
struct clock_event_device ced;
|
||||
void __iomem *base;
|
||||
unsigned long periodic_delta;
|
||||
u32 enable_val;
|
||||
};
|
||||
|
||||
static void __iomem *jcore_pit_base;
|
||||
static struct jcore_pit __percpu *jcore_pit_percpu;
|
||||
|
||||
static notrace u64 jcore_sched_clock_read(void)
|
||||
{
|
||||
u32 seclo, nsec, seclo0;
|
||||
__iomem void *base = jcore_pit_base;
|
||||
|
||||
seclo = readl(base + REG_SECLO);
|
||||
do {
|
||||
seclo0 = seclo;
|
||||
nsec = readl(base + REG_NSEC);
|
||||
seclo = readl(base + REG_SECLO);
|
||||
} while (seclo0 != seclo);
|
||||
|
||||
return seclo * NSEC_PER_SEC + nsec;
|
||||
}
|
||||
|
||||
static cycle_t jcore_clocksource_read(struct clocksource *cs)
|
||||
{
|
||||
return jcore_sched_clock_read();
|
||||
}
|
||||
|
||||
static int jcore_pit_disable(struct jcore_pit *pit)
|
||||
{
|
||||
writel(0, pit->base + REG_PITEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jcore_pit_set(unsigned long delta, struct jcore_pit *pit)
|
||||
{
|
||||
jcore_pit_disable(pit);
|
||||
writel(delta, pit->base + REG_THROT);
|
||||
writel(pit->enable_val, pit->base + REG_PITEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jcore_pit_set_state_shutdown(struct clock_event_device *ced)
|
||||
{
|
||||
struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
|
||||
|
||||
return jcore_pit_disable(pit);
|
||||
}
|
||||
|
||||
static int jcore_pit_set_state_oneshot(struct clock_event_device *ced)
|
||||
{
|
||||
struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
|
||||
|
||||
return jcore_pit_disable(pit);
|
||||
}
|
||||
|
||||
static int jcore_pit_set_state_periodic(struct clock_event_device *ced)
|
||||
{
|
||||
struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
|
||||
|
||||
return jcore_pit_set(pit->periodic_delta, pit);
|
||||
}
|
||||
|
||||
static int jcore_pit_set_next_event(unsigned long delta,
|
||||
struct clock_event_device *ced)
|
||||
{
|
||||
struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
|
||||
|
||||
return jcore_pit_set(delta, pit);
|
||||
}
|
||||
|
||||
static int jcore_pit_local_init(unsigned cpu)
|
||||
{
|
||||
struct jcore_pit *pit = this_cpu_ptr(jcore_pit_percpu);
|
||||
unsigned buspd, freq;
|
||||
|
||||
pr_info("Local J-Core PIT init on cpu %u\n", cpu);
|
||||
|
||||
buspd = readl(pit->base + REG_BUSPD);
|
||||
freq = DIV_ROUND_CLOSEST(NSEC_PER_SEC, buspd);
|
||||
pit->periodic_delta = DIV_ROUND_CLOSEST(NSEC_PER_SEC, HZ * buspd);
|
||||
|
||||
clockevents_config_and_register(&pit->ced, freq, 1, ULONG_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t jcore_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct jcore_pit *pit = this_cpu_ptr(dev_id);
|
||||
|
||||
if (clockevent_state_oneshot(&pit->ced))
|
||||
jcore_pit_disable(pit);
|
||||
|
||||
pit->ced.event_handler(&pit->ced);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init jcore_pit_init(struct device_node *node)
|
||||
{
|
||||
int err;
|
||||
unsigned pit_irq, cpu;
|
||||
unsigned long hwirq;
|
||||
u32 irqprio, enable_val;
|
||||
|
||||
jcore_pit_base = of_iomap(node, 0);
|
||||
if (!jcore_pit_base) {
|
||||
pr_err("Error: Cannot map base address for J-Core PIT\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pit_irq = irq_of_parse_and_map(node, 0);
|
||||
if (!pit_irq) {
|
||||
pr_err("Error: J-Core PIT has no IRQ\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pr_info("Initializing J-Core PIT at %p IRQ %d\n",
|
||||
jcore_pit_base, pit_irq);
|
||||
|
||||
err = clocksource_mmio_init(jcore_pit_base, "jcore_pit_cs",
|
||||
NSEC_PER_SEC, 400, 32,
|
||||
jcore_clocksource_read);
|
||||
if (err) {
|
||||
pr_err("Error registering clocksource device: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
sched_clock_register(jcore_sched_clock_read, 32, NSEC_PER_SEC);
|
||||
|
||||
jcore_pit_percpu = alloc_percpu(struct jcore_pit);
|
||||
if (!jcore_pit_percpu) {
|
||||
pr_err("Failed to allocate memory for clock event device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = request_irq(pit_irq, jcore_timer_interrupt,
|
||||
IRQF_TIMER | IRQF_PERCPU,
|
||||
"jcore_pit", jcore_pit_percpu);
|
||||
if (err) {
|
||||
pr_err("pit irq request failed: %d\n", err);
|
||||
free_percpu(jcore_pit_percpu);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* The J-Core PIT is not hard-wired to a particular IRQ, but
|
||||
* integrated with the interrupt controller such that the IRQ it
|
||||
* generates is programmable, as follows:
|
||||
*
|
||||
* The bit layout of the PIT enable register is:
|
||||
*
|
||||
* .....e..ppppiiiiiiii............
|
||||
*
|
||||
* where the .'s indicate unrelated/unused bits, e is enable,
|
||||
* p is priority, and i is hard irq number.
|
||||
*
|
||||
* For the PIT included in AIC1 (obsolete but still in use),
|
||||
* any hard irq (trap number) can be programmed via the 8
|
||||
* iiiiiiii bits, and a priority (0-15) is programmable
|
||||
* separately in the pppp bits.
|
||||
*
|
||||
* For the PIT included in AIC2 (current), the programming
|
||||
* interface is equivalent modulo interrupt mapping. This is
|
||||
* why a different compatible tag was not used. However only
|
||||
* traps 64-127 (the ones actually intended to be used for
|
||||
* interrupts, rather than syscalls/exceptions/etc.) can be
|
||||
* programmed (the high 2 bits of i are ignored) and the
|
||||
* priority pppp is <<2'd and or'd onto the irq number. This
|
||||
* choice seems to have been made on the hardware engineering
|
||||
* side under an assumption that preserving old AIC1 priority
|
||||
* mappings was important. Future models will likely ignore
|
||||
* the pppp field.
|
||||
*/
|
||||
hwirq = irq_get_irq_data(pit_irq)->hwirq;
|
||||
irqprio = (hwirq >> 2) & PIT_PRIO_MASK;
|
||||
enable_val = (1U << PIT_ENABLE_SHIFT)
|
||||
| (hwirq << PIT_IRQ_SHIFT)
|
||||
| (irqprio << PIT_PRIO_SHIFT);
|
||||
|
||||
for_each_present_cpu(cpu) {
|
||||
struct jcore_pit *pit = per_cpu_ptr(jcore_pit_percpu, cpu);
|
||||
|
||||
pit->base = of_iomap(node, cpu);
|
||||
if (!pit->base) {
|
||||
pr_err("Unable to map PIT for cpu %u\n", cpu);
|
||||
continue;
|
||||
}
|
||||
|
||||
pit->ced.name = "jcore_pit";
|
||||
pit->ced.features = CLOCK_EVT_FEAT_PERIODIC
|
||||
| CLOCK_EVT_FEAT_ONESHOT
|
||||
| CLOCK_EVT_FEAT_PERCPU;
|
||||
pit->ced.cpumask = cpumask_of(cpu);
|
||||
pit->ced.rating = 400;
|
||||
pit->ced.irq = pit_irq;
|
||||
pit->ced.set_state_shutdown = jcore_pit_set_state_shutdown;
|
||||
pit->ced.set_state_periodic = jcore_pit_set_state_periodic;
|
||||
pit->ced.set_state_oneshot = jcore_pit_set_state_oneshot;
|
||||
pit->ced.set_next_event = jcore_pit_set_next_event;
|
||||
|
||||
pit->enable_val = enable_val;
|
||||
}
|
||||
|
||||
cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING,
|
||||
"AP_JCORE_TIMER_STARTING",
|
||||
jcore_pit_local_init, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLOCKSOURCE_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init);
|
@ -152,6 +152,13 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static cycle_t sun5i_clksrc_read(struct clocksource *clksrc)
|
||||
{
|
||||
struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
|
||||
|
||||
return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1));
|
||||
}
|
||||
|
||||
static int sun5i_rate_cb_clksrc(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
@ -210,8 +217,13 @@ static int __init sun5i_setup_clocksource(struct device_node *node,
|
||||
writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
|
||||
base + TIMER_CTL_REG(1));
|
||||
|
||||
ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name,
|
||||
rate, 340, 32, clocksource_mmio_readl_down);
|
||||
cs->clksrc.name = node->name;
|
||||
cs->clksrc.rating = 340;
|
||||
cs->clksrc.read = sun5i_clksrc_read;
|
||||
cs->clksrc.mask = CLOCKSOURCE_MASK(32);
|
||||
cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
|
||||
|
||||
ret = clocksource_register_hz(&cs->clksrc, rate);
|
||||
if (ret) {
|
||||
pr_err("Couldn't register clock source.\n");
|
||||
goto err_remove_notifier;
|
||||
|
@ -566,6 +566,11 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
|
||||
|
||||
lynx->registers = ioremap_nocache(pci_resource_start(dev, 0),
|
||||
PCILYNX_MAX_REGISTER);
|
||||
if (lynx->registers == NULL) {
|
||||
dev_err(&dev->dev, "Failed to map registers\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail_deallocate_lynx;
|
||||
}
|
||||
|
||||
lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device,
|
||||
sizeof(struct pcl), &lynx->rcv_start_pcl_bus);
|
||||
@ -578,7 +583,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
|
||||
lynx->rcv_buffer == NULL) {
|
||||
dev_err(&dev->dev, "Failed to allocate receive buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail_deallocate;
|
||||
goto fail_deallocate_buffers;
|
||||
}
|
||||
lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus);
|
||||
lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID);
|
||||
@ -641,7 +646,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
|
||||
dev_err(&dev->dev,
|
||||
"Failed to allocate shared interrupt %d\n", dev->irq);
|
||||
ret = -EIO;
|
||||
goto fail_deallocate;
|
||||
goto fail_deallocate_buffers;
|
||||
}
|
||||
|
||||
lynx->misc.parent = &dev->dev;
|
||||
@ -668,7 +673,7 @@ fail_free_irq:
|
||||
reg_write(lynx, PCI_INT_ENABLE, 0);
|
||||
free_irq(lynx->pci_device->irq, lynx);
|
||||
|
||||
fail_deallocate:
|
||||
fail_deallocate_buffers:
|
||||
if (lynx->rcv_start_pcl)
|
||||
pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
|
||||
lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
|
||||
@ -679,6 +684,8 @@ fail_deallocate:
|
||||
pci_free_consistent(lynx->pci_device, PAGE_SIZE,
|
||||
lynx->rcv_buffer, lynx->rcv_buffer_bus);
|
||||
iounmap(lynx->registers);
|
||||
|
||||
fail_deallocate_lynx:
|
||||
kfree(lynx);
|
||||
|
||||
fail_disable:
|
||||
|
@ -11,7 +11,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
|
||||
-mno-mmx -mno-sse
|
||||
|
||||
cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS))
|
||||
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
|
||||
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \
|
||||
-fno-builtin -fpic -mno-single-pic-base
|
||||
|
||||
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
|
||||
@ -79,5 +79,6 @@ quiet_cmd_stubcopy = STUBCPY $@
|
||||
# decompressor. So move our .data to .data.efistub, which is preserved
|
||||
# explicitly by the decompressor linker script.
|
||||
#
|
||||
STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub
|
||||
STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub \
|
||||
-R ___ksymtab+sort -R ___kcrctab+sort
|
||||
STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
|
||||
|
@ -765,7 +765,7 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void amdgpu_connector_destroy(struct drm_connector *connector)
|
||||
static void amdgpu_connector_unregister(struct drm_connector *connector)
|
||||
{
|
||||
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
|
||||
|
||||
@ -773,6 +773,12 @@ static void amdgpu_connector_destroy(struct drm_connector *connector)
|
||||
drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux);
|
||||
amdgpu_connector->ddc_bus->has_aux = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
|
||||
|
||||
amdgpu_connector_free_edid(connector);
|
||||
kfree(amdgpu_connector->con_priv);
|
||||
drm_connector_unregister(connector);
|
||||
@ -826,6 +832,7 @@ static const struct drm_connector_funcs amdgpu_connector_lvds_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.detect = amdgpu_connector_lvds_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.early_unregister = amdgpu_connector_unregister,
|
||||
.destroy = amdgpu_connector_destroy,
|
||||
.set_property = amdgpu_connector_set_lcd_property,
|
||||
};
|
||||
@ -936,6 +943,7 @@ static const struct drm_connector_funcs amdgpu_connector_vga_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.detect = amdgpu_connector_vga_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.early_unregister = amdgpu_connector_unregister,
|
||||
.destroy = amdgpu_connector_destroy,
|
||||
.set_property = amdgpu_connector_set_property,
|
||||
};
|
||||
@ -1203,6 +1211,7 @@ static const struct drm_connector_funcs amdgpu_connector_dvi_funcs = {
|
||||
.detect = amdgpu_connector_dvi_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = amdgpu_connector_set_property,
|
||||
.early_unregister = amdgpu_connector_unregister,
|
||||
.destroy = amdgpu_connector_destroy,
|
||||
.force = amdgpu_connector_dvi_force,
|
||||
};
|
||||
@ -1493,6 +1502,7 @@ static const struct drm_connector_funcs amdgpu_connector_dp_funcs = {
|
||||
.detect = amdgpu_connector_dp_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = amdgpu_connector_set_property,
|
||||
.early_unregister = amdgpu_connector_unregister,
|
||||
.destroy = amdgpu_connector_destroy,
|
||||
.force = amdgpu_connector_dvi_force,
|
||||
};
|
||||
@ -1502,6 +1512,7 @@ static const struct drm_connector_funcs amdgpu_connector_edp_funcs = {
|
||||
.detect = amdgpu_connector_dp_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = amdgpu_connector_set_lcd_property,
|
||||
.early_unregister = amdgpu_connector_unregister,
|
||||
.destroy = amdgpu_connector_destroy,
|
||||
.force = amdgpu_connector_dvi_force,
|
||||
};
|
||||
|
@ -43,6 +43,9 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, struct amdgpu_ctx *ctx)
|
||||
ctx->rings[i].sequence = 1;
|
||||
ctx->rings[i].fences = &ctx->fences[amdgpu_sched_jobs * i];
|
||||
}
|
||||
|
||||
ctx->reset_counter = atomic_read(&adev->gpu_reset_counter);
|
||||
|
||||
/* create context entity for each ring */
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
|
@ -1408,16 +1408,6 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_UVD ||
|
||||
adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_VCE)
|
||||
continue;
|
||||
/* enable clockgating to save power */
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
|
||||
AMD_CG_STATE_GATE);
|
||||
if (r) {
|
||||
DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", adev->ip_blocks[i].funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
if (adev->ip_blocks[i].funcs->late_init) {
|
||||
r = adev->ip_blocks[i].funcs->late_init((void *)adev);
|
||||
if (r) {
|
||||
@ -1426,6 +1416,18 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
|
||||
}
|
||||
adev->ip_block_status[i].late_initialized = true;
|
||||
}
|
||||
/* skip CG for VCE/UVD, it's handled specially */
|
||||
if (adev->ip_blocks[i].type != AMD_IP_BLOCK_TYPE_UVD &&
|
||||
adev->ip_blocks[i].type != AMD_IP_BLOCK_TYPE_VCE) {
|
||||
/* enable clockgating to save power */
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
|
||||
AMD_CG_STATE_GATE);
|
||||
if (r) {
|
||||
DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1435,6 +1437,30 @@ static int amdgpu_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
/* need to disable SMC first */
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_block_status[i].hw)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_SMC) {
|
||||
/* ungate blocks before hw fini so that we can shutdown the blocks safely */
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
if (r) {
|
||||
DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
|
||||
/* XXX handle errors */
|
||||
if (r) {
|
||||
DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].funcs->name, r);
|
||||
}
|
||||
adev->ip_block_status[i].hw = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
|
||||
if (!adev->ip_block_status[i].hw)
|
||||
continue;
|
||||
@ -2073,7 +2099,8 @@ static bool amdgpu_check_soft_reset(struct amdgpu_device *adev)
|
||||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].funcs->check_soft_reset)
|
||||
adev->ip_blocks[i].funcs->check_soft_reset(adev);
|
||||
adev->ip_block_status[i].hang =
|
||||
adev->ip_blocks[i].funcs->check_soft_reset(adev);
|
||||
if (adev->ip_block_status[i].hang) {
|
||||
DRM_INFO("IP block:%d is hang!\n", i);
|
||||
asic_hang = true;
|
||||
@ -2102,12 +2129,20 @@ static int amdgpu_pre_soft_reset(struct amdgpu_device *adev)
|
||||
|
||||
static bool amdgpu_need_full_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang ||
|
||||
adev->ip_block_status[AMD_IP_BLOCK_TYPE_SMC].hang ||
|
||||
adev->ip_block_status[AMD_IP_BLOCK_TYPE_ACP].hang ||
|
||||
adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) {
|
||||
DRM_INFO("Some block need full reset!\n");
|
||||
return true;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
if ((adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) ||
|
||||
(adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_SMC) ||
|
||||
(adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_ACP) ||
|
||||
(adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_DCE)) {
|
||||
if (adev->ip_block_status[i].hang) {
|
||||
DRM_INFO("Some block need full reset!\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -113,24 +113,26 @@ void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
|
||||
u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev)
|
||||
{
|
||||
struct drm_device *dev = adev->ddev;
|
||||
struct drm_crtc *crtc;
|
||||
struct amdgpu_crtc *amdgpu_crtc;
|
||||
u32 line_time_us, vblank_lines;
|
||||
u32 vblank_in_pixels;
|
||||
u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
|
||||
|
||||
if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
amdgpu_crtc = to_amdgpu_crtc(crtc);
|
||||
if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
|
||||
line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
|
||||
amdgpu_crtc->hw_mode.clock;
|
||||
vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
|
||||
vblank_in_pixels =
|
||||
amdgpu_crtc->hw_mode.crtc_htotal *
|
||||
(amdgpu_crtc->hw_mode.crtc_vblank_end -
|
||||
amdgpu_crtc->hw_mode.crtc_vdisplay +
|
||||
(amdgpu_crtc->v_border * 2);
|
||||
vblank_time_us = vblank_lines * line_time_us;
|
||||
(amdgpu_crtc->v_border * 2));
|
||||
|
||||
vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -345,8 +345,8 @@ static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
|
||||
ent = debugfs_create_file(name,
|
||||
S_IFREG | S_IRUGO, root,
|
||||
ring, &amdgpu_debugfs_ring_fops);
|
||||
if (IS_ERR(ent))
|
||||
return PTR_ERR(ent);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
|
||||
i_size_write(ent->d_inode, ring->ring_size + 12);
|
||||
ring->ent = ent;
|
||||
|
@ -555,10 +555,13 @@ struct amdgpu_ttm_tt {
|
||||
int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
|
||||
{
|
||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
|
||||
unsigned int flags = 0;
|
||||
unsigned pinned = 0;
|
||||
int r;
|
||||
|
||||
if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
|
||||
flags |= FOLL_WRITE;
|
||||
|
||||
if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
|
||||
/* check that we only use anonymous memory
|
||||
to prevent problems with writeback */
|
||||
@ -581,7 +584,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
|
||||
list_add(&guptask.list, >t->guptasks);
|
||||
spin_unlock(>t->guptasklock);
|
||||
|
||||
r = get_user_pages(userptr, num_pages, write, 0, p, NULL);
|
||||
r = get_user_pages(userptr, num_pages, flags, p, NULL);
|
||||
|
||||
spin_lock(>t->guptasklock);
|
||||
list_del(&guptask.list);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user