KVM: s390: features for 4.12
1. guarded storage support for guests This contains an s390 base Linux feature branch that is necessary to implement the KVM part 2. Provide an interface to implement adapter interruption suppression which is necessary for proper zPCI support 3. Use more defines instead of numbers 4. Provide logging for lazy enablement of runtime instrumentation -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJY50fGAAoJEBF7vIC1phx8TK4P/0y7J6go7NFniVXf0K5/teAZ kH6BRwoWQDCGAwkpz8fqhKTNxdEq1bjLS5aNf2R3oGt61yoKim4GLSYeRymhKWo0 WZbwq8VpCWxjysx4wyg1nm4J05EDqaPvfxtD9ONCxZNXvPeZR5pIY1uo3twuNROS z+bOtP1YK7FyzbgGsHnc47YKrOMa3LwTQfAAhf3eVHs5f9cksIqlQYlo/H7fJY96 Z3qpZmrwWP5avZAenxfUKS2dEiT2lzFvUP1waYwm4sZ7fImdgBRlnFzFK/O7qiIV c9KHW+qao37NU1AsqJibXZvFQBJixKxWa8nCKsagpkZAMDoPNoutHsxXpNJNrp4S Zq+OWbiYRKXnndGI94RtMUE+bmRvcj37a648+nwzRPA9N889GQR829qKLANsqCwY 7bM3gE9d5BkAASp0uZ4bgrfyU4tlGTH8WLNSLM+upeOGjWEk3HdOEFuJQNspgaWQ oaAl4TROQhGvZXYxzTHP26jEG0IAIkUd2CUULAe8lZ2vk+kc4xPAfhjQ41DFembz fDMXXKgjtHvT6Z5USbGJdkOBkhzGyOuETZJyrj7D60OmlHXeoBPgWIJ21cS8ZU4F M0cM+1DcXbOOKjfIbZRbLh9OdAhBya8VzHnyw7T2vl9hXIAhEH9MwTfVsnBujdca Q4BBOIh3HV9VfT0exaaF =Jtjb -----END PGP SIGNATURE----- Merge tag 'kvm-s390-next-4.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux From: Christian Borntraeger <borntraeger@de.ibm.com> KVM: s390: features for 4.12 1. guarded storage support for guests This contains an s390 base Linux feature branch that is necessary to implement the KVM part 2. Provide an interface to implement adapter interruption suppression which is necessary for proper zPCI support 3. Use more defines instead of numbers 4. Provide logging for lazy enablement of runtime instrumentation
This commit is contained in:
commit
f7b1a77d3b
|
@ -3983,6 +3983,23 @@ to take care of that.
|
||||||
This capability can be enabled dynamically even if VCPUs were already
|
This capability can be enabled dynamically even if VCPUs were already
|
||||||
created and are running.
|
created and are running.
|
||||||
|
|
||||||
|
7.9 KVM_CAP_S390_GS
|
||||||
|
|
||||||
|
Architectures: s390
|
||||||
|
Parameters: none
|
||||||
|
Returns: 0 on success; -EINVAL if the machine does not support
|
||||||
|
guarded storage; -EBUSY if a VCPU has already been created.
|
||||||
|
|
||||||
|
Allows use of guarded storage for the KVM guest.
|
||||||
|
|
||||||
|
7.10 KVM_CAP_S390_AIS
|
||||||
|
|
||||||
|
Architectures: s390
|
||||||
|
Parameters: none
|
||||||
|
|
||||||
|
Allow use of adapter-interruption suppression.
|
||||||
|
Returns: 0 on success; -EBUSY if a VCPU has already been created.
|
||||||
|
|
||||||
8. Other capabilities.
|
8. Other capabilities.
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ FLIC provides support to
|
||||||
- purge one pending floating I/O interrupt (KVM_DEV_FLIC_CLEAR_IO_IRQ)
|
- purge one pending floating I/O interrupt (KVM_DEV_FLIC_CLEAR_IO_IRQ)
|
||||||
- enable/disable for the guest transparent async page faults
|
- enable/disable for the guest transparent async page faults
|
||||||
- register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*)
|
- register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*)
|
||||||
|
- modify AIS (adapter-interruption-suppression) mode state (KVM_DEV_FLIC_AISM)
|
||||||
|
- inject adapter interrupts on a specified adapter (KVM_DEV_FLIC_AIRQ_INJECT)
|
||||||
|
|
||||||
Groups:
|
Groups:
|
||||||
KVM_DEV_FLIC_ENQUEUE
|
KVM_DEV_FLIC_ENQUEUE
|
||||||
|
@ -64,12 +66,18 @@ struct kvm_s390_io_adapter {
|
||||||
__u8 isc;
|
__u8 isc;
|
||||||
__u8 maskable;
|
__u8 maskable;
|
||||||
__u8 swap;
|
__u8 swap;
|
||||||
__u8 pad;
|
__u8 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
id contains the unique id for the adapter, isc the I/O interruption subclass
|
id contains the unique id for the adapter, isc the I/O interruption subclass
|
||||||
to use, maskable whether this adapter may be masked (interrupts turned off)
|
to use, maskable whether this adapter may be masked (interrupts turned off),
|
||||||
and swap whether the indicators need to be byte swapped.
|
swap whether the indicators need to be byte swapped, and flags contains
|
||||||
|
further characteristics of the adapter.
|
||||||
|
Currently defined values for 'flags' are:
|
||||||
|
- KVM_S390_ADAPTER_SUPPRESSIBLE: adapter is subject to AIS
|
||||||
|
(adapter-interrupt-suppression) facility. This flag only has an effect if
|
||||||
|
the AIS capability is enabled.
|
||||||
|
Unknown flag values are ignored.
|
||||||
|
|
||||||
|
|
||||||
KVM_DEV_FLIC_ADAPTER_MODIFY
|
KVM_DEV_FLIC_ADAPTER_MODIFY
|
||||||
|
@ -101,6 +109,33 @@ struct kvm_s390_io_adapter_req {
|
||||||
release a userspace page for the translated address specified in addr
|
release a userspace page for the translated address specified in addr
|
||||||
from the list of mappings
|
from the list of mappings
|
||||||
|
|
||||||
|
KVM_DEV_FLIC_AISM
|
||||||
|
modify the adapter-interruption-suppression mode for a given isc if the
|
||||||
|
AIS capability is enabled. Takes a kvm_s390_ais_req describing:
|
||||||
|
|
||||||
|
struct kvm_s390_ais_req {
|
||||||
|
__u8 isc;
|
||||||
|
__u16 mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
isc contains the target I/O interruption subclass, mode the target
|
||||||
|
adapter-interruption-suppression mode. The following modes are
|
||||||
|
currently supported:
|
||||||
|
- KVM_S390_AIS_MODE_ALL: ALL-Interruptions Mode, i.e. airq injection
|
||||||
|
is always allowed;
|
||||||
|
- KVM_S390_AIS_MODE_SINGLE: SINGLE-Interruption Mode, i.e. airq
|
||||||
|
injection is only allowed once and the following adapter interrupts
|
||||||
|
will be suppressed until the mode is set again to ALL-Interruptions
|
||||||
|
or SINGLE-Interruption mode.
|
||||||
|
|
||||||
|
KVM_DEV_FLIC_AIRQ_INJECT
|
||||||
|
Inject adapter interrupts on a specified adapter.
|
||||||
|
attr->attr contains the unique id for the adapter, which allows for
|
||||||
|
adapter-specific checks and actions.
|
||||||
|
For adapters subject to AIS, handle the airq injection suppression for
|
||||||
|
an isc according to the adapter-interruption-suppression mode on condition
|
||||||
|
that the AIS capability is enabled.
|
||||||
|
|
||||||
Note: The KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR device ioctls executed on
|
Note: The KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR device ioctls executed on
|
||||||
FLIC with an unknown group or attribute gives the error code EINVAL (instead of
|
FLIC with an unknown group or attribute gives the error code EINVAL (instead of
|
||||||
ENXIO, as specified in the API documentation). It is not possible to conclude
|
ENXIO, as specified in the API documentation). It is not possible to conclude
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
#define HWCAP_S390_VXRS 2048
|
#define HWCAP_S390_VXRS 2048
|
||||||
#define HWCAP_S390_VXRS_BCD 4096
|
#define HWCAP_S390_VXRS_BCD 4096
|
||||||
#define HWCAP_S390_VXRS_EXT 8192
|
#define HWCAP_S390_VXRS_EXT 8192
|
||||||
|
#define HWCAP_S390_GS 16384
|
||||||
|
|
||||||
/* Internal bits, not exposed via elf */
|
/* Internal bits, not exposed via elf */
|
||||||
#define HWCAP_INT_SIE 1UL
|
#define HWCAP_INT_SIE 1UL
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/fpu/api.h>
|
#include <asm/fpu/api.h>
|
||||||
#include <asm/isc.h>
|
#include <asm/isc.h>
|
||||||
|
#include <asm/guarded_storage.h>
|
||||||
|
|
||||||
#define KVM_S390_BSCA_CPU_SLOTS 64
|
#define KVM_S390_BSCA_CPU_SLOTS 64
|
||||||
#define KVM_S390_ESCA_CPU_SLOTS 248
|
#define KVM_S390_ESCA_CPU_SLOTS 248
|
||||||
|
@ -164,11 +165,21 @@ struct kvm_s390_sie_block {
|
||||||
#define ICTL_RRBE 0x00001000
|
#define ICTL_RRBE 0x00001000
|
||||||
#define ICTL_TPROT 0x00000200
|
#define ICTL_TPROT 0x00000200
|
||||||
__u32 ictl; /* 0x0048 */
|
__u32 ictl; /* 0x0048 */
|
||||||
|
#define ECA_CEI 0x80000000
|
||||||
|
#define ECA_IB 0x40000000
|
||||||
|
#define ECA_SIGPI 0x10000000
|
||||||
|
#define ECA_MVPGI 0x01000000
|
||||||
|
#define ECA_VX 0x00020000
|
||||||
|
#define ECA_PROTEXCI 0x00002000
|
||||||
|
#define ECA_SII 0x00000001
|
||||||
__u32 eca; /* 0x004c */
|
__u32 eca; /* 0x004c */
|
||||||
#define ICPT_INST 0x04
|
#define ICPT_INST 0x04
|
||||||
#define ICPT_PROGI 0x08
|
#define ICPT_PROGI 0x08
|
||||||
#define ICPT_INSTPROGI 0x0C
|
#define ICPT_INSTPROGI 0x0C
|
||||||
|
#define ICPT_EXTREQ 0x10
|
||||||
#define ICPT_EXTINT 0x14
|
#define ICPT_EXTINT 0x14
|
||||||
|
#define ICPT_IOREQ 0x18
|
||||||
|
#define ICPT_WAIT 0x1c
|
||||||
#define ICPT_VALIDITY 0x20
|
#define ICPT_VALIDITY 0x20
|
||||||
#define ICPT_STOP 0x28
|
#define ICPT_STOP 0x28
|
||||||
#define ICPT_OPEREXC 0x2C
|
#define ICPT_OPEREXC 0x2C
|
||||||
|
@ -182,10 +193,19 @@ struct kvm_s390_sie_block {
|
||||||
__u32 ipb; /* 0x0058 */
|
__u32 ipb; /* 0x0058 */
|
||||||
__u32 scaoh; /* 0x005c */
|
__u32 scaoh; /* 0x005c */
|
||||||
__u8 reserved60; /* 0x0060 */
|
__u8 reserved60; /* 0x0060 */
|
||||||
|
#define ECB_GS 0x40
|
||||||
|
#define ECB_TE 0x10
|
||||||
|
#define ECB_SRSI 0x04
|
||||||
|
#define ECB_HOSTPROTINT 0x02
|
||||||
__u8 ecb; /* 0x0061 */
|
__u8 ecb; /* 0x0061 */
|
||||||
|
#define ECB2_CMMA 0x80
|
||||||
|
#define ECB2_IEP 0x20
|
||||||
|
#define ECB2_PFMFI 0x08
|
||||||
|
#define ECB2_ESCA 0x04
|
||||||
__u8 ecb2; /* 0x0062 */
|
__u8 ecb2; /* 0x0062 */
|
||||||
#define ECB3_AES 0x04
|
|
||||||
#define ECB3_DEA 0x08
|
#define ECB3_DEA 0x08
|
||||||
|
#define ECB3_AES 0x04
|
||||||
|
#define ECB3_RI 0x01
|
||||||
__u8 ecb3; /* 0x0063 */
|
__u8 ecb3; /* 0x0063 */
|
||||||
__u32 scaol; /* 0x0064 */
|
__u32 scaol; /* 0x0064 */
|
||||||
__u8 reserved68[4]; /* 0x0068 */
|
__u8 reserved68[4]; /* 0x0068 */
|
||||||
|
@ -219,11 +239,14 @@ struct kvm_s390_sie_block {
|
||||||
__u32 crycbd; /* 0x00fc */
|
__u32 crycbd; /* 0x00fc */
|
||||||
__u64 gcr[16]; /* 0x0100 */
|
__u64 gcr[16]; /* 0x0100 */
|
||||||
__u64 gbea; /* 0x0180 */
|
__u64 gbea; /* 0x0180 */
|
||||||
__u8 reserved188[24]; /* 0x0188 */
|
__u8 reserved188[8]; /* 0x0188 */
|
||||||
|
__u64 sdnxo; /* 0x0190 */
|
||||||
|
__u8 reserved198[8]; /* 0x0198 */
|
||||||
__u32 fac; /* 0x01a0 */
|
__u32 fac; /* 0x01a0 */
|
||||||
__u8 reserved1a4[20]; /* 0x01a4 */
|
__u8 reserved1a4[20]; /* 0x01a4 */
|
||||||
__u64 cbrlo; /* 0x01b8 */
|
__u64 cbrlo; /* 0x01b8 */
|
||||||
__u8 reserved1c0[8]; /* 0x01c0 */
|
__u8 reserved1c0[8]; /* 0x01c0 */
|
||||||
|
#define ECD_HOSTREGMGMT 0x20000000
|
||||||
__u32 ecd; /* 0x01c8 */
|
__u32 ecd; /* 0x01c8 */
|
||||||
__u8 reserved1cc[18]; /* 0x01cc */
|
__u8 reserved1cc[18]; /* 0x01cc */
|
||||||
__u64 pp; /* 0x01de */
|
__u64 pp; /* 0x01de */
|
||||||
|
@ -498,6 +521,12 @@ struct kvm_s390_local_interrupt {
|
||||||
#define FIRQ_CNTR_PFAULT 3
|
#define FIRQ_CNTR_PFAULT 3
|
||||||
#define FIRQ_MAX_COUNT 4
|
#define FIRQ_MAX_COUNT 4
|
||||||
|
|
||||||
|
/* mask the AIS mode for a given ISC */
|
||||||
|
#define AIS_MODE_MASK(isc) (0x80 >> isc)
|
||||||
|
|
||||||
|
#define KVM_S390_AIS_MODE_ALL 0
|
||||||
|
#define KVM_S390_AIS_MODE_SINGLE 1
|
||||||
|
|
||||||
struct kvm_s390_float_interrupt {
|
struct kvm_s390_float_interrupt {
|
||||||
unsigned long pending_irqs;
|
unsigned long pending_irqs;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
@ -507,6 +536,10 @@ struct kvm_s390_float_interrupt {
|
||||||
struct kvm_s390_ext_info srv_signal;
|
struct kvm_s390_ext_info srv_signal;
|
||||||
int next_rr_cpu;
|
int next_rr_cpu;
|
||||||
unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
|
unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
|
||||||
|
struct mutex ais_lock;
|
||||||
|
u8 simm;
|
||||||
|
u8 nimm;
|
||||||
|
int ais_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kvm_hw_wp_info_arch {
|
struct kvm_hw_wp_info_arch {
|
||||||
|
@ -554,6 +587,7 @@ struct kvm_vcpu_arch {
|
||||||
/* if vsie is active, currently executed shadow sie control block */
|
/* if vsie is active, currently executed shadow sie control block */
|
||||||
struct kvm_s390_sie_block *vsie_block;
|
struct kvm_s390_sie_block *vsie_block;
|
||||||
unsigned int host_acrs[NUM_ACRS];
|
unsigned int host_acrs[NUM_ACRS];
|
||||||
|
struct gs_cb *host_gscb;
|
||||||
struct fpu host_fpregs;
|
struct fpu host_fpregs;
|
||||||
struct kvm_s390_local_interrupt local_int;
|
struct kvm_s390_local_interrupt local_int;
|
||||||
struct hrtimer ckc_timer;
|
struct hrtimer ckc_timer;
|
||||||
|
@ -574,6 +608,7 @@ struct kvm_vcpu_arch {
|
||||||
*/
|
*/
|
||||||
seqcount_t cputm_seqcount;
|
seqcount_t cputm_seqcount;
|
||||||
__u64 cputm_start;
|
__u64 cputm_start;
|
||||||
|
bool gs_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kvm_vm_stat {
|
struct kvm_vm_stat {
|
||||||
|
@ -596,6 +631,7 @@ struct s390_io_adapter {
|
||||||
bool maskable;
|
bool maskable;
|
||||||
bool masked;
|
bool masked;
|
||||||
bool swap;
|
bool swap;
|
||||||
|
bool suppressible;
|
||||||
struct rw_semaphore maps_lock;
|
struct rw_semaphore maps_lock;
|
||||||
struct list_head maps;
|
struct list_head maps;
|
||||||
atomic_t nr_maps;
|
atomic_t nr_maps;
|
||||||
|
|
|
@ -157,8 +157,8 @@ struct lowcore {
|
||||||
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||||
__u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */
|
__u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */
|
||||||
|
|
||||||
/* Pointer to vector register save area */
|
/* Pointer to the machine check extended save area */
|
||||||
__u64 vector_save_area_addr; /* 0x11b0 */
|
__u64 mcesad; /* 0x11b0 */
|
||||||
|
|
||||||
/* 64 bit extparam used for pfault/diag 250: defined by architecture */
|
/* 64 bit extparam used for pfault/diag 250: defined by architecture */
|
||||||
__u64 ext_params2; /* 0x11B8 */
|
__u64 ext_params2; /* 0x11B8 */
|
||||||
|
@ -182,10 +182,7 @@ struct lowcore {
|
||||||
|
|
||||||
/* Transaction abort diagnostic block */
|
/* Transaction abort diagnostic block */
|
||||||
__u8 pgm_tdb[256]; /* 0x1800 */
|
__u8 pgm_tdb[256]; /* 0x1800 */
|
||||||
__u8 pad_0x1900[0x1c00-0x1900]; /* 0x1900 */
|
__u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */
|
||||||
|
|
||||||
/* Software defined save area for vector registers */
|
|
||||||
__u8 vector_save_area[1024]; /* 0x1c00 */
|
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define S390_lowcore (*((struct lowcore *) 0))
|
#define S390_lowcore (*((struct lowcore *) 0))
|
||||||
|
|
|
@ -58,7 +58,9 @@ union mci {
|
||||||
u64 ie : 1; /* 32 indirect storage error */
|
u64 ie : 1; /* 32 indirect storage error */
|
||||||
u64 ar : 1; /* 33 access register validity */
|
u64 ar : 1; /* 33 access register validity */
|
||||||
u64 da : 1; /* 34 delayed access exception */
|
u64 da : 1; /* 34 delayed access exception */
|
||||||
u64 : 7; /* 35-41 */
|
u64 : 1; /* 35 */
|
||||||
|
u64 gs : 1; /* 36 guarded storage registers */
|
||||||
|
u64 : 5; /* 37-41 */
|
||||||
u64 pr : 1; /* 42 tod programmable register validity */
|
u64 pr : 1; /* 42 tod programmable register validity */
|
||||||
u64 fc : 1; /* 43 fp control register validity */
|
u64 fc : 1; /* 43 fp control register validity */
|
||||||
u64 ap : 1; /* 44 ancillary report */
|
u64 ap : 1; /* 44 ancillary report */
|
||||||
|
@ -69,6 +71,14 @@ union mci {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MCESA_ORIGIN_MASK (~0x3ffUL)
|
||||||
|
#define MCESA_LC_MASK (0xfUL)
|
||||||
|
|
||||||
|
struct mcesa {
|
||||||
|
u8 vector_save_area[1024];
|
||||||
|
u8 guarded_storage_save_area[32];
|
||||||
|
};
|
||||||
|
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
|
|
||||||
extern void s390_handle_mcck(void);
|
extern void s390_handle_mcck(void);
|
||||||
|
|
|
@ -135,6 +135,8 @@ struct thread_struct {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
/* cpu runtime instrumentation */
|
/* cpu runtime instrumentation */
|
||||||
struct runtime_instr_cb *ri_cb;
|
struct runtime_instr_cb *ri_cb;
|
||||||
|
struct gs_cb *gs_cb; /* Current guarded storage cb */
|
||||||
|
struct gs_cb *gs_bc_cb; /* Broadcast guarded storage cb */
|
||||||
unsigned char trap_tdb[256]; /* Transaction abort diagnose block */
|
unsigned char trap_tdb[256]; /* Transaction abort diagnose block */
|
||||||
/*
|
/*
|
||||||
* Warning: 'fpu' is dynamically-sized. It *MUST* be at
|
* Warning: 'fpu' is dynamically-sized. It *MUST* be at
|
||||||
|
@ -215,6 +217,9 @@ void show_cacheinfo(struct seq_file *m);
|
||||||
/* Free all resources held by a thread. */
|
/* Free all resources held by a thread. */
|
||||||
extern void release_thread(struct task_struct *);
|
extern void release_thread(struct task_struct *);
|
||||||
|
|
||||||
|
/* Free guarded storage control block for current */
|
||||||
|
void exit_thread_gs(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return saved PC of a blocked thread.
|
* Return saved PC of a blocked thread.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define MACHINE_FLAG_VX _BITUL(13)
|
#define MACHINE_FLAG_VX _BITUL(13)
|
||||||
#define MACHINE_FLAG_CAD _BITUL(14)
|
#define MACHINE_FLAG_CAD _BITUL(14)
|
||||||
#define MACHINE_FLAG_NX _BITUL(15)
|
#define MACHINE_FLAG_NX _BITUL(15)
|
||||||
|
#define MACHINE_FLAG_GS _BITUL(16)
|
||||||
|
|
||||||
#define LPP_MAGIC _BITUL(31)
|
#define LPP_MAGIC _BITUL(31)
|
||||||
#define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL)
|
#define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL)
|
||||||
|
@ -70,6 +71,7 @@ extern void detect_memory_memblock(void);
|
||||||
#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
|
#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
|
||||||
#define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD)
|
#define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD)
|
||||||
#define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX)
|
#define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX)
|
||||||
|
#define MACHINE_HAS_GS (S390_lowcore.machine_flags & MACHINE_FLAG_GS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Console mode. Override with conmode=
|
* Console mode. Override with conmode=
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
#include <asm/fpu/api.h>
|
#include <asm/fpu/api.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
#include <asm/guarded_storage.h>
|
||||||
|
|
||||||
extern struct task_struct *__switch_to(void *, void *);
|
extern struct task_struct *__switch_to(void *, void *);
|
||||||
extern void update_cr_regs(struct task_struct *task);
|
extern void update_cr_regs(struct task_struct *task);
|
||||||
|
@ -33,12 +34,14 @@ static inline void restore_access_regs(unsigned int *acrs)
|
||||||
save_fpu_regs(); \
|
save_fpu_regs(); \
|
||||||
save_access_regs(&prev->thread.acrs[0]); \
|
save_access_regs(&prev->thread.acrs[0]); \
|
||||||
save_ri_cb(prev->thread.ri_cb); \
|
save_ri_cb(prev->thread.ri_cb); \
|
||||||
|
save_gs_cb(prev->thread.gs_cb); \
|
||||||
} \
|
} \
|
||||||
if (next->mm) { \
|
if (next->mm) { \
|
||||||
update_cr_regs(next); \
|
update_cr_regs(next); \
|
||||||
set_cpu_flag(CIF_FPU); \
|
set_cpu_flag(CIF_FPU); \
|
||||||
restore_access_regs(&next->thread.acrs[0]); \
|
restore_access_regs(&next->thread.acrs[0]); \
|
||||||
restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \
|
restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \
|
||||||
|
restore_gs_cb(next->thread.gs_cb); \
|
||||||
} \
|
} \
|
||||||
prev = __switch_to(prev,next); \
|
prev = __switch_to(prev,next); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
|
@ -54,11 +54,12 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
|
||||||
#define TIF_NOTIFY_RESUME 0 /* callback before returning to user */
|
#define TIF_NOTIFY_RESUME 0 /* callback before returning to user */
|
||||||
#define TIF_SIGPENDING 1 /* signal pending */
|
#define TIF_SIGPENDING 1 /* signal pending */
|
||||||
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
|
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
|
||||||
#define TIF_SYSCALL_TRACE 3 /* syscall trace active */
|
#define TIF_UPROBE 3 /* breakpointed or single-stepping */
|
||||||
#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */
|
#define TIF_GUARDED_STORAGE 4 /* load guarded storage control block */
|
||||||
#define TIF_SECCOMP 5 /* secure computing */
|
#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
|
||||||
#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */
|
#define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */
|
||||||
#define TIF_UPROBE 7 /* breakpointed or single-stepping */
|
#define TIF_SECCOMP 10 /* secure computing */
|
||||||
|
#define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */
|
||||||
#define TIF_31BIT 16 /* 32bit process */
|
#define TIF_31BIT 16 /* 32bit process */
|
||||||
#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
|
#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
|
||||||
#define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */
|
#define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */
|
||||||
|
@ -76,5 +77,6 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
|
||||||
#define _TIF_UPROBE _BITUL(TIF_UPROBE)
|
#define _TIF_UPROBE _BITUL(TIF_UPROBE)
|
||||||
#define _TIF_31BIT _BITUL(TIF_31BIT)
|
#define _TIF_31BIT _BITUL(TIF_31BIT)
|
||||||
#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP)
|
#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP)
|
||||||
|
#define _TIF_GUARDED_STORAGE _BITUL(TIF_GUARDED_STORAGE)
|
||||||
|
|
||||||
#endif /* _ASM_THREAD_INFO_H */
|
#endif /* _ASM_THREAD_INFO_H */
|
||||||
|
|
|
@ -12,6 +12,7 @@ header-y += dasd.h
|
||||||
header-y += debug.h
|
header-y += debug.h
|
||||||
header-y += errno.h
|
header-y += errno.h
|
||||||
header-y += fcntl.h
|
header-y += fcntl.h
|
||||||
|
header-y += guarded_storage.h
|
||||||
header-y += hypfs.h
|
header-y += hypfs.h
|
||||||
header-y += ioctl.h
|
header-y += ioctl.h
|
||||||
header-y += ioctls.h
|
header-y += ioctls.h
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
#ifndef _GUARDED_STORAGE_H
|
||||||
|
#define _GUARDED_STORAGE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct gs_cb {
|
||||||
|
__u64 reserved;
|
||||||
|
__u64 gsd;
|
||||||
|
__u64 gssm;
|
||||||
|
__u64 gs_epl_a;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gs_epl {
|
||||||
|
__u8 pad1;
|
||||||
|
union {
|
||||||
|
__u8 gs_eam;
|
||||||
|
struct {
|
||||||
|
__u8 : 6;
|
||||||
|
__u8 e : 1;
|
||||||
|
__u8 b : 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
__u8 gs_eci;
|
||||||
|
struct {
|
||||||
|
__u8 tx : 1;
|
||||||
|
__u8 cx : 1;
|
||||||
|
__u8 : 5;
|
||||||
|
__u8 in : 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
__u8 gs_eai;
|
||||||
|
struct {
|
||||||
|
__u8 : 1;
|
||||||
|
__u8 t : 1;
|
||||||
|
__u8 as : 2;
|
||||||
|
__u8 ar : 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
__u32 pad2;
|
||||||
|
__u64 gs_eha;
|
||||||
|
__u64 gs_eia;
|
||||||
|
__u64 gs_eoa;
|
||||||
|
__u64 gs_eir;
|
||||||
|
__u64 gs_era;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GS_ENABLE 0
|
||||||
|
#define GS_DISABLE 1
|
||||||
|
#define GS_SET_BC_CB 2
|
||||||
|
#define GS_CLEAR_BC_CB 3
|
||||||
|
#define GS_BROADCAST 4
|
||||||
|
|
||||||
|
static inline void load_gs_cb(struct gs_cb *gs_cb)
|
||||||
|
{
|
||||||
|
asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void store_gs_cb(struct gs_cb *gs_cb)
|
||||||
|
{
|
||||||
|
asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void save_gs_cb(struct gs_cb *gs_cb)
|
||||||
|
{
|
||||||
|
if (gs_cb)
|
||||||
|
store_gs_cb(gs_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void restore_gs_cb(struct gs_cb *gs_cb)
|
||||||
|
{
|
||||||
|
if (gs_cb)
|
||||||
|
load_gs_cb(gs_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _GUARDED_STORAGE_H */
|
|
@ -26,6 +26,8 @@
|
||||||
#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
|
#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
|
||||||
#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
|
#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
|
||||||
#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8
|
#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8
|
||||||
|
#define KVM_DEV_FLIC_AISM 9
|
||||||
|
#define KVM_DEV_FLIC_AIRQ_INJECT 10
|
||||||
/*
|
/*
|
||||||
* We can have up to 4*64k pending subchannels + 8 adapter interrupts,
|
* We can have up to 4*64k pending subchannels + 8 adapter interrupts,
|
||||||
* as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
|
* as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
|
||||||
|
@ -41,7 +43,14 @@ struct kvm_s390_io_adapter {
|
||||||
__u8 isc;
|
__u8 isc;
|
||||||
__u8 maskable;
|
__u8 maskable;
|
||||||
__u8 swap;
|
__u8 swap;
|
||||||
__u8 pad;
|
__u8 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KVM_S390_ADAPTER_SUPPRESSIBLE 0x01
|
||||||
|
|
||||||
|
struct kvm_s390_ais_req {
|
||||||
|
__u8 isc;
|
||||||
|
__u16 mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KVM_S390_IO_ADAPTER_MASK 1
|
#define KVM_S390_IO_ADAPTER_MASK 1
|
||||||
|
@ -197,6 +206,10 @@ struct kvm_guest_debug_arch {
|
||||||
#define KVM_SYNC_VRS (1UL << 6)
|
#define KVM_SYNC_VRS (1UL << 6)
|
||||||
#define KVM_SYNC_RICCB (1UL << 7)
|
#define KVM_SYNC_RICCB (1UL << 7)
|
||||||
#define KVM_SYNC_FPRS (1UL << 8)
|
#define KVM_SYNC_FPRS (1UL << 8)
|
||||||
|
#define KVM_SYNC_GSCB (1UL << 9)
|
||||||
|
/* length and alignment of the sdnx as a power of two */
|
||||||
|
#define SDNXC 8
|
||||||
|
#define SDNXL (1UL << SDNXC)
|
||||||
/* definition of registers in kvm_run */
|
/* definition of registers in kvm_run */
|
||||||
struct kvm_sync_regs {
|
struct kvm_sync_regs {
|
||||||
__u64 prefix; /* prefix register */
|
__u64 prefix; /* prefix register */
|
||||||
|
@ -217,8 +230,16 @@ struct kvm_sync_regs {
|
||||||
};
|
};
|
||||||
__u8 reserved[512]; /* for future vector expansion */
|
__u8 reserved[512]; /* for future vector expansion */
|
||||||
__u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */
|
__u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */
|
||||||
__u8 padding[52]; /* riccb needs to be 64byte aligned */
|
__u8 padding1[52]; /* riccb needs to be 64byte aligned */
|
||||||
__u8 riccb[64]; /* runtime instrumentation controls block */
|
__u8 riccb[64]; /* runtime instrumentation controls block */
|
||||||
|
__u8 padding2[192]; /* sdnx needs to be 256byte aligned */
|
||||||
|
union {
|
||||||
|
__u8 sdnx[SDNXL]; /* state description annex */
|
||||||
|
struct {
|
||||||
|
__u64 reserved1[2];
|
||||||
|
__u64 gscb[4];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
|
#define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
|
||||||
|
|
|
@ -313,7 +313,7 @@
|
||||||
#define __NR_copy_file_range 375
|
#define __NR_copy_file_range 375
|
||||||
#define __NR_preadv2 376
|
#define __NR_preadv2 376
|
||||||
#define __NR_pwritev2 377
|
#define __NR_pwritev2 377
|
||||||
/* Number 378 is reserved for guarded storage */
|
#define __NR_s390_guarded_storage 378
|
||||||
#define __NR_statx 379
|
#define __NR_statx 379
|
||||||
#define NR_syscalls 380
|
#define NR_syscalls 380
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
|
||||||
obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
|
obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
|
||||||
obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
|
obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
|
||||||
obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
|
obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
|
||||||
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o
|
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o
|
||||||
obj-y += entry.o reipl.o relocate_kernel.o
|
obj-y += entry.o reipl.o relocate_kernel.o
|
||||||
|
|
||||||
extra-y += head.o head64.o vmlinux.lds
|
extra-y += head.o head64.o vmlinux.lds
|
||||||
|
|
|
@ -175,7 +175,7 @@ int main(void)
|
||||||
/* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
|
/* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
|
||||||
OFFSET(__LC_DUMP_REIPL, lowcore, ipib);
|
OFFSET(__LC_DUMP_REIPL, lowcore, ipib);
|
||||||
/* hardware defined lowcore locations 0x1000 - 0x18ff */
|
/* hardware defined lowcore locations 0x1000 - 0x18ff */
|
||||||
OFFSET(__LC_VX_SAVE_AREA_ADDR, lowcore, vector_save_area_addr);
|
OFFSET(__LC_MCESAD, lowcore, mcesad);
|
||||||
OFFSET(__LC_EXT_PARAMS2, lowcore, ext_params2);
|
OFFSET(__LC_EXT_PARAMS2, lowcore, ext_params2);
|
||||||
OFFSET(__LC_FPREGS_SAVE_AREA, lowcore, floating_pt_save_area);
|
OFFSET(__LC_FPREGS_SAVE_AREA, lowcore, floating_pt_save_area);
|
||||||
OFFSET(__LC_GPREGS_SAVE_AREA, lowcore, gpregs_save_area);
|
OFFSET(__LC_GPREGS_SAVE_AREA, lowcore, gpregs_save_area);
|
||||||
|
|
|
@ -178,4 +178,5 @@ COMPAT_SYSCALL_WRAP3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
|
||||||
COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len);
|
COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len);
|
||||||
COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
|
COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
|
||||||
COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
|
COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
|
||||||
|
COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
|
||||||
COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
|
COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
|
||||||
|
|
|
@ -358,6 +358,8 @@ static __init void detect_machine_facilities(void)
|
||||||
S390_lowcore.machine_flags |= MACHINE_FLAG_NX;
|
S390_lowcore.machine_flags |= MACHINE_FLAG_NX;
|
||||||
__ctl_set_bit(0, 20);
|
__ctl_set_bit(0, 20);
|
||||||
}
|
}
|
||||||
|
if (test_facility(133))
|
||||||
|
S390_lowcore.machine_flags |= MACHINE_FLAG_GS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void save_vector_registers(void)
|
static inline void save_vector_registers(void)
|
||||||
|
|
|
@ -47,7 +47,7 @@ STACK_SIZE = 1 << STACK_SHIFT
|
||||||
STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
|
STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
|
||||||
|
|
||||||
_TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
|
_TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
|
||||||
_TIF_UPROBE)
|
_TIF_UPROBE | _TIF_GUARDED_STORAGE)
|
||||||
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
|
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
|
||||||
_TIF_SYSCALL_TRACEPOINT)
|
_TIF_SYSCALL_TRACEPOINT)
|
||||||
_CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \
|
_CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \
|
||||||
|
@ -332,6 +332,8 @@ ENTRY(system_call)
|
||||||
TSTMSK __TI_flags(%r12),_TIF_UPROBE
|
TSTMSK __TI_flags(%r12),_TIF_UPROBE
|
||||||
jo .Lsysc_uprobe_notify
|
jo .Lsysc_uprobe_notify
|
||||||
#endif
|
#endif
|
||||||
|
TSTMSK __TI_flags(%r12),_TIF_GUARDED_STORAGE
|
||||||
|
jo .Lsysc_guarded_storage
|
||||||
TSTMSK __PT_FLAGS(%r11),_PIF_PER_TRAP
|
TSTMSK __PT_FLAGS(%r11),_PIF_PER_TRAP
|
||||||
jo .Lsysc_singlestep
|
jo .Lsysc_singlestep
|
||||||
TSTMSK __TI_flags(%r12),_TIF_SIGPENDING
|
TSTMSK __TI_flags(%r12),_TIF_SIGPENDING
|
||||||
|
@ -408,6 +410,14 @@ ENTRY(system_call)
|
||||||
jg uprobe_notify_resume
|
jg uprobe_notify_resume
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# _TIF_GUARDED_STORAGE is set, call guarded_storage_load
|
||||||
|
#
|
||||||
|
.Lsysc_guarded_storage:
|
||||||
|
lgr %r2,%r11 # pass pointer to pt_regs
|
||||||
|
larl %r14,.Lsysc_return
|
||||||
|
jg gs_load_bc_cb
|
||||||
|
|
||||||
#
|
#
|
||||||
# _PIF_PER_TRAP is set, call do_per_trap
|
# _PIF_PER_TRAP is set, call do_per_trap
|
||||||
#
|
#
|
||||||
|
@ -663,6 +673,8 @@ ENTRY(io_int_handler)
|
||||||
jo .Lio_sigpending
|
jo .Lio_sigpending
|
||||||
TSTMSK __TI_flags(%r12),_TIF_NOTIFY_RESUME
|
TSTMSK __TI_flags(%r12),_TIF_NOTIFY_RESUME
|
||||||
jo .Lio_notify_resume
|
jo .Lio_notify_resume
|
||||||
|
TSTMSK __TI_flags(%r12),_TIF_GUARDED_STORAGE
|
||||||
|
jo .Lio_guarded_storage
|
||||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
||||||
jo .Lio_vxrs
|
jo .Lio_vxrs
|
||||||
TSTMSK __LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY)
|
TSTMSK __LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY)
|
||||||
|
@ -696,6 +708,18 @@ ENTRY(io_int_handler)
|
||||||
larl %r14,.Lio_return
|
larl %r14,.Lio_return
|
||||||
jg load_fpu_regs
|
jg load_fpu_regs
|
||||||
|
|
||||||
|
#
|
||||||
|
# _TIF_GUARDED_STORAGE is set, call guarded_storage_load
|
||||||
|
#
|
||||||
|
.Lio_guarded_storage:
|
||||||
|
# TRACE_IRQS_ON already done at .Lio_return
|
||||||
|
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||||
|
lgr %r2,%r11 # pass pointer to pt_regs
|
||||||
|
brasl %r14,gs_load_bc_cb
|
||||||
|
ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
|
||||||
|
TRACE_IRQS_OFF
|
||||||
|
j .Lio_return
|
||||||
|
|
||||||
#
|
#
|
||||||
# _TIF_NEED_RESCHED is set, call schedule
|
# _TIF_NEED_RESCHED is set, call schedule
|
||||||
#
|
#
|
||||||
|
|
|
@ -74,12 +74,14 @@ long sys_sigreturn(void);
|
||||||
|
|
||||||
long sys_s390_personality(unsigned int personality);
|
long sys_s390_personality(unsigned int personality);
|
||||||
long sys_s390_runtime_instr(int command, int signum);
|
long sys_s390_runtime_instr(int command, int signum);
|
||||||
|
long sys_s390_guarded_storage(int command, struct gs_cb __user *);
|
||||||
long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
|
long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
|
||||||
long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
|
long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
|
||||||
|
|
||||||
DECLARE_PER_CPU(u64, mt_cycles[8]);
|
DECLARE_PER_CPU(u64, mt_cycles[8]);
|
||||||
|
|
||||||
void verify_facilities(void);
|
void verify_facilities(void);
|
||||||
|
void gs_load_bc_cb(struct pt_regs *regs);
|
||||||
void set_fs_fixup(void);
|
void set_fs_fixup(void);
|
||||||
|
|
||||||
#endif /* _ENTRY_H */
|
#endif /* _ENTRY_H */
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2016
|
||||||
|
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <linux/signal.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <asm/guarded_storage.h>
|
||||||
|
#include "entry.h"
|
||||||
|
|
||||||
|
void exit_thread_gs(void)
|
||||||
|
{
|
||||||
|
kfree(current->thread.gs_cb);
|
||||||
|
kfree(current->thread.gs_bc_cb);
|
||||||
|
current->thread.gs_cb = current->thread.gs_bc_cb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gs_enable(void)
|
||||||
|
{
|
||||||
|
struct gs_cb *gs_cb;
|
||||||
|
|
||||||
|
if (!current->thread.gs_cb) {
|
||||||
|
gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
|
||||||
|
if (!gs_cb)
|
||||||
|
return -ENOMEM;
|
||||||
|
gs_cb->gsd = 25;
|
||||||
|
preempt_disable();
|
||||||
|
__ctl_set_bit(2, 4);
|
||||||
|
load_gs_cb(gs_cb);
|
||||||
|
current->thread.gs_cb = gs_cb;
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gs_disable(void)
|
||||||
|
{
|
||||||
|
if (current->thread.gs_cb) {
|
||||||
|
preempt_disable();
|
||||||
|
kfree(current->thread.gs_cb);
|
||||||
|
current->thread.gs_cb = NULL;
|
||||||
|
__ctl_clear_bit(2, 4);
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gs_set_bc_cb(struct gs_cb __user *u_gs_cb)
|
||||||
|
{
|
||||||
|
struct gs_cb *gs_cb;
|
||||||
|
|
||||||
|
gs_cb = current->thread.gs_bc_cb;
|
||||||
|
if (!gs_cb) {
|
||||||
|
gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
|
||||||
|
if (!gs_cb)
|
||||||
|
return -ENOMEM;
|
||||||
|
current->thread.gs_bc_cb = gs_cb;
|
||||||
|
}
|
||||||
|
if (copy_from_user(gs_cb, u_gs_cb, sizeof(*gs_cb)))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gs_clear_bc_cb(void)
|
||||||
|
{
|
||||||
|
struct gs_cb *gs_cb;
|
||||||
|
|
||||||
|
gs_cb = current->thread.gs_bc_cb;
|
||||||
|
current->thread.gs_bc_cb = NULL;
|
||||||
|
kfree(gs_cb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gs_load_bc_cb(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct gs_cb *gs_cb;
|
||||||
|
|
||||||
|
preempt_disable();
|
||||||
|
clear_thread_flag(TIF_GUARDED_STORAGE);
|
||||||
|
gs_cb = current->thread.gs_bc_cb;
|
||||||
|
if (gs_cb) {
|
||||||
|
kfree(current->thread.gs_cb);
|
||||||
|
current->thread.gs_bc_cb = NULL;
|
||||||
|
__ctl_set_bit(2, 4);
|
||||||
|
load_gs_cb(gs_cb);
|
||||||
|
current->thread.gs_cb = gs_cb;
|
||||||
|
}
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gs_broadcast(void)
|
||||||
|
{
|
||||||
|
struct task_struct *sibling;
|
||||||
|
|
||||||
|
read_lock(&tasklist_lock);
|
||||||
|
for_each_thread(current, sibling) {
|
||||||
|
if (!sibling->thread.gs_bc_cb)
|
||||||
|
continue;
|
||||||
|
if (test_and_set_tsk_thread_flag(sibling, TIF_GUARDED_STORAGE))
|
||||||
|
kick_process(sibling);
|
||||||
|
}
|
||||||
|
read_unlock(&tasklist_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCALL_DEFINE2(s390_guarded_storage, int, command,
|
||||||
|
struct gs_cb __user *, gs_cb)
|
||||||
|
{
|
||||||
|
if (!MACHINE_HAS_GS)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
switch (command) {
|
||||||
|
case GS_ENABLE:
|
||||||
|
return gs_enable();
|
||||||
|
case GS_DISABLE:
|
||||||
|
return gs_disable();
|
||||||
|
case GS_SET_BC_CB:
|
||||||
|
return gs_set_bc_cb(gs_cb);
|
||||||
|
case GS_CLEAR_BC_CB:
|
||||||
|
return gs_clear_bc_cb();
|
||||||
|
case GS_BROADCAST:
|
||||||
|
return gs_broadcast();
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/os_info.h>
|
#include <asm/os_info.h>
|
||||||
#include <asm/switch_to.h>
|
#include <asm/switch_to.h>
|
||||||
|
#include <asm/nmi.h>
|
||||||
|
|
||||||
typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
|
typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
|
||||||
|
|
||||||
|
@ -102,6 +103,8 @@ static void __do_machine_kdump(void *image)
|
||||||
*/
|
*/
|
||||||
static noinline void __machine_kdump(void *image)
|
static noinline void __machine_kdump(void *image)
|
||||||
{
|
{
|
||||||
|
struct mcesa *mcesa;
|
||||||
|
unsigned long cr2_old, cr2_new;
|
||||||
int this_cpu, cpu;
|
int this_cpu, cpu;
|
||||||
|
|
||||||
lgr_info_log();
|
lgr_info_log();
|
||||||
|
@ -114,8 +117,16 @@ static noinline void __machine_kdump(void *image)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Store status of the boot CPU */
|
/* Store status of the boot CPU */
|
||||||
|
mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
|
||||||
if (MACHINE_HAS_VX)
|
if (MACHINE_HAS_VX)
|
||||||
save_vx_regs((void *) &S390_lowcore.vector_save_area);
|
save_vx_regs((__vector128 *) mcesa->vector_save_area);
|
||||||
|
if (MACHINE_HAS_GS) {
|
||||||
|
__ctl_store(cr2_old, 2, 2);
|
||||||
|
cr2_new = cr2_old | (1UL << 4);
|
||||||
|
__ctl_load(cr2_new, 2, 2);
|
||||||
|
save_gs_cb((struct gs_cb *) mcesa->guarded_storage_save_area);
|
||||||
|
__ctl_load(cr2_old, 2, 2);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* To create a good backchain for this CPU in the dump store_status
|
* To create a good backchain for this CPU in the dump store_status
|
||||||
* is passed the address of a function. The address is saved into
|
* is passed the address of a function. The address is saved into
|
||||||
|
|
|
@ -106,6 +106,7 @@ static int notrace s390_validate_registers(union mci mci, int umode)
|
||||||
int kill_task;
|
int kill_task;
|
||||||
u64 zero;
|
u64 zero;
|
||||||
void *fpt_save_area;
|
void *fpt_save_area;
|
||||||
|
struct mcesa *mcesa;
|
||||||
|
|
||||||
kill_task = 0;
|
kill_task = 0;
|
||||||
zero = 0;
|
zero = 0;
|
||||||
|
@ -165,6 +166,7 @@ static int notrace s390_validate_registers(union mci mci, int umode)
|
||||||
: : "Q" (S390_lowcore.fpt_creg_save_area));
|
: : "Q" (S390_lowcore.fpt_creg_save_area));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
|
||||||
if (!MACHINE_HAS_VX) {
|
if (!MACHINE_HAS_VX) {
|
||||||
/* Validate floating point registers */
|
/* Validate floating point registers */
|
||||||
asm volatile(
|
asm volatile(
|
||||||
|
@ -209,8 +211,8 @@ static int notrace s390_validate_registers(union mci mci, int umode)
|
||||||
" la 1,%0\n"
|
" la 1,%0\n"
|
||||||
" .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
|
" .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
|
||||||
" .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
|
" .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
|
||||||
: : "Q" (*(struct vx_array *)
|
: : "Q" (*(struct vx_array *) mcesa->vector_save_area)
|
||||||
&S390_lowcore.vector_save_area) : "1");
|
: "1");
|
||||||
__ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
|
__ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
|
||||||
}
|
}
|
||||||
/* Validate access registers */
|
/* Validate access registers */
|
||||||
|
@ -224,6 +226,19 @@ static int notrace s390_validate_registers(union mci mci, int umode)
|
||||||
*/
|
*/
|
||||||
kill_task = 1;
|
kill_task = 1;
|
||||||
}
|
}
|
||||||
|
/* Validate guarded storage registers */
|
||||||
|
if (MACHINE_HAS_GS && (S390_lowcore.cregs_save_area[2] & (1UL << 4))) {
|
||||||
|
if (!mci.gs)
|
||||||
|
/*
|
||||||
|
* Guarded storage register can't be restored and
|
||||||
|
* the current processes uses guarded storage.
|
||||||
|
* It has to be terminated.
|
||||||
|
*/
|
||||||
|
kill_task = 1;
|
||||||
|
else
|
||||||
|
load_gs_cb((struct gs_cb *)
|
||||||
|
mcesa->guarded_storage_save_area);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* We don't even try to validate the TOD register, since we simply
|
* We don't even try to validate the TOD register, since we simply
|
||||||
* can't write something sensible into that register.
|
* can't write something sensible into that register.
|
||||||
|
|
|
@ -73,8 +73,10 @@ extern void kernel_thread_starter(void);
|
||||||
*/
|
*/
|
||||||
void exit_thread(struct task_struct *tsk)
|
void exit_thread(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
if (tsk == current)
|
if (tsk == current) {
|
||||||
exit_thread_runtime_instr();
|
exit_thread_runtime_instr();
|
||||||
|
exit_thread_gs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush_thread(void)
|
void flush_thread(void)
|
||||||
|
@ -159,6 +161,9 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp,
|
||||||
/* Don't copy runtime instrumentation info */
|
/* Don't copy runtime instrumentation info */
|
||||||
p->thread.ri_cb = NULL;
|
p->thread.ri_cb = NULL;
|
||||||
frame->childregs.psw.mask &= ~PSW_MASK_RI;
|
frame->childregs.psw.mask &= ~PSW_MASK_RI;
|
||||||
|
/* Don't copy guarded storage control block */
|
||||||
|
p->thread.gs_cb = NULL;
|
||||||
|
p->thread.gs_bc_cb = NULL;
|
||||||
|
|
||||||
/* Set a new TLS ? */
|
/* Set a new TLS ? */
|
||||||
if (clone_flags & CLONE_SETTLS) {
|
if (clone_flags & CLONE_SETTLS) {
|
||||||
|
|
|
@ -95,7 +95,7 @@ static void show_cpu_summary(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
static const char *hwcap_str[] = {
|
static const char *hwcap_str[] = {
|
||||||
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
|
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
|
||||||
"edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe"
|
"edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe", "gs"
|
||||||
};
|
};
|
||||||
static const char * const int_hwcap_str[] = {
|
static const char * const int_hwcap_str[] = {
|
||||||
"sie"
|
"sie"
|
||||||
|
|
|
@ -44,30 +44,42 @@ void update_cr_regs(struct task_struct *task)
|
||||||
struct pt_regs *regs = task_pt_regs(task);
|
struct pt_regs *regs = task_pt_regs(task);
|
||||||
struct thread_struct *thread = &task->thread;
|
struct thread_struct *thread = &task->thread;
|
||||||
struct per_regs old, new;
|
struct per_regs old, new;
|
||||||
|
unsigned long cr0_old, cr0_new;
|
||||||
|
unsigned long cr2_old, cr2_new;
|
||||||
|
int cr0_changed, cr2_changed;
|
||||||
|
|
||||||
|
__ctl_store(cr0_old, 0, 0);
|
||||||
|
__ctl_store(cr2_old, 2, 2);
|
||||||
|
cr0_new = cr0_old;
|
||||||
|
cr2_new = cr2_old;
|
||||||
/* Take care of the enable/disable of transactional execution. */
|
/* Take care of the enable/disable of transactional execution. */
|
||||||
if (MACHINE_HAS_TE) {
|
if (MACHINE_HAS_TE) {
|
||||||
unsigned long cr, cr_new;
|
|
||||||
|
|
||||||
__ctl_store(cr, 0, 0);
|
|
||||||
/* Set or clear transaction execution TXC bit 8. */
|
/* Set or clear transaction execution TXC bit 8. */
|
||||||
cr_new = cr | (1UL << 55);
|
cr0_new |= (1UL << 55);
|
||||||
if (task->thread.per_flags & PER_FLAG_NO_TE)
|
if (task->thread.per_flags & PER_FLAG_NO_TE)
|
||||||
cr_new &= ~(1UL << 55);
|
cr0_new &= ~(1UL << 55);
|
||||||
if (cr_new != cr)
|
|
||||||
__ctl_load(cr_new, 0, 0);
|
|
||||||
/* Set or clear transaction execution TDC bits 62 and 63. */
|
/* Set or clear transaction execution TDC bits 62 and 63. */
|
||||||
__ctl_store(cr, 2, 2);
|
cr2_new &= ~3UL;
|
||||||
cr_new = cr & ~3UL;
|
|
||||||
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
|
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
|
||||||
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
|
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
|
||||||
cr_new |= 1UL;
|
cr2_new |= 1UL;
|
||||||
else
|
else
|
||||||
cr_new |= 2UL;
|
cr2_new |= 2UL;
|
||||||
}
|
}
|
||||||
if (cr_new != cr)
|
|
||||||
__ctl_load(cr_new, 2, 2);
|
|
||||||
}
|
}
|
||||||
|
/* Take care of enable/disable of guarded storage. */
|
||||||
|
if (MACHINE_HAS_GS) {
|
||||||
|
cr2_new &= ~(1UL << 4);
|
||||||
|
if (task->thread.gs_cb)
|
||||||
|
cr2_new |= (1UL << 4);
|
||||||
|
}
|
||||||
|
/* Load control register 0/2 iff changed */
|
||||||
|
cr0_changed = cr0_new != cr0_old;
|
||||||
|
cr2_changed = cr2_new != cr2_old;
|
||||||
|
if (cr0_changed)
|
||||||
|
__ctl_load(cr0_new, 0, 0);
|
||||||
|
if (cr2_changed)
|
||||||
|
__ctl_load(cr2_new, 2, 2);
|
||||||
/* Copy user specified PER registers */
|
/* Copy user specified PER registers */
|
||||||
new.control = thread->per_user.control;
|
new.control = thread->per_user.control;
|
||||||
new.start = thread->per_user.start;
|
new.start = thread->per_user.start;
|
||||||
|
@ -1137,6 +1149,36 @@ static int s390_system_call_set(struct task_struct *target,
|
||||||
data, 0, sizeof(unsigned int));
|
data, 0, sizeof(unsigned int));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int s390_gs_cb_get(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
void *kbuf, void __user *ubuf)
|
||||||
|
{
|
||||||
|
struct gs_cb *data = target->thread.gs_cb;
|
||||||
|
|
||||||
|
if (!MACHINE_HAS_GS)
|
||||||
|
return -ENODEV;
|
||||||
|
if (!data)
|
||||||
|
return -ENODATA;
|
||||||
|
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||||
|
data, 0, sizeof(struct gs_cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s390_gs_cb_set(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
const void *kbuf, const void __user *ubuf)
|
||||||
|
{
|
||||||
|
struct gs_cb *data = target->thread.gs_cb;
|
||||||
|
|
||||||
|
if (!MACHINE_HAS_GS)
|
||||||
|
return -ENODEV;
|
||||||
|
if (!data)
|
||||||
|
return -ENODATA;
|
||||||
|
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||||
|
data, 0, sizeof(struct gs_cb));
|
||||||
|
}
|
||||||
|
|
||||||
static const struct user_regset s390_regsets[] = {
|
static const struct user_regset s390_regsets[] = {
|
||||||
{
|
{
|
||||||
.core_note_type = NT_PRSTATUS,
|
.core_note_type = NT_PRSTATUS,
|
||||||
|
@ -1194,6 +1236,14 @@ static const struct user_regset s390_regsets[] = {
|
||||||
.get = s390_vxrs_high_get,
|
.get = s390_vxrs_high_get,
|
||||||
.set = s390_vxrs_high_set,
|
.set = s390_vxrs_high_set,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.core_note_type = NT_S390_GS_CB,
|
||||||
|
.n = sizeof(struct gs_cb) / sizeof(__u64),
|
||||||
|
.size = sizeof(__u64),
|
||||||
|
.align = sizeof(__u64),
|
||||||
|
.get = s390_gs_cb_get,
|
||||||
|
.set = s390_gs_cb_set,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct user_regset_view user_s390_view = {
|
static const struct user_regset_view user_s390_view = {
|
||||||
|
@ -1422,6 +1472,14 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||||
.get = s390_compat_regs_high_get,
|
.get = s390_compat_regs_high_get,
|
||||||
.set = s390_compat_regs_high_set,
|
.set = s390_compat_regs_high_set,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.core_note_type = NT_S390_GS_CB,
|
||||||
|
.n = sizeof(struct gs_cb) / sizeof(__u64),
|
||||||
|
.size = sizeof(__u64),
|
||||||
|
.align = sizeof(__u64),
|
||||||
|
.get = s390_gs_cb_get,
|
||||||
|
.set = s390_gs_cb_set,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct user_regset_view user_s390_compat_view = {
|
static const struct user_regset_view user_s390_compat_view = {
|
||||||
|
|
|
@ -339,9 +339,15 @@ static void __init setup_lowcore(void)
|
||||||
lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
|
lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
|
||||||
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
|
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
|
||||||
MAX_FACILITY_BIT/8);
|
MAX_FACILITY_BIT/8);
|
||||||
if (MACHINE_HAS_VX)
|
if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
|
||||||
lc->vector_save_area_addr =
|
unsigned long bits, size;
|
||||||
(unsigned long) &lc->vector_save_area;
|
|
||||||
|
bits = MACHINE_HAS_GS ? 11 : 10;
|
||||||
|
size = 1UL << bits;
|
||||||
|
lc->mcesad = (__u64) memblock_virt_alloc(size, size);
|
||||||
|
if (MACHINE_HAS_GS)
|
||||||
|
lc->mcesad |= bits;
|
||||||
|
}
|
||||||
lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
|
lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
|
||||||
lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
|
lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
|
||||||
lc->async_enter_timer = S390_lowcore.async_enter_timer;
|
lc->async_enter_timer = S390_lowcore.async_enter_timer;
|
||||||
|
@ -779,6 +785,12 @@ static int __init setup_hwcaps(void)
|
||||||
elf_hwcap |= HWCAP_S390_VXRS_BCD;
|
elf_hwcap |= HWCAP_S390_VXRS_BCD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guarded storage support HWCAP_S390_GS is bit 12.
|
||||||
|
*/
|
||||||
|
if (MACHINE_HAS_GS)
|
||||||
|
elf_hwcap |= HWCAP_S390_GS;
|
||||||
|
|
||||||
get_cpu_id(&cpu_id);
|
get_cpu_id(&cpu_id);
|
||||||
add_device_randomness(&cpu_id, sizeof(cpu_id));
|
add_device_randomness(&cpu_id, sizeof(cpu_id));
|
||||||
switch (cpu_id.machine) {
|
switch (cpu_id.machine) {
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include <asm/os_info.h>
|
#include <asm/os_info.h>
|
||||||
#include <asm/sigp.h>
|
#include <asm/sigp.h>
|
||||||
#include <asm/idle.h>
|
#include <asm/idle.h>
|
||||||
|
#include <asm/nmi.h>
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -78,6 +79,8 @@ struct pcpu {
|
||||||
static u8 boot_core_type;
|
static u8 boot_core_type;
|
||||||
static struct pcpu pcpu_devices[NR_CPUS];
|
static struct pcpu pcpu_devices[NR_CPUS];
|
||||||
|
|
||||||
|
static struct kmem_cache *pcpu_mcesa_cache;
|
||||||
|
|
||||||
unsigned int smp_cpu_mt_shift;
|
unsigned int smp_cpu_mt_shift;
|
||||||
EXPORT_SYMBOL(smp_cpu_mt_shift);
|
EXPORT_SYMBOL(smp_cpu_mt_shift);
|
||||||
|
|
||||||
|
@ -188,8 +191,10 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
|
||||||
static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
||||||
{
|
{
|
||||||
unsigned long async_stack, panic_stack;
|
unsigned long async_stack, panic_stack;
|
||||||
|
unsigned long mcesa_origin, mcesa_bits;
|
||||||
struct lowcore *lc;
|
struct lowcore *lc;
|
||||||
|
|
||||||
|
mcesa_origin = mcesa_bits = 0;
|
||||||
if (pcpu != &pcpu_devices[0]) {
|
if (pcpu != &pcpu_devices[0]) {
|
||||||
pcpu->lowcore = (struct lowcore *)
|
pcpu->lowcore = (struct lowcore *)
|
||||||
__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
|
__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
|
||||||
|
@ -197,20 +202,27 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
||||||
panic_stack = __get_free_page(GFP_KERNEL);
|
panic_stack = __get_free_page(GFP_KERNEL);
|
||||||
if (!pcpu->lowcore || !panic_stack || !async_stack)
|
if (!pcpu->lowcore || !panic_stack || !async_stack)
|
||||||
goto out;
|
goto out;
|
||||||
|
if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
|
||||||
|
mcesa_origin = (unsigned long)
|
||||||
|
kmem_cache_alloc(pcpu_mcesa_cache, GFP_KERNEL);
|
||||||
|
if (!mcesa_origin)
|
||||||
|
goto out;
|
||||||
|
mcesa_bits = MACHINE_HAS_GS ? 11 : 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET;
|
async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET;
|
||||||
panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET;
|
panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET;
|
||||||
|
mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK;
|
||||||
|
mcesa_bits = pcpu->lowcore->mcesad & MCESA_LC_MASK;
|
||||||
}
|
}
|
||||||
lc = pcpu->lowcore;
|
lc = pcpu->lowcore;
|
||||||
memcpy(lc, &S390_lowcore, 512);
|
memcpy(lc, &S390_lowcore, 512);
|
||||||
memset((char *) lc + 512, 0, sizeof(*lc) - 512);
|
memset((char *) lc + 512, 0, sizeof(*lc) - 512);
|
||||||
lc->async_stack = async_stack + ASYNC_FRAME_OFFSET;
|
lc->async_stack = async_stack + ASYNC_FRAME_OFFSET;
|
||||||
lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
|
lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
|
||||||
|
lc->mcesad = mcesa_origin | mcesa_bits;
|
||||||
lc->cpu_nr = cpu;
|
lc->cpu_nr = cpu;
|
||||||
lc->spinlock_lockval = arch_spin_lockval(cpu);
|
lc->spinlock_lockval = arch_spin_lockval(cpu);
|
||||||
if (MACHINE_HAS_VX)
|
|
||||||
lc->vector_save_area_addr =
|
|
||||||
(unsigned long) &lc->vector_save_area;
|
|
||||||
if (vdso_alloc_per_cpu(lc))
|
if (vdso_alloc_per_cpu(lc))
|
||||||
goto out;
|
goto out;
|
||||||
lowcore_ptr[cpu] = lc;
|
lowcore_ptr[cpu] = lc;
|
||||||
|
@ -218,6 +230,9 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
if (pcpu != &pcpu_devices[0]) {
|
if (pcpu != &pcpu_devices[0]) {
|
||||||
|
if (mcesa_origin)
|
||||||
|
kmem_cache_free(pcpu_mcesa_cache,
|
||||||
|
(void *) mcesa_origin);
|
||||||
free_page(panic_stack);
|
free_page(panic_stack);
|
||||||
free_pages(async_stack, ASYNC_ORDER);
|
free_pages(async_stack, ASYNC_ORDER);
|
||||||
free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
|
free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
|
||||||
|
@ -229,11 +244,17 @@ out:
|
||||||
|
|
||||||
static void pcpu_free_lowcore(struct pcpu *pcpu)
|
static void pcpu_free_lowcore(struct pcpu *pcpu)
|
||||||
{
|
{
|
||||||
|
unsigned long mcesa_origin;
|
||||||
|
|
||||||
pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
|
pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
|
||||||
lowcore_ptr[pcpu - pcpu_devices] = NULL;
|
lowcore_ptr[pcpu - pcpu_devices] = NULL;
|
||||||
vdso_free_per_cpu(pcpu->lowcore);
|
vdso_free_per_cpu(pcpu->lowcore);
|
||||||
if (pcpu == &pcpu_devices[0])
|
if (pcpu == &pcpu_devices[0])
|
||||||
return;
|
return;
|
||||||
|
if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
|
||||||
|
mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK;
|
||||||
|
kmem_cache_free(pcpu_mcesa_cache, (void *) mcesa_origin);
|
||||||
|
}
|
||||||
free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET);
|
free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET);
|
||||||
free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER);
|
free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER);
|
||||||
free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
|
free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
|
||||||
|
@ -550,9 +571,11 @@ int smp_store_status(int cpu)
|
||||||
if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS,
|
if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS,
|
||||||
pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (!MACHINE_HAS_VX)
|
if (!MACHINE_HAS_VX && !MACHINE_HAS_GS)
|
||||||
return 0;
|
return 0;
|
||||||
pa = __pa(pcpu->lowcore->vector_save_area_addr);
|
pa = __pa(pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK);
|
||||||
|
if (MACHINE_HAS_GS)
|
||||||
|
pa |= pcpu->lowcore->mcesad & MCESA_LC_MASK;
|
||||||
if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
|
if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
|
||||||
pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -897,12 +920,22 @@ void __init smp_fill_possible_mask(void)
|
||||||
|
|
||||||
void __init smp_prepare_cpus(unsigned int max_cpus)
|
void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||||
{
|
{
|
||||||
|
unsigned long size;
|
||||||
|
|
||||||
/* request the 0x1201 emergency signal external interrupt */
|
/* request the 0x1201 emergency signal external interrupt */
|
||||||
if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt))
|
if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt))
|
||||||
panic("Couldn't request external interrupt 0x1201");
|
panic("Couldn't request external interrupt 0x1201");
|
||||||
/* request the 0x1202 external call external interrupt */
|
/* request the 0x1202 external call external interrupt */
|
||||||
if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
|
if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
|
||||||
panic("Couldn't request external interrupt 0x1202");
|
panic("Couldn't request external interrupt 0x1202");
|
||||||
|
/* create slab cache for the machine-check-extended-save-areas */
|
||||||
|
if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
|
||||||
|
size = 1UL << (MACHINE_HAS_GS ? 11 : 10);
|
||||||
|
pcpu_mcesa_cache = kmem_cache_create("nmi_save_areas",
|
||||||
|
size, size, 0, NULL);
|
||||||
|
if (!pcpu_mcesa_cache)
|
||||||
|
panic("Couldn't create nmi save area cache");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init smp_prepare_boot_cpu(void)
|
void __init smp_prepare_boot_cpu(void)
|
||||||
|
|
|
@ -386,5 +386,5 @@ SYSCALL(sys_mlock2,compat_sys_mlock2)
|
||||||
SYSCALL(sys_copy_file_range,compat_sys_copy_file_range) /* 375 */
|
SYSCALL(sys_copy_file_range,compat_sys_copy_file_range) /* 375 */
|
||||||
SYSCALL(sys_preadv2,compat_sys_preadv2)
|
SYSCALL(sys_preadv2,compat_sys_preadv2)
|
||||||
SYSCALL(sys_pwritev2,compat_sys_pwritev2)
|
SYSCALL(sys_pwritev2,compat_sys_pwritev2)
|
||||||
NI_SYSCALL
|
SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */
|
||||||
SYSCALL(sys_statx,compat_sys_statx)
|
SYSCALL(sys_statx,compat_sys_statx)
|
||||||
|
|
|
@ -262,7 +262,7 @@ struct aste {
|
||||||
|
|
||||||
int ipte_lock_held(struct kvm_vcpu *vcpu)
|
int ipte_lock_held(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (vcpu->arch.sie_block->eca & 1) {
|
if (vcpu->arch.sie_block->eca & ECA_SII) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
read_lock(&vcpu->kvm->arch.sca_lock);
|
read_lock(&vcpu->kvm->arch.sca_lock);
|
||||||
|
@ -361,7 +361,7 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
void ipte_lock(struct kvm_vcpu *vcpu)
|
void ipte_lock(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (vcpu->arch.sie_block->eca & 1)
|
if (vcpu->arch.sie_block->eca & ECA_SII)
|
||||||
ipte_lock_siif(vcpu);
|
ipte_lock_siif(vcpu);
|
||||||
else
|
else
|
||||||
ipte_lock_simple(vcpu);
|
ipte_lock_simple(vcpu);
|
||||||
|
@ -369,7 +369,7 @@ void ipte_lock(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
void ipte_unlock(struct kvm_vcpu *vcpu)
|
void ipte_unlock(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (vcpu->arch.sie_block->eca & 1)
|
if (vcpu->arch.sie_block->eca & ECA_SII)
|
||||||
ipte_unlock_siif(vcpu);
|
ipte_unlock_siif(vcpu);
|
||||||
else
|
else
|
||||||
ipte_unlock_simple(vcpu);
|
ipte_unlock_simple(vcpu);
|
||||||
|
|
|
@ -35,6 +35,7 @@ static const intercept_handler_t instruction_handlers[256] = {
|
||||||
[0xb6] = kvm_s390_handle_stctl,
|
[0xb6] = kvm_s390_handle_stctl,
|
||||||
[0xb7] = kvm_s390_handle_lctl,
|
[0xb7] = kvm_s390_handle_lctl,
|
||||||
[0xb9] = kvm_s390_handle_b9,
|
[0xb9] = kvm_s390_handle_b9,
|
||||||
|
[0xe3] = kvm_s390_handle_e3,
|
||||||
[0xe5] = kvm_s390_handle_e5,
|
[0xe5] = kvm_s390_handle_e5,
|
||||||
[0xeb] = kvm_s390_handle_eb,
|
[0xeb] = kvm_s390_handle_eb,
|
||||||
};
|
};
|
||||||
|
@ -368,8 +369,7 @@ static int handle_operexc(struct kvm_vcpu *vcpu)
|
||||||
trace_kvm_s390_handle_operexc(vcpu, vcpu->arch.sie_block->ipa,
|
trace_kvm_s390_handle_operexc(vcpu, vcpu->arch.sie_block->ipa,
|
||||||
vcpu->arch.sie_block->ipb);
|
vcpu->arch.sie_block->ipb);
|
||||||
|
|
||||||
if (vcpu->arch.sie_block->ipa == 0xb256 &&
|
if (vcpu->arch.sie_block->ipa == 0xb256)
|
||||||
test_kvm_facility(vcpu->kvm, 74))
|
|
||||||
return handle_sthyi(vcpu);
|
return handle_sthyi(vcpu);
|
||||||
|
|
||||||
if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0)
|
if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0)
|
||||||
|
@ -404,26 +404,26 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
switch (vcpu->arch.sie_block->icptcode) {
|
switch (vcpu->arch.sie_block->icptcode) {
|
||||||
case 0x10:
|
case ICPT_EXTREQ:
|
||||||
case 0x18:
|
case ICPT_IOREQ:
|
||||||
return handle_noop(vcpu);
|
return handle_noop(vcpu);
|
||||||
case 0x04:
|
case ICPT_INST:
|
||||||
rc = handle_instruction(vcpu);
|
rc = handle_instruction(vcpu);
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case ICPT_PROGI:
|
||||||
return handle_prog(vcpu);
|
return handle_prog(vcpu);
|
||||||
case 0x14:
|
case ICPT_EXTINT:
|
||||||
return handle_external_interrupt(vcpu);
|
return handle_external_interrupt(vcpu);
|
||||||
case 0x1c:
|
case ICPT_WAIT:
|
||||||
return kvm_s390_handle_wait(vcpu);
|
return kvm_s390_handle_wait(vcpu);
|
||||||
case 0x20:
|
case ICPT_VALIDITY:
|
||||||
return handle_validity(vcpu);
|
return handle_validity(vcpu);
|
||||||
case 0x28:
|
case ICPT_STOP:
|
||||||
return handle_stop(vcpu);
|
return handle_stop(vcpu);
|
||||||
case 0x2c:
|
case ICPT_OPEREXC:
|
||||||
rc = handle_operexc(vcpu);
|
rc = handle_operexc(vcpu);
|
||||||
break;
|
break;
|
||||||
case 0x38:
|
case ICPT_PARTEXEC:
|
||||||
rc = handle_partial_execution(vcpu);
|
rc = handle_partial_execution(vcpu);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -410,6 +410,7 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_s390_mchk_info *mchk)
|
struct kvm_s390_mchk_info *mchk)
|
||||||
{
|
{
|
||||||
unsigned long ext_sa_addr;
|
unsigned long ext_sa_addr;
|
||||||
|
unsigned long lc;
|
||||||
freg_t fprs[NUM_FPRS];
|
freg_t fprs[NUM_FPRS];
|
||||||
union mci mci;
|
union mci mci;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -420,10 +421,30 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
|
||||||
save_access_regs(vcpu->run->s.regs.acrs);
|
save_access_regs(vcpu->run->s.regs.acrs);
|
||||||
|
|
||||||
/* Extended save area */
|
/* Extended save area */
|
||||||
rc = read_guest_lc(vcpu, __LC_VX_SAVE_AREA_ADDR, &ext_sa_addr,
|
rc = read_guest_lc(vcpu, __LC_MCESAD, &ext_sa_addr,
|
||||||
sizeof(unsigned long));
|
sizeof(unsigned long));
|
||||||
/* Only bits 0-53 are used for address formation */
|
/* Only bits 0 through 63-LC are used for address formation */
|
||||||
ext_sa_addr &= ~0x3ffUL;
|
lc = ext_sa_addr & MCESA_LC_MASK;
|
||||||
|
if (test_kvm_facility(vcpu->kvm, 133)) {
|
||||||
|
switch (lc) {
|
||||||
|
case 0:
|
||||||
|
case 10:
|
||||||
|
ext_sa_addr &= ~0x3ffUL;
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
ext_sa_addr &= ~0x7ffUL;
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
ext_sa_addr &= ~0xfffUL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ext_sa_addr = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ext_sa_addr &= ~0x3ffUL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) {
|
if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) {
|
||||||
if (write_guest_abs(vcpu, ext_sa_addr, vcpu->run->s.regs.vrs,
|
if (write_guest_abs(vcpu, ext_sa_addr, vcpu->run->s.regs.vrs,
|
||||||
512))
|
512))
|
||||||
|
@ -431,6 +452,14 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
|
||||||
} else {
|
} else {
|
||||||
mci.vr = 0;
|
mci.vr = 0;
|
||||||
}
|
}
|
||||||
|
if (!rc && mci.gs && ext_sa_addr && test_kvm_facility(vcpu->kvm, 133)
|
||||||
|
&& (lc == 11 || lc == 12)) {
|
||||||
|
if (write_guest_abs(vcpu, ext_sa_addr + 1024,
|
||||||
|
&vcpu->run->s.regs.gscb, 32))
|
||||||
|
mci.gs = 0;
|
||||||
|
} else {
|
||||||
|
mci.gs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* General interruption information */
|
/* General interruption information */
|
||||||
rc |= put_guest_lc(vcpu, 1, (u8 __user *) __LC_AR_MODE_ID);
|
rc |= put_guest_lc(vcpu, 1, (u8 __user *) __LC_AR_MODE_ID);
|
||||||
|
@ -1968,6 +1997,8 @@ static int register_io_adapter(struct kvm_device *dev,
|
||||||
adapter->maskable = adapter_info.maskable;
|
adapter->maskable = adapter_info.maskable;
|
||||||
adapter->masked = false;
|
adapter->masked = false;
|
||||||
adapter->swap = adapter_info.swap;
|
adapter->swap = adapter_info.swap;
|
||||||
|
adapter->suppressible = (adapter_info.flags) &
|
||||||
|
KVM_S390_ADAPTER_SUPPRESSIBLE;
|
||||||
dev->kvm->arch.adapters[adapter->id] = adapter;
|
dev->kvm->arch.adapters[adapter->id] = adapter;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2121,6 +2152,87 @@ static int clear_io_irq(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int modify_ais_mode(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
|
||||||
|
struct kvm_s390_ais_req req;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!fi->ais_enabled)
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (req.isc > MAX_ISC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
trace_kvm_s390_modify_ais_mode(req.isc,
|
||||||
|
(fi->simm & AIS_MODE_MASK(req.isc)) ?
|
||||||
|
(fi->nimm & AIS_MODE_MASK(req.isc)) ?
|
||||||
|
2 : KVM_S390_AIS_MODE_SINGLE :
|
||||||
|
KVM_S390_AIS_MODE_ALL, req.mode);
|
||||||
|
|
||||||
|
mutex_lock(&fi->ais_lock);
|
||||||
|
switch (req.mode) {
|
||||||
|
case KVM_S390_AIS_MODE_ALL:
|
||||||
|
fi->simm &= ~AIS_MODE_MASK(req.isc);
|
||||||
|
fi->nimm &= ~AIS_MODE_MASK(req.isc);
|
||||||
|
break;
|
||||||
|
case KVM_S390_AIS_MODE_SINGLE:
|
||||||
|
fi->simm |= AIS_MODE_MASK(req.isc);
|
||||||
|
fi->nimm &= ~AIS_MODE_MASK(req.isc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&fi->ais_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_inject_airq(struct kvm *kvm,
|
||||||
|
struct s390_io_adapter *adapter)
|
||||||
|
{
|
||||||
|
struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
|
||||||
|
struct kvm_s390_interrupt s390int = {
|
||||||
|
.type = KVM_S390_INT_IO(1, 0, 0, 0),
|
||||||
|
.parm = 0,
|
||||||
|
.parm64 = (adapter->isc << 27) | 0x80000000,
|
||||||
|
};
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!fi->ais_enabled || !adapter->suppressible)
|
||||||
|
return kvm_s390_inject_vm(kvm, &s390int);
|
||||||
|
|
||||||
|
mutex_lock(&fi->ais_lock);
|
||||||
|
if (fi->nimm & AIS_MODE_MASK(adapter->isc)) {
|
||||||
|
trace_kvm_s390_airq_suppressed(adapter->id, adapter->isc);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = kvm_s390_inject_vm(kvm, &s390int);
|
||||||
|
if (!ret && (fi->simm & AIS_MODE_MASK(adapter->isc))) {
|
||||||
|
fi->nimm |= AIS_MODE_MASK(adapter->isc);
|
||||||
|
trace_kvm_s390_modify_ais_mode(adapter->isc,
|
||||||
|
KVM_S390_AIS_MODE_SINGLE, 2);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
mutex_unlock(&fi->ais_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int flic_inject_airq(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
unsigned int id = attr->attr;
|
||||||
|
struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
|
||||||
|
|
||||||
|
if (!adapter)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return kvm_s390_inject_airq(kvm, adapter);
|
||||||
|
}
|
||||||
|
|
||||||
static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -2157,6 +2269,12 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
||||||
case KVM_DEV_FLIC_CLEAR_IO_IRQ:
|
case KVM_DEV_FLIC_CLEAR_IO_IRQ:
|
||||||
r = clear_io_irq(dev->kvm, attr);
|
r = clear_io_irq(dev->kvm, attr);
|
||||||
break;
|
break;
|
||||||
|
case KVM_DEV_FLIC_AISM:
|
||||||
|
r = modify_ais_mode(dev->kvm, attr);
|
||||||
|
break;
|
||||||
|
case KVM_DEV_FLIC_AIRQ_INJECT:
|
||||||
|
r = flic_inject_airq(dev->kvm, attr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -2176,6 +2294,8 @@ static int flic_has_attr(struct kvm_device *dev,
|
||||||
case KVM_DEV_FLIC_ADAPTER_REGISTER:
|
case KVM_DEV_FLIC_ADAPTER_REGISTER:
|
||||||
case KVM_DEV_FLIC_ADAPTER_MODIFY:
|
case KVM_DEV_FLIC_ADAPTER_MODIFY:
|
||||||
case KVM_DEV_FLIC_CLEAR_IO_IRQ:
|
case KVM_DEV_FLIC_CLEAR_IO_IRQ:
|
||||||
|
case KVM_DEV_FLIC_AISM:
|
||||||
|
case KVM_DEV_FLIC_AIRQ_INJECT:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
@ -2286,12 +2406,7 @@ static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
|
||||||
ret = adapter_indicators_set(kvm, adapter, &e->adapter);
|
ret = adapter_indicators_set(kvm, adapter, &e->adapter);
|
||||||
up_read(&adapter->maps_lock);
|
up_read(&adapter->maps_lock);
|
||||||
if ((ret > 0) && !adapter->masked) {
|
if ((ret > 0) && !adapter->masked) {
|
||||||
struct kvm_s390_interrupt s390int = {
|
ret = kvm_s390_inject_airq(kvm, adapter);
|
||||||
.type = KVM_S390_INT_IO(1, 0, 0, 0),
|
|
||||||
.parm = 0,
|
|
||||||
.parm64 = (adapter->isc << 27) | 0x80000000,
|
|
||||||
};
|
|
||||||
ret = kvm_s390_inject_vm(kvm, &s390int);
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,6 +380,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||||
case KVM_CAP_S390_SKEYS:
|
case KVM_CAP_S390_SKEYS:
|
||||||
case KVM_CAP_S390_IRQ_STATE:
|
case KVM_CAP_S390_IRQ_STATE:
|
||||||
case KVM_CAP_S390_USER_INSTR0:
|
case KVM_CAP_S390_USER_INSTR0:
|
||||||
|
case KVM_CAP_S390_AIS:
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
case KVM_CAP_S390_MEM_OP:
|
case KVM_CAP_S390_MEM_OP:
|
||||||
|
@ -405,6 +406,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||||
case KVM_CAP_S390_RI:
|
case KVM_CAP_S390_RI:
|
||||||
r = test_facility(64);
|
r = test_facility(64);
|
||||||
break;
|
break;
|
||||||
|
case KVM_CAP_S390_GS:
|
||||||
|
r = test_facility(133);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
r = 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
|
@ -541,6 +545,34 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
|
||||||
VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s",
|
VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s",
|
||||||
r ? "(not available)" : "(success)");
|
r ? "(not available)" : "(success)");
|
||||||
break;
|
break;
|
||||||
|
case KVM_CAP_S390_AIS:
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
if (kvm->created_vcpus) {
|
||||||
|
r = -EBUSY;
|
||||||
|
} else {
|
||||||
|
set_kvm_facility(kvm->arch.model.fac_mask, 72);
|
||||||
|
set_kvm_facility(kvm->arch.model.fac_list, 72);
|
||||||
|
kvm->arch.float_int.ais_enabled = 1;
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
VM_EVENT(kvm, 3, "ENABLE: AIS %s",
|
||||||
|
r ? "(not available)" : "(success)");
|
||||||
|
break;
|
||||||
|
case KVM_CAP_S390_GS:
|
||||||
|
r = -EINVAL;
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
if (atomic_read(&kvm->online_vcpus)) {
|
||||||
|
r = -EBUSY;
|
||||||
|
} else if (test_facility(133)) {
|
||||||
|
set_kvm_facility(kvm->arch.model.fac_mask, 133);
|
||||||
|
set_kvm_facility(kvm->arch.model.fac_list, 133);
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
VM_EVENT(kvm, 3, "ENABLE: CAP_S390_GS %s",
|
||||||
|
r ? "(not available)" : "(success)");
|
||||||
|
break;
|
||||||
case KVM_CAP_S390_USER_STSI:
|
case KVM_CAP_S390_USER_STSI:
|
||||||
VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI");
|
VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI");
|
||||||
kvm->arch.user_stsi = 1;
|
kvm->arch.user_stsi = 1;
|
||||||
|
@ -1498,6 +1530,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
|
|
||||||
kvm_s390_crypto_init(kvm);
|
kvm_s390_crypto_init(kvm);
|
||||||
|
|
||||||
|
mutex_init(&kvm->arch.float_int.ais_lock);
|
||||||
|
kvm->arch.float_int.simm = 0;
|
||||||
|
kvm->arch.float_int.nimm = 0;
|
||||||
|
kvm->arch.float_int.ais_enabled = 0;
|
||||||
spin_lock_init(&kvm->arch.float_int.lock);
|
spin_lock_init(&kvm->arch.float_int.lock);
|
||||||
for (i = 0; i < FIRQ_LIST_COUNT; i++)
|
for (i = 0; i < FIRQ_LIST_COUNT; i++)
|
||||||
INIT_LIST_HEAD(&kvm->arch.float_int.lists[i]);
|
INIT_LIST_HEAD(&kvm->arch.float_int.lists[i]);
|
||||||
|
@ -1646,7 +1682,7 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu)
|
||||||
sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
|
sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
|
||||||
vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
|
vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
|
||||||
vcpu->arch.sie_block->scaol = (__u32)(__u64)sca & ~0x3fU;
|
vcpu->arch.sie_block->scaol = (__u32)(__u64)sca & ~0x3fU;
|
||||||
vcpu->arch.sie_block->ecb2 |= 0x04U;
|
vcpu->arch.sie_block->ecb2 |= ECB2_ESCA;
|
||||||
set_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
|
set_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
|
||||||
} else {
|
} else {
|
||||||
struct bsca_block *sca = vcpu->kvm->arch.sca;
|
struct bsca_block *sca = vcpu->kvm->arch.sca;
|
||||||
|
@ -1700,7 +1736,7 @@ static int sca_switch_to_extended(struct kvm *kvm)
|
||||||
kvm_for_each_vcpu(vcpu_idx, vcpu, kvm) {
|
kvm_for_each_vcpu(vcpu_idx, vcpu, kvm) {
|
||||||
vcpu->arch.sie_block->scaoh = scaoh;
|
vcpu->arch.sie_block->scaoh = scaoh;
|
||||||
vcpu->arch.sie_block->scaol = scaol;
|
vcpu->arch.sie_block->scaol = scaol;
|
||||||
vcpu->arch.sie_block->ecb2 |= 0x04U;
|
vcpu->arch.sie_block->ecb2 |= ECB2_ESCA;
|
||||||
}
|
}
|
||||||
kvm->arch.sca = new_sca;
|
kvm->arch.sca = new_sca;
|
||||||
kvm->arch.use_esca = 1;
|
kvm->arch.use_esca = 1;
|
||||||
|
@ -1749,6 +1785,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
|
||||||
kvm_s390_set_prefix(vcpu, 0);
|
kvm_s390_set_prefix(vcpu, 0);
|
||||||
if (test_kvm_facility(vcpu->kvm, 64))
|
if (test_kvm_facility(vcpu->kvm, 64))
|
||||||
vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
|
vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
|
||||||
|
if (test_kvm_facility(vcpu->kvm, 133))
|
||||||
|
vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB;
|
||||||
/* fprs can be synchronized via vrs, even if the guest has no vx. With
|
/* fprs can be synchronized via vrs, even if the guest has no vx. With
|
||||||
* MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format.
|
* MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format.
|
||||||
*/
|
*/
|
||||||
|
@ -1939,8 +1977,8 @@ int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu)
|
||||||
if (!vcpu->arch.sie_block->cbrlo)
|
if (!vcpu->arch.sie_block->cbrlo)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
vcpu->arch.sie_block->ecb2 |= 0x80;
|
vcpu->arch.sie_block->ecb2 |= ECB2_CMMA;
|
||||||
vcpu->arch.sie_block->ecb2 &= ~0x08;
|
vcpu->arch.sie_block->ecb2 &= ~ECB2_PFMFI;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1970,29 +2008,31 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
/* pgste_set_pte has special handling for !MACHINE_HAS_ESOP */
|
/* pgste_set_pte has special handling for !MACHINE_HAS_ESOP */
|
||||||
if (MACHINE_HAS_ESOP)
|
if (MACHINE_HAS_ESOP)
|
||||||
vcpu->arch.sie_block->ecb |= 0x02;
|
vcpu->arch.sie_block->ecb |= ECB_HOSTPROTINT;
|
||||||
if (test_kvm_facility(vcpu->kvm, 9))
|
if (test_kvm_facility(vcpu->kvm, 9))
|
||||||
vcpu->arch.sie_block->ecb |= 0x04;
|
vcpu->arch.sie_block->ecb |= ECB_SRSI;
|
||||||
if (test_kvm_facility(vcpu->kvm, 73))
|
if (test_kvm_facility(vcpu->kvm, 73))
|
||||||
vcpu->arch.sie_block->ecb |= 0x10;
|
vcpu->arch.sie_block->ecb |= ECB_TE;
|
||||||
|
|
||||||
if (test_kvm_facility(vcpu->kvm, 8) && sclp.has_pfmfi)
|
if (test_kvm_facility(vcpu->kvm, 8) && sclp.has_pfmfi)
|
||||||
vcpu->arch.sie_block->ecb2 |= 0x08;
|
vcpu->arch.sie_block->ecb2 |= ECB2_PFMFI;
|
||||||
if (test_kvm_facility(vcpu->kvm, 130))
|
if (test_kvm_facility(vcpu->kvm, 130))
|
||||||
vcpu->arch.sie_block->ecb2 |= 0x20;
|
vcpu->arch.sie_block->ecb2 |= ECB2_IEP;
|
||||||
vcpu->arch.sie_block->eca = 0x1002000U;
|
vcpu->arch.sie_block->eca = ECA_MVPGI | ECA_PROTEXCI;
|
||||||
if (sclp.has_cei)
|
if (sclp.has_cei)
|
||||||
vcpu->arch.sie_block->eca |= 0x80000000U;
|
vcpu->arch.sie_block->eca |= ECA_CEI;
|
||||||
if (sclp.has_ib)
|
if (sclp.has_ib)
|
||||||
vcpu->arch.sie_block->eca |= 0x40000000U;
|
vcpu->arch.sie_block->eca |= ECA_IB;
|
||||||
if (sclp.has_siif)
|
if (sclp.has_siif)
|
||||||
vcpu->arch.sie_block->eca |= 1;
|
vcpu->arch.sie_block->eca |= ECA_SII;
|
||||||
if (sclp.has_sigpif)
|
if (sclp.has_sigpif)
|
||||||
vcpu->arch.sie_block->eca |= 0x10000000U;
|
vcpu->arch.sie_block->eca |= ECA_SIGPI;
|
||||||
if (test_kvm_facility(vcpu->kvm, 129)) {
|
if (test_kvm_facility(vcpu->kvm, 129)) {
|
||||||
vcpu->arch.sie_block->eca |= 0x00020000;
|
vcpu->arch.sie_block->eca |= ECA_VX;
|
||||||
vcpu->arch.sie_block->ecd |= 0x20000000;
|
vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
|
||||||
}
|
}
|
||||||
|
vcpu->arch.sie_block->sdnxo = ((unsigned long) &vcpu->run->s.regs.sdnx)
|
||||||
|
| SDNXC;
|
||||||
vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
|
vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
|
||||||
vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
|
vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
|
||||||
|
|
||||||
|
@ -2719,6 +2759,11 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
{
|
{
|
||||||
|
struct runtime_instr_cb *riccb;
|
||||||
|
struct gs_cb *gscb;
|
||||||
|
|
||||||
|
riccb = (struct runtime_instr_cb *) &kvm_run->s.regs.riccb;
|
||||||
|
gscb = (struct gs_cb *) &kvm_run->s.regs.gscb;
|
||||||
vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
|
vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
|
||||||
vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
|
vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
|
||||||
if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX)
|
if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX)
|
||||||
|
@ -2747,12 +2792,24 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
* we should enable RI here instead of doing the lazy enablement.
|
* we should enable RI here instead of doing the lazy enablement.
|
||||||
*/
|
*/
|
||||||
if ((kvm_run->kvm_dirty_regs & KVM_SYNC_RICCB) &&
|
if ((kvm_run->kvm_dirty_regs & KVM_SYNC_RICCB) &&
|
||||||
test_kvm_facility(vcpu->kvm, 64)) {
|
test_kvm_facility(vcpu->kvm, 64) &&
|
||||||
struct runtime_instr_cb *riccb =
|
riccb->valid &&
|
||||||
(struct runtime_instr_cb *) &kvm_run->s.regs.riccb;
|
!(vcpu->arch.sie_block->ecb3 & ECB3_RI)) {
|
||||||
|
VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (sync_regs)");
|
||||||
if (riccb->valid)
|
vcpu->arch.sie_block->ecb3 |= ECB3_RI;
|
||||||
vcpu->arch.sie_block->ecb3 |= 0x01;
|
}
|
||||||
|
/*
|
||||||
|
* If userspace sets the gscb (e.g. after migration) to non-zero,
|
||||||
|
* we should enable GS here instead of doing the lazy enablement.
|
||||||
|
*/
|
||||||
|
if ((kvm_run->kvm_dirty_regs & KVM_SYNC_GSCB) &&
|
||||||
|
test_kvm_facility(vcpu->kvm, 133) &&
|
||||||
|
gscb->gssm &&
|
||||||
|
!vcpu->arch.gs_enabled) {
|
||||||
|
VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (sync_regs)");
|
||||||
|
vcpu->arch.sie_block->ecb |= ECB_GS;
|
||||||
|
vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
|
||||||
|
vcpu->arch.gs_enabled = 1;
|
||||||
}
|
}
|
||||||
save_access_regs(vcpu->arch.host_acrs);
|
save_access_regs(vcpu->arch.host_acrs);
|
||||||
restore_access_regs(vcpu->run->s.regs.acrs);
|
restore_access_regs(vcpu->run->s.regs.acrs);
|
||||||
|
@ -2768,6 +2825,20 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
if (test_fp_ctl(current->thread.fpu.fpc))
|
if (test_fp_ctl(current->thread.fpu.fpc))
|
||||||
/* User space provided an invalid FPC, let's clear it */
|
/* User space provided an invalid FPC, let's clear it */
|
||||||
current->thread.fpu.fpc = 0;
|
current->thread.fpu.fpc = 0;
|
||||||
|
if (MACHINE_HAS_GS) {
|
||||||
|
preempt_disable();
|
||||||
|
__ctl_set_bit(2, 4);
|
||||||
|
if (current->thread.gs_cb) {
|
||||||
|
vcpu->arch.host_gscb = current->thread.gs_cb;
|
||||||
|
save_gs_cb(vcpu->arch.host_gscb);
|
||||||
|
}
|
||||||
|
if (vcpu->arch.gs_enabled) {
|
||||||
|
current->thread.gs_cb = (struct gs_cb *)
|
||||||
|
&vcpu->run->s.regs.gscb;
|
||||||
|
restore_gs_cb(current->thread.gs_cb);
|
||||||
|
}
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
kvm_run->kvm_dirty_regs = 0;
|
kvm_run->kvm_dirty_regs = 0;
|
||||||
}
|
}
|
||||||
|
@ -2794,6 +2865,18 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
/* Restore will be done lazily at return */
|
/* Restore will be done lazily at return */
|
||||||
current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
|
current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
|
||||||
current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
|
current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
|
||||||
|
if (MACHINE_HAS_GS) {
|
||||||
|
__ctl_set_bit(2, 4);
|
||||||
|
if (vcpu->arch.gs_enabled)
|
||||||
|
save_gs_cb(current->thread.gs_cb);
|
||||||
|
preempt_disable();
|
||||||
|
current->thread.gs_cb = vcpu->arch.host_gscb;
|
||||||
|
restore_gs_cb(vcpu->arch.host_gscb);
|
||||||
|
preempt_enable();
|
||||||
|
if (!vcpu->arch.host_gscb)
|
||||||
|
__ctl_clear_bit(2, 4);
|
||||||
|
vcpu->arch.host_gscb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
|
typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
|
||||||
|
|
||||||
/* Transactional Memory Execution related macros */
|
/* Transactional Memory Execution related macros */
|
||||||
#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10))
|
#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & ECB_TE))
|
||||||
#define TDB_FORMAT1 1
|
#define TDB_FORMAT1 1
|
||||||
#define IS_ITDB_VALID(vcpu) ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1))
|
#define IS_ITDB_VALID(vcpu) ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1))
|
||||||
|
|
||||||
|
@ -246,6 +246,7 @@ static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu)
|
||||||
int is_valid_psw(psw_t *psw);
|
int is_valid_psw(psw_t *psw);
|
||||||
int kvm_s390_handle_aa(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_aa(struct kvm_vcpu *vcpu);
|
||||||
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
|
||||||
|
int kvm_s390_handle_e3(struct kvm_vcpu *vcpu);
|
||||||
int kvm_s390_handle_e5(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_e5(struct kvm_vcpu *vcpu);
|
||||||
int kvm_s390_handle_01(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_01(struct kvm_vcpu *vcpu);
|
||||||
int kvm_s390_handle_b9(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_b9(struct kvm_vcpu *vcpu);
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
static int handle_ri(struct kvm_vcpu *vcpu)
|
static int handle_ri(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (test_kvm_facility(vcpu->kvm, 64)) {
|
if (test_kvm_facility(vcpu->kvm, 64)) {
|
||||||
vcpu->arch.sie_block->ecb3 |= 0x01;
|
VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (lazy)");
|
||||||
|
vcpu->arch.sie_block->ecb3 |= ECB3_RI;
|
||||||
kvm_s390_retry_instr(vcpu);
|
kvm_s390_retry_instr(vcpu);
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
|
@ -52,6 +53,33 @@ int kvm_s390_handle_aa(struct kvm_vcpu *vcpu)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_gs(struct kvm_vcpu *vcpu)
|
||||||
|
{
|
||||||
|
if (test_kvm_facility(vcpu->kvm, 133)) {
|
||||||
|
VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (lazy)");
|
||||||
|
preempt_disable();
|
||||||
|
__ctl_set_bit(2, 4);
|
||||||
|
current->thread.gs_cb = (struct gs_cb *)&vcpu->run->s.regs.gscb;
|
||||||
|
restore_gs_cb(current->thread.gs_cb);
|
||||||
|
preempt_enable();
|
||||||
|
vcpu->arch.sie_block->ecb |= ECB_GS;
|
||||||
|
vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
|
||||||
|
vcpu->arch.gs_enabled = 1;
|
||||||
|
kvm_s390_retry_instr(vcpu);
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_s390_handle_e3(struct kvm_vcpu *vcpu)
|
||||||
|
{
|
||||||
|
int code = vcpu->arch.sie_block->ipb & 0xff;
|
||||||
|
|
||||||
|
if (code == 0x49 || code == 0x4d)
|
||||||
|
return handle_gs(vcpu);
|
||||||
|
else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
/* Handle SCK (SET CLOCK) interception */
|
/* Handle SCK (SET CLOCK) interception */
|
||||||
static int handle_set_clock(struct kvm_vcpu *vcpu)
|
static int handle_set_clock(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
|
@ -759,6 +787,7 @@ static const intercept_handler_t b2_handlers[256] = {
|
||||||
[0x3b] = handle_io_inst,
|
[0x3b] = handle_io_inst,
|
||||||
[0x3c] = handle_io_inst,
|
[0x3c] = handle_io_inst,
|
||||||
[0x50] = handle_ipte_interlock,
|
[0x50] = handle_ipte_interlock,
|
||||||
|
[0x56] = handle_sthyi,
|
||||||
[0x5f] = handle_io_inst,
|
[0x5f] = handle_io_inst,
|
||||||
[0x74] = handle_io_inst,
|
[0x74] = handle_io_inst,
|
||||||
[0x76] = handle_io_inst,
|
[0x76] = handle_io_inst,
|
||||||
|
|
|
@ -404,6 +404,9 @@ int handle_sthyi(struct kvm_vcpu *vcpu)
|
||||||
u64 code, addr, cc = 0;
|
u64 code, addr, cc = 0;
|
||||||
struct sthyi_sctns *sctns = NULL;
|
struct sthyi_sctns *sctns = NULL;
|
||||||
|
|
||||||
|
if (!test_kvm_facility(vcpu->kvm, 74))
|
||||||
|
return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* STHYI requires extensive locking in the higher hypervisors
|
* STHYI requires extensive locking in the higher hypervisors
|
||||||
* and is very computational/memory expensive. Therefore we
|
* and is very computational/memory expensive. Therefore we
|
||||||
|
|
|
@ -280,6 +280,58 @@ TRACE_EVENT(kvm_s390_enable_disable_ibs,
|
||||||
__entry->state ? "enabling" : "disabling", __entry->id)
|
__entry->state ? "enabling" : "disabling", __entry->id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trace point for modifying ais mode for a given isc.
|
||||||
|
*/
|
||||||
|
TRACE_EVENT(kvm_s390_modify_ais_mode,
|
||||||
|
TP_PROTO(__u8 isc, __u16 from, __u16 to),
|
||||||
|
TP_ARGS(isc, from, to),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(__u8, isc)
|
||||||
|
__field(__u16, from)
|
||||||
|
__field(__u16, to)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->isc = isc;
|
||||||
|
__entry->from = from;
|
||||||
|
__entry->to = to;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("for isc %x, modifying interruption mode from %s to %s",
|
||||||
|
__entry->isc,
|
||||||
|
(__entry->from == KVM_S390_AIS_MODE_ALL) ?
|
||||||
|
"ALL-Interruptions Mode" :
|
||||||
|
(__entry->from == KVM_S390_AIS_MODE_SINGLE) ?
|
||||||
|
"Single-Interruption Mode" : "No-Interruptions Mode",
|
||||||
|
(__entry->to == KVM_S390_AIS_MODE_ALL) ?
|
||||||
|
"ALL-Interruptions Mode" :
|
||||||
|
(__entry->to == KVM_S390_AIS_MODE_SINGLE) ?
|
||||||
|
"Single-Interruption Mode" : "No-Interruptions Mode")
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trace point for suppressed adapter I/O interrupt.
|
||||||
|
*/
|
||||||
|
TRACE_EVENT(kvm_s390_airq_suppressed,
|
||||||
|
TP_PROTO(__u32 id, __u8 isc),
|
||||||
|
TP_ARGS(id, isc),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(__u32, id)
|
||||||
|
__field(__u8, isc)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->id = id;
|
||||||
|
__entry->isc = isc;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("adapter I/O interrupt suppressed (id:%x isc:%x)",
|
||||||
|
__entry->id, __entry->isc)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _TRACE_KVMS390_H */
|
#endif /* _TRACE_KVMS390_H */
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
{
|
{
|
||||||
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
|
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
|
||||||
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
|
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
|
||||||
bool had_tx = scb_s->ecb & 0x10U;
|
bool had_tx = scb_s->ecb & ECB_TE;
|
||||||
unsigned long new_mso = 0;
|
unsigned long new_mso = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -307,34 +307,39 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
scb_s->ihcpu = scb_o->ihcpu;
|
scb_s->ihcpu = scb_o->ihcpu;
|
||||||
|
|
||||||
/* MVPG and Protection Exception Interpretation are always available */
|
/* MVPG and Protection Exception Interpretation are always available */
|
||||||
scb_s->eca |= scb_o->eca & 0x01002000U;
|
scb_s->eca |= scb_o->eca & (ECA_MVPGI | ECA_PROTEXCI);
|
||||||
/* Host-protection-interruption introduced with ESOP */
|
/* Host-protection-interruption introduced with ESOP */
|
||||||
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP))
|
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP))
|
||||||
scb_s->ecb |= scb_o->ecb & 0x02U;
|
scb_s->ecb |= scb_o->ecb & ECB_HOSTPROTINT;
|
||||||
/* transactional execution */
|
/* transactional execution */
|
||||||
if (test_kvm_facility(vcpu->kvm, 73)) {
|
if (test_kvm_facility(vcpu->kvm, 73)) {
|
||||||
/* remap the prefix is tx is toggled on */
|
/* remap the prefix is tx is toggled on */
|
||||||
if ((scb_o->ecb & 0x10U) && !had_tx)
|
if ((scb_o->ecb & ECB_TE) && !had_tx)
|
||||||
prefix_unmapped(vsie_page);
|
prefix_unmapped(vsie_page);
|
||||||
scb_s->ecb |= scb_o->ecb & 0x10U;
|
scb_s->ecb |= scb_o->ecb & ECB_TE;
|
||||||
}
|
}
|
||||||
/* SIMD */
|
/* SIMD */
|
||||||
if (test_kvm_facility(vcpu->kvm, 129)) {
|
if (test_kvm_facility(vcpu->kvm, 129)) {
|
||||||
scb_s->eca |= scb_o->eca & 0x00020000U;
|
scb_s->eca |= scb_o->eca & ECA_VX;
|
||||||
scb_s->ecd |= scb_o->ecd & 0x20000000U;
|
scb_s->ecd |= scb_o->ecd & ECD_HOSTREGMGMT;
|
||||||
}
|
}
|
||||||
/* Run-time-Instrumentation */
|
/* Run-time-Instrumentation */
|
||||||
if (test_kvm_facility(vcpu->kvm, 64))
|
if (test_kvm_facility(vcpu->kvm, 64))
|
||||||
scb_s->ecb3 |= scb_o->ecb3 & 0x01U;
|
scb_s->ecb3 |= scb_o->ecb3 & ECB3_RI;
|
||||||
/* Instruction Execution Prevention */
|
/* Instruction Execution Prevention */
|
||||||
if (test_kvm_facility(vcpu->kvm, 130))
|
if (test_kvm_facility(vcpu->kvm, 130))
|
||||||
scb_s->ecb2 |= scb_o->ecb2 & 0x20U;
|
scb_s->ecb2 |= scb_o->ecb2 & ECB2_IEP;
|
||||||
|
/* Guarded Storage */
|
||||||
|
if (test_kvm_facility(vcpu->kvm, 133)) {
|
||||||
|
scb_s->ecb |= scb_o->ecb & ECB_GS;
|
||||||
|
scb_s->ecd |= scb_o->ecd & ECD_HOSTREGMGMT;
|
||||||
|
}
|
||||||
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_SIIF))
|
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_SIIF))
|
||||||
scb_s->eca |= scb_o->eca & 0x00000001U;
|
scb_s->eca |= scb_o->eca & ECA_SII;
|
||||||
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_IB))
|
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_IB))
|
||||||
scb_s->eca |= scb_o->eca & 0x40000000U;
|
scb_s->eca |= scb_o->eca & ECA_IB;
|
||||||
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
|
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
|
||||||
scb_s->eca |= scb_o->eca & 0x80000000U;
|
scb_s->eca |= scb_o->eca & ECA_CEI;
|
||||||
|
|
||||||
prepare_ibc(vcpu, vsie_page);
|
prepare_ibc(vcpu, vsie_page);
|
||||||
rc = shadow_crycb(vcpu, vsie_page);
|
rc = shadow_crycb(vcpu, vsie_page);
|
||||||
|
@ -406,7 +411,7 @@ static int map_prefix(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
prefix += scb_s->mso;
|
prefix += scb_s->mso;
|
||||||
|
|
||||||
rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap, prefix);
|
rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap, prefix);
|
||||||
if (!rc && (scb_s->ecb & 0x10U))
|
if (!rc && (scb_s->ecb & ECB_TE))
|
||||||
rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap,
|
rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap,
|
||||||
prefix + PAGE_SIZE);
|
prefix + PAGE_SIZE);
|
||||||
/*
|
/*
|
||||||
|
@ -496,6 +501,13 @@ static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
unpin_guest_page(vcpu->kvm, gpa, hpa);
|
unpin_guest_page(vcpu->kvm, gpa, hpa);
|
||||||
scb_s->riccbd = 0;
|
scb_s->riccbd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hpa = scb_s->sdnxo;
|
||||||
|
if (hpa) {
|
||||||
|
gpa = scb_o->sdnxo;
|
||||||
|
unpin_guest_page(vcpu->kvm, gpa, hpa);
|
||||||
|
scb_s->sdnxo = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -543,7 +555,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
}
|
}
|
||||||
|
|
||||||
gpa = scb_o->itdba & ~0xffUL;
|
gpa = scb_o->itdba & ~0xffUL;
|
||||||
if (gpa && (scb_s->ecb & 0x10U)) {
|
if (gpa && (scb_s->ecb & ECB_TE)) {
|
||||||
if (!(gpa & ~0x1fffU)) {
|
if (!(gpa & ~0x1fffU)) {
|
||||||
rc = set_validity_icpt(scb_s, 0x0080U);
|
rc = set_validity_icpt(scb_s, 0x0080U);
|
||||||
goto unpin;
|
goto unpin;
|
||||||
|
@ -558,8 +570,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
}
|
}
|
||||||
|
|
||||||
gpa = scb_o->gvrd & ~0x1ffUL;
|
gpa = scb_o->gvrd & ~0x1ffUL;
|
||||||
if (gpa && (scb_s->eca & 0x00020000U) &&
|
if (gpa && (scb_s->eca & ECA_VX) && !(scb_s->ecd & ECD_HOSTREGMGMT)) {
|
||||||
!(scb_s->ecd & 0x20000000U)) {
|
|
||||||
if (!(gpa & ~0x1fffUL)) {
|
if (!(gpa & ~0x1fffUL)) {
|
||||||
rc = set_validity_icpt(scb_s, 0x1310U);
|
rc = set_validity_icpt(scb_s, 0x1310U);
|
||||||
goto unpin;
|
goto unpin;
|
||||||
|
@ -577,7 +588,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
}
|
}
|
||||||
|
|
||||||
gpa = scb_o->riccbd & ~0x3fUL;
|
gpa = scb_o->riccbd & ~0x3fUL;
|
||||||
if (gpa && (scb_s->ecb3 & 0x01U)) {
|
if (gpa && (scb_s->ecb3 & ECB3_RI)) {
|
||||||
if (!(gpa & ~0x1fffUL)) {
|
if (!(gpa & ~0x1fffUL)) {
|
||||||
rc = set_validity_icpt(scb_s, 0x0043U);
|
rc = set_validity_icpt(scb_s, 0x0043U);
|
||||||
goto unpin;
|
goto unpin;
|
||||||
|
@ -591,6 +602,33 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
goto unpin;
|
goto unpin;
|
||||||
scb_s->riccbd = hpa;
|
scb_s->riccbd = hpa;
|
||||||
}
|
}
|
||||||
|
if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) {
|
||||||
|
unsigned long sdnxc;
|
||||||
|
|
||||||
|
gpa = scb_o->sdnxo & ~0xfUL;
|
||||||
|
sdnxc = scb_o->sdnxo & 0xfUL;
|
||||||
|
if (!gpa || !(gpa & ~0x1fffUL)) {
|
||||||
|
rc = set_validity_icpt(scb_s, 0x10b0U);
|
||||||
|
goto unpin;
|
||||||
|
}
|
||||||
|
if (sdnxc < 6 || sdnxc > 12) {
|
||||||
|
rc = set_validity_icpt(scb_s, 0x10b1U);
|
||||||
|
goto unpin;
|
||||||
|
}
|
||||||
|
if (gpa & ((1 << sdnxc) - 1)) {
|
||||||
|
rc = set_validity_icpt(scb_s, 0x10b2U);
|
||||||
|
goto unpin;
|
||||||
|
}
|
||||||
|
/* Due to alignment rules (checked above) this cannot
|
||||||
|
* cross page boundaries
|
||||||
|
*/
|
||||||
|
rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
|
||||||
|
if (rc == -EINVAL)
|
||||||
|
rc = set_validity_icpt(scb_s, 0x10b0U);
|
||||||
|
if (rc)
|
||||||
|
goto unpin;
|
||||||
|
scb_s->sdnxo = hpa;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
unpin:
|
unpin:
|
||||||
unpin_blocks(vcpu, vsie_page);
|
unpin_blocks(vcpu, vsie_page);
|
||||||
|
|
|
@ -96,7 +96,7 @@ static int altr_a10sr_gpio_probe(struct platform_device *pdev)
|
||||||
gpio->regmap = a10sr->regmap;
|
gpio->regmap = a10sr->regmap;
|
||||||
|
|
||||||
gpio->gp = altr_a10sr_gc;
|
gpio->gp = altr_a10sr_gc;
|
||||||
|
gpio->gp.parent = pdev->dev.parent;
|
||||||
gpio->gp.of_node = pdev->dev.of_node;
|
gpio->gp.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
|
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
|
||||||
|
|
|
@ -90,21 +90,18 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
|
||||||
|
|
||||||
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
||||||
|
|
||||||
if (type == IRQ_TYPE_NONE)
|
if (type == IRQ_TYPE_NONE) {
|
||||||
|
irq_set_handler_locked(d, handle_bad_irq);
|
||||||
return 0;
|
return 0;
|
||||||
if (type == IRQ_TYPE_LEVEL_HIGH &&
|
}
|
||||||
altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
|
if (type == altera_gc->interrupt_trigger) {
|
||||||
|
if (type == IRQ_TYPE_LEVEL_HIGH)
|
||||||
|
irq_set_handler_locked(d, handle_level_irq);
|
||||||
|
else
|
||||||
|
irq_set_handler_locked(d, handle_simple_irq);
|
||||||
return 0;
|
return 0;
|
||||||
if (type == IRQ_TYPE_EDGE_RISING &&
|
}
|
||||||
altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_RISING)
|
irq_set_handler_locked(d, handle_bad_irq);
|
||||||
return 0;
|
|
||||||
if (type == IRQ_TYPE_EDGE_FALLING &&
|
|
||||||
altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_FALLING)
|
|
||||||
return 0;
|
|
||||||
if (type == IRQ_TYPE_EDGE_BOTH &&
|
|
||||||
altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_BOTH)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +227,6 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
|
||||||
chained_irq_exit(chip, desc);
|
chained_irq_exit(chip, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
|
static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct altera_gpio_chip *altera_gc;
|
struct altera_gpio_chip *altera_gc;
|
||||||
|
@ -310,7 +306,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
||||||
altera_gc->interrupt_trigger = reg;
|
altera_gc->interrupt_trigger = reg;
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
|
ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
|
||||||
handle_simple_irq, IRQ_TYPE_NONE);
|
handle_bad_irq, IRQ_TYPE_NONE);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "could not add irqchip\n");
|
dev_err(&pdev->dev, "could not add irqchip\n");
|
||||||
|
|
|
@ -270,8 +270,10 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
static irqreturn_t mcp23s08_irq(int irq, void *data)
|
static irqreturn_t mcp23s08_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct mcp23s08 *mcp = data;
|
struct mcp23s08 *mcp = data;
|
||||||
int intcap, intf, i;
|
int intcap, intf, i, gpio, gpio_orig, intcap_mask;
|
||||||
unsigned int child_irq;
|
unsigned int child_irq;
|
||||||
|
bool intf_set, intcap_changed, gpio_bit_changed,
|
||||||
|
defval_changed, gpio_set;
|
||||||
|
|
||||||
mutex_lock(&mcp->lock);
|
mutex_lock(&mcp->lock);
|
||||||
if (mcp_read(mcp, MCP_INTF, &intf) < 0) {
|
if (mcp_read(mcp, MCP_INTF, &intf) < 0) {
|
||||||
|
@ -287,14 +289,67 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
mcp->cache[MCP_INTCAP] = intcap;
|
mcp->cache[MCP_INTCAP] = intcap;
|
||||||
|
|
||||||
|
/* This clears the interrupt(configurable on S18) */
|
||||||
|
if (mcp_read(mcp, MCP_GPIO, &gpio) < 0) {
|
||||||
|
mutex_unlock(&mcp->lock);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
gpio_orig = mcp->cache[MCP_GPIO];
|
||||||
|
mcp->cache[MCP_GPIO] = gpio;
|
||||||
mutex_unlock(&mcp->lock);
|
mutex_unlock(&mcp->lock);
|
||||||
|
|
||||||
|
if (mcp->cache[MCP_INTF] == 0) {
|
||||||
|
/* There is no interrupt pending */
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(mcp->chip.parent,
|
||||||
|
"intcap 0x%04X intf 0x%04X gpio_orig 0x%04X gpio 0x%04X\n",
|
||||||
|
intcap, intf, gpio_orig, gpio);
|
||||||
|
|
||||||
for (i = 0; i < mcp->chip.ngpio; i++) {
|
for (i = 0; i < mcp->chip.ngpio; i++) {
|
||||||
if ((BIT(i) & mcp->cache[MCP_INTF]) &&
|
/* We must check all of the inputs on the chip,
|
||||||
((BIT(i) & intcap & mcp->irq_rise) ||
|
* otherwise we may not notice a change on >=2 pins.
|
||||||
(mcp->irq_fall & ~intcap & BIT(i)) ||
|
*
|
||||||
(BIT(i) & mcp->cache[MCP_INTCON]))) {
|
* On at least the mcp23s17, INTCAP is only updated
|
||||||
|
* one byte at a time(INTCAPA and INTCAPB are
|
||||||
|
* not written to at the same time - only on a per-bank
|
||||||
|
* basis).
|
||||||
|
*
|
||||||
|
* INTF only contains the single bit that caused the
|
||||||
|
* interrupt per-bank. On the mcp23s17, there is
|
||||||
|
* INTFA and INTFB. If two pins are changed on the A
|
||||||
|
* side at the same time, INTF will only have one bit
|
||||||
|
* set. If one pin on the A side and one pin on the B
|
||||||
|
* side are changed at the same time, INTF will have
|
||||||
|
* two bits set. Thus, INTF can't be the only check
|
||||||
|
* to see if the input has changed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
intf_set = BIT(i) & mcp->cache[MCP_INTF];
|
||||||
|
if (i < 8 && intf_set)
|
||||||
|
intcap_mask = 0x00FF;
|
||||||
|
else if (i >= 8 && intf_set)
|
||||||
|
intcap_mask = 0xFF00;
|
||||||
|
else
|
||||||
|
intcap_mask = 0x00;
|
||||||
|
|
||||||
|
intcap_changed = (intcap_mask &
|
||||||
|
(BIT(i) & mcp->cache[MCP_INTCAP])) !=
|
||||||
|
(intcap_mask & (BIT(i) & gpio_orig));
|
||||||
|
gpio_set = BIT(i) & mcp->cache[MCP_GPIO];
|
||||||
|
gpio_bit_changed = (BIT(i) & gpio_orig) !=
|
||||||
|
(BIT(i) & mcp->cache[MCP_GPIO]);
|
||||||
|
defval_changed = (BIT(i) & mcp->cache[MCP_INTCON]) &&
|
||||||
|
((BIT(i) & mcp->cache[MCP_GPIO]) !=
|
||||||
|
(BIT(i) & mcp->cache[MCP_DEFVAL]));
|
||||||
|
|
||||||
|
if (((gpio_bit_changed || intcap_changed) &&
|
||||||
|
(BIT(i) & mcp->irq_rise) && gpio_set) ||
|
||||||
|
((gpio_bit_changed || intcap_changed) &&
|
||||||
|
(BIT(i) & mcp->irq_fall) && !gpio_set) ||
|
||||||
|
defval_changed) {
|
||||||
child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
|
child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
|
||||||
handle_nested_irq(child_irq);
|
handle_nested_irq(child_irq);
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,7 +197,7 @@ static ssize_t gpio_mockup_event_write(struct file *file,
|
||||||
struct seq_file *sfile;
|
struct seq_file *sfile;
|
||||||
struct gpio_desc *desc;
|
struct gpio_desc *desc;
|
||||||
struct gpio_chip *gc;
|
struct gpio_chip *gc;
|
||||||
int status, val;
|
int val;
|
||||||
char buf;
|
char buf;
|
||||||
|
|
||||||
sfile = file->private_data;
|
sfile = file->private_data;
|
||||||
|
@ -206,9 +206,8 @@ static ssize_t gpio_mockup_event_write(struct file *file,
|
||||||
chip = priv->chip;
|
chip = priv->chip;
|
||||||
gc = &chip->gc;
|
gc = &chip->gc;
|
||||||
|
|
||||||
status = copy_from_user(&buf, usr_buf, 1);
|
if (copy_from_user(&buf, usr_buf, 1))
|
||||||
if (status)
|
return -EFAULT;
|
||||||
return status;
|
|
||||||
|
|
||||||
if (buf == '0')
|
if (buf == '0')
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
|
@ -42,9 +42,7 @@ struct xgene_gpio {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
#ifdef CONFIG_PM
|
|
||||||
u32 set_dr_val[XGENE_MAX_GPIO_BANKS];
|
u32 set_dr_val[XGENE_MAX_GPIO_BANKS];
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||||
|
@ -138,8 +136,7 @@ static int xgene_gpio_dir_out(struct gpio_chip *gc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
static __maybe_unused int xgene_gpio_suspend(struct device *dev)
|
||||||
static int xgene_gpio_suspend(struct device *dev)
|
|
||||||
{
|
{
|
||||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||||
unsigned long bank_offset;
|
unsigned long bank_offset;
|
||||||
|
@ -152,7 +149,7 @@ static int xgene_gpio_suspend(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgene_gpio_resume(struct device *dev)
|
static __maybe_unused int xgene_gpio_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||||
unsigned long bank_offset;
|
unsigned long bank_offset;
|
||||||
|
@ -166,10 +163,6 @@ static int xgene_gpio_resume(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
||||||
#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm)
|
|
||||||
#else
|
|
||||||
#define XGENE_GPIO_PM_OPS NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int xgene_gpio_probe(struct platform_device *pdev)
|
static int xgene_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
@ -241,7 +234,7 @@ static struct platform_driver xgene_gpio_driver = {
|
||||||
.name = "xgene-gpio",
|
.name = "xgene-gpio",
|
||||||
.of_match_table = xgene_gpio_of_match,
|
.of_match_table = xgene_gpio_of_match,
|
||||||
.acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
|
.acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
|
||||||
.pm = XGENE_GPIO_PM_OPS,
|
.pm = &xgene_gpio_pm,
|
||||||
},
|
},
|
||||||
.probe = xgene_gpio_probe,
|
.probe = xgene_gpio_probe,
|
||||||
};
|
};
|
||||||
|
|
|
@ -175,11 +175,11 @@ config HID_CHERRY
|
||||||
Support for Cherry Cymotion keyboard.
|
Support for Cherry Cymotion keyboard.
|
||||||
|
|
||||||
config HID_CHICONY
|
config HID_CHICONY
|
||||||
tristate "Chicony Tactical pad"
|
tristate "Chicony devices"
|
||||||
depends on HID
|
depends on HID
|
||||||
default !EXPERT
|
default !EXPERT
|
||||||
---help---
|
---help---
|
||||||
Support for Chicony Tactical pad.
|
Support for Chicony Tactical pad and special keys on Chicony keyboards.
|
||||||
|
|
||||||
config HID_CORSAIR
|
config HID_CORSAIR
|
||||||
tristate "Corsair devices"
|
tristate "Corsair devices"
|
||||||
|
@ -190,6 +190,7 @@ config HID_CORSAIR
|
||||||
|
|
||||||
Supported devices:
|
Supported devices:
|
||||||
- Vengeance K90
|
- Vengeance K90
|
||||||
|
- Scimitar PRO RGB
|
||||||
|
|
||||||
config HID_PRODIKEYS
|
config HID_PRODIKEYS
|
||||||
tristate "Prodikeys PC-MIDI Keyboard support"
|
tristate "Prodikeys PC-MIDI Keyboard support"
|
||||||
|
|
|
@ -86,6 +86,7 @@ static const struct hid_device_id ch_devices[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_JESS_ZEN_AIO_KBD) },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(hid, ch_devices);
|
MODULE_DEVICE_TABLE(hid, ch_devices);
|
||||||
|
|
|
@ -1870,6 +1870,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
|
||||||
|
@ -1910,6 +1911,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_JESS_ZEN_AIO_KBD) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
|
||||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
*
|
*
|
||||||
* Supported devices:
|
* Supported devices:
|
||||||
* - Vengeance K90 Keyboard
|
* - Vengeance K90 Keyboard
|
||||||
|
* - Scimitar PRO RGB Gaming Mouse
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015 Clement Vuchener
|
* Copyright (c) 2015 Clement Vuchener
|
||||||
|
* Copyright (c) 2017 Oscar Campos
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -670,10 +672,51 @@ static int corsair_input_mapping(struct hid_device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The report descriptor of Corsair Scimitar RGB Pro gaming mouse is
|
||||||
|
* non parseable as they define two consecutive Logical Minimum for
|
||||||
|
* the Usage Page (Consumer) in rdescs bytes 75 and 77 being 77 0x16
|
||||||
|
* that should be obviousy 0x26 for Logical Magimum of 16 bits. This
|
||||||
|
* prevents poper parsing of the report descriptor due Logical
|
||||||
|
* Minimum being larger than Logical Maximum.
|
||||||
|
*
|
||||||
|
* This driver fixes the report descriptor for:
|
||||||
|
* - USB ID b1c:1b3e, sold as Scimitar RGB Pro Gaming mouse
|
||||||
|
*/
|
||||||
|
|
||||||
|
static __u8 *corsair_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
|
unsigned int *rsize)
|
||||||
|
{
|
||||||
|
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||||
|
|
||||||
|
if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
|
||||||
|
/*
|
||||||
|
* Corsair Scimitar RGB Pro report descriptor is broken and
|
||||||
|
* defines two different Logical Minimum for the Consumer
|
||||||
|
* Application. The byte 77 should be a 0x26 defining a 16
|
||||||
|
* bits integer for the Logical Maximum but it is a 0x16
|
||||||
|
* instead (Logical Minimum)
|
||||||
|
*/
|
||||||
|
switch (hdev->product) {
|
||||||
|
case USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB:
|
||||||
|
if (*rsize >= 172 && rdesc[75] == 0x15 && rdesc[77] == 0x16
|
||||||
|
&& rdesc[78] == 0xff && rdesc[79] == 0x0f) {
|
||||||
|
hid_info(hdev, "Fixing up report descriptor\n");
|
||||||
|
rdesc[77] = 0x26;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return rdesc;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct hid_device_id corsair_devices[] = {
|
static const struct hid_device_id corsair_devices[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90),
|
||||||
.driver_data = CORSAIR_USE_K90_MACRO |
|
.driver_data = CORSAIR_USE_K90_MACRO |
|
||||||
CORSAIR_USE_K90_BACKLIGHT },
|
CORSAIR_USE_K90_BACKLIGHT },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR,
|
||||||
|
USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -686,10 +729,14 @@ static struct hid_driver corsair_driver = {
|
||||||
.event = corsair_event,
|
.event = corsair_event,
|
||||||
.remove = corsair_remove,
|
.remove = corsair_remove,
|
||||||
.input_mapping = corsair_input_mapping,
|
.input_mapping = corsair_input_mapping,
|
||||||
|
.report_fixup = corsair_mouse_report_fixup,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_hid_driver(corsair_driver);
|
module_hid_driver(corsair_driver);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
/* Original K90 driver author */
|
||||||
MODULE_AUTHOR("Clement Vuchener");
|
MODULE_AUTHOR("Clement Vuchener");
|
||||||
|
/* Scimitar PRO RGB driver author */
|
||||||
|
MODULE_AUTHOR("Oscar Campos");
|
||||||
MODULE_DESCRIPTION("HID driver for Corsair devices");
|
MODULE_DESCRIPTION("HID driver for Corsair devices");
|
||||||
|
|
|
@ -278,6 +278,9 @@
|
||||||
#define USB_DEVICE_ID_CORSAIR_K70RGB 0x1b13
|
#define USB_DEVICE_ID_CORSAIR_K70RGB 0x1b13
|
||||||
#define USB_DEVICE_ID_CORSAIR_STRAFE 0x1b15
|
#define USB_DEVICE_ID_CORSAIR_STRAFE 0x1b15
|
||||||
#define USB_DEVICE_ID_CORSAIR_K65RGB 0x1b17
|
#define USB_DEVICE_ID_CORSAIR_K65RGB 0x1b17
|
||||||
|
#define USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE 0x1b38
|
||||||
|
#define USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE 0x1b39
|
||||||
|
#define USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB 0x1b3e
|
||||||
|
|
||||||
#define USB_VENDOR_ID_CREATIVELABS 0x041e
|
#define USB_VENDOR_ID_CREATIVELABS 0x041e
|
||||||
#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c
|
#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c
|
||||||
|
@ -557,6 +560,7 @@
|
||||||
|
|
||||||
#define USB_VENDOR_ID_JESS 0x0c45
|
#define USB_VENDOR_ID_JESS 0x0c45
|
||||||
#define USB_DEVICE_ID_JESS_YUREX 0x1010
|
#define USB_DEVICE_ID_JESS_YUREX 0x1010
|
||||||
|
#define USB_DEVICE_ID_JESS_ZEN_AIO_KBD 0x5112
|
||||||
|
|
||||||
#define USB_VENDOR_ID_JESS2 0x0f30
|
#define USB_VENDOR_ID_JESS2 0x0f30
|
||||||
#define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111
|
#define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111
|
||||||
|
|
|
@ -2632,6 +2632,8 @@ err_stop:
|
||||||
sony_leds_remove(sc);
|
sony_leds_remove(sc);
|
||||||
if (sc->quirks & SONY_BATTERY_SUPPORT)
|
if (sc->quirks & SONY_BATTERY_SUPPORT)
|
||||||
sony_battery_remove(sc);
|
sony_battery_remove(sc);
|
||||||
|
if (sc->touchpad)
|
||||||
|
sony_unregister_touchpad(sc);
|
||||||
sony_cancel_work_sync(sc);
|
sony_cancel_work_sync(sc);
|
||||||
kfree(sc->output_report_dmabuf);
|
kfree(sc->output_report_dmabuf);
|
||||||
sony_remove_dev_list(sc);
|
sony_remove_dev_list(sc);
|
||||||
|
|
|
@ -80,6 +80,9 @@ static const struct hid_blacklist {
|
||||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB, HID_QUIRK_NO_INIT_REPORTS },
|
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB, HID_QUIRK_NO_INIT_REPORTS },
|
||||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB, HID_QUIRK_NO_INIT_REPORTS },
|
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB, HID_QUIRK_NO_INIT_REPORTS },
|
||||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||||
|
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||||
|
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||||
|
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||||
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
|
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
|
||||||
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
||||||
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
|
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
|
||||||
|
|
|
@ -2579,7 +2579,9 @@ static void wacom_remove(struct hid_device *hdev)
|
||||||
|
|
||||||
/* make sure we don't trigger the LEDs */
|
/* make sure we don't trigger the LEDs */
|
||||||
wacom_led_groups_release(wacom);
|
wacom_led_groups_release(wacom);
|
||||||
wacom_release_resources(wacom);
|
|
||||||
|
if (wacom->wacom_wac.features.type != REMOTE)
|
||||||
|
wacom_release_resources(wacom);
|
||||||
|
|
||||||
hid_set_drvdata(hdev, NULL);
|
hid_set_drvdata(hdev, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1959,8 +1959,10 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
||||||
input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
|
input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
|
||||||
input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
|
input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
|
||||||
input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
|
input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
|
||||||
input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
|
if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
|
||||||
input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
|
input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
|
||||||
|
input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WACOM_HID_WD_FINGERWHEEL:
|
case WACOM_HID_WD_FINGERWHEEL:
|
||||||
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
|
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
|
||||||
|
@ -4197,10 +4199,10 @@ static const struct wacom_features wacom_features_0x343 =
|
||||||
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
|
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
|
||||||
static const struct wacom_features wacom_features_0x360 =
|
static const struct wacom_features wacom_features_0x360 =
|
||||||
{ "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
|
{ "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
|
||||||
INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
|
INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
|
||||||
static const struct wacom_features wacom_features_0x361 =
|
static const struct wacom_features wacom_features_0x361 =
|
||||||
{ "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
|
{ "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
|
||||||
INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
|
INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
|
||||||
|
|
||||||
static const struct wacom_features wacom_features_HID_ANY_ID =
|
static const struct wacom_features wacom_features_HID_ANY_ID =
|
||||||
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
|
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
|
||||||
|
|
|
@ -76,7 +76,7 @@ config QCOM_ADSP_PIL
|
||||||
depends on OF && ARCH_QCOM
|
depends on OF && ARCH_QCOM
|
||||||
depends on REMOTEPROC
|
depends on REMOTEPROC
|
||||||
depends on QCOM_SMEM
|
depends on QCOM_SMEM
|
||||||
depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n)
|
depends on RPMSG_QCOM_SMD || QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n && RPMSG_QCOM_SMD=n)
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
select QCOM_MDT_LOADER
|
select QCOM_MDT_LOADER
|
||||||
select QCOM_RPROC_COMMON
|
select QCOM_RPROC_COMMON
|
||||||
|
@ -93,7 +93,7 @@ config QCOM_Q6V5_PIL
|
||||||
depends on OF && ARCH_QCOM
|
depends on OF && ARCH_QCOM
|
||||||
depends on QCOM_SMEM
|
depends on QCOM_SMEM
|
||||||
depends on REMOTEPROC
|
depends on REMOTEPROC
|
||||||
depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n)
|
depends on RPMSG_QCOM_SMD || QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n && RPMSG_QCOM_SMD=n)
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
select QCOM_RPROC_COMMON
|
select QCOM_RPROC_COMMON
|
||||||
select QCOM_SCM
|
select QCOM_SCM
|
||||||
|
@ -104,7 +104,7 @@ config QCOM_Q6V5_PIL
|
||||||
config QCOM_WCNSS_PIL
|
config QCOM_WCNSS_PIL
|
||||||
tristate "Qualcomm WCNSS Peripheral Image Loader"
|
tristate "Qualcomm WCNSS Peripheral Image Loader"
|
||||||
depends on OF && ARCH_QCOM
|
depends on OF && ARCH_QCOM
|
||||||
depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n)
|
depends on RPMSG_QCOM_SMD || QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n && RPMSG_QCOM_SMD=n)
|
||||||
depends on QCOM_SMEM
|
depends on QCOM_SMEM
|
||||||
depends on REMOTEPROC
|
depends on REMOTEPROC
|
||||||
select QCOM_MDT_LOADER
|
select QCOM_MDT_LOADER
|
||||||
|
|
|
@ -1253,20 +1253,6 @@ config SCSI_LPFC_DEBUG_FS
|
||||||
This makes debugging information from the lpfc driver
|
This makes debugging information from the lpfc driver
|
||||||
available via the debugfs filesystem.
|
available via the debugfs filesystem.
|
||||||
|
|
||||||
config LPFC_NVME_INITIATOR
|
|
||||||
bool "Emulex LightPulse Fibre Channel NVME Initiator Support"
|
|
||||||
depends on SCSI_LPFC && NVME_FC
|
|
||||||
---help---
|
|
||||||
This enables NVME Initiator support in the Emulex lpfc driver.
|
|
||||||
|
|
||||||
config LPFC_NVME_TARGET
|
|
||||||
bool "Emulex LightPulse Fibre Channel NVME Initiator Support"
|
|
||||||
depends on SCSI_LPFC && NVME_TARGET_FC
|
|
||||||
---help---
|
|
||||||
This enables NVME Target support in the Emulex lpfc driver.
|
|
||||||
Target enablement must still be enabled on a per adapter
|
|
||||||
basis by module parameters.
|
|
||||||
|
|
||||||
config SCSI_SIM710
|
config SCSI_SIM710
|
||||||
tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
|
tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
|
||||||
depends on (EISA || MCA) && SCSI
|
depends on (EISA || MCA) && SCSI
|
||||||
|
|
|
@ -2956,7 +2956,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
|
||||||
/* fill_cmd can't fail here, no data buffer to map. */
|
/* fill_cmd can't fail here, no data buffer to map. */
|
||||||
(void) fill_cmd(c, reset_type, h, NULL, 0, 0,
|
(void) fill_cmd(c, reset_type, h, NULL, 0, 0,
|
||||||
scsi3addr, TYPE_MSG);
|
scsi3addr, TYPE_MSG);
|
||||||
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, DEFAULT_TIMEOUT);
|
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_warn(&h->pdev->dev, "Failed to send reset command\n");
|
dev_warn(&h->pdev->dev, "Failed to send reset command\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -3714,7 +3714,7 @@ exit_failed:
|
||||||
* # (integer code indicating one of several NOT READY states
|
* # (integer code indicating one of several NOT READY states
|
||||||
* describing why a volume is to be kept offline)
|
* describing why a volume is to be kept offline)
|
||||||
*/
|
*/
|
||||||
static int hpsa_volume_offline(struct ctlr_info *h,
|
static unsigned char hpsa_volume_offline(struct ctlr_info *h,
|
||||||
unsigned char scsi3addr[])
|
unsigned char scsi3addr[])
|
||||||
{
|
{
|
||||||
struct CommandList *c;
|
struct CommandList *c;
|
||||||
|
@ -3735,7 +3735,7 @@ static int hpsa_volume_offline(struct ctlr_info *h,
|
||||||
DEFAULT_TIMEOUT);
|
DEFAULT_TIMEOUT);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cmd_free(h, c);
|
cmd_free(h, c);
|
||||||
return 0;
|
return HPSA_VPD_LV_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
sense = c->err_info->SenseInfo;
|
sense = c->err_info->SenseInfo;
|
||||||
if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
|
if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
|
||||||
|
@ -3746,19 +3746,13 @@ static int hpsa_volume_offline(struct ctlr_info *h,
|
||||||
cmd_status = c->err_info->CommandStatus;
|
cmd_status = c->err_info->CommandStatus;
|
||||||
scsi_status = c->err_info->ScsiStatus;
|
scsi_status = c->err_info->ScsiStatus;
|
||||||
cmd_free(h, c);
|
cmd_free(h, c);
|
||||||
/* Is the volume 'not ready'? */
|
|
||||||
if (cmd_status != CMD_TARGET_STATUS ||
|
|
||||||
scsi_status != SAM_STAT_CHECK_CONDITION ||
|
|
||||||
sense_key != NOT_READY ||
|
|
||||||
asc != ASC_LUN_NOT_READY) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the reason for not ready state */
|
/* Determine the reason for not ready state */
|
||||||
ldstat = hpsa_get_volume_status(h, scsi3addr);
|
ldstat = hpsa_get_volume_status(h, scsi3addr);
|
||||||
|
|
||||||
/* Keep volume offline in certain cases: */
|
/* Keep volume offline in certain cases: */
|
||||||
switch (ldstat) {
|
switch (ldstat) {
|
||||||
|
case HPSA_LV_FAILED:
|
||||||
case HPSA_LV_UNDERGOING_ERASE:
|
case HPSA_LV_UNDERGOING_ERASE:
|
||||||
case HPSA_LV_NOT_AVAILABLE:
|
case HPSA_LV_NOT_AVAILABLE:
|
||||||
case HPSA_LV_UNDERGOING_RPI:
|
case HPSA_LV_UNDERGOING_RPI:
|
||||||
|
@ -3780,7 +3774,7 @@ static int hpsa_volume_offline(struct ctlr_info *h,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return HPSA_LV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3853,10 +3847,10 @@ static int hpsa_update_device_info(struct ctlr_info *h,
|
||||||
/* Do an inquiry to the device to see what it is. */
|
/* Do an inquiry to the device to see what it is. */
|
||||||
if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
|
if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
|
||||||
(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
|
(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
|
||||||
/* Inquiry failed (msg printed already) */
|
|
||||||
dev_err(&h->pdev->dev,
|
dev_err(&h->pdev->dev,
|
||||||
"hpsa_update_device_info: inquiry failed\n");
|
"%s: inquiry failed, device will be skipped.\n",
|
||||||
rc = -EIO;
|
__func__);
|
||||||
|
rc = HPSA_INQUIRY_FAILED;
|
||||||
goto bail_out;
|
goto bail_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3885,15 +3879,19 @@ static int hpsa_update_device_info(struct ctlr_info *h,
|
||||||
if ((this_device->devtype == TYPE_DISK ||
|
if ((this_device->devtype == TYPE_DISK ||
|
||||||
this_device->devtype == TYPE_ZBC) &&
|
this_device->devtype == TYPE_ZBC) &&
|
||||||
is_logical_dev_addr_mode(scsi3addr)) {
|
is_logical_dev_addr_mode(scsi3addr)) {
|
||||||
int volume_offline;
|
unsigned char volume_offline;
|
||||||
|
|
||||||
hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
|
hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
|
||||||
if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
|
if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
|
||||||
hpsa_get_ioaccel_status(h, scsi3addr, this_device);
|
hpsa_get_ioaccel_status(h, scsi3addr, this_device);
|
||||||
volume_offline = hpsa_volume_offline(h, scsi3addr);
|
volume_offline = hpsa_volume_offline(h, scsi3addr);
|
||||||
if (volume_offline < 0 || volume_offline > 0xff)
|
if (volume_offline == HPSA_LV_FAILED) {
|
||||||
volume_offline = HPSA_VPD_LV_STATUS_UNSUPPORTED;
|
rc = HPSA_LV_FAILED;
|
||||||
this_device->volume_offline = volume_offline & 0xff;
|
dev_err(&h->pdev->dev,
|
||||||
|
"%s: LV failed, device will be skipped.\n",
|
||||||
|
__func__);
|
||||||
|
goto bail_out;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this_device->raid_level = RAID_UNKNOWN;
|
this_device->raid_level = RAID_UNKNOWN;
|
||||||
this_device->offload_config = 0;
|
this_device->offload_config = 0;
|
||||||
|
@ -4379,8 +4377,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_warn(&h->pdev->dev,
|
h->drv_req_rescan = 1;
|
||||||
"Inquiry failed, skipping device.\n");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5558,7 +5555,7 @@ static void hpsa_scan_complete(struct ctlr_info *h)
|
||||||
|
|
||||||
spin_lock_irqsave(&h->scan_lock, flags);
|
spin_lock_irqsave(&h->scan_lock, flags);
|
||||||
h->scan_finished = 1;
|
h->scan_finished = 1;
|
||||||
wake_up_all(&h->scan_wait_queue);
|
wake_up(&h->scan_wait_queue);
|
||||||
spin_unlock_irqrestore(&h->scan_lock, flags);
|
spin_unlock_irqrestore(&h->scan_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5576,11 +5573,23 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
|
||||||
if (unlikely(lockup_detected(h)))
|
if (unlikely(lockup_detected(h)))
|
||||||
return hpsa_scan_complete(h);
|
return hpsa_scan_complete(h);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a scan is already waiting to run, no need to add another
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&h->scan_lock, flags);
|
||||||
|
if (h->scan_waiting) {
|
||||||
|
spin_unlock_irqrestore(&h->scan_lock, flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&h->scan_lock, flags);
|
||||||
|
|
||||||
/* wait until any scan already in progress is finished. */
|
/* wait until any scan already in progress is finished. */
|
||||||
while (1) {
|
while (1) {
|
||||||
spin_lock_irqsave(&h->scan_lock, flags);
|
spin_lock_irqsave(&h->scan_lock, flags);
|
||||||
if (h->scan_finished)
|
if (h->scan_finished)
|
||||||
break;
|
break;
|
||||||
|
h->scan_waiting = 1;
|
||||||
spin_unlock_irqrestore(&h->scan_lock, flags);
|
spin_unlock_irqrestore(&h->scan_lock, flags);
|
||||||
wait_event(h->scan_wait_queue, h->scan_finished);
|
wait_event(h->scan_wait_queue, h->scan_finished);
|
||||||
/* Note: We don't need to worry about a race between this
|
/* Note: We don't need to worry about a race between this
|
||||||
|
@ -5590,6 +5599,7 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
h->scan_finished = 0; /* mark scan as in progress */
|
h->scan_finished = 0; /* mark scan as in progress */
|
||||||
|
h->scan_waiting = 0;
|
||||||
spin_unlock_irqrestore(&h->scan_lock, flags);
|
spin_unlock_irqrestore(&h->scan_lock, flags);
|
||||||
|
|
||||||
if (unlikely(lockup_detected(h)))
|
if (unlikely(lockup_detected(h)))
|
||||||
|
@ -8792,6 +8802,7 @@ reinit_after_soft_reset:
|
||||||
init_waitqueue_head(&h->event_sync_wait_queue);
|
init_waitqueue_head(&h->event_sync_wait_queue);
|
||||||
mutex_init(&h->reset_mutex);
|
mutex_init(&h->reset_mutex);
|
||||||
h->scan_finished = 1; /* no scan currently in progress */
|
h->scan_finished = 1; /* no scan currently in progress */
|
||||||
|
h->scan_waiting = 0;
|
||||||
|
|
||||||
pci_set_drvdata(pdev, h);
|
pci_set_drvdata(pdev, h);
|
||||||
h->ndevices = 0;
|
h->ndevices = 0;
|
||||||
|
|
|
@ -201,6 +201,7 @@ struct ctlr_info {
|
||||||
dma_addr_t errinfo_pool_dhandle;
|
dma_addr_t errinfo_pool_dhandle;
|
||||||
unsigned long *cmd_pool_bits;
|
unsigned long *cmd_pool_bits;
|
||||||
int scan_finished;
|
int scan_finished;
|
||||||
|
u8 scan_waiting : 1;
|
||||||
spinlock_t scan_lock;
|
spinlock_t scan_lock;
|
||||||
wait_queue_head_t scan_wait_queue;
|
wait_queue_head_t scan_wait_queue;
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,7 @@
|
||||||
#define CFGTBL_BusType_Fibre2G 0x00000200l
|
#define CFGTBL_BusType_Fibre2G 0x00000200l
|
||||||
|
|
||||||
/* VPD Inquiry types */
|
/* VPD Inquiry types */
|
||||||
|
#define HPSA_INQUIRY_FAILED 0x02
|
||||||
#define HPSA_VPD_SUPPORTED_PAGES 0x00
|
#define HPSA_VPD_SUPPORTED_PAGES 0x00
|
||||||
#define HPSA_VPD_LV_DEVICE_ID 0x83
|
#define HPSA_VPD_LV_DEVICE_ID 0x83
|
||||||
#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
|
#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
|
||||||
|
@ -166,6 +167,7 @@
|
||||||
/* Logical volume states */
|
/* Logical volume states */
|
||||||
#define HPSA_VPD_LV_STATUS_UNSUPPORTED 0xff
|
#define HPSA_VPD_LV_STATUS_UNSUPPORTED 0xff
|
||||||
#define HPSA_LV_OK 0x0
|
#define HPSA_LV_OK 0x0
|
||||||
|
#define HPSA_LV_FAILED 0x01
|
||||||
#define HPSA_LV_NOT_AVAILABLE 0x0b
|
#define HPSA_LV_NOT_AVAILABLE 0x0b
|
||||||
#define HPSA_LV_UNDERGOING_ERASE 0x0F
|
#define HPSA_LV_UNDERGOING_ERASE 0x0F
|
||||||
#define HPSA_LV_UNDERGOING_RPI 0x12
|
#define HPSA_LV_UNDERGOING_RPI 0x12
|
||||||
|
|
|
@ -3315,9 +3315,9 @@ LPFC_ATTR_R(nvmet_mrq_post, LPFC_DEF_MRQ_POST,
|
||||||
* lpfc_enable_fc4_type: Defines what FC4 types are supported.
|
* lpfc_enable_fc4_type: Defines what FC4 types are supported.
|
||||||
* Supported Values: 1 - register just FCP
|
* Supported Values: 1 - register just FCP
|
||||||
* 3 - register both FCP and NVME
|
* 3 - register both FCP and NVME
|
||||||
* Supported values are [1,3]. Default value is 3
|
* Supported values are [1,3]. Default value is 1
|
||||||
*/
|
*/
|
||||||
LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_BOTH,
|
LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_FCP,
|
||||||
LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH,
|
LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH,
|
||||||
"Define fc4 type to register with fabric.");
|
"Define fc4 type to register with fabric.");
|
||||||
|
|
||||||
|
|
|
@ -5891,10 +5891,17 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||||
/* Check to see if it matches any module parameter */
|
/* Check to see if it matches any module parameter */
|
||||||
for (i = 0; i < lpfc_enable_nvmet_cnt; i++) {
|
for (i = 0; i < lpfc_enable_nvmet_cnt; i++) {
|
||||||
if (wwn == lpfc_enable_nvmet[i]) {
|
if (wwn == lpfc_enable_nvmet[i]) {
|
||||||
|
#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||||
"6017 NVME Target %016llx\n",
|
"6017 NVME Target %016llx\n",
|
||||||
wwn);
|
wwn);
|
||||||
phba->nvmet_support = 1; /* a match */
|
phba->nvmet_support = 1; /* a match */
|
||||||
|
#else
|
||||||
|
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||||
|
"6021 Can't enable NVME Target."
|
||||||
|
" NVME_TARGET_FC infrastructure"
|
||||||
|
" is not in kernel\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2149,7 +2149,7 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
|
||||||
/* localport is allocated from the stack, but the registration
|
/* localport is allocated from the stack, but the registration
|
||||||
* call allocates heap memory as well as the private area.
|
* call allocates heap memory as well as the private area.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_LPFC_NVME_INITIATOR
|
#if (IS_ENABLED(CONFIG_NVME_FC))
|
||||||
ret = nvme_fc_register_localport(&nfcp_info, &lpfc_nvme_template,
|
ret = nvme_fc_register_localport(&nfcp_info, &lpfc_nvme_template,
|
||||||
&vport->phba->pcidev->dev, &localport);
|
&vport->phba->pcidev->dev, &localport);
|
||||||
#else
|
#else
|
||||||
|
@ -2190,7 +2190,7 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
|
||||||
void
|
void
|
||||||
lpfc_nvme_destroy_localport(struct lpfc_vport *vport)
|
lpfc_nvme_destroy_localport(struct lpfc_vport *vport)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LPFC_NVME_INITIATOR
|
#if (IS_ENABLED(CONFIG_NVME_FC))
|
||||||
struct nvme_fc_local_port *localport;
|
struct nvme_fc_local_port *localport;
|
||||||
struct lpfc_nvme_lport *lport;
|
struct lpfc_nvme_lport *lport;
|
||||||
struct lpfc_nvme_rport *rport = NULL, *rport_next = NULL;
|
struct lpfc_nvme_rport *rport = NULL, *rport_next = NULL;
|
||||||
|
@ -2274,7 +2274,7 @@ lpfc_nvme_update_localport(struct lpfc_vport *vport)
|
||||||
int
|
int
|
||||||
lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LPFC_NVME_INITIATOR
|
#if (IS_ENABLED(CONFIG_NVME_FC))
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct nvme_fc_local_port *localport;
|
struct nvme_fc_local_port *localport;
|
||||||
struct lpfc_nvme_lport *lport;
|
struct lpfc_nvme_lport *lport;
|
||||||
|
@ -2403,7 +2403,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
||||||
void
|
void
|
||||||
lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LPFC_NVME_INITIATOR
|
#if (IS_ENABLED(CONFIG_NVME_FC))
|
||||||
int ret;
|
int ret;
|
||||||
struct nvme_fc_local_port *localport;
|
struct nvme_fc_local_port *localport;
|
||||||
struct lpfc_nvme_lport *lport;
|
struct lpfc_nvme_lport *lport;
|
||||||
|
|
|
@ -671,7 +671,7 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba)
|
||||||
lpfc_tgttemplate.target_features = NVMET_FCTGTFEAT_READDATA_RSP |
|
lpfc_tgttemplate.target_features = NVMET_FCTGTFEAT_READDATA_RSP |
|
||||||
NVMET_FCTGTFEAT_NEEDS_CMD_CPUSCHED;
|
NVMET_FCTGTFEAT_NEEDS_CMD_CPUSCHED;
|
||||||
|
|
||||||
#ifdef CONFIG_LPFC_NVME_TARGET
|
#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
|
||||||
error = nvmet_fc_register_targetport(&pinfo, &lpfc_tgttemplate,
|
error = nvmet_fc_register_targetport(&pinfo, &lpfc_tgttemplate,
|
||||||
&phba->pcidev->dev,
|
&phba->pcidev->dev,
|
||||||
&phba->targetport);
|
&phba->targetport);
|
||||||
|
@ -756,7 +756,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
|
||||||
void
|
void
|
||||||
lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
|
lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LPFC_NVME_TARGET
|
#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
|
||||||
struct lpfc_nvmet_tgtport *tgtp;
|
struct lpfc_nvmet_tgtport *tgtp;
|
||||||
|
|
||||||
if (phba->nvmet_support == 0)
|
if (phba->nvmet_support == 0)
|
||||||
|
@ -788,7 +788,7 @@ static void
|
||||||
lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||||
struct hbq_dmabuf *nvmebuf)
|
struct hbq_dmabuf *nvmebuf)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LPFC_NVME_TARGET
|
#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
|
||||||
struct lpfc_nvmet_tgtport *tgtp;
|
struct lpfc_nvmet_tgtport *tgtp;
|
||||||
struct fc_frame_header *fc_hdr;
|
struct fc_frame_header *fc_hdr;
|
||||||
struct lpfc_nvmet_rcv_ctx *ctxp;
|
struct lpfc_nvmet_rcv_ctx *ctxp;
|
||||||
|
@ -891,7 +891,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
|
||||||
struct rqb_dmabuf *nvmebuf,
|
struct rqb_dmabuf *nvmebuf,
|
||||||
uint64_t isr_timestamp)
|
uint64_t isr_timestamp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LPFC_NVME_TARGET
|
#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
|
||||||
struct lpfc_nvmet_rcv_ctx *ctxp;
|
struct lpfc_nvmet_rcv_ctx *ctxp;
|
||||||
struct lpfc_nvmet_tgtport *tgtp;
|
struct lpfc_nvmet_tgtport *tgtp;
|
||||||
struct fc_frame_header *fc_hdr;
|
struct fc_frame_header *fc_hdr;
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
/*
|
/*
|
||||||
* MegaRAID SAS Driver meta data
|
* MegaRAID SAS Driver meta data
|
||||||
*/
|
*/
|
||||||
#define MEGASAS_VERSION "07.701.16.00-rc1"
|
#define MEGASAS_VERSION "07.701.17.00-rc1"
|
||||||
#define MEGASAS_RELDATE "February 2, 2017"
|
#define MEGASAS_RELDATE "March 2, 2017"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Device IDs
|
* Device IDs
|
||||||
|
|
|
@ -1963,6 +1963,9 @@ scan_target:
|
||||||
if (!mr_device_priv_data)
|
if (!mr_device_priv_data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
sdev->hostdata = mr_device_priv_data;
|
sdev->hostdata = mr_device_priv_data;
|
||||||
|
|
||||||
|
atomic_set(&mr_device_priv_data->r1_ldio_hint,
|
||||||
|
instance->r1_ldio_hint_default);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5034,10 +5037,12 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
|
||||||
&instance->irq_context[j]);
|
&instance->irq_context[j]);
|
||||||
/* Retry irq register for IO_APIC*/
|
/* Retry irq register for IO_APIC*/
|
||||||
instance->msix_vectors = 0;
|
instance->msix_vectors = 0;
|
||||||
if (is_probe)
|
if (is_probe) {
|
||||||
|
pci_free_irq_vectors(instance->pdev);
|
||||||
return megasas_setup_irqs_ioapic(instance);
|
return megasas_setup_irqs_ioapic(instance);
|
||||||
else
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5277,9 +5282,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
|
||||||
MPI2_REPLY_POST_HOST_INDEX_OFFSET);
|
MPI2_REPLY_POST_HOST_INDEX_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
|
if (!instance->msix_vectors) {
|
||||||
if (i < 0)
|
i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
|
||||||
goto fail_setup_irqs;
|
if (i < 0)
|
||||||
|
goto fail_setup_irqs;
|
||||||
|
}
|
||||||
|
|
||||||
dev_info(&instance->pdev->dev,
|
dev_info(&instance->pdev->dev,
|
||||||
"firmware supports msix\t: (%d)", fw_msix_count);
|
"firmware supports msix\t: (%d)", fw_msix_count);
|
||||||
|
|
|
@ -2159,7 +2159,7 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
|
||||||
cpu_sel = MR_RAID_CTX_CPUSEL_1;
|
cpu_sel = MR_RAID_CTX_CPUSEL_1;
|
||||||
|
|
||||||
if (is_stream_detected(rctx_g35) &&
|
if (is_stream_detected(rctx_g35) &&
|
||||||
(raid->level == 5) &&
|
((raid->level == 5) || (raid->level == 6)) &&
|
||||||
(raid->writeMode == MR_RL_WRITE_THROUGH_MODE) &&
|
(raid->writeMode == MR_RL_WRITE_THROUGH_MODE) &&
|
||||||
(cpu_sel == MR_RAID_CTX_CPUSEL_FCFS))
|
(cpu_sel == MR_RAID_CTX_CPUSEL_FCFS))
|
||||||
cpu_sel = MR_RAID_CTX_CPUSEL_0;
|
cpu_sel = MR_RAID_CTX_CPUSEL_0;
|
||||||
|
@ -2338,7 +2338,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
|
||||||
fp_possible = false;
|
fp_possible = false;
|
||||||
atomic_dec(&instance->fw_outstanding);
|
atomic_dec(&instance->fw_outstanding);
|
||||||
} else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
|
} else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
|
||||||
atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint)) {
|
(atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) {
|
||||||
fp_possible = false;
|
fp_possible = false;
|
||||||
atomic_dec(&instance->fw_outstanding);
|
atomic_dec(&instance->fw_outstanding);
|
||||||
if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
|
if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
|
||||||
|
|
|
@ -7642,7 +7642,7 @@ static inline ssize_t ufshcd_pm_lvl_store(struct device *dev,
|
||||||
if (kstrtoul(buf, 0, &value))
|
if (kstrtoul(buf, 0, &value))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
|
if (value >= UFS_PM_LVL_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
|
|
|
@ -575,12 +575,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
pinctrl_select_state(ascport->pinctrl,
|
pinctrl_select_state(ascport->pinctrl,
|
||||||
ascport->states[NO_HW_FLOWCTRL]);
|
ascport->states[NO_HW_FLOWCTRL]);
|
||||||
|
|
||||||
gpiod = devm_get_gpiod_from_child(port->dev, "rts",
|
gpiod = devm_fwnode_get_gpiod_from_child(port->dev,
|
||||||
&np->fwnode);
|
"rts",
|
||||||
if (!IS_ERR(gpiod)) {
|
&np->fwnode,
|
||||||
gpiod_direction_output(gpiod, 0);
|
GPIOD_OUT_LOW,
|
||||||
|
np->name);
|
||||||
|
if (!IS_ERR(gpiod))
|
||||||
ascport->rts = gpiod;
|
ascport->rts = gpiod;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
|
||||||
si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
|
si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
|
||||||
si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
|
si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
|
||||||
si->base_mem += NM_I(sbi)->nat_blocks / 8;
|
si->base_mem += NM_I(sbi)->nat_blocks / 8;
|
||||||
|
si->base_mem += NM_I(sbi)->nat_blocks * sizeof(unsigned short);
|
||||||
|
|
||||||
get_cache:
|
get_cache:
|
||||||
si->cache_mem = 0;
|
si->cache_mem = 0;
|
||||||
|
|
|
@ -750,7 +750,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||||
dentry_blk = page_address(page);
|
dentry_blk = page_address(page);
|
||||||
bit_pos = dentry - dentry_blk->dentry;
|
bit_pos = dentry - dentry_blk->dentry;
|
||||||
for (i = 0; i < slots; i++)
|
for (i = 0; i < slots; i++)
|
||||||
clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
|
__clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
|
||||||
|
|
||||||
/* Let's check and deallocate this dentry page */
|
/* Let's check and deallocate this dentry page */
|
||||||
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
|
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
|
||||||
|
|
|
@ -561,6 +561,8 @@ struct f2fs_nm_info {
|
||||||
struct mutex build_lock; /* lock for build free nids */
|
struct mutex build_lock; /* lock for build free nids */
|
||||||
unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE];
|
unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE];
|
||||||
unsigned char *nat_block_bitmap;
|
unsigned char *nat_block_bitmap;
|
||||||
|
unsigned short *free_nid_count; /* free nid count of NAT block */
|
||||||
|
spinlock_t free_nid_lock; /* protect updating of nid count */
|
||||||
|
|
||||||
/* for checkpoint */
|
/* for checkpoint */
|
||||||
char *nat_bitmap; /* NAT bitmap pointer */
|
char *nat_bitmap; /* NAT bitmap pointer */
|
||||||
|
|
163
fs/f2fs/node.c
163
fs/f2fs/node.c
|
@ -338,9 +338,6 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||||
set_nat_flag(e, IS_CHECKPOINTED, false);
|
set_nat_flag(e, IS_CHECKPOINTED, false);
|
||||||
__set_nat_cache_dirty(nm_i, e);
|
__set_nat_cache_dirty(nm_i, e);
|
||||||
|
|
||||||
if (enabled_nat_bits(sbi, NULL) && new_blkaddr == NEW_ADDR)
|
|
||||||
clear_bit_le(NAT_BLOCK_OFFSET(ni->nid), nm_i->empty_nat_bits);
|
|
||||||
|
|
||||||
/* update fsync_mark if its inode nat entry is still alive */
|
/* update fsync_mark if its inode nat entry is still alive */
|
||||||
if (ni->nid != ni->ino)
|
if (ni->nid != ni->ino)
|
||||||
e = __lookup_nat_cache(nm_i, ni->ino);
|
e = __lookup_nat_cache(nm_i, ni->ino);
|
||||||
|
@ -1823,7 +1820,8 @@ static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
|
||||||
kmem_cache_free(free_nid_slab, i);
|
kmem_cache_free(free_nid_slab, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, bool set)
|
static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid,
|
||||||
|
bool set, bool build, bool locked)
|
||||||
{
|
{
|
||||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||||
unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
|
unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
|
||||||
|
@ -1833,9 +1831,18 @@ void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, bool set)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
|
__set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
|
||||||
else
|
else
|
||||||
clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
|
__clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
|
||||||
|
|
||||||
|
if (!locked)
|
||||||
|
spin_lock(&nm_i->free_nid_lock);
|
||||||
|
if (set)
|
||||||
|
nm_i->free_nid_count[nat_ofs]++;
|
||||||
|
else if (!build)
|
||||||
|
nm_i->free_nid_count[nat_ofs]--;
|
||||||
|
if (!locked)
|
||||||
|
spin_unlock(&nm_i->free_nid_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scan_nat_page(struct f2fs_sb_info *sbi,
|
static void scan_nat_page(struct f2fs_sb_info *sbi,
|
||||||
|
@ -1847,7 +1854,10 @@ static void scan_nat_page(struct f2fs_sb_info *sbi,
|
||||||
unsigned int nat_ofs = NAT_BLOCK_OFFSET(start_nid);
|
unsigned int nat_ofs = NAT_BLOCK_OFFSET(start_nid);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
set_bit_le(nat_ofs, nm_i->nat_block_bitmap);
|
if (test_bit_le(nat_ofs, nm_i->nat_block_bitmap))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__set_bit_le(nat_ofs, nm_i->nat_block_bitmap);
|
||||||
|
|
||||||
i = start_nid % NAT_ENTRY_PER_BLOCK;
|
i = start_nid % NAT_ENTRY_PER_BLOCK;
|
||||||
|
|
||||||
|
@ -1861,7 +1871,7 @@ static void scan_nat_page(struct f2fs_sb_info *sbi,
|
||||||
f2fs_bug_on(sbi, blk_addr == NEW_ADDR);
|
f2fs_bug_on(sbi, blk_addr == NEW_ADDR);
|
||||||
if (blk_addr == NULL_ADDR)
|
if (blk_addr == NULL_ADDR)
|
||||||
freed = add_free_nid(sbi, start_nid, true);
|
freed = add_free_nid(sbi, start_nid, true);
|
||||||
update_free_nid_bitmap(sbi, start_nid, freed);
|
update_free_nid_bitmap(sbi, start_nid, freed, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1877,6 +1887,8 @@ static void scan_free_nid_bits(struct f2fs_sb_info *sbi)
|
||||||
for (i = 0; i < nm_i->nat_blocks; i++) {
|
for (i = 0; i < nm_i->nat_blocks; i++) {
|
||||||
if (!test_bit_le(i, nm_i->nat_block_bitmap))
|
if (!test_bit_le(i, nm_i->nat_block_bitmap))
|
||||||
continue;
|
continue;
|
||||||
|
if (!nm_i->free_nid_count[i])
|
||||||
|
continue;
|
||||||
for (idx = 0; idx < NAT_ENTRY_PER_BLOCK; idx++) {
|
for (idx = 0; idx < NAT_ENTRY_PER_BLOCK; idx++) {
|
||||||
nid_t nid;
|
nid_t nid;
|
||||||
|
|
||||||
|
@ -1907,58 +1919,6 @@ out:
|
||||||
up_read(&nm_i->nat_tree_lock);
|
up_read(&nm_i->nat_tree_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scan_nat_bits(struct f2fs_sb_info *sbi)
|
|
||||||
{
|
|
||||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
|
||||||
struct page *page;
|
|
||||||
unsigned int i = 0;
|
|
||||||
nid_t nid;
|
|
||||||
|
|
||||||
if (!enabled_nat_bits(sbi, NULL))
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
down_read(&nm_i->nat_tree_lock);
|
|
||||||
check_empty:
|
|
||||||
i = find_next_bit_le(nm_i->empty_nat_bits, nm_i->nat_blocks, i);
|
|
||||||
if (i >= nm_i->nat_blocks) {
|
|
||||||
i = 0;
|
|
||||||
goto check_partial;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (nid = i * NAT_ENTRY_PER_BLOCK; nid < (i + 1) * NAT_ENTRY_PER_BLOCK;
|
|
||||||
nid++) {
|
|
||||||
if (unlikely(nid >= nm_i->max_nid))
|
|
||||||
break;
|
|
||||||
add_free_nid(sbi, nid, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nm_i->nid_cnt[FREE_NID_LIST] >= MAX_FREE_NIDS)
|
|
||||||
goto out;
|
|
||||||
i++;
|
|
||||||
goto check_empty;
|
|
||||||
|
|
||||||
check_partial:
|
|
||||||
i = find_next_zero_bit_le(nm_i->full_nat_bits, nm_i->nat_blocks, i);
|
|
||||||
if (i >= nm_i->nat_blocks) {
|
|
||||||
disable_nat_bits(sbi, true);
|
|
||||||
up_read(&nm_i->nat_tree_lock);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nid = i * NAT_ENTRY_PER_BLOCK;
|
|
||||||
page = get_current_nat_page(sbi, nid);
|
|
||||||
scan_nat_page(sbi, page, nid);
|
|
||||||
f2fs_put_page(page, 1);
|
|
||||||
|
|
||||||
if (nm_i->nid_cnt[FREE_NID_LIST] < MAX_FREE_NIDS) {
|
|
||||||
i++;
|
|
||||||
goto check_partial;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
up_read(&nm_i->nat_tree_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||||
{
|
{
|
||||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||||
|
@ -1980,21 +1940,6 @@ static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||||
|
|
||||||
if (nm_i->nid_cnt[FREE_NID_LIST])
|
if (nm_i->nid_cnt[FREE_NID_LIST])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* try to find free nids with nat_bits */
|
|
||||||
if (!scan_nat_bits(sbi) && nm_i->nid_cnt[FREE_NID_LIST])
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find next valid candidate */
|
|
||||||
if (enabled_nat_bits(sbi, NULL)) {
|
|
||||||
int idx = find_next_zero_bit_le(nm_i->full_nat_bits,
|
|
||||||
nm_i->nat_blocks, 0);
|
|
||||||
|
|
||||||
if (idx >= nm_i->nat_blocks)
|
|
||||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
|
||||||
else
|
|
||||||
nid = idx * NAT_ENTRY_PER_BLOCK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* readahead nat pages to be scanned */
|
/* readahead nat pages to be scanned */
|
||||||
|
@ -2081,7 +2026,7 @@ retry:
|
||||||
__insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false);
|
__insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false);
|
||||||
nm_i->available_nids--;
|
nm_i->available_nids--;
|
||||||
|
|
||||||
update_free_nid_bitmap(sbi, *nid, false);
|
update_free_nid_bitmap(sbi, *nid, false, false, false);
|
||||||
|
|
||||||
spin_unlock(&nm_i->nid_list_lock);
|
spin_unlock(&nm_i->nid_list_lock);
|
||||||
return true;
|
return true;
|
||||||
|
@ -2137,7 +2082,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
|
||||||
|
|
||||||
nm_i->available_nids++;
|
nm_i->available_nids++;
|
||||||
|
|
||||||
update_free_nid_bitmap(sbi, nid, true);
|
update_free_nid_bitmap(sbi, nid, true, false, false);
|
||||||
|
|
||||||
spin_unlock(&nm_i->nid_list_lock);
|
spin_unlock(&nm_i->nid_list_lock);
|
||||||
|
|
||||||
|
@ -2383,7 +2328,7 @@ add_out:
|
||||||
list_add_tail(&nes->set_list, head);
|
list_add_tail(&nes->set_list, head);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid,
|
static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid,
|
||||||
struct page *page)
|
struct page *page)
|
||||||
{
|
{
|
||||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||||
|
@ -2402,16 +2347,16 @@ void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid,
|
||||||
valid++;
|
valid++;
|
||||||
}
|
}
|
||||||
if (valid == 0) {
|
if (valid == 0) {
|
||||||
set_bit_le(nat_index, nm_i->empty_nat_bits);
|
__set_bit_le(nat_index, nm_i->empty_nat_bits);
|
||||||
clear_bit_le(nat_index, nm_i->full_nat_bits);
|
__clear_bit_le(nat_index, nm_i->full_nat_bits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_bit_le(nat_index, nm_i->empty_nat_bits);
|
__clear_bit_le(nat_index, nm_i->empty_nat_bits);
|
||||||
if (valid == NAT_ENTRY_PER_BLOCK)
|
if (valid == NAT_ENTRY_PER_BLOCK)
|
||||||
set_bit_le(nat_index, nm_i->full_nat_bits);
|
__set_bit_le(nat_index, nm_i->full_nat_bits);
|
||||||
else
|
else
|
||||||
clear_bit_le(nat_index, nm_i->full_nat_bits);
|
__clear_bit_le(nat_index, nm_i->full_nat_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
|
static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
|
||||||
|
@ -2467,11 +2412,11 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
|
||||||
add_free_nid(sbi, nid, false);
|
add_free_nid(sbi, nid, false);
|
||||||
spin_lock(&NM_I(sbi)->nid_list_lock);
|
spin_lock(&NM_I(sbi)->nid_list_lock);
|
||||||
NM_I(sbi)->available_nids++;
|
NM_I(sbi)->available_nids++;
|
||||||
update_free_nid_bitmap(sbi, nid, true);
|
update_free_nid_bitmap(sbi, nid, true, false, false);
|
||||||
spin_unlock(&NM_I(sbi)->nid_list_lock);
|
spin_unlock(&NM_I(sbi)->nid_list_lock);
|
||||||
} else {
|
} else {
|
||||||
spin_lock(&NM_I(sbi)->nid_list_lock);
|
spin_lock(&NM_I(sbi)->nid_list_lock);
|
||||||
update_free_nid_bitmap(sbi, nid, false);
|
update_free_nid_bitmap(sbi, nid, false, false, false);
|
||||||
spin_unlock(&NM_I(sbi)->nid_list_lock);
|
spin_unlock(&NM_I(sbi)->nid_list_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2577,6 +2522,40 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void load_free_nid_bitmap(struct f2fs_sb_info *sbi)
|
||||||
|
{
|
||||||
|
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||||
|
unsigned int i = 0;
|
||||||
|
nid_t nid, last_nid;
|
||||||
|
|
||||||
|
if (!enabled_nat_bits(sbi, NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < nm_i->nat_blocks; i++) {
|
||||||
|
i = find_next_bit_le(nm_i->empty_nat_bits, nm_i->nat_blocks, i);
|
||||||
|
if (i >= nm_i->nat_blocks)
|
||||||
|
break;
|
||||||
|
|
||||||
|
__set_bit_le(i, nm_i->nat_block_bitmap);
|
||||||
|
|
||||||
|
nid = i * NAT_ENTRY_PER_BLOCK;
|
||||||
|
last_nid = (i + 1) * NAT_ENTRY_PER_BLOCK;
|
||||||
|
|
||||||
|
spin_lock(&nm_i->free_nid_lock);
|
||||||
|
for (; nid < last_nid; nid++)
|
||||||
|
update_free_nid_bitmap(sbi, nid, true, true, true);
|
||||||
|
spin_unlock(&nm_i->free_nid_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nm_i->nat_blocks; i++) {
|
||||||
|
i = find_next_bit_le(nm_i->full_nat_bits, nm_i->nat_blocks, i);
|
||||||
|
if (i >= nm_i->nat_blocks)
|
||||||
|
break;
|
||||||
|
|
||||||
|
__set_bit_le(i, nm_i->nat_block_bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int init_node_manager(struct f2fs_sb_info *sbi)
|
static int init_node_manager(struct f2fs_sb_info *sbi)
|
||||||
{
|
{
|
||||||
struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi);
|
struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi);
|
||||||
|
@ -2638,7 +2617,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_free_nid_cache(struct f2fs_sb_info *sbi)
|
static int init_free_nid_cache(struct f2fs_sb_info *sbi)
|
||||||
{
|
{
|
||||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||||
|
|
||||||
|
@ -2651,6 +2630,14 @@ int init_free_nid_cache(struct f2fs_sb_info *sbi)
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!nm_i->nat_block_bitmap)
|
if (!nm_i->nat_block_bitmap)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
nm_i->free_nid_count = f2fs_kvzalloc(nm_i->nat_blocks *
|
||||||
|
sizeof(unsigned short), GFP_KERNEL);
|
||||||
|
if (!nm_i->free_nid_count)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
spin_lock_init(&nm_i->free_nid_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2670,6 +2657,9 @@ int build_node_manager(struct f2fs_sb_info *sbi)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* load free nid status from nat_bits table */
|
||||||
|
load_free_nid_bitmap(sbi);
|
||||||
|
|
||||||
build_free_nids(sbi, true, true);
|
build_free_nids(sbi, true, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2730,6 +2720,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||||
|
|
||||||
kvfree(nm_i->nat_block_bitmap);
|
kvfree(nm_i->nat_block_bitmap);
|
||||||
kvfree(nm_i->free_nid_bitmap);
|
kvfree(nm_i->free_nid_bitmap);
|
||||||
|
kvfree(nm_i->free_nid_count);
|
||||||
|
|
||||||
kfree(nm_i->nat_bitmap);
|
kfree(nm_i->nat_bitmap);
|
||||||
kfree(nm_i->nat_bits);
|
kfree(nm_i->nat_bits);
|
||||||
|
|
|
@ -1163,6 +1163,12 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
|
||||||
if (f2fs_discard_en(sbi) &&
|
if (f2fs_discard_en(sbi) &&
|
||||||
!f2fs_test_and_set_bit(offset, se->discard_map))
|
!f2fs_test_and_set_bit(offset, se->discard_map))
|
||||||
sbi->discard_blks--;
|
sbi->discard_blks--;
|
||||||
|
|
||||||
|
/* don't overwrite by SSR to keep node chain */
|
||||||
|
if (se->type == CURSEG_WARM_NODE) {
|
||||||
|
if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
|
||||||
|
se->ckpt_valid_blocks++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map)) {
|
if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map)) {
|
||||||
#ifdef CONFIG_F2FS_CHECK_FS
|
#ifdef CONFIG_F2FS_CHECK_FS
|
||||||
|
|
|
@ -143,15 +143,6 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
|
||||||
struct fwnode_handle *child,
|
struct fwnode_handle *child,
|
||||||
enum gpiod_flags flags,
|
enum gpiod_flags flags,
|
||||||
const char *label);
|
const char *label);
|
||||||
/* FIXME: delete this helper when users are switched over */
|
|
||||||
static inline struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
|
|
||||||
const char *con_id, struct fwnode_handle *child)
|
|
||||||
{
|
|
||||||
return devm_fwnode_get_index_gpiod_from_child(dev, con_id,
|
|
||||||
0, child,
|
|
||||||
GPIOD_ASIS,
|
|
||||||
"?");
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* CONFIG_GPIOLIB */
|
#else /* CONFIG_GPIOLIB */
|
||||||
|
|
||||||
|
@ -444,13 +435,6 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
|
||||||
return ERR_PTR(-ENOSYS);
|
return ERR_PTR(-ENOSYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: delete this when all users are switched over */
|
|
||||||
static inline struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
|
|
||||||
const char *con_id, struct fwnode_handle *child)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_GPIOLIB */
|
#endif /* CONFIG_GPIOLIB */
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
|
|
|
@ -409,6 +409,7 @@ typedef struct elf64_shdr {
|
||||||
#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
|
#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
|
||||||
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */
|
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */
|
||||||
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
|
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
|
||||||
|
#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
|
||||||
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
|
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
|
||||||
#define NT_ARM_TLS 0x401 /* ARM TLS register */
|
#define NT_ARM_TLS 0x401 /* ARM TLS register */
|
||||||
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
|
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
|
||||||
|
|
|
@ -890,6 +890,8 @@ struct kvm_ppc_resize_hpt {
|
||||||
#define KVM_CAP_MIPS_VZ 137
|
#define KVM_CAP_MIPS_VZ 137
|
||||||
#define KVM_CAP_MIPS_TE 138
|
#define KVM_CAP_MIPS_TE 138
|
||||||
#define KVM_CAP_MIPS_64BIT 139
|
#define KVM_CAP_MIPS_64BIT 139
|
||||||
|
#define KVM_CAP_S390_GS 140
|
||||||
|
#define KVM_CAP_S390_AIS 141
|
||||||
|
|
||||||
#ifdef KVM_CAP_IRQ_ROUTING
|
#ifdef KVM_CAP_IRQ_ROUTING
|
||||||
|
|
||||||
|
|
|
@ -267,8 +267,6 @@ int free_swap_slot(swp_entry_t entry)
|
||||||
{
|
{
|
||||||
struct swap_slots_cache *cache;
|
struct swap_slots_cache *cache;
|
||||||
|
|
||||||
WARN_ON_ONCE(!swap_slot_cache_initialized);
|
|
||||||
|
|
||||||
cache = &get_cpu_var(swp_slots);
|
cache = &get_cpu_var(swp_slots);
|
||||||
if (use_swap_slot_cache && cache->slots_ret) {
|
if (use_swap_slot_cache && cache->slots_ret) {
|
||||||
spin_lock_irq(&cache->free_lock);
|
spin_lock_irq(&cache->free_lock);
|
||||||
|
|
Loading…
Reference in New Issue