[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:
parent
1e54622e04
commit
f6649a7e5a
15 changed files with 57 additions and 49 deletions
|
@ -12,7 +12,7 @@
|
|||
|
||||
#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 {
|
||||
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_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
|
||||
#ifdef CONFIG_32BIT
|
||||
DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params));
|
||||
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
|
||||
#else /* CONFIG_32BIT */
|
||||
DEFINE(__LC_PFAULT_INTPARM, 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(__LC_PASTE, offsetof(struct _lowcore, paste));
|
||||
|
|
|
@ -722,7 +722,8 @@ ext_no_vtime:
|
|||
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
|
||||
TRACE_IRQS_OFF
|
||||
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)
|
||||
basr %r14,%r1
|
||||
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,
|
||||
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);
|
||||
void __init startup_init(void);
|
||||
void die(const char * str, struct pt_regs * regs, long err);
|
||||
|
|
|
@ -727,8 +727,11 @@ ext_int_handler:
|
|||
ext_no_vtime:
|
||||
HANDLE_SIE_INTERCEPT
|
||||
TRACE_IRQS_OFF
|
||||
lghi %r1,4096
|
||||
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
|
||||
j io_return
|
||||
|
||||
|
|
|
@ -113,12 +113,15 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
|
|||
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;
|
||||
int index;
|
||||
struct pt_regs *old_regs;
|
||||
|
||||
code = (unsigned short) ext_int_code;
|
||||
old_regs = set_irq_regs(regs);
|
||||
s390_idle_check(regs, S390_lowcore.int_clock,
|
||||
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);
|
||||
for (p = ext_int_hash[index]; p; p = p->next) {
|
||||
if (likely(p->code == code))
|
||||
p->handler(code);
|
||||
p->handler(ext_int_code, param32, param64);
|
||||
}
|
||||
irq_exit();
|
||||
set_irq_regs(old_regs);
|
||||
|
|
|
@ -156,7 +156,8 @@ void smp_send_stop(void)
|
|||
* 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;
|
||||
|
||||
|
|
|
@ -155,7 +155,9 @@ void init_cpu_timer(void)
|
|||
__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)
|
||||
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 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)
|
||||
etr_timing_alert((struct etr_irq_parm *)
|
||||
&S390_lowcore.ext_params);
|
||||
if (S390_lowcore.ext_params & 0x00038000)
|
||||
stp_timing_alert((struct stp_irq_parm *)
|
||||
&S390_lowcore.ext_params);
|
||||
if (param32 & 0x00c40000)
|
||||
etr_timing_alert((struct etr_irq_parm *) ¶m32);
|
||||
if (param32 & 0x00038000)
|
||||
stp_timing_alert((struct stp_irq_parm *) ¶m32);
|
||||
}
|
||||
|
||||
static void etr_reset(void);
|
||||
|
|
|
@ -314,7 +314,8 @@ static void do_callbacks(struct list_head *cb_list)
|
|||
/*
|
||||
* 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_list *event, *tmp;
|
||||
|
|
|
@ -542,7 +542,8 @@ void pfault_fini(void)
|
|||
: : "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;
|
||||
__u16 subcode;
|
||||
|
@ -553,14 +554,18 @@ static void pfault_interrupt(__u16 int_code)
|
|||
* in the 'cpu address' field associated with the
|
||||
* external interrupt.
|
||||
*/
|
||||
subcode = S390_lowcore.cpu_addr;
|
||||
subcode = ext_int_code >> 16;
|
||||
if ((subcode & 0xff00) != __SUBCODE_MASK)
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
/* 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. */
|
||||
static void
|
||||
dasd_ext_handler(__u16 code)
|
||||
static void dasd_ext_handler(unsigned int ext_int_code,
|
||||
unsigned int param32, unsigned long param64)
|
||||
{
|
||||
struct dasd_ccw_req *cqr, *next;
|
||||
struct dasd_device *device;
|
||||
unsigned long long expires;
|
||||
unsigned long flags;
|
||||
u8 int_code, status;
|
||||
addr_t ip;
|
||||
int rc;
|
||||
|
||||
int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
|
||||
status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
|
||||
switch (int_code) {
|
||||
switch (ext_int_code >> 24) {
|
||||
case DASD_DIAG_CODE_31BIT:
|
||||
ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
|
||||
ip = (addr_t) param32;
|
||||
break;
|
||||
case DASD_DIAG_CODE_64BIT:
|
||||
ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
|
||||
ip = (addr_t) param64;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
@ -281,7 +278,7 @@ dasd_ext_handler(__u16 code)
|
|||
cqr->stopclk = get_clock();
|
||||
|
||||
expires = 0;
|
||||
if (status == 0) {
|
||||
if ((ext_int_code & 0xff0000) == 0) {
|
||||
cqr->status = DASD_CQR_SUCCESS;
|
||||
/* Start first request on queue if possible -> fast_io. */
|
||||
if (!list_empty(&device->ccw_queue)) {
|
||||
|
@ -296,8 +293,8 @@ dasd_ext_handler(__u16 code)
|
|||
} else {
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
|
||||
"request %p was %d (%d retries left)", cqr, status,
|
||||
cqr->retries);
|
||||
"request %p was %d (%d retries left)", cqr,
|
||||
(ext_int_code >> 16) & 0xff, cqr->retries);
|
||||
dasd_diag_erp(device);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
#define DEV_CLASS_FBA 0x01
|
||||
#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_64BIT 0x07
|
||||
|
||||
|
|
|
@ -395,16 +395,16 @@ __sclp_find_req(u32 sccb)
|
|||
/* Handler for external interruption. Perform request post-processing.
|
||||
* Prepare read event data request if necessary. Start processing of next
|
||||
* request on queue. */
|
||||
static void
|
||||
sclp_interrupt_handler(__u16 code)
|
||||
static void sclp_interrupt_handler(unsigned int ext_int_code,
|
||||
unsigned int param32, unsigned long param64)
|
||||
{
|
||||
struct sclp_req *req;
|
||||
u32 finished_sccb;
|
||||
u32 evbuf_pending;
|
||||
|
||||
spin_lock(&sclp_lock);
|
||||
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
||||
evbuf_pending = S390_lowcore.ext_params & 0x3;
|
||||
finished_sccb = param32 & 0xfffffff8;
|
||||
evbuf_pending = param32 & 0x3;
|
||||
if (finished_sccb) {
|
||||
del_timer(&sclp_request_timer);
|
||||
sclp_running_state = sclp_running_state_reset_pending;
|
||||
|
@ -819,12 +819,12 @@ EXPORT_SYMBOL(sclp_reactivate);
|
|||
|
||||
/* Handler for external interruption used during initialization. Modify
|
||||
* request state to done. */
|
||||
static void
|
||||
sclp_check_handler(__u16 code)
|
||||
static void sclp_check_handler(unsigned int ext_int_code,
|
||||
unsigned int param32, unsigned long param64)
|
||||
{
|
||||
u32 finished_sccb;
|
||||
|
||||
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
||||
finished_sccb = param32 & 0xfffffff8;
|
||||
/* Is this the interrupt we are waiting for? */
|
||||
if (finished_sccb == 0)
|
||||
return;
|
||||
|
|
|
@ -372,21 +372,22 @@ static void hotplug_devices(struct work_struct *dummy)
|
|||
/*
|
||||
* 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;
|
||||
u16 subcode;
|
||||
u32 param;
|
||||
|
||||
subcode = S390_lowcore.cpu_addr;
|
||||
subcode = ext_int_code >> 16;
|
||||
if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
|
||||
return;
|
||||
|
||||
/* 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 */
|
||||
param = S390_lowcore.ext_params & VIRTIO_PARAM_MASK;
|
||||
param = param32 & VIRTIO_PARAM_MASK;
|
||||
|
||||
switch (param) {
|
||||
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.
|
||||
* 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_list *work;
|
||||
|
|
Loading…
Reference in a new issue