[S390] cleanup lowcore access from external interrupts
Read external interrupts parameters from the lowcore in the first level interrupt handler in entry[64].S. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Родитель
1e54622e04
Коммит
f6649a7e5a
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
typedef void (*ext_int_handler_t)(__u16 code);
|
typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
|
||||||
|
|
||||||
typedef struct ext_int_info_t {
|
typedef struct ext_int_info_t {
|
||||||
struct ext_int_info_t *next;
|
struct ext_int_info_t *next;
|
||||||
|
|
|
@ -143,10 +143,8 @@ int main(void)
|
||||||
DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
|
DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
|
||||||
DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
|
DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
|
||||||
#ifdef CONFIG_32BIT
|
#ifdef CONFIG_32BIT
|
||||||
DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params));
|
|
||||||
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
|
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
|
||||||
#else /* CONFIG_32BIT */
|
#else /* CONFIG_32BIT */
|
||||||
DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params2));
|
|
||||||
DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2));
|
DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2));
|
||||||
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area));
|
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area));
|
||||||
DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste));
|
DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste));
|
||||||
|
|
|
@ -722,7 +722,8 @@ ext_no_vtime:
|
||||||
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
|
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
la %r2,SP_PTREGS(%r15) # address of register-save area
|
la %r2,SP_PTREGS(%r15) # address of register-save area
|
||||||
lh %r3,__LC_EXT_INT_CODE # get interruption code
|
l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code
|
||||||
|
l %r4,__LC_EXT_PARAMS # get external parameters
|
||||||
l %r1,BASED(.Ldo_extint)
|
l %r1,BASED(.Ldo_extint)
|
||||||
basr %r14,%r1
|
basr %r14,%r1
|
||||||
b BASED(io_return)
|
b BASED(io_return)
|
||||||
|
|
|
@ -19,7 +19,7 @@ void do_signal(struct pt_regs *regs);
|
||||||
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||||
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
|
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
|
||||||
|
|
||||||
void do_extint(struct pt_regs *regs, unsigned short code);
|
void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
|
||||||
int __cpuinit start_secondary(void *cpuvoid);
|
int __cpuinit start_secondary(void *cpuvoid);
|
||||||
void __init startup_init(void);
|
void __init startup_init(void);
|
||||||
void die(const char * str, struct pt_regs * regs, long err);
|
void die(const char * str, struct pt_regs * regs, long err);
|
||||||
|
|
|
@ -727,8 +727,11 @@ ext_int_handler:
|
||||||
ext_no_vtime:
|
ext_no_vtime:
|
||||||
HANDLE_SIE_INTERCEPT
|
HANDLE_SIE_INTERCEPT
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
|
lghi %r1,4096
|
||||||
la %r2,SP_PTREGS(%r15) # address of register-save area
|
la %r2,SP_PTREGS(%r15) # address of register-save area
|
||||||
llgh %r3,__LC_EXT_INT_CODE # get interruption code
|
llgf %r3,__LC_CPU_ADDRESS # get cpu address + interruption code
|
||||||
|
llgf %r4,__LC_EXT_PARAMS # get external parameter
|
||||||
|
lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter
|
||||||
brasl %r14,do_extint
|
brasl %r14,do_extint
|
||||||
j io_return
|
j io_return
|
||||||
|
|
||||||
|
|
|
@ -113,12 +113,15 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
|
void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
|
struct pt_regs *old_regs;
|
||||||
|
unsigned short code;
|
||||||
ext_int_info_t *p;
|
ext_int_info_t *p;
|
||||||
int index;
|
int index;
|
||||||
struct pt_regs *old_regs;
|
|
||||||
|
|
||||||
|
code = (unsigned short) ext_int_code;
|
||||||
old_regs = set_irq_regs(regs);
|
old_regs = set_irq_regs(regs);
|
||||||
s390_idle_check(regs, S390_lowcore.int_clock,
|
s390_idle_check(regs, S390_lowcore.int_clock,
|
||||||
S390_lowcore.async_enter_timer);
|
S390_lowcore.async_enter_timer);
|
||||||
|
@ -132,7 +135,7 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
|
||||||
index = ext_hash(code);
|
index = ext_hash(code);
|
||||||
for (p = ext_int_hash[index]; p; p = p->next) {
|
for (p = ext_int_hash[index]; p; p = p->next) {
|
||||||
if (likely(p->code == code))
|
if (likely(p->code == code))
|
||||||
p->handler(code);
|
p->handler(ext_int_code, param32, param64);
|
||||||
}
|
}
|
||||||
irq_exit();
|
irq_exit();
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
|
|
|
@ -156,7 +156,8 @@ void smp_send_stop(void)
|
||||||
* cpus are handled.
|
* cpus are handled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void do_ext_call_interrupt(__u16 code)
|
static void do_ext_call_interrupt(unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
unsigned long bits;
|
unsigned long bits;
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,9 @@ void init_cpu_timer(void)
|
||||||
__ctl_set_bit(0, 4);
|
__ctl_set_bit(0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clock_comparator_interrupt(__u16 code)
|
static void clock_comparator_interrupt(unsigned int ext_int_code,
|
||||||
|
unsigned int param32,
|
||||||
|
unsigned long param64)
|
||||||
{
|
{
|
||||||
if (S390_lowcore.clock_comparator == -1ULL)
|
if (S390_lowcore.clock_comparator == -1ULL)
|
||||||
set_clock_comparator(S390_lowcore.clock_comparator);
|
set_clock_comparator(S390_lowcore.clock_comparator);
|
||||||
|
@ -164,14 +166,13 @@ static void clock_comparator_interrupt(__u16 code)
|
||||||
static void etr_timing_alert(struct etr_irq_parm *);
|
static void etr_timing_alert(struct etr_irq_parm *);
|
||||||
static void stp_timing_alert(struct stp_irq_parm *);
|
static void stp_timing_alert(struct stp_irq_parm *);
|
||||||
|
|
||||||
static void timing_alert_interrupt(__u16 code)
|
static void timing_alert_interrupt(unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
if (S390_lowcore.ext_params & 0x00c40000)
|
if (param32 & 0x00c40000)
|
||||||
etr_timing_alert((struct etr_irq_parm *)
|
etr_timing_alert((struct etr_irq_parm *) ¶m32);
|
||||||
&S390_lowcore.ext_params);
|
if (param32 & 0x00038000)
|
||||||
if (S390_lowcore.ext_params & 0x00038000)
|
stp_timing_alert((struct stp_irq_parm *) ¶m32);
|
||||||
stp_timing_alert((struct stp_irq_parm *)
|
|
||||||
&S390_lowcore.ext_params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void etr_reset(void);
|
static void etr_reset(void);
|
||||||
|
|
|
@ -314,7 +314,8 @@ static void do_callbacks(struct list_head *cb_list)
|
||||||
/*
|
/*
|
||||||
* Handler for the virtual CPU timer.
|
* Handler for the virtual CPU timer.
|
||||||
*/
|
*/
|
||||||
static void do_cpu_timer_interrupt(__u16 error_code)
|
static void do_cpu_timer_interrupt(unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
struct vtimer_queue *vq;
|
struct vtimer_queue *vq;
|
||||||
struct vtimer_list *event, *tmp;
|
struct vtimer_list *event, *tmp;
|
||||||
|
|
|
@ -542,7 +542,8 @@ void pfault_fini(void)
|
||||||
: : "a" (&refbk), "m" (refbk) : "cc");
|
: : "a" (&refbk), "m" (refbk) : "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pfault_interrupt(__u16 int_code)
|
static void pfault_interrupt(unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
__u16 subcode;
|
__u16 subcode;
|
||||||
|
@ -553,14 +554,18 @@ static void pfault_interrupt(__u16 int_code)
|
||||||
* in the 'cpu address' field associated with the
|
* in the 'cpu address' field associated with the
|
||||||
* external interrupt.
|
* external interrupt.
|
||||||
*/
|
*/
|
||||||
subcode = S390_lowcore.cpu_addr;
|
subcode = ext_int_code >> 16;
|
||||||
if ((subcode & 0xff00) != __SUBCODE_MASK)
|
if ((subcode & 0xff00) != __SUBCODE_MASK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the token (= address of the task structure of the affected task).
|
* Get the token (= address of the task structure of the affected task).
|
||||||
*/
|
*/
|
||||||
tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
|
#ifdef CONFIG_64BIT
|
||||||
|
tsk = *(struct task_struct **) param64;
|
||||||
|
#else
|
||||||
|
tsk = *(struct task_struct **) param32;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (subcode & 0x0080) {
|
if (subcode & 0x0080) {
|
||||||
/* signal bit is set -> a page has been swapped in by VM */
|
/* signal bit is set -> a page has been swapped in by VM */
|
||||||
|
|
|
@ -228,25 +228,22 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle external interruption. */
|
/* Handle external interruption. */
|
||||||
static void
|
static void dasd_ext_handler(unsigned int ext_int_code,
|
||||||
dasd_ext_handler(__u16 code)
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
struct dasd_ccw_req *cqr, *next;
|
struct dasd_ccw_req *cqr, *next;
|
||||||
struct dasd_device *device;
|
struct dasd_device *device;
|
||||||
unsigned long long expires;
|
unsigned long long expires;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u8 int_code, status;
|
|
||||||
addr_t ip;
|
addr_t ip;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
|
switch (ext_int_code >> 24) {
|
||||||
status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
|
|
||||||
switch (int_code) {
|
|
||||||
case DASD_DIAG_CODE_31BIT:
|
case DASD_DIAG_CODE_31BIT:
|
||||||
ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
|
ip = (addr_t) param32;
|
||||||
break;
|
break;
|
||||||
case DASD_DIAG_CODE_64BIT:
|
case DASD_DIAG_CODE_64BIT:
|
||||||
ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
|
ip = (addr_t) param64;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
@ -281,7 +278,7 @@ dasd_ext_handler(__u16 code)
|
||||||
cqr->stopclk = get_clock();
|
cqr->stopclk = get_clock();
|
||||||
|
|
||||||
expires = 0;
|
expires = 0;
|
||||||
if (status == 0) {
|
if ((ext_int_code & 0xff0000) == 0) {
|
||||||
cqr->status = DASD_CQR_SUCCESS;
|
cqr->status = DASD_CQR_SUCCESS;
|
||||||
/* Start first request on queue if possible -> fast_io. */
|
/* Start first request on queue if possible -> fast_io. */
|
||||||
if (!list_empty(&device->ccw_queue)) {
|
if (!list_empty(&device->ccw_queue)) {
|
||||||
|
@ -296,8 +293,8 @@ dasd_ext_handler(__u16 code)
|
||||||
} else {
|
} else {
|
||||||
cqr->status = DASD_CQR_QUEUED;
|
cqr->status = DASD_CQR_QUEUED;
|
||||||
DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
|
DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
|
||||||
"request %p was %d (%d retries left)", cqr, status,
|
"request %p was %d (%d retries left)", cqr,
|
||||||
cqr->retries);
|
(ext_int_code >> 16) & 0xff, cqr->retries);
|
||||||
dasd_diag_erp(device);
|
dasd_diag_erp(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
#define DEV_CLASS_FBA 0x01
|
#define DEV_CLASS_FBA 0x01
|
||||||
#define DEV_CLASS_ECKD 0x04
|
#define DEV_CLASS_ECKD 0x04
|
||||||
|
|
||||||
#define DASD_DIAG_LC_INT_CODE 132
|
|
||||||
#define DASD_DIAG_LC_INT_STATUS 133
|
|
||||||
#define DASD_DIAG_LC_INT_PARM_31BIT 128
|
|
||||||
#define DASD_DIAG_LC_INT_PARM_64BIT 4536
|
|
||||||
#define DASD_DIAG_CODE_31BIT 0x03
|
#define DASD_DIAG_CODE_31BIT 0x03
|
||||||
#define DASD_DIAG_CODE_64BIT 0x07
|
#define DASD_DIAG_CODE_64BIT 0x07
|
||||||
|
|
||||||
|
|
|
@ -395,16 +395,16 @@ __sclp_find_req(u32 sccb)
|
||||||
/* Handler for external interruption. Perform request post-processing.
|
/* Handler for external interruption. Perform request post-processing.
|
||||||
* Prepare read event data request if necessary. Start processing of next
|
* Prepare read event data request if necessary. Start processing of next
|
||||||
* request on queue. */
|
* request on queue. */
|
||||||
static void
|
static void sclp_interrupt_handler(unsigned int ext_int_code,
|
||||||
sclp_interrupt_handler(__u16 code)
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
struct sclp_req *req;
|
struct sclp_req *req;
|
||||||
u32 finished_sccb;
|
u32 finished_sccb;
|
||||||
u32 evbuf_pending;
|
u32 evbuf_pending;
|
||||||
|
|
||||||
spin_lock(&sclp_lock);
|
spin_lock(&sclp_lock);
|
||||||
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
finished_sccb = param32 & 0xfffffff8;
|
||||||
evbuf_pending = S390_lowcore.ext_params & 0x3;
|
evbuf_pending = param32 & 0x3;
|
||||||
if (finished_sccb) {
|
if (finished_sccb) {
|
||||||
del_timer(&sclp_request_timer);
|
del_timer(&sclp_request_timer);
|
||||||
sclp_running_state = sclp_running_state_reset_pending;
|
sclp_running_state = sclp_running_state_reset_pending;
|
||||||
|
@ -819,12 +819,12 @@ EXPORT_SYMBOL(sclp_reactivate);
|
||||||
|
|
||||||
/* Handler for external interruption used during initialization. Modify
|
/* Handler for external interruption used during initialization. Modify
|
||||||
* request state to done. */
|
* request state to done. */
|
||||||
static void
|
static void sclp_check_handler(unsigned int ext_int_code,
|
||||||
sclp_check_handler(__u16 code)
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
u32 finished_sccb;
|
u32 finished_sccb;
|
||||||
|
|
||||||
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
finished_sccb = param32 & 0xfffffff8;
|
||||||
/* Is this the interrupt we are waiting for? */
|
/* Is this the interrupt we are waiting for? */
|
||||||
if (finished_sccb == 0)
|
if (finished_sccb == 0)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -372,21 +372,22 @@ static void hotplug_devices(struct work_struct *dummy)
|
||||||
/*
|
/*
|
||||||
* we emulate the request_irq behaviour on top of s390 extints
|
* we emulate the request_irq behaviour on top of s390 extints
|
||||||
*/
|
*/
|
||||||
static void kvm_extint_handler(u16 code)
|
static void kvm_extint_handler(unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
struct virtqueue *vq;
|
struct virtqueue *vq;
|
||||||
u16 subcode;
|
u16 subcode;
|
||||||
u32 param;
|
u32 param;
|
||||||
|
|
||||||
subcode = S390_lowcore.cpu_addr;
|
subcode = ext_int_code >> 16;
|
||||||
if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
|
if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* The LSB might be overloaded, we have to mask it */
|
/* The LSB might be overloaded, we have to mask it */
|
||||||
vq = (struct virtqueue *)(S390_lowcore.ext_params2 & ~1UL);
|
vq = (struct virtqueue *)(param64 & ~1UL);
|
||||||
|
|
||||||
/* We use ext_params to decide what this interrupt means */
|
/* We use ext_params to decide what this interrupt means */
|
||||||
param = S390_lowcore.ext_params & VIRTIO_PARAM_MASK;
|
param = param32 & VIRTIO_PARAM_MASK;
|
||||||
|
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case VIRTIO_PARAM_CONFIG_CHANGED:
|
case VIRTIO_PARAM_CONFIG_CHANGED:
|
||||||
|
|
|
@ -1798,7 +1798,8 @@ static void iucv_work_fn(struct work_struct *work)
|
||||||
* Handles external interrupts coming in from CP.
|
* Handles external interrupts coming in from CP.
|
||||||
* Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
|
* Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
|
||||||
*/
|
*/
|
||||||
static void iucv_external_interrupt(u16 code)
|
static void iucv_external_interrupt(unsigned int ext_int_code,
|
||||||
|
unsigned int param32, unsigned long param64)
|
||||||
{
|
{
|
||||||
struct iucv_irq_data *p;
|
struct iucv_irq_data *p;
|
||||||
struct iucv_irq_list *work;
|
struct iucv_irq_list *work;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче