Merge tag 's390-5.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Vasily Gorbik: - Update maintainers. Niklas Schnelle takes over zpci and Vineeth Vijayan common io code. - Extend cpuinfo to include topology information. - Add new extended counters for IBM z15 and sampling buffer allocation rework in perf code. - Add control over zeroing out memory during system restart. - CCA protected key block version 2 support and other fixes/improvements in crypto code. - Convert to new fallthrough; annotations. - Replace zero-length arrays with flexible-arrays. - QDIO debugfs and other small improvements. - Drop 2-level paging support optimization for compat tasks. Varios mm cleanups. - Remove broken and unused hibernate / power management support. - Remove fake numa support which does not bring any benefits. - Exclude offline CPUs from CPU topology masks to be more consistent with other architectures. - Prevent last branching instruction address leaking to userspace. - Other small various fixes and improvements all over the code. * tag 's390-5.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (57 commits) s390/mm: cleanup init_new_context() callback s390/mm: cleanup virtual memory constants usage s390/mm: remove page table downgrade support s390/qdio: set qdio_irq->cdev at allocation time s390/qdio: remove unused function declarations s390/ccwgroup: remove pm support s390/ap: remove power management code from ap bus and drivers s390/zcrypt: use kvmalloc instead of kmalloc for 256k alloc s390/mm: cleanup arch_get_unmapped_area() and friends s390/ism: remove pm support s390/cio: use fallthrough; s390/vfio: use fallthrough; s390/zcrypt: use fallthrough; s390: use fallthrough; s390/cpum_sf: Fix wrong page count in error message s390/diag: fix display of diagnose call statistics s390/ap: Remove ap device suspend and resume callbacks s390/pci: Improve handling of unset UID s390/pci: Fix zpci_alloc_domain() over allocation s390/qdio: pass ISC as parameter to chsc_sadc() ...
This commit is contained in:
@@ -54,7 +54,6 @@ CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE)
|
||||
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o
|
||||
obj-$(CONFIG_HIBERNATION) += suspend.o swsusp.o
|
||||
obj-$(CONFIG_AUDIT) += audit.o
|
||||
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
|
||||
obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
|
||||
|
||||
@@ -124,6 +124,8 @@ int main(void)
|
||||
OFFSET(__LC_EXT_DAMAGE_CODE, lowcore, external_damage_code);
|
||||
OFFSET(__LC_MCCK_FAIL_STOR_ADDR, lowcore, failing_storage_address);
|
||||
OFFSET(__LC_LAST_BREAK, lowcore, breaking_event_addr);
|
||||
OFFSET(__LC_RETURN_LPSWE, lowcore, return_lpswe);
|
||||
OFFSET(__LC_RETURN_MCCK_LPSWE, lowcore, return_mcck_lpswe);
|
||||
OFFSET(__LC_RST_OLD_PSW, lowcore, restart_old_psw);
|
||||
OFFSET(__LC_EXT_OLD_PSW, lowcore, external_old_psw);
|
||||
OFFSET(__LC_SVC_OLD_PSW, lowcore, svc_old_psw);
|
||||
|
||||
@@ -84,7 +84,7 @@ static int show_diag_stat(struct seq_file *m, void *v)
|
||||
|
||||
static void *show_diag_stat_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return *pos <= nr_cpu_ids ? (void *)((unsigned long) *pos + 1) : NULL;
|
||||
return *pos <= NR_DIAG_STAT ? (void *)((unsigned long) *pos + 1) : NULL;
|
||||
}
|
||||
|
||||
static void *show_diag_stat_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
|
||||
@@ -115,26 +115,29 @@ _LPP_OFFSET = __LC_LPP
|
||||
|
||||
.macro SWITCH_ASYNC savearea,timer
|
||||
tmhh %r8,0x0001 # interrupting from user ?
|
||||
jnz 1f
|
||||
jnz 2f
|
||||
lgr %r14,%r9
|
||||
cghi %r14,__LC_RETURN_LPSWE
|
||||
je 0f
|
||||
slg %r14,BASED(.Lcritical_start)
|
||||
clg %r14,BASED(.Lcritical_length)
|
||||
jhe 0f
|
||||
jhe 1f
|
||||
0:
|
||||
lghi %r11,\savearea # inside critical section, do cleanup
|
||||
brasl %r14,cleanup_critical
|
||||
tmhh %r8,0x0001 # retest problem state after cleanup
|
||||
jnz 1f
|
||||
0: lg %r14,__LC_ASYNC_STACK # are we already on the target stack?
|
||||
jnz 2f
|
||||
1: lg %r14,__LC_ASYNC_STACK # are we already on the target stack?
|
||||
slgr %r14,%r15
|
||||
srag %r14,%r14,STACK_SHIFT
|
||||
jnz 2f
|
||||
jnz 3f
|
||||
CHECK_STACK \savearea
|
||||
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
j 3f
|
||||
1: UPDATE_VTIME %r14,%r15,\timer
|
||||
j 4f
|
||||
2: UPDATE_VTIME %r14,%r15,\timer
|
||||
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
2: lg %r15,__LC_ASYNC_STACK # load async stack
|
||||
3: la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
3: lg %r15,__LC_ASYNC_STACK # load async stack
|
||||
4: la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
.endm
|
||||
|
||||
.macro UPDATE_VTIME w1,w2,enter_timer
|
||||
@@ -401,7 +404,7 @@ ENTRY(system_call)
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
lmg %r11,%r15,__PT_R11(%r11)
|
||||
lpswe __LC_RETURN_PSW
|
||||
b __LC_RETURN_LPSWE(%r0)
|
||||
.Lsysc_done:
|
||||
|
||||
#
|
||||
@@ -608,43 +611,50 @@ ENTRY(pgm_check_handler)
|
||||
BPOFF
|
||||
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
|
||||
lg %r10,__LC_LAST_BREAK
|
||||
lg %r12,__LC_CURRENT
|
||||
srag %r11,%r10,12
|
||||
jnz 0f
|
||||
/* if __LC_LAST_BREAK is < 4096, it contains one of
|
||||
* the lpswe addresses in lowcore. Set it to 1 (initial state)
|
||||
* to prevent leaking that address to userspace.
|
||||
*/
|
||||
lghi %r10,1
|
||||
0: lg %r12,__LC_CURRENT
|
||||
lghi %r11,0
|
||||
larl %r13,cleanup_critical
|
||||
lmg %r8,%r9,__LC_PGM_OLD_PSW
|
||||
tmhh %r8,0x0001 # test problem state bit
|
||||
jnz 2f # -> fault in user space
|
||||
jnz 3f # -> fault in user space
|
||||
#if IS_ENABLED(CONFIG_KVM)
|
||||
# cleanup critical section for program checks in sie64a
|
||||
lgr %r14,%r9
|
||||
slg %r14,BASED(.Lsie_critical_start)
|
||||
clg %r14,BASED(.Lsie_critical_length)
|
||||
jhe 0f
|
||||
jhe 1f
|
||||
lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer
|
||||
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
|
||||
larl %r9,sie_exit # skip forward to sie_exit
|
||||
lghi %r11,_PIF_GUEST_FAULT
|
||||
#endif
|
||||
0: tmhh %r8,0x4000 # PER bit set in old PSW ?
|
||||
jnz 1f # -> enabled, can't be a double fault
|
||||
1: tmhh %r8,0x4000 # PER bit set in old PSW ?
|
||||
jnz 2f # -> enabled, can't be a double fault
|
||||
tm __LC_PGM_ILC+3,0x80 # check for per exception
|
||||
jnz .Lpgm_svcper # -> single stepped svc
|
||||
1: CHECK_STACK __LC_SAVE_AREA_SYNC
|
||||
2: CHECK_STACK __LC_SAVE_AREA_SYNC
|
||||
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
# CHECK_VMAP_STACK branches to stack_overflow or 4f
|
||||
CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f
|
||||
2: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
|
||||
# CHECK_VMAP_STACK branches to stack_overflow or 5f
|
||||
CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,5f
|
||||
3: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
|
||||
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
lg %r15,__LC_KERNEL_STACK
|
||||
lgr %r14,%r12
|
||||
aghi %r14,__TASK_thread # pointer to thread_struct
|
||||
lghi %r13,__LC_PGM_TDB
|
||||
tm __LC_PGM_ILC+2,0x02 # check for transaction abort
|
||||
jz 3f
|
||||
jz 4f
|
||||
mvc __THREAD_trap_tdb(256,%r14),0(%r13)
|
||||
3: stg %r10,__THREAD_last_break(%r14)
|
||||
4: lgr %r13,%r11
|
||||
4: stg %r10,__THREAD_last_break(%r14)
|
||||
5: lgr %r13,%r11
|
||||
la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
# clear user controlled registers to prevent speculative use
|
||||
@@ -663,14 +673,14 @@ ENTRY(pgm_check_handler)
|
||||
stg %r13,__PT_FLAGS(%r11)
|
||||
stg %r10,__PT_ARGS(%r11)
|
||||
tm __LC_PGM_ILC+3,0x80 # check for per exception
|
||||
jz 5f
|
||||
jz 6f
|
||||
tmhh %r8,0x0001 # kernel per event ?
|
||||
jz .Lpgm_kprobe
|
||||
oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP
|
||||
mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS
|
||||
mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE
|
||||
mvc __THREAD_per_paid(1,%r14),__LC_PER_ACCESS_ID
|
||||
5: REENABLE_IRQS
|
||||
6: REENABLE_IRQS
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
larl %r1,pgm_check_table
|
||||
llgh %r10,__PT_INT_CODE+2(%r11)
|
||||
@@ -775,7 +785,7 @@ ENTRY(io_int_handler)
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
.Lio_exit_kernel:
|
||||
lmg %r11,%r15,__PT_R11(%r11)
|
||||
lpswe __LC_RETURN_PSW
|
||||
b __LC_RETURN_LPSWE(%r0)
|
||||
.Lio_done:
|
||||
|
||||
#
|
||||
@@ -1214,7 +1224,7 @@ ENTRY(mcck_int_handler)
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
0: lmg %r11,%r15,__PT_R11(%r11)
|
||||
lpswe __LC_RETURN_MCCK_PSW
|
||||
b __LC_RETURN_MCCK_LPSWE
|
||||
|
||||
.Lmcck_panic:
|
||||
lg %r15,__LC_NODAT_STACK
|
||||
@@ -1271,6 +1281,8 @@ ENDPROC(stack_overflow)
|
||||
#endif
|
||||
|
||||
ENTRY(cleanup_critical)
|
||||
cghi %r9,__LC_RETURN_LPSWE
|
||||
je .Lcleanup_lpswe
|
||||
#if IS_ENABLED(CONFIG_KVM)
|
||||
clg %r9,BASED(.Lcleanup_table_sie) # .Lsie_gmap
|
||||
jl 0f
|
||||
@@ -1424,6 +1436,7 @@ ENDPROC(cleanup_critical)
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r9)
|
||||
mvc 0(64,%r11),__PT_R8(%r9)
|
||||
lmg %r0,%r7,__PT_R0(%r9)
|
||||
.Lcleanup_lpswe:
|
||||
1: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
BR_EX %r14,%r11
|
||||
.Lcleanup_sysc_restore_insn:
|
||||
|
||||
@@ -144,6 +144,9 @@ static struct ipl_parameter_block *dump_block_ccw;
|
||||
|
||||
static struct sclp_ipl_info sclp_ipl_info;
|
||||
|
||||
static bool reipl_fcp_clear;
|
||||
static bool reipl_ccw_clear;
|
||||
|
||||
static inline int __diag308(unsigned long subcode, void *addr)
|
||||
{
|
||||
register unsigned long _addr asm("0") = (unsigned long) addr;
|
||||
@@ -691,6 +694,21 @@ static struct kobj_attribute sys_reipl_fcp_loadparm_attr =
|
||||
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show,
|
||||
reipl_fcp_loadparm_store);
|
||||
|
||||
static ssize_t reipl_fcp_clear_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", reipl_fcp_clear);
|
||||
}
|
||||
|
||||
static ssize_t reipl_fcp_clear_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
if (strtobool(buf, &reipl_fcp_clear) < 0)
|
||||
return -EINVAL;
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct attribute *reipl_fcp_attrs[] = {
|
||||
&sys_reipl_fcp_device_attr.attr,
|
||||
&sys_reipl_fcp_wwpn_attr.attr,
|
||||
@@ -706,6 +724,9 @@ static struct attribute_group reipl_fcp_attr_group = {
|
||||
.bin_attrs = reipl_fcp_bin_attrs,
|
||||
};
|
||||
|
||||
static struct kobj_attribute sys_reipl_fcp_clear_attr =
|
||||
__ATTR(clear, 0644, reipl_fcp_clear_show, reipl_fcp_clear_store);
|
||||
|
||||
/* CCW reipl device attributes */
|
||||
DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw);
|
||||
|
||||
@@ -741,16 +762,36 @@ static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
|
||||
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
|
||||
reipl_ccw_loadparm_store);
|
||||
|
||||
static ssize_t reipl_ccw_clear_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", reipl_ccw_clear);
|
||||
}
|
||||
|
||||
static ssize_t reipl_ccw_clear_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
if (strtobool(buf, &reipl_ccw_clear) < 0)
|
||||
return -EINVAL;
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct kobj_attribute sys_reipl_ccw_clear_attr =
|
||||
__ATTR(clear, 0644, reipl_ccw_clear_show, reipl_ccw_clear_store);
|
||||
|
||||
static struct attribute *reipl_ccw_attrs_vm[] = {
|
||||
&sys_reipl_ccw_device_attr.attr,
|
||||
&sys_reipl_ccw_loadparm_attr.attr,
|
||||
&sys_reipl_ccw_vmparm_attr.attr,
|
||||
&sys_reipl_ccw_clear_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *reipl_ccw_attrs_lpar[] = {
|
||||
&sys_reipl_ccw_device_attr.attr,
|
||||
&sys_reipl_ccw_loadparm_attr.attr,
|
||||
&sys_reipl_ccw_clear_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -892,11 +933,17 @@ static void __reipl_run(void *unused)
|
||||
switch (reipl_type) {
|
||||
case IPL_TYPE_CCW:
|
||||
diag308(DIAG308_SET, reipl_block_ccw);
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
if (reipl_ccw_clear)
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
else
|
||||
diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
|
||||
break;
|
||||
case IPL_TYPE_FCP:
|
||||
diag308(DIAG308_SET, reipl_block_fcp);
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
if (reipl_fcp_clear)
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
else
|
||||
diag308(DIAG308_LOAD_NORMAL, NULL);
|
||||
break;
|
||||
case IPL_TYPE_NSS:
|
||||
diag308(DIAG308_SET, reipl_block_nss);
|
||||
@@ -1008,11 +1055,16 @@ static int __init reipl_fcp_init(void)
|
||||
}
|
||||
|
||||
rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
|
||||
if (rc) {
|
||||
kset_unregister(reipl_fcp_kset);
|
||||
free_page((unsigned long) reipl_block_fcp);
|
||||
return rc;
|
||||
}
|
||||
if (rc)
|
||||
goto out1;
|
||||
|
||||
if (test_facility(141)) {
|
||||
rc = sysfs_create_file(&reipl_fcp_kset->kobj,
|
||||
&sys_reipl_fcp_clear_attr.attr);
|
||||
if (rc)
|
||||
goto out2;
|
||||
} else
|
||||
reipl_fcp_clear = true;
|
||||
|
||||
if (ipl_info.type == IPL_TYPE_FCP) {
|
||||
memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block));
|
||||
@@ -1032,6 +1084,13 @@ static int __init reipl_fcp_init(void)
|
||||
}
|
||||
reipl_capabilities |= IPL_TYPE_FCP;
|
||||
return 0;
|
||||
|
||||
out2:
|
||||
sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
|
||||
out1:
|
||||
kset_unregister(reipl_fcp_kset);
|
||||
free_page((unsigned long) reipl_block_fcp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __init reipl_type_init(void)
|
||||
|
||||
@@ -95,14 +95,6 @@ static const struct irq_class irqclass_sub_desc[] = {
|
||||
{.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"},
|
||||
};
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
BUILD_BUG_ON(ARRAY_SIZE(irqclass_sub_desc) != NR_ARCH_IRQS);
|
||||
init_cio_interrupts();
|
||||
init_airq_interrupts();
|
||||
init_ext_interrupts();
|
||||
}
|
||||
|
||||
void do_IRQ(struct pt_regs *regs, int irq)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
@@ -294,12 +286,7 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction external_interrupt = {
|
||||
.name = "EXT",
|
||||
.handler = do_ext_interrupt,
|
||||
};
|
||||
|
||||
void __init init_ext_interrupts(void)
|
||||
static void __init init_ext_interrupts(void)
|
||||
{
|
||||
int idx;
|
||||
|
||||
@@ -308,7 +295,16 @@ void __init init_ext_interrupts(void)
|
||||
|
||||
irq_set_chip_and_handler(EXT_INTERRUPT,
|
||||
&dummy_irq_chip, handle_percpu_irq);
|
||||
setup_irq(EXT_INTERRUPT, &external_interrupt);
|
||||
if (request_irq(EXT_INTERRUPT, do_ext_interrupt, 0, "EXT", NULL))
|
||||
panic("Failed to register EXT interrupt\n");
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
BUILD_BUG_ON(ARRAY_SIZE(irqclass_sub_desc) != NR_ARCH_IRQS);
|
||||
init_cio_interrupts();
|
||||
init_airq_interrupts();
|
||||
init_ext_interrupts();
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(irq_subclass_lock);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/debug_locks.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgtable.h>
|
||||
@@ -38,36 +37,6 @@ extern const unsigned long long relocate_kernel_len;
|
||||
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
|
||||
/*
|
||||
* PM notifier callback for kdump
|
||||
*/
|
||||
static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action,
|
||||
void *ptr)
|
||||
{
|
||||
switch (action) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
if (kexec_crash_image)
|
||||
arch_kexec_unprotect_crashkres();
|
||||
break;
|
||||
case PM_POST_SUSPEND:
|
||||
case PM_POST_HIBERNATION:
|
||||
if (kexec_crash_image)
|
||||
arch_kexec_protect_crashkres();
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int __init machine_kdump_pm_init(void)
|
||||
{
|
||||
pm_notifier(machine_kdump_pm_cb, 0);
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(machine_kdump_pm_init);
|
||||
|
||||
/*
|
||||
* Reset the system, copy boot CPU registers to absolute zero,
|
||||
* and jump to the kdump image
|
||||
|
||||
@@ -238,6 +238,64 @@ CPUMF_EVENT_ATTR(cf_z14, TX_C_TABORT_SPECIAL, 0x00f5);
|
||||
CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
|
||||
CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
|
||||
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_RO_EXCL_WRITES, 0x0080);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DTLB2_WRITES, 0x0081);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DTLB2_MISSES, 0x0082);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DTLB2_HPAGE_WRITES, 0x0083);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DTLB2_GPAGE_WRITES, 0x0084);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_L2D_SOURCED_WRITES, 0x0085);
|
||||
CPUMF_EVENT_ATTR(cf_z15, ITLB2_WRITES, 0x0086);
|
||||
CPUMF_EVENT_ATTR(cf_z15, ITLB2_MISSES, 0x0087);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_L2I_SOURCED_WRITES, 0x0088);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TLB2_PTE_WRITES, 0x0089);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TLB2_CRSTE_WRITES, 0x008a);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TLB2_ENGINES_BUSY, 0x008b);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TX_C_TEND, 0x008c);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TX_NC_TEND, 0x008d);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1C_TLB2_MISSES, 0x008f);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES, 0x0090);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_MEMORY_SOURCED_WRITES, 0x0091);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_IV, 0x0092);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES, 0x0093);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x0094);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x0095);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES, 0x0096);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x0097);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x0098);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES, 0x0099);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x009a);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x009b);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONDRAWER_L4_SOURCED_WRITES, 0x009c);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L4_SOURCED_WRITES, 0x009d);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_RO, 0x009e);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES, 0x00a2);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_MEMORY_SOURCED_WRITES, 0x00a3);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES_IV, 0x00a4);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES, 0x00a5);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x00a6);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x00a7);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES, 0x00a8);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x00a9);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x00aa);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES, 0x00ab);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x00ac);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x00ad);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_ONDRAWER_L4_SOURCED_WRITES, 0x00ae);
|
||||
CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L4_SOURCED_WRITES, 0x00af);
|
||||
CPUMF_EVENT_ATTR(cf_z15, BCD_DFP_EXECUTION_SLOTS, 0x00e0);
|
||||
CPUMF_EVENT_ATTR(cf_z15, VX_BCD_EXECUTION_SLOTS, 0x00e1);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DECIMAL_INSTRUCTIONS, 0x00e2);
|
||||
CPUMF_EVENT_ATTR(cf_z15, LAST_HOST_TRANSLATIONS, 0x00e8);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TX_NC_TABORT, 0x00f3);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_NO_SPECIAL, 0x00f4);
|
||||
CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_SPECIAL, 0x00f5);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_ACCESS, 0x00f7);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CYCLES, 0x00fc);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CC, 0x00108);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CCERROR, 0x00109);
|
||||
CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
|
||||
CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
|
||||
|
||||
static struct attribute *cpumcf_fvn1_pmu_event_attr[] __initdata = {
|
||||
CPUMF_EVENT_PTR(cf_fvn1, CPU_CYCLES),
|
||||
CPUMF_EVENT_PTR(cf_fvn1, INSTRUCTIONS),
|
||||
@@ -516,6 +574,67 @@ static struct attribute *cpumcf_z14_pmu_event_attr[] __initdata = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *cpumcf_z15_pmu_event_attr[] __initdata = {
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_RO_EXCL_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, DTLB2_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, DTLB2_MISSES),
|
||||
CPUMF_EVENT_PTR(cf_z15, DTLB2_HPAGE_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, DTLB2_GPAGE_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_L2D_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, ITLB2_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, ITLB2_MISSES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_L2I_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, TLB2_PTE_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, TLB2_CRSTE_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, TLB2_ENGINES_BUSY),
|
||||
CPUMF_EVENT_PTR(cf_z15, TX_C_TEND),
|
||||
CPUMF_EVENT_PTR(cf_z15, TX_NC_TEND),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1C_TLB2_MISSES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONDRAWER_L4_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L4_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_RO),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_ONDRAWER_L4_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L4_SOURCED_WRITES),
|
||||
CPUMF_EVENT_PTR(cf_z15, BCD_DFP_EXECUTION_SLOTS),
|
||||
CPUMF_EVENT_PTR(cf_z15, VX_BCD_EXECUTION_SLOTS),
|
||||
CPUMF_EVENT_PTR(cf_z15, DECIMAL_INSTRUCTIONS),
|
||||
CPUMF_EVENT_PTR(cf_z15, LAST_HOST_TRANSLATIONS),
|
||||
CPUMF_EVENT_PTR(cf_z15, TX_NC_TABORT),
|
||||
CPUMF_EVENT_PTR(cf_z15, TX_C_TABORT_NO_SPECIAL),
|
||||
CPUMF_EVENT_PTR(cf_z15, TX_C_TABORT_SPECIAL),
|
||||
CPUMF_EVENT_PTR(cf_z15, DFLT_ACCESS),
|
||||
CPUMF_EVENT_PTR(cf_z15, DFLT_CYCLES),
|
||||
CPUMF_EVENT_PTR(cf_z15, DFLT_CC),
|
||||
CPUMF_EVENT_PTR(cf_z15, DFLT_CCERROR),
|
||||
CPUMF_EVENT_PTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE),
|
||||
CPUMF_EVENT_PTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE),
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* END: CPUM_CF COUNTER DEFINITIONS ===================================== */
|
||||
|
||||
static struct attribute_group cpumcf_pmu_events_group = {
|
||||
@@ -624,9 +743,11 @@ __init const struct attribute_group **cpumf_cf_event_group(void)
|
||||
break;
|
||||
case 0x3906:
|
||||
case 0x3907:
|
||||
model = cpumcf_z14_pmu_event_attr;
|
||||
break;
|
||||
case 0x8561:
|
||||
case 0x8562:
|
||||
model = cpumcf_z14_pmu_event_attr;
|
||||
model = cpumcf_z15_pmu_event_attr;
|
||||
break;
|
||||
default:
|
||||
model = none;
|
||||
|
||||
@@ -372,28 +372,33 @@ static void deallocate_buffers(struct cpu_hw_sf *cpuhw)
|
||||
|
||||
static int allocate_buffers(struct cpu_hw_sf *cpuhw, struct hw_perf_event *hwc)
|
||||
{
|
||||
unsigned long n_sdb, freq, factor;
|
||||
unsigned long n_sdb, freq;
|
||||
size_t sample_size;
|
||||
|
||||
/* Calculate sampling buffers using 4K pages
|
||||
*
|
||||
* 1. Determine the sample data size which depends on the used
|
||||
* sampling functions, for example, basic-sampling or
|
||||
* basic-sampling with diagnostic-sampling.
|
||||
* 1. The sampling size is 32 bytes for basic sampling. This size
|
||||
* is the same for all machine types. Diagnostic
|
||||
* sampling uses auxlilary data buffer setup which provides the
|
||||
* memory for SDBs using linux common code auxiliary trace
|
||||
* setup.
|
||||
*
|
||||
* 2. Use the sampling frequency as input. The sampling buffer is
|
||||
* designed for almost one second. This can be adjusted through
|
||||
* the "factor" variable.
|
||||
* In any case, alloc_sampling_buffer() sets the Alert Request
|
||||
* 2. Function alloc_sampling_buffer() sets the Alert Request
|
||||
* Control indicator to trigger a measurement-alert to harvest
|
||||
* sample-data-blocks (sdb).
|
||||
* sample-data-blocks (SDB). This is done per SDB. This
|
||||
* measurement alert interrupt fires quick enough to handle
|
||||
* one SDB, on very high frequency and work loads there might
|
||||
* be 2 to 3 SBDs available for sample processing.
|
||||
* Currently there is no need for setup alert request on every
|
||||
* n-th page. This is counterproductive as one IRQ triggers
|
||||
* a very high number of samples to be processed at one IRQ.
|
||||
*
|
||||
* 3. Compute the number of sample-data-blocks and ensure a minimum
|
||||
* of CPUM_SF_MIN_SDB. Also ensure the upper limit does not
|
||||
* exceed a "calculated" maximum. The symbolic maximum is
|
||||
* designed for basic-sampling only and needs to be increased if
|
||||
* diagnostic-sampling is active.
|
||||
* See also the remarks for these symbolic constants.
|
||||
* 3. Use the sampling frequency as input.
|
||||
* Compute the number of SDBs and ensure a minimum
|
||||
* of CPUM_SF_MIN_SDB. Depending on frequency add some more
|
||||
* SDBs to handle a higher sampling rate.
|
||||
* Use a minimum of CPUM_SF_MIN_SDB and allow for 100 samples
|
||||
* (one SDB) for every 10000 HZ frequency increment.
|
||||
*
|
||||
* 4. Compute the number of sample-data-block-tables (SDBT) and
|
||||
* ensure a minimum of CPUM_SF_MIN_SDBT (one table can manage up
|
||||
@@ -401,10 +406,7 @@ static int allocate_buffers(struct cpu_hw_sf *cpuhw, struct hw_perf_event *hwc)
|
||||
*/
|
||||
sample_size = sizeof(struct hws_basic_entry);
|
||||
freq = sample_rate_to_freq(&cpuhw->qsi, SAMPL_RATE(hwc));
|
||||
factor = 1;
|
||||
n_sdb = DIV_ROUND_UP(freq, factor * ((PAGE_SIZE-64) / sample_size));
|
||||
if (n_sdb < CPUM_SF_MIN_SDB)
|
||||
n_sdb = CPUM_SF_MIN_SDB;
|
||||
n_sdb = CPUM_SF_MIN_SDB + DIV_ROUND_UP(freq, 10000);
|
||||
|
||||
/* If there is already a sampling buffer allocated, it is very likely
|
||||
* that the sampling facility is enabled too. If the event to be
|
||||
@@ -1576,6 +1578,7 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
|
||||
unsigned long range = 0, size;
|
||||
unsigned long long overflow = 0;
|
||||
struct perf_output_handle *handle = &cpuhw->handle;
|
||||
unsigned long num_sdb;
|
||||
|
||||
aux = perf_get_aux(handle);
|
||||
if (WARN_ON_ONCE(!aux))
|
||||
@@ -1587,13 +1590,14 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
|
||||
size >> PAGE_SHIFT);
|
||||
perf_aux_output_end(handle, size);
|
||||
|
||||
num_sdb = aux->sfb.num_sdb;
|
||||
while (!done) {
|
||||
/* Get an output handle */
|
||||
aux = perf_aux_output_begin(handle, cpuhw->event);
|
||||
if (handle->size == 0) {
|
||||
pr_err("The AUX buffer with %lu pages for the "
|
||||
"diagnostic-sampling mode is full\n",
|
||||
aux->sfb.num_sdb);
|
||||
num_sdb);
|
||||
debug_sprintf_event(sfdbg, 1,
|
||||
"%s: AUX buffer used up\n",
|
||||
__func__);
|
||||
|
||||
@@ -106,6 +106,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp,
|
||||
p->thread.system_timer = 0;
|
||||
p->thread.hardirq_timer = 0;
|
||||
p->thread.softirq_timer = 0;
|
||||
p->thread.last_break = 1;
|
||||
|
||||
frame->sf.back_chain = 0;
|
||||
/* new return point is ret_from_fork */
|
||||
|
||||
@@ -151,10 +151,35 @@ static void show_cpu_summary(struct seq_file *m, void *v)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_cpu_topology(struct seq_file *m, unsigned long n)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_TOPOLOGY
|
||||
seq_printf(m, "physical id : %d\n", topology_physical_package_id(n));
|
||||
seq_printf(m, "core id : %d\n", topology_core_id(n));
|
||||
seq_printf(m, "book id : %d\n", topology_book_id(n));
|
||||
seq_printf(m, "drawer id : %d\n", topology_drawer_id(n));
|
||||
seq_printf(m, "dedicated : %d\n", topology_cpu_dedicated(n));
|
||||
seq_printf(m, "address : %d\n", smp_cpu_get_cpu_address(n));
|
||||
seq_printf(m, "siblings : %d\n", cpumask_weight(topology_core_cpumask(n)));
|
||||
seq_printf(m, "cpu cores : %d\n", topology_booted_cores(n));
|
||||
#endif /* CONFIG_SCHED_TOPOLOGY */
|
||||
}
|
||||
|
||||
static void show_cpu_ids(struct seq_file *m, unsigned long n)
|
||||
{
|
||||
struct cpuid *id = &per_cpu(cpu_info.cpu_id, n);
|
||||
|
||||
seq_printf(m, "version : %02X\n", id->version);
|
||||
seq_printf(m, "identification : %06X\n", id->ident);
|
||||
seq_printf(m, "machine : %04X\n", id->machine);
|
||||
}
|
||||
|
||||
static void show_cpu_mhz(struct seq_file *m, unsigned long n)
|
||||
{
|
||||
struct cpu_info *c = per_cpu_ptr(&cpu_info, n);
|
||||
|
||||
if (!machine_has_cpu_mhz)
|
||||
return;
|
||||
seq_printf(m, "cpu MHz dynamic : %d\n", c->cpu_mhz_dynamic);
|
||||
seq_printf(m, "cpu MHz static : %d\n", c->cpu_mhz_static);
|
||||
}
|
||||
@@ -165,12 +190,13 @@ static void show_cpu_mhz(struct seq_file *m, unsigned long n)
|
||||
static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
{
|
||||
unsigned long n = (unsigned long) v - 1;
|
||||
unsigned long first = cpumask_first(cpu_online_mask);
|
||||
|
||||
if (!n)
|
||||
if (n == first)
|
||||
show_cpu_summary(m, v);
|
||||
if (!machine_has_cpu_mhz)
|
||||
return 0;
|
||||
seq_printf(m, "\ncpu number : %ld\n", n);
|
||||
show_cpu_topology(m, n);
|
||||
show_cpu_ids(m, n);
|
||||
show_cpu_mhz(m, n);
|
||||
return 0;
|
||||
}
|
||||
@@ -179,6 +205,8 @@ static inline void *c_update(loff_t *pos)
|
||||
{
|
||||
if (*pos)
|
||||
*pos = cpumask_next(*pos - 1, cpu_online_mask);
|
||||
else
|
||||
*pos = cpumask_first(cpu_online_mask);
|
||||
return *pos < nr_cpu_ids ? (void *)*pos + 1 : NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/mem_detect.h>
|
||||
#include <asm/uv.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
@@ -446,6 +447,8 @@ static void __init setup_lowcore_dat_off(void)
|
||||
lc->spinlock_index = 0;
|
||||
arch_spin_lock_setup(0);
|
||||
lc->br_r1_trampoline = 0x07f1; /* br %r1 */
|
||||
lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW);
|
||||
lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW);
|
||||
|
||||
set_prefix((u32)(unsigned long) lc);
|
||||
lowcore_ptr[0] = lc;
|
||||
@@ -789,6 +792,7 @@ static void __init memblock_add_mem_detect_info(void)
|
||||
memblock_physmem_add(start, end - start);
|
||||
}
|
||||
memblock_set_bottom_up(false);
|
||||
memblock_set_node(0, ULONG_MAX, &memblock.memory, 0);
|
||||
memblock_dump_all();
|
||||
}
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ void do_signal(struct pt_regs *regs)
|
||||
regs->gprs[2] = -EINTR;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
fallthrough;
|
||||
case -ERESTARTNOINTR:
|
||||
regs->gprs[2] = regs->orig_gpr2;
|
||||
regs->psw.addr =
|
||||
@@ -514,7 +514,7 @@ void do_signal(struct pt_regs *regs)
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
/* Restart with sys_restart_syscall */
|
||||
regs->int_code = __NR_restart_syscall;
|
||||
/* fallthrough */
|
||||
fallthrough;
|
||||
case -ERESTARTNOHAND:
|
||||
case -ERESTARTSYS:
|
||||
case -ERESTARTNOINTR:
|
||||
|
||||
@@ -212,6 +212,8 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
||||
lc->spinlock_lockval = arch_spin_lockval(cpu);
|
||||
lc->spinlock_index = 0;
|
||||
lc->br_r1_trampoline = 0x07f1; /* br %r1 */
|
||||
lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW);
|
||||
lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW);
|
||||
if (nmi_alloc_per_cpu(lc))
|
||||
goto out_async;
|
||||
if (vdso_alloc_per_cpu(lc))
|
||||
@@ -701,6 +703,11 @@ int smp_cpu_get_polarization(int cpu)
|
||||
return pcpu_devices[cpu].polarization;
|
||||
}
|
||||
|
||||
int smp_cpu_get_cpu_address(int cpu)
|
||||
{
|
||||
return pcpu_devices[cpu].address;
|
||||
}
|
||||
|
||||
static void __ref smp_get_core_info(struct sclp_core_info *info, int early)
|
||||
{
|
||||
static int use_sigp_detection;
|
||||
@@ -851,12 +858,13 @@ static void smp_init_secondary(void)
|
||||
init_cpu_timer();
|
||||
vtime_init();
|
||||
pfault_init();
|
||||
notify_cpu_starting(smp_processor_id());
|
||||
notify_cpu_starting(cpu);
|
||||
if (topology_cpu_dedicated(cpu))
|
||||
set_cpu_flag(CIF_DEDICATED_CPU);
|
||||
else
|
||||
clear_cpu_flag(CIF_DEDICATED_CPU);
|
||||
set_cpu_online(smp_processor_id(), true);
|
||||
set_cpu_online(cpu, true);
|
||||
update_cpu_masks();
|
||||
inc_irq_stat(CPU_RST);
|
||||
local_irq_enable();
|
||||
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
|
||||
@@ -928,6 +936,7 @@ int __cpu_disable(void)
|
||||
/* Handle possible pending IPIs */
|
||||
smp_handle_ext_call();
|
||||
set_cpu_online(smp_processor_id(), false);
|
||||
update_cpu_masks();
|
||||
/* Disable pseudo page faults on this cpu. */
|
||||
pfault_fini();
|
||||
/* Disable interrupt sources via control register. */
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Suspend support specific for s390.
|
||||
*
|
||||
* Copyright IBM Corp. 2009
|
||||
*
|
||||
* Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/ctl_reg.h>
|
||||
#include <asm/ipl.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/sections.h>
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* The restore of the saved pages in an hibernation image will set
|
||||
* the change and referenced bits in the storage key for each page.
|
||||
* Overindication of the referenced bits after an hibernation cycle
|
||||
* does not cause any harm but the overindication of the change bits
|
||||
* would cause trouble.
|
||||
* Use the ARCH_SAVE_PAGE_KEYS hooks to save the storage key of each
|
||||
* page to the most significant byte of the associated page frame
|
||||
* number in the hibernation image.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Key storage is allocated as a linked list of pages.
|
||||
* The size of the keys array is (PAGE_SIZE - sizeof(long))
|
||||
*/
|
||||
struct page_key_data {
|
||||
struct page_key_data *next;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
#define PAGE_KEY_DATA_SIZE (PAGE_SIZE - sizeof(struct page_key_data *))
|
||||
|
||||
static struct page_key_data *page_key_data;
|
||||
static struct page_key_data *page_key_rp, *page_key_wp;
|
||||
static unsigned long page_key_rx, page_key_wx;
|
||||
unsigned long suspend_zero_pages;
|
||||
|
||||
/*
|
||||
* For each page in the hibernation image one additional byte is
|
||||
* stored in the most significant byte of the page frame number.
|
||||
* On suspend no additional memory is required but on resume the
|
||||
* keys need to be memorized until the page data has been restored.
|
||||
* Only then can the storage keys be set to their old state.
|
||||
*/
|
||||
unsigned long page_key_additional_pages(unsigned long pages)
|
||||
{
|
||||
return DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free page_key_data list of arrays.
|
||||
*/
|
||||
void page_key_free(void)
|
||||
{
|
||||
struct page_key_data *pkd;
|
||||
|
||||
while (page_key_data) {
|
||||
pkd = page_key_data;
|
||||
page_key_data = pkd->next;
|
||||
free_page((unsigned long) pkd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate page_key_data list of arrays with enough room to store
|
||||
* one byte for each page in the hibernation image.
|
||||
*/
|
||||
int page_key_alloc(unsigned long pages)
|
||||
{
|
||||
struct page_key_data *pk;
|
||||
unsigned long size;
|
||||
|
||||
size = DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
|
||||
while (size--) {
|
||||
pk = (struct page_key_data *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!pk) {
|
||||
page_key_free();
|
||||
return -ENOMEM;
|
||||
}
|
||||
pk->next = page_key_data;
|
||||
page_key_data = pk;
|
||||
}
|
||||
page_key_rp = page_key_wp = page_key_data;
|
||||
page_key_rx = page_key_wx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the storage key into the upper 8 bits of the page frame number.
|
||||
*/
|
||||
void page_key_read(unsigned long *pfn)
|
||||
{
|
||||
struct page *page;
|
||||
unsigned long addr;
|
||||
unsigned char key;
|
||||
|
||||
page = pfn_to_page(*pfn);
|
||||
addr = (unsigned long) page_address(page);
|
||||
key = (unsigned char) page_get_storage_key(addr) & 0x7f;
|
||||
if (arch_test_page_nodat(page))
|
||||
key |= 0x80;
|
||||
*(unsigned char *) pfn = key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the storage key from the upper 8 bits of the page frame number
|
||||
* and store it in the page_key_data list of arrays.
|
||||
*/
|
||||
void page_key_memorize(unsigned long *pfn)
|
||||
{
|
||||
page_key_wp->data[page_key_wx] = *(unsigned char *) pfn;
|
||||
*(unsigned char *) pfn = 0;
|
||||
if (++page_key_wx < PAGE_KEY_DATA_SIZE)
|
||||
return;
|
||||
page_key_wp = page_key_wp->next;
|
||||
page_key_wx = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next key from the page_key_data list of arrays and set the
|
||||
* storage key of the page referred by @address. If @address refers to
|
||||
* a "safe" page the swsusp_arch_resume code will transfer the storage
|
||||
* key from the buffer page to the original page.
|
||||
*/
|
||||
void page_key_write(void *address)
|
||||
{
|
||||
struct page *page;
|
||||
unsigned char key;
|
||||
|
||||
key = page_key_rp->data[page_key_rx];
|
||||
page_set_storage_key((unsigned long) address, key & 0x7f, 0);
|
||||
page = virt_to_page(address);
|
||||
if (key & 0x80)
|
||||
arch_set_page_nodat(page, 0);
|
||||
else
|
||||
arch_set_page_dat(page, 0);
|
||||
if (++page_key_rx >= PAGE_KEY_DATA_SIZE)
|
||||
return;
|
||||
page_key_rp = page_key_rp->next;
|
||||
page_key_rx = 0;
|
||||
}
|
||||
|
||||
int pfn_is_nosave(unsigned long pfn)
|
||||
{
|
||||
unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
|
||||
unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end));
|
||||
unsigned long end_rodata_pfn = PFN_DOWN(__pa(__end_rodata)) - 1;
|
||||
unsigned long stext_pfn = PFN_DOWN(__pa(_stext));
|
||||
|
||||
/* Always save lowcore pages (LC protection might be enabled). */
|
||||
if (pfn <= LC_PAGES)
|
||||
return 0;
|
||||
if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
|
||||
return 1;
|
||||
/* Skip memory holes and read-only pages (DCSS, ...). */
|
||||
if (pfn >= stext_pfn && pfn <= end_rodata_pfn)
|
||||
return 0;
|
||||
if (tprot(PFN_PHYS(pfn)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PM notifier callback for suspend
|
||||
*/
|
||||
static int suspend_pm_cb(struct notifier_block *nb, unsigned long action,
|
||||
void *ptr)
|
||||
{
|
||||
switch (action) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER);
|
||||
if (!suspend_zero_pages)
|
||||
return NOTIFY_BAD;
|
||||
break;
|
||||
case PM_POST_SUSPEND:
|
||||
case PM_POST_HIBERNATION:
|
||||
free_pages(suspend_zero_pages, LC_ORDER);
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int __init suspend_pm_init(void)
|
||||
{
|
||||
pm_notifier(suspend_pm_cb, 0);
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(suspend_pm_init);
|
||||
|
||||
void save_processor_state(void)
|
||||
{
|
||||
/* swsusp_arch_suspend() actually saves all cpu register contents.
|
||||
* Machine checks must be disabled since swsusp_arch_suspend() stores
|
||||
* register contents to their lowcore save areas. That's the same
|
||||
* place where register contents on machine checks would be saved.
|
||||
* To avoid register corruption disable machine checks.
|
||||
* We must also disable machine checks in the new psw mask for
|
||||
* program checks, since swsusp_arch_suspend() may generate program
|
||||
* checks. Disabling machine checks for all other new psw masks is
|
||||
* just paranoia.
|
||||
*/
|
||||
local_mcck_disable();
|
||||
/* Disable lowcore protection */
|
||||
__ctl_clear_bit(0,28);
|
||||
S390_lowcore.external_new_psw.mask &= ~PSW_MASK_MCHECK;
|
||||
S390_lowcore.svc_new_psw.mask &= ~PSW_MASK_MCHECK;
|
||||
S390_lowcore.io_new_psw.mask &= ~PSW_MASK_MCHECK;
|
||||
S390_lowcore.program_new_psw.mask &= ~PSW_MASK_MCHECK;
|
||||
}
|
||||
|
||||
void restore_processor_state(void)
|
||||
{
|
||||
S390_lowcore.external_new_psw.mask |= PSW_MASK_MCHECK;
|
||||
S390_lowcore.svc_new_psw.mask |= PSW_MASK_MCHECK;
|
||||
S390_lowcore.io_new_psw.mask |= PSW_MASK_MCHECK;
|
||||
S390_lowcore.program_new_psw.mask |= PSW_MASK_MCHECK;
|
||||
/* Enable lowcore protection */
|
||||
__ctl_set_bit(0,28);
|
||||
local_mcck_enable();
|
||||
}
|
||||
|
||||
/* Called at the end of swsusp_arch_resume */
|
||||
void s390_early_resume(void)
|
||||
{
|
||||
lgr_info_log();
|
||||
channel_subsystem_reinit();
|
||||
zpci_rescan();
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* S390 64-bit swsusp implementation
|
||||
*
|
||||
* Copyright IBM Corp. 2009
|
||||
*
|
||||
* Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
|
||||
* Michael Holzheu <holzheu@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/nospec-insn.h>
|
||||
#include <asm/sigp.h>
|
||||
|
||||
/*
|
||||
* Save register context in absolute 0 lowcore and call swsusp_save() to
|
||||
* create in-memory kernel image. The context is saved in the designated
|
||||
* "store status" memory locations (see POP).
|
||||
* We return from this function twice. The first time during the suspend to
|
||||
* disk process. The second time via the swsusp_arch_resume() function
|
||||
* (see below) in the resume process.
|
||||
* This function runs with disabled interrupts.
|
||||
*/
|
||||
GEN_BR_THUNK %r14
|
||||
|
||||
.section .text
|
||||
ENTRY(swsusp_arch_suspend)
|
||||
lg %r1,__LC_NODAT_STACK
|
||||
stmg %r6,%r15,__SF_GPRS(%r1)
|
||||
aghi %r1,-STACK_FRAME_OVERHEAD
|
||||
stg %r15,__SF_BACKCHAIN(%r1)
|
||||
lgr %r15,%r1
|
||||
|
||||
/* Store FPU registers */
|
||||
brasl %r14,save_fpu_regs
|
||||
|
||||
/* Deactivate DAT */
|
||||
stnsm __SF_EMPTY(%r15),0xfb
|
||||
|
||||
/* Store prefix register on stack */
|
||||
stpx __SF_EMPTY(%r15)
|
||||
|
||||
/* Save prefix register contents for lowcore copy */
|
||||
llgf %r10,__SF_EMPTY(%r15)
|
||||
|
||||
/* Get pointer to save area */
|
||||
lghi %r1,0x1000
|
||||
|
||||
/* Save CPU address */
|
||||
stap __LC_EXT_CPU_ADDR(%r0)
|
||||
|
||||
/* Store registers */
|
||||
mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */
|
||||
stam %a0,%a15,0x340(%r1) /* store access registers */
|
||||
stctg %c0,%c15,0x380(%r1) /* store control registers */
|
||||
stmg %r0,%r15,0x280(%r1) /* store general registers */
|
||||
|
||||
stpt 0x328(%r1) /* store timer */
|
||||
stck __SF_EMPTY(%r15) /* store clock */
|
||||
stckc 0x330(%r1) /* store clock comparator */
|
||||
|
||||
/* Update cputime accounting before going to sleep */
|
||||
lg %r0,__LC_LAST_UPDATE_TIMER
|
||||
slg %r0,0x328(%r1)
|
||||
alg %r0,__LC_SYSTEM_TIMER
|
||||
stg %r0,__LC_SYSTEM_TIMER
|
||||
mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1)
|
||||
lg %r0,__LC_LAST_UPDATE_CLOCK
|
||||
slg %r0,__SF_EMPTY(%r15)
|
||||
alg %r0,__LC_STEAL_TIMER
|
||||
stg %r0,__LC_STEAL_TIMER
|
||||
mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15)
|
||||
|
||||
/* Activate DAT */
|
||||
stosm __SF_EMPTY(%r15),0x04
|
||||
|
||||
/* Set prefix page to zero */
|
||||
xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
|
||||
spx __SF_EMPTY(%r15)
|
||||
|
||||
/* Save absolute zero pages */
|
||||
larl %r2,suspend_zero_pages
|
||||
lg %r2,0(%r2)
|
||||
lghi %r4,0
|
||||
lghi %r3,2*PAGE_SIZE
|
||||
lghi %r5,2*PAGE_SIZE
|
||||
1: mvcle %r2,%r4,0
|
||||
jo 1b
|
||||
|
||||
/* Copy lowcore to absolute zero lowcore */
|
||||
lghi %r2,0
|
||||
lgr %r4,%r10
|
||||
lghi %r3,2*PAGE_SIZE
|
||||
lghi %r5,2*PAGE_SIZE
|
||||
1: mvcle %r2,%r4,0
|
||||
jo 1b
|
||||
|
||||
/* Save image */
|
||||
brasl %r14,swsusp_save
|
||||
|
||||
/* Restore prefix register and return */
|
||||
lghi %r1,0x1000
|
||||
spx 0x318(%r1)
|
||||
lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
|
||||
lghi %r2,0
|
||||
BR_EX %r14
|
||||
ENDPROC(swsusp_arch_suspend)
|
||||
|
||||
/*
|
||||
* Restore saved memory image to correct place and restore register context.
|
||||
* Then we return to the function that called swsusp_arch_suspend().
|
||||
* swsusp_arch_resume() runs with disabled interrupts.
|
||||
*/
|
||||
ENTRY(swsusp_arch_resume)
|
||||
stmg %r6,%r15,__SF_GPRS(%r15)
|
||||
lgr %r1,%r15
|
||||
aghi %r15,-STACK_FRAME_OVERHEAD
|
||||
stg %r1,__SF_BACKCHAIN(%r15)
|
||||
|
||||
/* Make all free pages stable */
|
||||
lghi %r2,1
|
||||
brasl %r14,arch_set_page_states
|
||||
|
||||
/* Set prefix page to zero */
|
||||
xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
|
||||
spx __SF_EMPTY(%r15)
|
||||
|
||||
/* Deactivate DAT */
|
||||
stnsm __SF_EMPTY(%r15),0xfb
|
||||
|
||||
/* Restore saved image */
|
||||
larl %r1,restore_pblist
|
||||
lg %r1,0(%r1)
|
||||
ltgr %r1,%r1
|
||||
jz 2f
|
||||
0:
|
||||
lg %r2,8(%r1)
|
||||
lg %r4,0(%r1)
|
||||
iske %r0,%r4
|
||||
lghi %r3,PAGE_SIZE
|
||||
lghi %r5,PAGE_SIZE
|
||||
1:
|
||||
mvcle %r2,%r4,0
|
||||
jo 1b
|
||||
lg %r2,8(%r1)
|
||||
sske %r0,%r2
|
||||
lg %r1,16(%r1)
|
||||
ltgr %r1,%r1
|
||||
jnz 0b
|
||||
2:
|
||||
ptlb /* flush tlb */
|
||||
|
||||
/* Reset System */
|
||||
larl %r1,.Lnew_pgm_check_psw
|
||||
epsw %r2,%r3
|
||||
stm %r2,%r3,0(%r1)
|
||||
mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1)
|
||||
larl %r1,__swsusp_reset_dma
|
||||
lg %r1,0(%r1)
|
||||
BASR_EX %r14,%r1
|
||||
larl %r1,smp_cpu_mt_shift
|
||||
icm %r1,15,0(%r1)
|
||||
jz smt_done
|
||||
llgfr %r1,%r1
|
||||
smt_loop:
|
||||
sigp %r1,%r0,SIGP_SET_MULTI_THREADING
|
||||
brc 8,smt_done /* accepted */
|
||||
brc 2,smt_loop /* busy, try again */
|
||||
smt_done:
|
||||
larl %r1,.Lnew_pgm_check_psw
|
||||
lpswe 0(%r1)
|
||||
pgm_check_entry:
|
||||
|
||||
/* Switch to original suspend CPU */
|
||||
larl %r1,.Lresume_cpu /* Resume CPU address: r2 */
|
||||
stap 0(%r1)
|
||||
llgh %r2,0(%r1)
|
||||
llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */
|
||||
cgr %r1,%r2
|
||||
je restore_registers /* r1 = r2 -> nothing to do */
|
||||
larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */
|
||||
mvc __LC_RST_NEW_PSW(16,%r0),0(%r4)
|
||||
3:
|
||||
sigp %r9,%r1,SIGP_INITIAL_CPU_RESET /* sigp initial cpu reset */
|
||||
brc 8,4f /* accepted */
|
||||
brc 2,3b /* busy, try again */
|
||||
|
||||
/* Suspend CPU not available -> panic */
|
||||
larl %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD
|
||||
larl %r2,.Lpanic_string
|
||||
brasl %r14,sclp_early_printk_force
|
||||
larl %r3,.Ldisabled_wait_31
|
||||
lpsw 0(%r3)
|
||||
4:
|
||||
/* Switch to suspend CPU */
|
||||
sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */
|
||||
brc 2,4b /* busy, try again */
|
||||
5:
|
||||
sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */
|
||||
brc 2,5b /* busy, try again */
|
||||
6: j 6b
|
||||
|
||||
restart_suspend:
|
||||
larl %r1,.Lresume_cpu
|
||||
llgh %r2,0(%r1)
|
||||
7:
|
||||
sigp %r9,%r2,SIGP_SENSE /* sigp sense, wait for resume CPU */
|
||||
brc 8,7b /* accepted, status 0, still running */
|
||||
brc 2,7b /* busy, try again */
|
||||
tmll %r9,0x40 /* Test if resume CPU is stopped */
|
||||
jz 7b
|
||||
|
||||
restore_registers:
|
||||
/* Restore registers */
|
||||
lghi %r13,0x1000 /* %r1 = pointer to save area */
|
||||
|
||||
/* Ignore time spent in suspended state. */
|
||||
llgf %r1,0x318(%r13)
|
||||
stck __LC_LAST_UPDATE_CLOCK(%r1)
|
||||
spt 0x328(%r13) /* reprogram timer */
|
||||
//sckc 0x330(%r13) /* set clock comparator */
|
||||
|
||||
lctlg %c0,%c15,0x380(%r13) /* load control registers */
|
||||
lam %a0,%a15,0x340(%r13) /* load access registers */
|
||||
|
||||
/* Load old stack */
|
||||
lg %r15,0x2f8(%r13)
|
||||
|
||||
/* Save prefix register */
|
||||
mvc __SF_EMPTY(4,%r15),0x318(%r13)
|
||||
|
||||
/* Restore absolute zero pages */
|
||||
lghi %r2,0
|
||||
larl %r4,suspend_zero_pages
|
||||
lg %r4,0(%r4)
|
||||
lghi %r3,2*PAGE_SIZE
|
||||
lghi %r5,2*PAGE_SIZE
|
||||
1: mvcle %r2,%r4,0
|
||||
jo 1b
|
||||
|
||||
/* Restore prefix register */
|
||||
spx __SF_EMPTY(%r15)
|
||||
|
||||
/* Activate DAT */
|
||||
stosm __SF_EMPTY(%r15),0x04
|
||||
|
||||
/* Make all free pages unstable */
|
||||
lghi %r2,0
|
||||
brasl %r14,arch_set_page_states
|
||||
|
||||
/* Call arch specific early resume code */
|
||||
brasl %r14,s390_early_resume
|
||||
|
||||
/* Return 0 */
|
||||
lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
|
||||
lghi %r2,0
|
||||
BR_EX %r14
|
||||
ENDPROC(swsusp_arch_resume)
|
||||
|
||||
.section .data..nosave,"aw",@progbits
|
||||
.align 8
|
||||
.Ldisabled_wait_31:
|
||||
.long 0x000a0000,0x00000000
|
||||
.Lpanic_string:
|
||||
.asciz "Resume not possible because suspend CPU is no longer available\n"
|
||||
.align 8
|
||||
.Lrestart_suspend_psw:
|
||||
.quad 0x0000000180000000,restart_suspend
|
||||
.Lnew_pgm_check_psw:
|
||||
.quad 0,pgm_check_entry
|
||||
.Lresume_cpu:
|
||||
.byte 0,0
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/node.h>
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#define PTF_HORIZONTAL (0UL)
|
||||
#define PTF_VERTICAL (1UL)
|
||||
@@ -63,8 +62,6 @@ static struct mask_info drawer_info;
|
||||
struct cpu_topology_s390 cpu_topology[NR_CPUS];
|
||||
EXPORT_SYMBOL_GPL(cpu_topology);
|
||||
|
||||
cpumask_t cpus_with_topology;
|
||||
|
||||
static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
|
||||
{
|
||||
cpumask_t mask;
|
||||
@@ -86,11 +83,12 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
|
||||
cpumask_copy(&mask, cpu_present_mask);
|
||||
break;
|
||||
default:
|
||||
/* fallthrough */
|
||||
fallthrough;
|
||||
case TOPOLOGY_MODE_SINGLE:
|
||||
cpumask_copy(&mask, cpumask_of(cpu));
|
||||
break;
|
||||
}
|
||||
cpumask_and(&mask, &mask, cpu_online_mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -106,6 +104,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu)
|
||||
for (i = 0; i <= smp_cpu_mtid; i++)
|
||||
if (cpu_present(cpu + i))
|
||||
cpumask_set_cpu(cpu + i, &mask);
|
||||
cpumask_and(&mask, &mask, cpu_online_mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -138,7 +137,6 @@ static void add_cpus_to_mask(struct topology_core *tl_core,
|
||||
cpumask_set_cpu(lcpu + i, &drawer->mask);
|
||||
cpumask_set_cpu(lcpu + i, &book->mask);
|
||||
cpumask_set_cpu(lcpu + i, &socket->mask);
|
||||
cpumask_set_cpu(lcpu + i, &cpus_with_topology);
|
||||
smp_cpu_set_polarization(lcpu + i, tl_core->pp);
|
||||
}
|
||||
}
|
||||
@@ -245,10 +243,10 @@ int topology_set_cpu_management(int fc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void update_cpu_masks(void)
|
||||
void update_cpu_masks(void)
|
||||
{
|
||||
struct cpu_topology_s390 *topo;
|
||||
int cpu, id;
|
||||
struct cpu_topology_s390 *topo, *topo_package, *topo_sibling;
|
||||
int cpu, sibling, pkg_first, smt_first, id;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
topo = &cpu_topology[cpu];
|
||||
@@ -256,6 +254,7 @@ static void update_cpu_masks(void)
|
||||
topo->core_mask = cpu_group_map(&socket_info, cpu);
|
||||
topo->book_mask = cpu_group_map(&book_info, cpu);
|
||||
topo->drawer_mask = cpu_group_map(&drawer_info, cpu);
|
||||
topo->booted_cores = 0;
|
||||
if (topology_mode != TOPOLOGY_MODE_HW) {
|
||||
id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu;
|
||||
topo->thread_id = cpu;
|
||||
@@ -263,11 +262,23 @@ static void update_cpu_masks(void)
|
||||
topo->socket_id = id;
|
||||
topo->book_id = id;
|
||||
topo->drawer_id = id;
|
||||
if (cpu_present(cpu))
|
||||
cpumask_set_cpu(cpu, &cpus_with_topology);
|
||||
}
|
||||
}
|
||||
numa_update_cpu_topology();
|
||||
for_each_online_cpu(cpu) {
|
||||
topo = &cpu_topology[cpu];
|
||||
pkg_first = cpumask_first(&topo->core_mask);
|
||||
topo_package = &cpu_topology[pkg_first];
|
||||
if (cpu == pkg_first) {
|
||||
for_each_cpu(sibling, &topo->core_mask) {
|
||||
topo_sibling = &cpu_topology[sibling];
|
||||
smt_first = cpumask_first(&topo_sibling->thread_mask);
|
||||
if (sibling == smt_first)
|
||||
topo_package->booted_cores++;
|
||||
}
|
||||
} else {
|
||||
topo->booted_cores = topo_package->booted_cores;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void store_topology(struct sysinfo_15_1_x *info)
|
||||
@@ -289,7 +300,6 @@ static int __arch_update_cpu_topology(void)
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&smp_cpu_state_mutex);
|
||||
cpumask_clear(&cpus_with_topology);
|
||||
if (MACHINE_HAS_TOPOLOGY) {
|
||||
rc = 1;
|
||||
store_topology(info);
|
||||
|
||||
@@ -271,7 +271,7 @@ void kernel_stack_overflow(struct pt_regs *regs)
|
||||
}
|
||||
NOKPROBE_SYMBOL(kernel_stack_overflow);
|
||||
|
||||
static void test_monitor_call(void)
|
||||
static void __init test_monitor_call(void)
|
||||
{
|
||||
int val = 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user