powerpc: Fix regression of per-CPU DSCR setting
Since commit "efcac65 powerpc: Per process DSCR + some fixes (try#4)" it is no longer possible to set the DSCR on a per-CPU basis. The old behaviour was to minipulate the DSCR SPR directly but this is no longer sufficient: the value is quickly overwritten by context switching. This patch stores the per-CPU DSCR value in a kernel variable rather than directly in the SPR and it is used whenever a process has not set the DSCR itself. The sysfs interface (/sys/devices/system/cpu/cpuN/dscr) is unchanged. Writes to the old global default (/sys/devices/system/cpu/dscr_default) now set all of the per-CPU values and reads return the last written value. The new per-CPU default is added to the paca_struct and is used everywhere outside of sysfs.c instead of the old global default. Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
Родитель
39a360ef72
Коммит
1739ea9e13
|
@ -92,7 +92,10 @@ struct paca_struct {
|
|||
struct slb_shadow *slb_shadow_ptr;
|
||||
struct dtl_entry *dispatch_log;
|
||||
struct dtl_entry *dispatch_log_end;
|
||||
#endif /* CONFIG_PPC_STD_MMU_64 */
|
||||
u64 dscr_default; /* per-CPU default DSCR */
|
||||
|
||||
#ifdef CONFIG_PPC_STD_MMU_64
|
||||
/*
|
||||
* Now, starting in cacheline 2, the exception save areas
|
||||
*/
|
||||
|
|
|
@ -247,6 +247,7 @@ int main(void)
|
|||
#endif
|
||||
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
|
||||
DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
|
||||
DEFINE(PACA_DSCR, offsetof(struct paca_struct, dscr_default));
|
||||
DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
|
||||
DEFINE(PACA_STARTTIME_USER, offsetof(struct paca_struct, starttime_user));
|
||||
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
|
||||
|
|
|
@ -387,12 +387,6 @@ _GLOBAL(ret_from_kernel_thread)
|
|||
li r3,0
|
||||
b syscall_exit
|
||||
|
||||
.section ".toc","aw"
|
||||
DSCR_DEFAULT:
|
||||
.tc dscr_default[TC],dscr_default
|
||||
|
||||
.section ".text"
|
||||
|
||||
/*
|
||||
* This routine switches between two different tasks. The process
|
||||
* state of one is saved on its kernel stack. Then the state
|
||||
|
@ -577,11 +571,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
|||
#ifdef CONFIG_PPC64
|
||||
BEGIN_FTR_SECTION
|
||||
lwz r6,THREAD_DSCR_INHERIT(r4)
|
||||
ld r7,DSCR_DEFAULT@toc(2)
|
||||
ld r0,THREAD_DSCR(r4)
|
||||
cmpwi r6,0
|
||||
bne 1f
|
||||
ld r0,0(r7)
|
||||
ld r0,PACA_DSCR(r13)
|
||||
1:
|
||||
BEGIN_FTR_SECTION_NESTED(70)
|
||||
mfspr r8, SPRN_FSCR
|
||||
|
|
|
@ -484,7 +484,6 @@ SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
|
|||
SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
|
||||
SYSFS_SPRSETUP(purr, SPRN_PURR);
|
||||
SYSFS_SPRSETUP(spurr, SPRN_SPURR);
|
||||
SYSFS_SPRSETUP(dscr, SPRN_DSCR);
|
||||
SYSFS_SPRSETUP(pir, SPRN_PIR);
|
||||
|
||||
/*
|
||||
|
@ -494,12 +493,27 @@ SYSFS_SPRSETUP(pir, SPRN_PIR);
|
|||
*/
|
||||
static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
|
||||
static DEVICE_ATTR(spurr, 0400, show_spurr, NULL);
|
||||
static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
|
||||
static DEVICE_ATTR(purr, 0400, show_purr, store_purr);
|
||||
static DEVICE_ATTR(pir, 0400, show_pir, NULL);
|
||||
|
||||
unsigned long dscr_default = 0;
|
||||
EXPORT_SYMBOL(dscr_default);
|
||||
static unsigned long dscr_default;
|
||||
|
||||
static void read_dscr(void *val)
|
||||
{
|
||||
*(unsigned long *)val = get_paca()->dscr_default;
|
||||
}
|
||||
|
||||
static void write_dscr(void *val)
|
||||
{
|
||||
get_paca()->dscr_default = *(unsigned long *)val;
|
||||
if (!current->thread.dscr_inherit) {
|
||||
current->thread.dscr = *(unsigned long *)val;
|
||||
mtspr(SPRN_DSCR, *(unsigned long *)val);
|
||||
}
|
||||
}
|
||||
|
||||
SYSFS_SPRSETUP_SHOW_STORE(dscr);
|
||||
static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
|
||||
|
||||
static void add_write_permission_dev_attr(struct device_attribute *attr)
|
||||
{
|
||||
|
@ -512,14 +526,6 @@ static ssize_t show_dscr_default(struct device *dev,
|
|||
return sprintf(buf, "%lx\n", dscr_default);
|
||||
}
|
||||
|
||||
static void update_dscr(void *dummy)
|
||||
{
|
||||
if (!current->thread.dscr_inherit) {
|
||||
current->thread.dscr = dscr_default;
|
||||
mtspr(SPRN_DSCR, dscr_default);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t __used store_dscr_default(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
|
@ -532,7 +538,7 @@ static ssize_t __used store_dscr_default(struct device *dev,
|
|||
return -EINVAL;
|
||||
dscr_default = val;
|
||||
|
||||
on_each_cpu(update_dscr, NULL, 1);
|
||||
on_each_cpu(write_dscr, &val, 1);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -78,12 +78,6 @@ _GLOBAL(tm_abort)
|
|||
TABORT(R3)
|
||||
blr
|
||||
|
||||
.section ".toc","aw"
|
||||
DSCR_DEFAULT:
|
||||
.tc dscr_default[TC],dscr_default
|
||||
|
||||
.section ".text"
|
||||
|
||||
/* void tm_reclaim(struct thread_struct *thread,
|
||||
* unsigned long orig_msr,
|
||||
* uint8_t cause)
|
||||
|
@ -298,9 +292,8 @@ dont_backup_fp:
|
|||
mtlr r0
|
||||
ld r2, STK_GOT(r1)
|
||||
|
||||
/* Load system default DSCR */
|
||||
ld r4, DSCR_DEFAULT@toc(r2)
|
||||
ld r0, 0(r4)
|
||||
/* Load CPU's default DSCR */
|
||||
ld r0, PACA_DSCR(r13)
|
||||
mtspr SPRN_DSCR, r0
|
||||
|
||||
blr
|
||||
|
@ -479,9 +472,8 @@ restore_gprs:
|
|||
mtlr r0
|
||||
ld r2, STK_GOT(r1)
|
||||
|
||||
/* Load system default DSCR */
|
||||
ld r4, DSCR_DEFAULT@toc(r2)
|
||||
ld r0, 0(r4)
|
||||
/* Load CPU's default DSCR */
|
||||
ld r0, PACA_DSCR(r13)
|
||||
mtspr SPRN_DSCR, r0
|
||||
|
||||
blr
|
||||
|
|
|
@ -286,8 +286,7 @@ kvm_start_guest:
|
|||
beq kvm_no_guest
|
||||
|
||||
/* Set HSTATE_DSCR(r13) to something sensible */
|
||||
LOAD_REG_ADDR(r6, dscr_default)
|
||||
ld r6, 0(r6)
|
||||
ld r6, PACA_DSCR(r13)
|
||||
std r6, HSTATE_DSCR(r13)
|
||||
|
||||
bl kvmppc_hv_entry
|
||||
|
|
Загрузка…
Ссылка в новой задаче