2011-09-20 00:44:57 +07:00
|
|
|
/*
|
|
|
|
* PowerNV OPAL API wrappers
|
|
|
|
*
|
|
|
|
* Copyright 2011 IBM Corp.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
2015-04-09 10:51:32 +07:00
|
|
|
#include <linux/jump_label.h>
|
2011-09-20 00:44:57 +07:00
|
|
|
#include <asm/ppc_asm.h>
|
|
|
|
#include <asm/hvcall.h>
|
|
|
|
#include <asm/asm-offsets.h>
|
|
|
|
#include <asm/opal.h>
|
2018-07-05 23:24:57 +07:00
|
|
|
#include <asm/asm-compat.h>
|
2018-07-05 23:25:01 +07:00
|
|
|
#include <asm/feature-fixups.h>
|
2014-07-03 14:20:50 +07:00
|
|
|
|
powerpc/powernv: move OPAL call wrapper tracing and interrupt handling to C
The OPAL call wrapper gets interrupt disabling wrong. It disables
interrupts just by clearing MSR[EE], which has two problems:
- It doesn't call into the IRQ tracing subsystem, which means tracing
across OPAL calls does not always notice IRQs have been disabled.
- It doesn't go through the IRQ soft-mask code, which causes a minor
bug. MSR[EE] can not be restored by saving the MSR then clearing
MSR[EE], because a racing interrupt while soft-masked could clear
MSR[EE] between the two steps. This can cause MSR[EE] to be
incorrectly enabled when the OPAL call returns. Fortunately that
should only result in another masked interrupt being taken to
disable MSR[EE] again, but it's a bit sloppy.
The existing code also saves MSR to PACA, which is not re-entrant if
there is a nested OPAL call from different MSR contexts, which can
happen these days with SRESET interrupts on bare metal.
To fix these issues, move the tracing and IRQ handling code to C, and
call into asm just for the low level call when everything is ready to
go. Save the MSR on stack rather than PACA.
Performance cost is kept to a minimum with a few optimisations:
- The endian switch upon return is combined with the MSR restore,
which avoids an expensive context synchronizing operation for LE
kernels. This makes up for the additional mtmsrd to enable
interrupts with local_irq_enable().
- blr is now used to return from the opal_* functions that are called
as C functions, to avoid link stack corruption. This requires a
skiboot fix as well to keep the call stack balanced.
A NULL call is more costly after this, (410ns->430ns on POWER9), but
OPAL calls are generally not performance critical at this scale.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-02-26 16:30:35 +07:00
|
|
|
.section ".text"
|
2011-09-20 00:44:57 +07:00
|
|
|
|
2017-03-23 14:54:01 +07:00
|
|
|
/*
|
powerpc/powernv: move OPAL call wrapper tracing and interrupt handling to C
The OPAL call wrapper gets interrupt disabling wrong. It disables
interrupts just by clearing MSR[EE], which has two problems:
- It doesn't call into the IRQ tracing subsystem, which means tracing
across OPAL calls does not always notice IRQs have been disabled.
- It doesn't go through the IRQ soft-mask code, which causes a minor
bug. MSR[EE] can not be restored by saving the MSR then clearing
MSR[EE], because a racing interrupt while soft-masked could clear
MSR[EE] between the two steps. This can cause MSR[EE] to be
incorrectly enabled when the OPAL call returns. Fortunately that
should only result in another masked interrupt being taken to
disable MSR[EE] again, but it's a bit sloppy.
The existing code also saves MSR to PACA, which is not re-entrant if
there is a nested OPAL call from different MSR contexts, which can
happen these days with SRESET interrupts on bare metal.
To fix these issues, move the tracing and IRQ handling code to C, and
call into asm just for the low level call when everything is ready to
go. Save the MSR on stack rather than PACA.
Performance cost is kept to a minimum with a few optimisations:
- The endian switch upon return is combined with the MSR restore,
which avoids an expensive context synchronizing operation for LE
kernels. This makes up for the additional mtmsrd to enable
interrupts with local_irq_enable().
- blr is now used to return from the opal_* functions that are called
as C functions, to avoid link stack corruption. This requires a
skiboot fix as well to keep the call stack balanced.
A NULL call is more costly after this, (410ns->430ns on POWER9), but
OPAL calls are generally not performance critical at this scale.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-02-26 16:30:35 +07:00
|
|
|
* r3-r10 - OPAL call arguments
|
|
|
|
* STK_PARAM(R11) - OPAL opcode
|
|
|
|
* STK_PARAM(R12) - MSR to restore
|
2011-09-20 00:44:57 +07:00
|
|
|
*/
|
powerpc/powernv: move OPAL call wrapper tracing and interrupt handling to C
The OPAL call wrapper gets interrupt disabling wrong. It disables
interrupts just by clearing MSR[EE], which has two problems:
- It doesn't call into the IRQ tracing subsystem, which means tracing
across OPAL calls does not always notice IRQs have been disabled.
- It doesn't go through the IRQ soft-mask code, which causes a minor
bug. MSR[EE] can not be restored by saving the MSR then clearing
MSR[EE], because a racing interrupt while soft-masked could clear
MSR[EE] between the two steps. This can cause MSR[EE] to be
incorrectly enabled when the OPAL call returns. Fortunately that
should only result in another masked interrupt being taken to
disable MSR[EE] again, but it's a bit sloppy.
The existing code also saves MSR to PACA, which is not re-entrant if
there is a nested OPAL call from different MSR contexts, which can
happen these days with SRESET interrupts on bare metal.
To fix these issues, move the tracing and IRQ handling code to C, and
call into asm just for the low level call when everything is ready to
go. Save the MSR on stack rather than PACA.
Performance cost is kept to a minimum with a few optimisations:
- The endian switch upon return is combined with the MSR restore,
which avoids an expensive context synchronizing operation for LE
kernels. This makes up for the additional mtmsrd to enable
interrupts with local_irq_enable().
- blr is now used to return from the opal_* functions that are called
as C functions, to avoid link stack corruption. This requires a
skiboot fix as well to keep the call stack balanced.
A NULL call is more costly after this, (410ns->430ns on POWER9), but
OPAL calls are generally not performance critical at this scale.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-02-26 16:30:35 +07:00
|
|
|
_GLOBAL_TOC(__opal_call)
|
|
|
|
mflr r0
|
|
|
|
std r0,PPC_LR_STKOFF(r1)
|
|
|
|
ld r12,STK_PARAM(R12)(r1)
|
|
|
|
li r0,MSR_IR|MSR_DR|MSR_LE
|
|
|
|
andc r12,r12,r0
|
|
|
|
LOAD_REG_ADDR(r11, opal_return)
|
|
|
|
mtlr r11
|
|
|
|
LOAD_REG_ADDR(r11, opal)
|
|
|
|
ld r2,0(r11)
|
|
|
|
ld r11,8(r11)
|
|
|
|
mtspr SPRN_HSRR0,r11
|
|
|
|
mtspr SPRN_HSRR1,r12
|
|
|
|
/* set token to r0 */
|
|
|
|
ld r0,STK_PARAM(R11)(r1)
|
2011-09-20 00:44:57 +07:00
|
|
|
hrfid
|
2014-02-04 12:04:52 +07:00
|
|
|
opal_return:
|
2013-09-23 09:05:03 +07:00
|
|
|
/*
|
powerpc/powernv: move OPAL call wrapper tracing and interrupt handling to C
The OPAL call wrapper gets interrupt disabling wrong. It disables
interrupts just by clearing MSR[EE], which has two problems:
- It doesn't call into the IRQ tracing subsystem, which means tracing
across OPAL calls does not always notice IRQs have been disabled.
- It doesn't go through the IRQ soft-mask code, which causes a minor
bug. MSR[EE] can not be restored by saving the MSR then clearing
MSR[EE], because a racing interrupt while soft-masked could clear
MSR[EE] between the two steps. This can cause MSR[EE] to be
incorrectly enabled when the OPAL call returns. Fortunately that
should only result in another masked interrupt being taken to
disable MSR[EE] again, but it's a bit sloppy.
The existing code also saves MSR to PACA, which is not re-entrant if
there is a nested OPAL call from different MSR contexts, which can
happen these days with SRESET interrupts on bare metal.
To fix these issues, move the tracing and IRQ handling code to C, and
call into asm just for the low level call when everything is ready to
go. Save the MSR on stack rather than PACA.
Performance cost is kept to a minimum with a few optimisations:
- The endian switch upon return is combined with the MSR restore,
which avoids an expensive context synchronizing operation for LE
kernels. This makes up for the additional mtmsrd to enable
interrupts with local_irq_enable().
- blr is now used to return from the opal_* functions that are called
as C functions, to avoid link stack corruption. This requires a
skiboot fix as well to keep the call stack balanced.
A NULL call is more costly after this, (410ns->430ns on POWER9), but
OPAL calls are generally not performance critical at this scale.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-02-26 16:30:35 +07:00
|
|
|
* Restore MSR on OPAL return. The MSR is set to big-endian.
|
2013-09-23 09:05:03 +07:00
|
|
|
*/
|
powerpc/powernv: move OPAL call wrapper tracing and interrupt handling to C
The OPAL call wrapper gets interrupt disabling wrong. It disables
interrupts just by clearing MSR[EE], which has two problems:
- It doesn't call into the IRQ tracing subsystem, which means tracing
across OPAL calls does not always notice IRQs have been disabled.
- It doesn't go through the IRQ soft-mask code, which causes a minor
bug. MSR[EE] can not be restored by saving the MSR then clearing
MSR[EE], because a racing interrupt while soft-masked could clear
MSR[EE] between the two steps. This can cause MSR[EE] to be
incorrectly enabled when the OPAL call returns. Fortunately that
should only result in another masked interrupt being taken to
disable MSR[EE] again, but it's a bit sloppy.
The existing code also saves MSR to PACA, which is not re-entrant if
there is a nested OPAL call from different MSR contexts, which can
happen these days with SRESET interrupts on bare metal.
To fix these issues, move the tracing and IRQ handling code to C, and
call into asm just for the low level call when everything is ready to
go. Save the MSR on stack rather than PACA.
Performance cost is kept to a minimum with a few optimisations:
- The endian switch upon return is combined with the MSR restore,
which avoids an expensive context synchronizing operation for LE
kernels. This makes up for the additional mtmsrd to enable
interrupts with local_irq_enable().
- blr is now used to return from the opal_* functions that are called
as C functions, to avoid link stack corruption. This requires a
skiboot fix as well to keep the call stack balanced.
A NULL call is more costly after this, (410ns->430ns on POWER9), but
OPAL calls are generally not performance critical at this scale.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-02-26 16:30:35 +07:00
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
ld r11,STK_PARAM(R12)(r1)
|
|
|
|
mtmsrd r11
|
|
|
|
#else
|
|
|
|
/* Endian can only be switched with rfi, must byte reverse MSR load */
|
|
|
|
.short 0x4039 /* li r10,STK_PARAM(R12) */
|
|
|
|
.byte (STK_PARAM(R12) >> 8) & 0xff
|
|
|
|
.byte STK_PARAM(R12) & 0xff
|
|
|
|
|
|
|
|
.long 0x280c6a7d /* ldbrx r11,r10,r1 */
|
|
|
|
.long 0x05009f42 /* bcl 20,31,$+4 */
|
|
|
|
.long 0xa602487d /* mflr r10 */
|
|
|
|
.long 0x14004a39 /* addi r10,r10,20 */
|
|
|
|
.long 0xa64b5a7d /* mthsrr0 r10 */
|
|
|
|
.long 0xa64b7b7d /* mthsrr1 r11 */
|
|
|
|
.long 0x2402004c /* hrfid */
|
|
|
|
#endif
|
|
|
|
ld r2,PACATOC(r13)
|
|
|
|
ld r0,PPC_LR_STKOFF(r1)
|
2014-07-03 14:20:50 +07:00
|
|
|
mtlr r0
|
|
|
|
blr
|