Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6:
  [S390] cio: Register/unregister subchannels only from kslowcrw.
  [S390] Add missing die_notifier() call to die().
  [S390] Fix memory detection.
  [S390] Explicitly code allocpercpu calls in iucv
  [S390] Dont overwrite lowcores on smp_send_stop().
  [S390] Optimize storage key handling for anonymous pages
  [S390] Fix kernel preemption.
  [S390] appldata: remove unused binary sysctls.
  [S390] cmm: remove unused binary sysctls.
  [S390] Fix irq tracing and lockdep_sys_exit calls.
  [S390] magic sysrq: check for in_atomic before doing an console_unblank
  [S390] cio: change device sense procedure to work with pav aliases
This commit is contained in:
Linus Torvalds 2007-11-26 19:09:22 -08:00
commit 9ccc236269
20 changed files with 263 additions and 307 deletions

View File

@ -45,7 +45,6 @@ struct appldata_ops {
int active; /* monitoring status */ int active; /* monitoring status */
/* fill in from here */ /* fill in from here */
unsigned int ctl_nr; /* sysctl ID */
char name[APPLDATA_PROC_NAME_LENGTH]; /* name of /proc fs node */ char name[APPLDATA_PROC_NAME_LENGTH]; /* name of /proc fs node */
unsigned char record_nr; /* Record Nr. for Product ID */ unsigned char record_nr; /* Record Nr. for Product ID */
void (*callback)(void *data); /* callback function */ void (*callback)(void *data); /* callback function */

View File

@ -53,29 +53,26 @@ static int appldata_interval_handler(ctl_table *ctl, int write,
static struct ctl_table_header *appldata_sysctl_header; static struct ctl_table_header *appldata_sysctl_header;
static struct ctl_table appldata_table[] = { static struct ctl_table appldata_table[] = {
{ {
.ctl_name = CTL_APPLDATA_TIMER,
.procname = "timer", .procname = "timer",
.mode = S_IRUGO | S_IWUSR, .mode = S_IRUGO | S_IWUSR,
.proc_handler = &appldata_timer_handler, .proc_handler = &appldata_timer_handler,
}, },
{ {
.ctl_name = CTL_APPLDATA_INTERVAL,
.procname = "interval", .procname = "interval",
.mode = S_IRUGO | S_IWUSR, .mode = S_IRUGO | S_IWUSR,
.proc_handler = &appldata_interval_handler, .proc_handler = &appldata_interval_handler,
}, },
{ .ctl_name = 0 } { },
}; };
static struct ctl_table appldata_dir_table[] = { static struct ctl_table appldata_dir_table[] = {
{ {
.ctl_name = CTL_APPLDATA,
.procname = appldata_proc_name, .procname = appldata_proc_name,
.maxlen = 0, .maxlen = 0,
.mode = S_IRUGO | S_IXUGO, .mode = S_IRUGO | S_IXUGO,
.child = appldata_table, .child = appldata_table,
}, },
{ .ctl_name = 0 } { },
}; };
/* /*
@ -441,75 +438,38 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
*/ */
int appldata_register_ops(struct appldata_ops *ops) int appldata_register_ops(struct appldata_ops *ops)
{ {
struct list_head *lh; if ((ops->size > APPLDATA_MAX_REC_SIZE) || (ops->size < 0))
struct appldata_ops *tmp_ops; return -EINVAL;
int i;
i = 0; ops->ctl_table = kzalloc(4 * sizeof(struct ctl_table), GFP_KERNEL);
if (!ops->ctl_table)
if ((ops->size > APPLDATA_MAX_REC_SIZE) ||
(ops->size < 0)){
P_ERROR("Invalid size of %s record = %i, maximum = %i!\n",
ops->name, ops->size, APPLDATA_MAX_REC_SIZE);
return -ENOMEM; return -ENOMEM;
}
if ((ops->ctl_nr == CTL_APPLDATA) ||
(ops->ctl_nr == CTL_APPLDATA_TIMER) ||
(ops->ctl_nr == CTL_APPLDATA_INTERVAL)) {
P_ERROR("ctl_nr %i already in use!\n", ops->ctl_nr);
return -EBUSY;
}
ops->ctl_table = kzalloc(4*sizeof(struct ctl_table), GFP_KERNEL);
if (ops->ctl_table == NULL) {
P_ERROR("Not enough memory for %s ctl_table!\n", ops->name);
return -ENOMEM;
}
spin_lock(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) {
tmp_ops = list_entry(lh, struct appldata_ops, list);
P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
++i, tmp_ops->name, tmp_ops->ctl_nr);
P_DEBUG("Comparing %s (ctl %i) with %s (ctl %i)\n",
tmp_ops->name, tmp_ops->ctl_nr, ops->name,
ops->ctl_nr);
if (strncmp(tmp_ops->name, ops->name,
APPLDATA_PROC_NAME_LENGTH) == 0) {
P_ERROR("Name \"%s\" already registered!\n", ops->name);
kfree(ops->ctl_table);
spin_unlock(&appldata_ops_lock);
return -EBUSY;
}
if (tmp_ops->ctl_nr == ops->ctl_nr) {
P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
kfree(ops->ctl_table);
spin_unlock(&appldata_ops_lock);
return -EBUSY;
}
}
list_add(&ops->list, &appldata_ops_list); list_add(&ops->list, &appldata_ops_list);
spin_unlock(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
ops->ctl_table[0].ctl_name = CTL_APPLDATA;
ops->ctl_table[0].procname = appldata_proc_name; ops->ctl_table[0].procname = appldata_proc_name;
ops->ctl_table[0].maxlen = 0; ops->ctl_table[0].maxlen = 0;
ops->ctl_table[0].mode = S_IRUGO | S_IXUGO; ops->ctl_table[0].mode = S_IRUGO | S_IXUGO;
ops->ctl_table[0].child = &ops->ctl_table[2]; ops->ctl_table[0].child = &ops->ctl_table[2];
ops->ctl_table[1].ctl_name = 0;
ops->ctl_table[2].ctl_name = ops->ctl_nr;
ops->ctl_table[2].procname = ops->name; ops->ctl_table[2].procname = ops->name;
ops->ctl_table[2].mode = S_IRUGO | S_IWUSR; ops->ctl_table[2].mode = S_IRUGO | S_IWUSR;
ops->ctl_table[2].proc_handler = appldata_generic_handler; ops->ctl_table[2].proc_handler = appldata_generic_handler;
ops->ctl_table[2].data = ops; ops->ctl_table[2].data = ops;
ops->ctl_table[3].ctl_name = 0;
ops->sysctl_header = register_sysctl_table(ops->ctl_table); ops->sysctl_header = register_sysctl_table(ops->ctl_table);
if (!ops->sysctl_header)
goto out;
P_INFO("%s-ops registered!\n", ops->name); P_INFO("%s-ops registered!\n", ops->name);
return 0; return 0;
out:
spin_lock(&appldata_ops_lock);
list_del(&ops->list);
spin_unlock(&appldata_ops_lock);
kfree(ops->ctl_table);
return -ENOMEM;
} }
/* /*
@ -519,15 +479,11 @@ int appldata_register_ops(struct appldata_ops *ops)
*/ */
void appldata_unregister_ops(struct appldata_ops *ops) void appldata_unregister_ops(struct appldata_ops *ops)
{ {
void *table;
spin_lock(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_del(&ops->list); list_del(&ops->list);
/* at that point any incoming access will fail */
table = ops->ctl_table;
ops->ctl_table = NULL;
spin_unlock(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
unregister_sysctl_table(ops->sysctl_header); unregister_sysctl_table(ops->sysctl_header);
kfree(table); kfree(ops->ctl_table);
P_INFO("%s-ops unregistered!\n", ops->name); P_INFO("%s-ops unregistered!\n", ops->name);
} }
/********************** module-ops management <END> **************************/ /********************** module-ops management <END> **************************/

View File

@ -147,7 +147,6 @@ static void appldata_get_mem_data(void *data)
static struct appldata_ops ops = { static struct appldata_ops ops = {
.ctl_nr = CTL_APPLDATA_MEM,
.name = "mem", .name = "mem",
.record_nr = APPLDATA_RECORD_MEM_ID, .record_nr = APPLDATA_RECORD_MEM_ID,
.size = sizeof(struct appldata_mem_data), .size = sizeof(struct appldata_mem_data),

View File

@ -142,7 +142,6 @@ static void appldata_get_net_sum_data(void *data)
static struct appldata_ops ops = { static struct appldata_ops ops = {
.ctl_nr = CTL_APPLDATA_NET_SUM,
.name = "net_sum", .name = "net_sum",
.record_nr = APPLDATA_RECORD_NET_SUM_ID, .record_nr = APPLDATA_RECORD_NET_SUM_ID,
.size = sizeof(struct appldata_net_sum_data), .size = sizeof(struct appldata_net_sum_data),

View File

@ -82,7 +82,6 @@ struct appldata_os_data {
static struct appldata_os_data *appldata_os_data; static struct appldata_os_data *appldata_os_data;
static struct appldata_ops ops = { static struct appldata_ops ops = {
.ctl_nr = CTL_APPLDATA_OS,
.name = "os", .name = "os",
.record_nr = APPLDATA_RECORD_OS_ID, .record_nr = APPLDATA_RECORD_OS_ID,
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -200,7 +200,7 @@ static noinline __init void find_memory_chunks(unsigned long memsize)
cc = __tprot(addr); cc = __tprot(addr);
while (cc == old_cc) { while (cc == old_cc) {
addr += CHUNK_INCR; addr += CHUNK_INCR;
if (addr >= memsize) if (memsize && addr >= memsize)
break; break;
#ifndef CONFIG_64BIT #ifndef CONFIG_64BIT
if (addr == ADDR2G) if (addr == ADDR2G)

View File

@ -69,13 +69,31 @@ STACK_SIZE = 1 << STACK_SHIFT
basr %r14,%r1 basr %r14,%r1
.endm .endm
.macro LOCKDEP_SYS_EXIT .macro TRACE_IRQS_CHECK
l %r1,BASED(.Llockdep_sys_exit) tm SP_PSW(%r15),0x03 # irqs enabled?
jz 0f
l %r1,BASED(.Ltrace_irq_on)
basr %r14,%r1 basr %r14,%r1
j 1f
0: l %r1,BASED(.Ltrace_irq_off)
basr %r14,%r1
1:
.endm .endm
#else #else
#define TRACE_IRQS_ON #define TRACE_IRQS_ON
#define TRACE_IRQS_OFF #define TRACE_IRQS_OFF
#define TRACE_IRQS_CHECK
#endif
#ifdef CONFIG_LOCKDEP
.macro LOCKDEP_SYS_EXIT
tm SP_PSW+1(%r15),0x01 # returning to user ?
jz 0f
l %r1,BASED(.Llockdep_sys_exit)
basr %r14,%r1
0:
.endm
#else
#define LOCKDEP_SYS_EXIT #define LOCKDEP_SYS_EXIT
#endif #endif
@ -234,8 +252,6 @@ sysc_saveall:
lh %r7,0x8a # get svc number from lowcore lh %r7,0x8a # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime: sysc_vtime:
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(sysc_do_svc)
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
sysc_stime: sysc_stime:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@ -263,19 +279,34 @@ sysc_do_restart:
sysc_return: sysc_return:
tm SP_PSW+1(%r15),0x01 # returning to user ? tm SP_PSW+1(%r15),0x01 # returning to user ?
bno BASED(sysc_leave) bno BASED(sysc_restore)
tm __TI_flags+3(%r9),_TIF_WORK_SVC tm __TI_flags+3(%r9),_TIF_WORK_SVC
bnz BASED(sysc_work) # there is work to do (signals etc.) bnz BASED(sysc_work) # there is work to do (signals etc.)
sysc_restore:
#ifdef CONFIG_TRACE_IRQFLAGS
la %r1,BASED(sysc_restore_trace_psw)
lpsw 0(%r1)
sysc_restore_trace:
TRACE_IRQS_CHECK
LOCKDEP_SYS_EXIT LOCKDEP_SYS_EXIT
#endif
sysc_leave: sysc_leave:
RESTORE_ALL __LC_RETURN_PSW,1 RESTORE_ALL __LC_RETURN_PSW,1
sysc_done:
#ifdef CONFIG_TRACE_IRQFLAGS
.align 8
.globl sysc_restore_trace_psw
sysc_restore_trace_psw:
.long 0, sysc_restore_trace + 0x80000000
#endif
# #
# recheck if there is more work to do # recheck if there is more work to do
# #
sysc_work_loop: sysc_work_loop:
tm __TI_flags+3(%r9),_TIF_WORK_SVC tm __TI_flags+3(%r9),_TIF_WORK_SVC
bz BASED(sysc_leave) # there is no work to do bz BASED(sysc_restore) # there is no work to do
# #
# One of the work bits is on. Find out which one. # One of the work bits is on. Find out which one.
# #
@ -290,8 +321,8 @@ sysc_work:
bo BASED(sysc_restart) bo BASED(sysc_restart)
tm __TI_flags+3(%r9),_TIF_SINGLE_STEP tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
bo BASED(sysc_singlestep) bo BASED(sysc_singlestep)
LOCKDEP_SYS_EXIT b BASED(sysc_restore)
b BASED(sysc_leave) sysc_work_done:
# #
# _TIF_NEED_RESCHED is set, call schedule # _TIF_NEED_RESCHED is set, call schedule
@ -458,6 +489,7 @@ pgm_check_handler:
pgm_no_vtime: pgm_no_vtime:
#endif #endif
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
l %r3,__LC_PGM_ILC # load program interruption code l %r3,__LC_PGM_ILC # load program interruption code
la %r8,0x7f la %r8,0x7f
nr %r8,%r3 nr %r8,%r3
@ -497,6 +529,7 @@ pgm_per_std:
pgm_no_vtime2: pgm_no_vtime2:
#endif #endif
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
l %r1,__TI_task(%r9) l %r1,__TI_task(%r9)
mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
@ -517,15 +550,13 @@ pgm_svcper:
SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime3)
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime3:
#endif #endif
lh %r7,0x8a # get svc number from lowcore lh %r7,0x8a # get svc number from lowcore
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
l %r1,__TI_task(%r9) l %r1,__TI_task(%r9)
mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
@ -542,7 +573,7 @@ kernel_per:
mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
l %r1,BASED(.Lhandle_per) # load adr. of per handler l %r1,BASED(.Lhandle_per) # load adr. of per handler
la %r14,BASED(sysc_leave) # load adr. of system return la %r14,BASED(sysc_restore)# load adr. of system return
br %r1 # branch to do_single_step br %r1 # branch to do_single_step
/* /*
@ -569,26 +600,38 @@ io_no_vtime:
l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to standard irq handler basr %r14,%r1 # branch to standard irq handler
TRACE_IRQS_ON
io_return: io_return:
tm SP_PSW+1(%r15),0x01 # returning to user ? tm SP_PSW+1(%r15),0x01 # returning to user ?
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
bno BASED(io_preempt) # no -> check for preemptive scheduling bno BASED(io_preempt) # no -> check for preemptive scheduling
#else #else
bno BASED(io_leave) # no-> skip resched & signal bno BASED(io_restore) # no-> skip resched & signal
#endif #endif
tm __TI_flags+3(%r9),_TIF_WORK_INT tm __TI_flags+3(%r9),_TIF_WORK_INT
bnz BASED(io_work) # there is work to do (signals etc.) bnz BASED(io_work) # there is work to do (signals etc.)
io_restore:
#ifdef CONFIG_TRACE_IRQFLAGS
la %r1,BASED(io_restore_trace_psw)
lpsw 0(%r1)
io_restore_trace:
TRACE_IRQS_CHECK
LOCKDEP_SYS_EXIT LOCKDEP_SYS_EXIT
#endif
io_leave: io_leave:
RESTORE_ALL __LC_RETURN_PSW,0 RESTORE_ALL __LC_RETURN_PSW,0
io_done: io_done:
#ifdef CONFIG_TRACE_IRQFLAGS
.align 8
.globl io_restore_trace_psw
io_restore_trace_psw:
.long 0, io_restore_trace + 0x80000000
#endif
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
io_preempt: io_preempt:
icm %r0,15,__TI_precount(%r9) icm %r0,15,__TI_precount(%r9)
bnz BASED(io_leave) bnz BASED(io_restore)
l %r1,SP_R15(%r15) l %r1,SP_R15(%r15)
s %r1,BASED(.Lc_spsize) s %r1,BASED(.Lc_spsize)
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
@ -596,14 +639,10 @@ io_preempt:
lr %r15,%r1 lr %r15,%r1
io_resume_loop: io_resume_loop:
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bno BASED(io_leave) bno BASED(io_restore)
mvc __TI_precount(4,%r9),BASED(.Lc_pactive) l %r1,BASED(.Lpreempt_schedule_irq)
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r14,BASED(io_resume_loop)
l %r1,BASED(.Lschedule) br %r1 # call schedule
basr %r14,%r1 # call schedule
stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
xc __TI_precount(4,%r9),__TI_precount(%r9)
b BASED(io_resume_loop)
#endif #endif
# #
@ -627,40 +666,42 @@ io_work_loop:
bo BASED(io_reschedule) bo BASED(io_reschedule)
tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK) tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
bnz BASED(io_sigpending) bnz BASED(io_sigpending)
LOCKDEP_SYS_EXIT b BASED(io_restore)
b BASED(io_leave) io_work_done:
# #
# _TIF_MCCK_PENDING is set, call handler # _TIF_MCCK_PENDING is set, call handler
# #
io_mcck_pending: io_mcck_pending:
TRACE_IRQS_OFF
l %r1,BASED(.Ls390_handle_mcck) l %r1,BASED(.Ls390_handle_mcck)
basr %r14,%r1 # TIF bit will be cleared by handler basr %r14,%r1 # TIF bit will be cleared by handler
TRACE_IRQS_ON
b BASED(io_work_loop) b BASED(io_work_loop)
# #
# _TIF_NEED_RESCHED is set, call schedule # _TIF_NEED_RESCHED is set, call schedule
# #
io_reschedule: io_reschedule:
TRACE_IRQS_ON
l %r1,BASED(.Lschedule) l %r1,BASED(.Lschedule)
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
basr %r14,%r1 # call scheduler basr %r14,%r1 # call scheduler
stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
TRACE_IRQS_OFF
tm __TI_flags+3(%r9),_TIF_WORK_INT tm __TI_flags+3(%r9),_TIF_WORK_INT
bz BASED(io_leave) # there is no work to do bz BASED(io_restore) # there is no work to do
b BASED(io_work_loop) b BASED(io_work_loop)
# #
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
# #
io_sigpending: io_sigpending:
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
la %r2,SP_PTREGS(%r15) # load pt_regs la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Ldo_signal) l %r1,BASED(.Ldo_signal)
basr %r14,%r1 # call do_signal basr %r14,%r1 # call do_signal
stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
TRACE_IRQS_OFF
b BASED(io_work_loop) b BASED(io_work_loop)
/* /*
@ -688,7 +729,6 @@ ext_no_vtime:
lh %r3,__LC_EXT_INT_CODE # get interruption code lh %r3,__LC_EXT_INT_CODE # get interruption code
l %r1,BASED(.Ldo_extint) l %r1,BASED(.Ldo_extint)
basr %r14,%r1 basr %r14,%r1
TRACE_IRQS_ON
b BASED(io_return) b BASED(io_return)
__critical_end: __critical_end:
@ -853,15 +893,15 @@ cleanup_table_system_call:
cleanup_table_sysc_return: cleanup_table_sysc_return:
.long sysc_return + 0x80000000, sysc_leave + 0x80000000 .long sysc_return + 0x80000000, sysc_leave + 0x80000000
cleanup_table_sysc_leave: cleanup_table_sysc_leave:
.long sysc_leave + 0x80000000, sysc_work_loop + 0x80000000 .long sysc_leave + 0x80000000, sysc_done + 0x80000000
cleanup_table_sysc_work_loop: cleanup_table_sysc_work_loop:
.long sysc_work_loop + 0x80000000, sysc_reschedule + 0x80000000 .long sysc_work_loop + 0x80000000, sysc_work_done + 0x80000000
cleanup_table_io_return: cleanup_table_io_return:
.long io_return + 0x80000000, io_leave + 0x80000000 .long io_return + 0x80000000, io_leave + 0x80000000
cleanup_table_io_leave: cleanup_table_io_leave:
.long io_leave + 0x80000000, io_done + 0x80000000 .long io_leave + 0x80000000, io_done + 0x80000000
cleanup_table_io_work_loop: cleanup_table_io_work_loop:
.long io_work_loop + 0x80000000, io_mcck_pending + 0x80000000 .long io_work_loop + 0x80000000, io_work_done + 0x80000000
cleanup_critical: cleanup_critical:
clc 4(4,%r12),BASED(cleanup_table_system_call) clc 4(4,%r12),BASED(cleanup_table_system_call)
@ -930,8 +970,6 @@ cleanup_system_call:
cleanup_vtime: cleanup_vtime:
clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12)
bhe BASED(cleanup_stime) bhe BASED(cleanup_stime)
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(cleanup_novtime)
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
cleanup_stime: cleanup_stime:
clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16) clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16)
@ -939,7 +977,6 @@ cleanup_stime:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
cleanup_update: cleanup_update:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
cleanup_novtime:
#endif #endif
mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4) mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4)
la %r12,__LC_RETURN_PSW la %r12,__LC_RETURN_PSW
@ -978,10 +1015,10 @@ cleanup_sysc_leave:
2: la %r12,__LC_RETURN_PSW 2: la %r12,__LC_RETURN_PSW
br %r14 br %r14
cleanup_sysc_leave_insn: cleanup_sysc_leave_insn:
.long sysc_done - 4 + 0x80000000
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
.long sysc_leave + 14 + 0x80000000 .long sysc_done - 8 + 0x80000000
#endif #endif
.long sysc_leave + 10 + 0x80000000
cleanup_io_return: cleanup_io_return:
mvc __LC_RETURN_PSW(4),0(%r12) mvc __LC_RETURN_PSW(4),0(%r12)
@ -1008,10 +1045,10 @@ cleanup_io_leave:
2: la %r12,__LC_RETURN_PSW 2: la %r12,__LC_RETURN_PSW
br %r14 br %r14
cleanup_io_leave_insn: cleanup_io_leave_insn:
.long io_done - 4 + 0x80000000
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
.long io_leave + 18 + 0x80000000 .long io_done - 8 + 0x80000000
#endif #endif
.long io_leave + 14 + 0x80000000
/* /*
* Integer constants * Integer constants
@ -1019,7 +1056,6 @@ cleanup_io_leave_insn:
.align 4 .align 4
.Lc_spsize: .long SP_SIZE .Lc_spsize: .long SP_SIZE
.Lc_overhead: .long STACK_FRAME_OVERHEAD .Lc_overhead: .long STACK_FRAME_OVERHEAD
.Lc_pactive: .long PREEMPT_ACTIVE
.Lnr_syscalls: .long NR_syscalls .Lnr_syscalls: .long NR_syscalls
.L0x018: .short 0x018 .L0x018: .short 0x018
.L0x020: .short 0x020 .L0x020: .short 0x020
@ -1043,6 +1079,8 @@ cleanup_io_leave_insn:
.Lexecve_tail: .long execve_tail .Lexecve_tail: .long execve_tail
.Ljump_table: .long pgm_check_table .Ljump_table: .long pgm_check_table
.Lschedule: .long schedule .Lschedule: .long schedule
.Lpreempt_schedule_irq:
.long preempt_schedule_irq
.Ltrace: .long syscall_trace .Ltrace: .long syscall_trace
.Lschedtail: .long schedule_tail .Lschedtail: .long schedule_tail
.Lsysc_table: .long sys_call_table .Lsysc_table: .long sys_call_table

View File

@ -67,12 +67,28 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
brasl %r14,trace_hardirqs_off brasl %r14,trace_hardirqs_off
.endm .endm
.macro LOCKDEP_SYS_EXIT .macro TRACE_IRQS_CHECK
brasl %r14,lockdep_sys_exit tm SP_PSW(%r15),0x03 # irqs enabled?
jz 0f
brasl %r14,trace_hardirqs_on
j 1f
0: brasl %r14,trace_hardirqs_off
1:
.endm .endm
#else #else
#define TRACE_IRQS_ON #define TRACE_IRQS_ON
#define TRACE_IRQS_OFF #define TRACE_IRQS_OFF
#define TRACE_IRQS_CHECK
#endif
#ifdef CONFIG_LOCKDEP
.macro LOCKDEP_SYS_EXIT
tm SP_PSW+1(%r15),0x01 # returning to user ?
jz 0f
brasl %r14,lockdep_sys_exit
0:
.endm
#else
#define LOCKDEP_SYS_EXIT #define LOCKDEP_SYS_EXIT
#endif #endif
@ -222,8 +238,6 @@ sysc_saveall:
llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime: sysc_vtime:
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz sysc_do_svc
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
sysc_stime: sysc_stime:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@ -257,19 +271,34 @@ sysc_noemu:
sysc_return: sysc_return:
tm SP_PSW+1(%r15),0x01 # returning to user ? tm SP_PSW+1(%r15),0x01 # returning to user ?
jno sysc_leave jno sysc_restore
tm __TI_flags+7(%r9),_TIF_WORK_SVC tm __TI_flags+7(%r9),_TIF_WORK_SVC
jnz sysc_work # there is work to do (signals etc.) jnz sysc_work # there is work to do (signals etc.)
sysc_restore:
#ifdef CONFIG_TRACE_IRQFLAGS
larl %r1,sysc_restore_trace_psw
lpswe 0(%r1)
sysc_restore_trace:
TRACE_IRQS_CHECK
LOCKDEP_SYS_EXIT LOCKDEP_SYS_EXIT
#endif
sysc_leave: sysc_leave:
RESTORE_ALL __LC_RETURN_PSW,1 RESTORE_ALL __LC_RETURN_PSW,1
sysc_done:
#ifdef CONFIG_TRACE_IRQFLAGS
.align 8
.globl sysc_restore_trace_psw
sysc_restore_trace_psw:
.quad 0, sysc_restore_trace
#endif
# #
# recheck if there is more work to do # recheck if there is more work to do
# #
sysc_work_loop: sysc_work_loop:
tm __TI_flags+7(%r9),_TIF_WORK_SVC tm __TI_flags+7(%r9),_TIF_WORK_SVC
jz sysc_leave # there is no work to do jz sysc_restore # there is no work to do
# #
# One of the work bits is on. Find out which one. # One of the work bits is on. Find out which one.
# #
@ -284,8 +313,8 @@ sysc_work:
jo sysc_restart jo sysc_restart
tm __TI_flags+7(%r9),_TIF_SINGLE_STEP tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
jo sysc_singlestep jo sysc_singlestep
LOCKDEP_SYS_EXIT j sysc_restore
j sysc_leave sysc_work_done:
# #
# _TIF_NEED_RESCHED is set, call schedule # _TIF_NEED_RESCHED is set, call schedule
@ -445,6 +474,7 @@ pgm_check_handler:
pgm_no_vtime: pgm_no_vtime:
#endif #endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
lgf %r3,__LC_PGM_ILC # load program interruption code lgf %r3,__LC_PGM_ILC # load program interruption code
lghi %r8,0x7f lghi %r8,0x7f
ngr %r8,%r3 ngr %r8,%r3
@ -484,6 +514,7 @@ pgm_per_std:
pgm_no_vtime2: pgm_no_vtime2:
#endif #endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
lg %r1,__TI_task(%r9) lg %r1,__TI_task(%r9)
tm SP_PSW+1(%r15),0x01 # kernel per event ? tm SP_PSW+1(%r15),0x01 # kernel per event ?
jz kernel_per jz kernel_per
@ -504,12 +535,9 @@ pgm_svcper:
SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime3
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime3:
#endif #endif
llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
@ -529,7 +557,7 @@ kernel_per:
lhi %r0,__LC_PGM_OLD_PSW lhi %r0,__LC_PGM_OLD_PSW
sth %r0,SP_TRAP(%r15) # set trap indication to pgm check sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
larl %r14,sysc_leave # load adr. of system ret, no work larl %r14,sysc_restore # load adr. of system ret, no work
jg do_single_step # branch to do_single_step jg do_single_step # branch to do_single_step
/* /*
@ -554,26 +582,38 @@ io_no_vtime:
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
brasl %r14,do_IRQ # call standard irq handler brasl %r14,do_IRQ # call standard irq handler
TRACE_IRQS_ON
io_return: io_return:
tm SP_PSW+1(%r15),0x01 # returning to user ? tm SP_PSW+1(%r15),0x01 # returning to user ?
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
jno io_preempt # no -> check for preemptive scheduling jno io_preempt # no -> check for preemptive scheduling
#else #else
jno io_leave # no-> skip resched & signal jno io_restore # no-> skip resched & signal
#endif #endif
tm __TI_flags+7(%r9),_TIF_WORK_INT tm __TI_flags+7(%r9),_TIF_WORK_INT
jnz io_work # there is work to do (signals etc.) jnz io_work # there is work to do (signals etc.)
io_restore:
#ifdef CONFIG_TRACE_IRQFLAGS
larl %r1,io_restore_trace_psw
lpswe 0(%r1)
io_restore_trace:
TRACE_IRQS_CHECK
LOCKDEP_SYS_EXIT LOCKDEP_SYS_EXIT
#endif
io_leave: io_leave:
RESTORE_ALL __LC_RETURN_PSW,0 RESTORE_ALL __LC_RETURN_PSW,0
io_done: io_done:
#ifdef CONFIG_TRACE_IRQFLAGS
.align 8
.globl io_restore_trace_psw
io_restore_trace_psw:
.quad 0, io_restore_trace
#endif
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
io_preempt: io_preempt:
icm %r0,15,__TI_precount(%r9) icm %r0,15,__TI_precount(%r9)
jnz io_leave jnz io_restore
# switch to kernel stack # switch to kernel stack
lg %r1,SP_R15(%r15) lg %r1,SP_R15(%r15)
aghi %r1,-SP_SIZE aghi %r1,-SP_SIZE
@ -582,14 +622,9 @@ io_preempt:
lgr %r15,%r1 lgr %r15,%r1
io_resume_loop: io_resume_loop:
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jno io_leave jno io_restore
larl %r1,.Lc_pactive larl %r14,io_resume_loop
mvc __TI_precount(4,%r9),0(%r1) jg preempt_schedule_irq
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
brasl %r14,schedule # call schedule
stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
xc __TI_precount(4,%r9),__TI_precount(%r9)
j io_resume_loop
#endif #endif
# #
@ -613,37 +648,39 @@ io_work_loop:
jo io_reschedule jo io_reschedule
tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK) tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
jnz io_sigpending jnz io_sigpending
LOCKDEP_SYS_EXIT j io_restore
j io_leave io_work_done:
# #
# _TIF_MCCK_PENDING is set, call handler # _TIF_MCCK_PENDING is set, call handler
# #
io_mcck_pending: io_mcck_pending:
TRACE_IRQS_OFF
brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler
TRACE_IRQS_ON
j io_work_loop j io_work_loop
# #
# _TIF_NEED_RESCHED is set, call schedule # _TIF_NEED_RESCHED is set, call schedule
# #
io_reschedule: io_reschedule:
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
brasl %r14,schedule # call scheduler brasl %r14,schedule # call scheduler
stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
TRACE_IRQS_OFF
tm __TI_flags+7(%r9),_TIF_WORK_INT tm __TI_flags+7(%r9),_TIF_WORK_INT
jz io_leave # there is no work to do jz io_restore # there is no work to do
j io_work_loop j io_work_loop
# #
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
# #
io_sigpending: io_sigpending:
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
la %r2,SP_PTREGS(%r15) # load pt_regs la %r2,SP_PTREGS(%r15) # load pt_regs
brasl %r14,do_signal # call do_signal brasl %r14,do_signal # call do_signal
stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
TRACE_IRQS_OFF
j io_work_loop j io_work_loop
/* /*
@ -669,7 +706,6 @@ ext_no_vtime:
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 llgh %r3,__LC_EXT_INT_CODE # get interruption code
brasl %r14,do_extint brasl %r14,do_extint
TRACE_IRQS_ON
j io_return j io_return
__critical_end: __critical_end:
@ -824,15 +860,15 @@ cleanup_table_system_call:
cleanup_table_sysc_return: cleanup_table_sysc_return:
.quad sysc_return, sysc_leave .quad sysc_return, sysc_leave
cleanup_table_sysc_leave: cleanup_table_sysc_leave:
.quad sysc_leave, sysc_work_loop .quad sysc_leave, sysc_done
cleanup_table_sysc_work_loop: cleanup_table_sysc_work_loop:
.quad sysc_work_loop, sysc_reschedule .quad sysc_work_loop, sysc_work_done
cleanup_table_io_return: cleanup_table_io_return:
.quad io_return, io_leave .quad io_return, io_leave
cleanup_table_io_leave: cleanup_table_io_leave:
.quad io_leave, io_done .quad io_leave, io_done
cleanup_table_io_work_loop: cleanup_table_io_work_loop:
.quad io_work_loop, io_mcck_pending .quad io_work_loop, io_work_done
cleanup_critical: cleanup_critical:
clc 8(8,%r12),BASED(cleanup_table_system_call) clc 8(8,%r12),BASED(cleanup_table_system_call)
@ -901,8 +937,6 @@ cleanup_system_call:
cleanup_vtime: cleanup_vtime:
clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
jhe cleanup_stime jhe cleanup_stime
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz cleanup_novtime
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
cleanup_stime: cleanup_stime:
clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32) clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32)
@ -910,7 +944,6 @@ cleanup_stime:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
cleanup_update: cleanup_update:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
cleanup_novtime:
#endif #endif
mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8)
la %r12,__LC_RETURN_PSW la %r12,__LC_RETURN_PSW
@ -949,10 +982,10 @@ cleanup_sysc_leave:
2: la %r12,__LC_RETURN_PSW 2: la %r12,__LC_RETURN_PSW
br %r14 br %r14
cleanup_sysc_leave_insn: cleanup_sysc_leave_insn:
.quad sysc_done - 4
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
.quad sysc_leave + 16 .quad sysc_done - 8
#endif #endif
.quad sysc_leave + 12
cleanup_io_return: cleanup_io_return:
mvc __LC_RETURN_PSW(8),0(%r12) mvc __LC_RETURN_PSW(8),0(%r12)
@ -979,17 +1012,16 @@ cleanup_io_leave:
2: la %r12,__LC_RETURN_PSW 2: la %r12,__LC_RETURN_PSW
br %r14 br %r14
cleanup_io_leave_insn: cleanup_io_leave_insn:
.quad io_done - 4
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
.quad io_leave + 20 .quad io_done - 8
#endif #endif
.quad io_leave + 16
/* /*
* Integer constants * Integer constants
*/ */
.align 4 .align 4
.Lconst: .Lconst:
.Lc_pactive: .long PREEMPT_ACTIVE
.Lnr_syscalls: .long NR_syscalls .Lnr_syscalls: .long NR_syscalls
.L0x0130: .short 0x130 .L0x0130: .short 0x130
.L0x0140: .short 0x140 .L0x0140: .short 0x140

View File

@ -347,7 +347,7 @@ void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
void machine_restart(char *command) void machine_restart(char *command)
{ {
if (!in_interrupt() || oops_in_progress) if ((!in_interrupt() && !in_atomic()) || oops_in_progress)
/* /*
* Only unblank the console if we are called in enabled * Only unblank the console if we are called in enabled
* context or a bust_spinlocks cleared the way for us. * context or a bust_spinlocks cleared the way for us.
@ -492,6 +492,10 @@ static void setup_addressing_mode(void)
printk("S390 address spaces switched, "); printk("S390 address spaces switched, ");
set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
} }
#ifdef CONFIG_TRACE_IRQFLAGS
sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
io_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
#endif
} }
static void __init static void __init

View File

@ -193,10 +193,16 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
} }
EXPORT_SYMBOL(smp_call_function_single); EXPORT_SYMBOL(smp_call_function_single);
static void do_send_stop(void) void smp_send_stop(void)
{ {
int cpu, rc; int cpu, rc;
/* Disable all interrupts/machine checks */
__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
/* write magic number to zero page (absolute 0) */
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
/* stop all processors */ /* stop all processors */
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
if (cpu == smp_processor_id()) if (cpu == smp_processor_id())
@ -204,60 +210,12 @@ static void do_send_stop(void)
do { do {
rc = signal_processor(cpu, sigp_stop); rc = signal_processor(cpu, sigp_stop);
} while (rc == sigp_busy); } while (rc == sigp_busy);
}
}
static void do_store_status(void)
{
int cpu, rc;
/* store status of all processors in their lowcores (real 0) */
for_each_online_cpu(cpu) {
if (cpu == smp_processor_id())
continue;
do {
rc = signal_processor_p(
(__u32)(unsigned long) lowcore_ptr[cpu], cpu,
sigp_store_status_at_address);
} while (rc == sigp_busy);
}
}
static void do_wait_for_stop(void)
{
int cpu;
/* Wait for all other cpus to enter stopped state */
for_each_online_cpu(cpu) {
if (cpu == smp_processor_id())
continue;
while (!smp_cpu_not_running(cpu)) while (!smp_cpu_not_running(cpu))
cpu_relax(); cpu_relax();
} }
} }
/*
* this function sends a 'stop' sigp to all other CPUs in the system.
* it goes straight through.
*/
void smp_send_stop(void)
{
/* Disable all interrupts/machine checks */
__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
/* write magic number to zero page (absolute 0) */
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
/* stop other processors. */
do_send_stop();
/* wait until other processors are stopped */
do_wait_for_stop();
/* store status of other processors. */
do_store_status();
}
/* /*
* Reboot, halt and power_off routines for SMP. * Reboot, halt and power_off routines for SMP.
*/ */

View File

@ -260,6 +260,7 @@ void die(const char * str, struct pt_regs * regs, long err)
bust_spinlocks(1); bust_spinlocks(1);
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
print_modules(); print_modules();
notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
show_regs(regs); show_regs(regs);
bust_spinlocks(0); bust_spinlocks(0);
add_taint(TAINT_DIE); add_taint(TAINT_DIE);

View File

@ -341,19 +341,16 @@ cmm_timeout_handler(ctl_table *ctl, int write, struct file *filp,
static struct ctl_table cmm_table[] = { static struct ctl_table cmm_table[] = {
{ {
.ctl_name = VM_CMM_PAGES,
.procname = "cmm_pages", .procname = "cmm_pages",
.mode = 0644, .mode = 0644,
.proc_handler = &cmm_pages_handler, .proc_handler = &cmm_pages_handler,
}, },
{ {
.ctl_name = VM_CMM_TIMED_PAGES,
.procname = "cmm_timed_pages", .procname = "cmm_timed_pages",
.mode = 0644, .mode = 0644,
.proc_handler = &cmm_pages_handler, .proc_handler = &cmm_pages_handler,
}, },
{ {
.ctl_name = VM_CMM_TIMEOUT,
.procname = "cmm_timeout", .procname = "cmm_timeout",
.mode = 0644, .mode = 0644,
.proc_handler = &cmm_timeout_handler, .proc_handler = &cmm_timeout_handler,

View File

@ -483,7 +483,7 @@ static DECLARE_WORK(css_reprobe_work, reprobe_all);
void css_schedule_reprobe(void) void css_schedule_reprobe(void)
{ {
need_reprobe = 1; need_reprobe = 1;
queue_work(ccw_device_work, &css_reprobe_work); queue_work(slow_path_wq, &css_reprobe_work);
} }
EXPORT_SYMBOL_GPL(css_schedule_reprobe); EXPORT_SYMBOL_GPL(css_schedule_reprobe);

View File

@ -1034,7 +1034,7 @@ device_trigger_reprobe(struct subchannel *sch)
if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
PREPARE_WORK(&cdev->private->kick_work, PREPARE_WORK(&cdev->private->kick_work,
ccw_device_move_to_orphanage); ccw_device_move_to_orphanage);
queue_work(ccw_device_work, &cdev->private->kick_work); queue_work(slow_path_wq, &cdev->private->kick_work);
} else } else
ccw_device_start_id(cdev, 0); ccw_device_start_id(cdev, 0);
} }

View File

@ -113,19 +113,10 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
{ {
struct subchannel *sch; struct subchannel *sch;
struct ccw1 *ccw; struct ccw1 *ccw;
int ret;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
/* Setup sense channel program. */ /* Setup sense channel program. */
ccw = cdev->private->iccws; ccw = cdev->private->iccws;
if (sch->schib.pmcw.pim != 0x80) {
/* more than one path installed. */
ccw->cmd_code = CCW_CMD_SUSPEND_RECONN;
ccw->cda = 0;
ccw->count = 0;
ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC;
ccw++;
}
ccw->cmd_code = CCW_CMD_SENSE_ID; ccw->cmd_code = CCW_CMD_SENSE_ID;
ccw->cda = (__u32) __pa (&cdev->private->senseid); ccw->cda = (__u32) __pa (&cdev->private->senseid);
ccw->count = sizeof (struct senseid); ccw->count = sizeof (struct senseid);
@ -133,25 +124,9 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
/* Reset device status. */ /* Reset device status. */
memset(&cdev->private->irb, 0, sizeof(struct irb)); memset(&cdev->private->irb, 0, sizeof(struct irb));
cdev->private->flags.intretry = 0;
/* Try on every path. */ return cio_start(sch, ccw, LPM_ANYPATH);
ret = -ENODEV;
while (cdev->private->imask != 0) {
if ((sch->opm & cdev->private->imask) != 0 &&
cdev->private->iretry > 0) {
cdev->private->iretry--;
/* Reset internal retry indication. */
cdev->private->flags.intretry = 0;
ret = cio_start (sch, cdev->private->iccws,
cdev->private->imask);
/* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret != -EACCES)
return ret;
}
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
}
return ret;
} }
void void
@ -161,8 +136,7 @@ ccw_device_sense_id_start(struct ccw_device *cdev)
memset (&cdev->private->senseid, 0, sizeof (struct senseid)); memset (&cdev->private->senseid, 0, sizeof (struct senseid));
cdev->private->senseid.cu_type = 0xFFFF; cdev->private->senseid.cu_type = 0xFFFF;
cdev->private->imask = 0x80; cdev->private->iretry = 3;
cdev->private->iretry = 5;
ret = __ccw_device_sense_id_start(cdev); ret = __ccw_device_sense_id_start(cdev);
if (ret && ret != -EBUSY) if (ret && ret != -EBUSY)
ccw_device_sense_id_done(cdev, ret); ccw_device_sense_id_done(cdev, ret);
@ -278,14 +252,13 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
ccw_device_sense_id_done(cdev, ret); ccw_device_sense_id_done(cdev, ret);
break; break;
case -EACCES: /* channel is not operational. */ case -EACCES: /* channel is not operational. */
sch->lpm &= ~cdev->private->imask;
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
/* fall through. */
case -EAGAIN: /* try again. */ case -EAGAIN: /* try again. */
ret = __ccw_device_sense_id_start(cdev); cdev->private->iretry--;
if (ret == 0 || ret == -EBUSY) if (cdev->private->iretry > 0) {
break; ret = __ccw_device_sense_id_start(cdev);
if (ret == 0 || ret == -EBUSY)
break;
}
/* fall through. */ /* fall through. */
default: /* Sense ID failed. Try asking VM. */ default: /* Sense ID failed. Try asking VM. */
if (MACHINE_IS_VM) { if (MACHINE_IS_VM) {

View File

@ -388,6 +388,11 @@ extern void (*_machine_power_off)(void);
#define arch_align_stack(x) (x) #define arch_align_stack(x) (x)
#ifdef CONFIG_TRACE_IRQFLAGS
extern psw_t sysc_restore_trace_psw;
extern psw_t io_restore_trace_psw;
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif #endif

View File

@ -70,7 +70,6 @@ enum
CTL_ABI=9, /* Binary emulation */ CTL_ABI=9, /* Binary emulation */
CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
CTL_ARLAN=254, /* arlan wireless driver */ CTL_ARLAN=254, /* arlan wireless driver */
CTL_APPLDATA=2120, /* s390 appldata */
CTL_S390DBF=5677, /* s390 debug */ CTL_S390DBF=5677, /* s390 debug */
CTL_SUNRPC=7249, /* sunrpc debug */ CTL_SUNRPC=7249, /* sunrpc debug */
CTL_PM=9899, /* frv power management */ CTL_PM=9899, /* frv power management */
@ -207,11 +206,6 @@ enum
VM_PANIC_ON_OOM=33, /* panic at out-of-memory */ VM_PANIC_ON_OOM=33, /* panic at out-of-memory */
VM_VDSO_ENABLED=34, /* map VDSO into new processes? */ VM_VDSO_ENABLED=34, /* map VDSO into new processes? */
VM_MIN_SLAB=35, /* Percent pages ignored by zone reclaim */ VM_MIN_SLAB=35, /* Percent pages ignored by zone reclaim */
/* s390 vm cmm sysctls */
VM_CMM_PAGES=1111,
VM_CMM_TIMED_PAGES=1112,
VM_CMM_TIMEOUT=1113,
}; };

View File

@ -140,9 +140,6 @@ static struct trans_ctl_table trans_vm_table[] = {
{ VM_PANIC_ON_OOM, "panic_on_oom" }, { VM_PANIC_ON_OOM, "panic_on_oom" },
{ VM_VDSO_ENABLED, "vdso_enabled" }, { VM_VDSO_ENABLED, "vdso_enabled" },
{ VM_MIN_SLAB, "min_slab_ratio" }, { VM_MIN_SLAB, "min_slab_ratio" },
{ VM_CMM_PAGES, "cmm_pages" },
{ VM_CMM_TIMED_PAGES, "cmm_timed_pages" },
{ VM_CMM_TIMEOUT, "cmm_timeout" },
{} {}
}; };
@ -1219,16 +1216,6 @@ static struct trans_ctl_table trans_arlan_table[] = {
{} {}
}; };
static struct trans_ctl_table trans_appldata_table[] = {
{ CTL_APPLDATA_TIMER, "timer" },
{ CTL_APPLDATA_INTERVAL, "interval" },
{ CTL_APPLDATA_OS, "os" },
{ CTL_APPLDATA_NET_SUM, "net_sum" },
{ CTL_APPLDATA_MEM, "mem" },
{}
};
static struct trans_ctl_table trans_s390dbf_table[] = { static struct trans_ctl_table trans_s390dbf_table[] = {
{ 5678 /* CTL_S390DBF_STOPPABLE */, "debug_stoppable" }, { 5678 /* CTL_S390DBF_STOPPABLE */, "debug_stoppable" },
{ 5679 /* CTL_S390DBF_ACTIVE */, "debug_active" }, { 5679 /* CTL_S390DBF_ACTIVE */, "debug_active" },
@ -1273,7 +1260,6 @@ static struct trans_ctl_table trans_root_table[] = {
{ CTL_ABI, "abi" }, { CTL_ABI, "abi" },
/* CTL_CPU not used */ /* CTL_CPU not used */
{ CTL_ARLAN, "arlan", trans_arlan_table }, { CTL_ARLAN, "arlan", trans_arlan_table },
{ CTL_APPLDATA, "appldata", trans_appldata_table },
{ CTL_S390DBF, "s390dbf", trans_s390dbf_table }, { CTL_S390DBF, "s390dbf", trans_s390dbf_table },
{ CTL_SUNRPC, "sunrpc", trans_sunrpc_table }, { CTL_SUNRPC, "sunrpc", trans_sunrpc_table },
{ CTL_PM, "pm", trans_pm_table }, { CTL_PM, "pm", trans_pm_table },

View File

@ -471,11 +471,12 @@ int page_mkclean(struct page *page)
if (page_mapped(page)) { if (page_mapped(page)) {
struct address_space *mapping = page_mapping(page); struct address_space *mapping = page_mapping(page);
if (mapping) if (mapping) {
ret = page_mkclean_file(mapping, page); ret = page_mkclean_file(mapping, page);
if (page_test_dirty(page)) { if (page_test_dirty(page)) {
page_clear_dirty(page); page_clear_dirty(page);
ret = 1; ret = 1;
}
} }
} }

View File

@ -97,7 +97,7 @@ struct iucv_irq_list {
struct iucv_irq_data data; struct iucv_irq_data data;
}; };
static struct iucv_irq_data *iucv_irq_data; static struct iucv_irq_data *iucv_irq_data[NR_CPUS];
static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE; static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE;
static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE; static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE;
@ -277,7 +277,7 @@ union iucv_param {
/* /*
* Anchor for per-cpu IUCV command parameter block. * Anchor for per-cpu IUCV command parameter block.
*/ */
static union iucv_param *iucv_param; static union iucv_param *iucv_param[NR_CPUS];
/** /**
* iucv_call_b2f0 * iucv_call_b2f0
@ -356,7 +356,7 @@ static void iucv_allow_cpu(void *data)
* 0x10 - Flag to allow priority message completion interrupts * 0x10 - Flag to allow priority message completion interrupts
* 0x08 - Flag to allow IUCV control interrupts * 0x08 - Flag to allow IUCV control interrupts
*/ */
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[cpu];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->set_mask.ipmask = 0xf8; parm->set_mask.ipmask = 0xf8;
iucv_call_b2f0(IUCV_SETMASK, parm); iucv_call_b2f0(IUCV_SETMASK, parm);
@ -377,7 +377,7 @@ static void iucv_block_cpu(void *data)
union iucv_param *parm; union iucv_param *parm;
/* Disable all iucv interrupts. */ /* Disable all iucv interrupts. */
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[cpu];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
iucv_call_b2f0(IUCV_SETMASK, parm); iucv_call_b2f0(IUCV_SETMASK, parm);
@ -401,9 +401,9 @@ static void iucv_declare_cpu(void *data)
return; return;
/* Declare interrupt buffer. */ /* Declare interrupt buffer. */
parm = percpu_ptr(iucv_param, cpu); parm = iucv_param[cpu];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->db.ipbfadr1 = virt_to_phys(percpu_ptr(iucv_irq_data, cpu)); parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]);
rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
if (rc) { if (rc) {
char *err = "Unknown"; char *err = "Unknown";
@ -458,7 +458,7 @@ static void iucv_retrieve_cpu(void *data)
iucv_block_cpu(NULL); iucv_block_cpu(NULL);
/* Retrieve interrupt buffer. */ /* Retrieve interrupt buffer. */
parm = percpu_ptr(iucv_param, cpu); parm = iucv_param[cpu];
iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm);
/* Clear indication that an iucv buffer exists for this cpu. */ /* Clear indication that an iucv buffer exists for this cpu. */
@ -558,22 +558,23 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
switch (action) { switch (action) {
case CPU_UP_PREPARE: case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN: case CPU_UP_PREPARE_FROZEN:
if (!percpu_populate(iucv_irq_data, iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
sizeof(struct iucv_irq_data), GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
GFP_KERNEL|GFP_DMA, cpu)) if (!iucv_irq_data[cpu])
return NOTIFY_BAD; return NOTIFY_BAD;
if (!percpu_populate(iucv_param, sizeof(union iucv_param), iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
GFP_KERNEL|GFP_DMA, cpu)) { GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
percpu_depopulate(iucv_irq_data, cpu); if (!iucv_param[cpu])
return NOTIFY_BAD; return NOTIFY_BAD;
}
break; break;
case CPU_UP_CANCELED: case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN: case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD: case CPU_DEAD:
case CPU_DEAD_FROZEN: case CPU_DEAD_FROZEN:
percpu_depopulate(iucv_param, cpu); kfree(iucv_param[cpu]);
percpu_depopulate(iucv_irq_data, cpu); iucv_param[cpu] = NULL;
kfree(iucv_irq_data[cpu]);
iucv_irq_data[cpu] = NULL;
break; break;
case CPU_ONLINE: case CPU_ONLINE:
case CPU_ONLINE_FROZEN: case CPU_ONLINE_FROZEN:
@ -612,7 +613,7 @@ static int iucv_sever_pathid(u16 pathid, u8 userdata[16])
{ {
union iucv_param *parm; union iucv_param *parm;
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (userdata) if (userdata)
memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
@ -755,7 +756,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
local_bh_disable(); local_bh_disable();
/* Prepare parameter block. */ /* Prepare parameter block. */
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->ctrl.ippathid = path->pathid; parm->ctrl.ippathid = path->pathid;
parm->ctrl.ipmsglim = path->msglim; parm->ctrl.ipmsglim = path->msglim;
@ -799,7 +800,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
BUG_ON(in_atomic()); BUG_ON(in_atomic());
spin_lock_bh(&iucv_table_lock); spin_lock_bh(&iucv_table_lock);
iucv_cleanup_queue(); iucv_cleanup_queue();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->ctrl.ipmsglim = path->msglim; parm->ctrl.ipmsglim = path->msglim;
parm->ctrl.ipflags1 = path->flags; parm->ctrl.ipflags1 = path->flags;
@ -854,7 +855,7 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (userdata) if (userdata)
memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
@ -881,7 +882,7 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16])
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (userdata) if (userdata)
memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
@ -936,7 +937,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->purge.ippathid = path->pathid; parm->purge.ippathid = path->pathid;
parm->purge.ipmsgid = msg->id; parm->purge.ipmsgid = msg->id;
@ -1003,7 +1004,7 @@ int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
} }
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->db.ipbfadr1 = (u32)(addr_t) buffer; parm->db.ipbfadr1 = (u32)(addr_t) buffer;
parm->db.ipbfln1f = (u32) size; parm->db.ipbfln1f = (u32) size;
@ -1040,7 +1041,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->db.ippathid = path->pathid; parm->db.ippathid = path->pathid;
parm->db.ipmsgid = msg->id; parm->db.ipmsgid = msg->id;
@ -1074,7 +1075,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (flags & IUCV_IPRMDATA) { if (flags & IUCV_IPRMDATA) {
parm->dpl.ippathid = path->pathid; parm->dpl.ippathid = path->pathid;
@ -1118,7 +1119,7 @@ int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (flags & IUCV_IPRMDATA) { if (flags & IUCV_IPRMDATA) {
/* Message of 8 bytes can be placed into the parameter list. */ /* Message of 8 bytes can be placed into the parameter list. */
@ -1172,7 +1173,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
parm = percpu_ptr(iucv_param, smp_processor_id()); parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (flags & IUCV_IPRMDATA) { if (flags & IUCV_IPRMDATA) {
parm->dpl.ippathid = path->pathid; parm->dpl.ippathid = path->pathid;
@ -1559,7 +1560,7 @@ static void iucv_external_interrupt(u16 code)
struct iucv_irq_data *p; struct iucv_irq_data *p;
struct iucv_irq_list *work; struct iucv_irq_list *work;
p = percpu_ptr(iucv_irq_data, smp_processor_id()); p = iucv_irq_data[smp_processor_id()];
if (p->ippathid >= iucv_max_pathid) { if (p->ippathid >= iucv_max_pathid) {
printk(KERN_WARNING "iucv_do_int: Got interrupt with " printk(KERN_WARNING "iucv_do_int: Got interrupt with "
"pathid %d > max_connections (%ld)\n", "pathid %d > max_connections (%ld)\n",
@ -1598,6 +1599,7 @@ static void iucv_external_interrupt(u16 code)
static int __init iucv_init(void) static int __init iucv_init(void)
{ {
int rc; int rc;
int cpu;
if (!MACHINE_IS_VM) { if (!MACHINE_IS_VM) {
rc = -EPROTONOSUPPORT; rc = -EPROTONOSUPPORT;
@ -1617,19 +1619,23 @@ static int __init iucv_init(void)
rc = PTR_ERR(iucv_root); rc = PTR_ERR(iucv_root);
goto out_bus; goto out_bus;
} }
/* Note: GFP_DMA used to get memory below 2G */
iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data), for_each_online_cpu(cpu) {
GFP_KERNEL|GFP_DMA); /* Note: GFP_DMA used to get memory below 2G */
if (!iucv_irq_data) { iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
rc = -ENOMEM; GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
goto out_root; if (!iucv_irq_data[cpu]) {
} rc = -ENOMEM;
/* Allocate parameter blocks. */ goto out_free;
iucv_param = percpu_alloc(sizeof(union iucv_param), }
GFP_KERNEL|GFP_DMA);
if (!iucv_param) { /* Allocate parameter blocks. */
rc = -ENOMEM; iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
goto out_extint; GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
if (!iucv_param[cpu]) {
rc = -ENOMEM;
goto out_free;
}
} }
register_hotcpu_notifier(&iucv_cpu_notifier); register_hotcpu_notifier(&iucv_cpu_notifier);
ASCEBC(iucv_error_no_listener, 16); ASCEBC(iucv_error_no_listener, 16);
@ -1638,9 +1644,13 @@ static int __init iucv_init(void)
iucv_available = 1; iucv_available = 1;
return 0; return 0;
out_extint: out_free:
percpu_free(iucv_irq_data); for_each_possible_cpu(cpu) {
out_root: kfree(iucv_param[cpu]);
iucv_param[cpu] = NULL;
kfree(iucv_irq_data[cpu]);
iucv_irq_data[cpu] = NULL;
}
s390_root_dev_unregister(iucv_root); s390_root_dev_unregister(iucv_root);
out_bus: out_bus:
bus_unregister(&iucv_bus); bus_unregister(&iucv_bus);
@ -1658,6 +1668,7 @@ static int __init iucv_init(void)
static void __exit iucv_exit(void) static void __exit iucv_exit(void)
{ {
struct iucv_irq_list *p, *n; struct iucv_irq_list *p, *n;
int cpu;
spin_lock_irq(&iucv_queue_lock); spin_lock_irq(&iucv_queue_lock);
list_for_each_entry_safe(p, n, &iucv_task_queue, list) list_for_each_entry_safe(p, n, &iucv_task_queue, list)
@ -1666,8 +1677,12 @@ static void __exit iucv_exit(void)
kfree(p); kfree(p);
spin_unlock_irq(&iucv_queue_lock); spin_unlock_irq(&iucv_queue_lock);
unregister_hotcpu_notifier(&iucv_cpu_notifier); unregister_hotcpu_notifier(&iucv_cpu_notifier);
percpu_free(iucv_param); for_each_possible_cpu(cpu) {
percpu_free(iucv_irq_data); kfree(iucv_param[cpu]);
iucv_param[cpu] = NULL;
kfree(iucv_irq_data[cpu]);
iucv_irq_data[cpu] = NULL;
}
s390_root_dev_unregister(iucv_root); s390_root_dev_unregister(iucv_root);
bus_unregister(&iucv_bus); bus_unregister(&iucv_bus);
unregister_external_interrupt(0x4000, iucv_external_interrupt); unregister_external_interrupt(0x4000, iucv_external_interrupt);