arm64: Add TLB conflict fault handler
Add TLB conflict fault handler and try to handle gracefully. Check whether TLB fault can be handled by EL2 and cause panic if EL2 is not able to handle. Change-Id: I276ec5413411932bd8a67ed4c85ebbf66f4affcf Signed-off-by: Runmin Wang <runminw@codeaurora.org> Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org> Signed-off-by: Naina Mehta <nainmeht@codeaurora.org>
This commit is contained in:
parent
ca0d1e3eaf
commit
7769d7fea8
@ -1793,6 +1793,14 @@ config BUILD_ARM64_DT_OVERLAY
|
||||
required flags to add DT overlay in the
|
||||
compilation.
|
||||
|
||||
config TLB_CONF_HANDLER
|
||||
bool "enable handler for TLB conflict"
|
||||
help
|
||||
This option enables graceful handling of TLB
|
||||
conflict in EL2. Say yes here to enable TLB
|
||||
conflict handler.
|
||||
If unsure, Say n.
|
||||
|
||||
config SYSVIPC_COMPAT
|
||||
def_bool y
|
||||
depends on COMPAT && SYSVIPC
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include <linux/preempt.h>
|
||||
#include <linux/hugetlb.h>
|
||||
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
#include <linux/qcom_scm.h>
|
||||
#endif
|
||||
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
@ -691,6 +695,15 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
static int do_tlb_conf_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||
{
|
||||
if (qcom_scm_tlb_conf_handler(addr))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct fault_info fault_info[] = {
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "ttbr address size fault" },
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "level 1 address size fault" },
|
||||
@ -740,7 +753,11 @@ static const struct fault_info fault_info[] = {
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "unknown 45" },
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "unknown 46" },
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "unknown 47" },
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
{ do_tlb_conf_fault, SIGKILL, SI_KERNEL, "TLB conflict abort" },
|
||||
#else
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "TLB conflict abort" },
|
||||
#endif
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "Unsupported atomic hardware update fault" },
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "unknown 50" },
|
||||
{ do_bad, SIGKILL, SI_KERNEL, "unknown 51" },
|
||||
|
@ -1020,6 +1020,27 @@ int __qcom_scm_sec_wdog_trigger(struct device *dev)
|
||||
return ret ? : desc.res[0];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
int __qcom_scm_tlb_conf_handler(struct device *dev, unsigned long addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#define SCM_TLB_CONFLICT_CMD 0x1F
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_MP,
|
||||
.cmd = SCM_TLB_CONFLICT_CMD,
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
|
||||
desc.args[0] = addr;
|
||||
desc.arginfo = QCOM_SCM_ARGS(1);
|
||||
|
||||
ret = qcom_scm_call_atomic(dev, &desc);
|
||||
|
||||
return ret ? : desc.res[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
void __qcom_scm_disable_sdi(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -160,6 +160,14 @@ int qcom_scm_sec_wdog_trigger(void)
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_sec_wdog_trigger);
|
||||
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
int qcom_scm_tlb_conf_handler(unsigned long addr)
|
||||
{
|
||||
return __qcom_scm_tlb_conf_handler(__scm->dev, addr);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_tlb_conf_handler);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* qcom_scm_disable_sdi() - Disable SDI
|
||||
*/
|
||||
|
@ -28,6 +28,9 @@ extern void __qcom_scm_cpu_power_down(struct device *dev, u32 flags);
|
||||
extern void __qcom_scm_cpu_hp(struct device *dev, u32 flags);
|
||||
extern int __qcom_scm_sec_wdog_deactivate(struct device *dev);
|
||||
extern int __qcom_scm_sec_wdog_trigger(struct device *dev);
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
extern int __qcom_scm_tlb_conf_handler(struct device *dev, unsigned long addr);
|
||||
#endif
|
||||
extern void __qcom_scm_disable_sdi(struct device *dev);
|
||||
extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
|
||||
extern int __qcom_scm_spin_cpu(struct device *dev);
|
||||
|
@ -86,6 +86,9 @@ extern void qcom_scm_cpu_power_down(u32 flags);
|
||||
extern void qcom_scm_cpu_hp(u32 flags);
|
||||
extern int qcom_scm_sec_wdog_deactivate(void);
|
||||
extern int qcom_scm_sec_wdog_trigger(void);
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
extern int qcom_scm_tlb_conf_handler(unsigned long addr);
|
||||
#endif
|
||||
extern void qcom_scm_disable_sdi(void);
|
||||
extern int qcom_scm_set_remote_state(u32 state, u32 id);
|
||||
extern int qcom_scm_spin_cpu(void);
|
||||
@ -231,6 +234,9 @@ static inline void qcom_scm_cpu_power_down(u32 flags) {}
|
||||
static inline void qcom_scm_cpu_hp(u32 flags) {}
|
||||
static inline int qcom_scm_sec_wdog_deactivate(void) { return -ENODEV; }
|
||||
static inline int qcom_scm_sec_wdog_trigger(void) { return -ENODEV; }
|
||||
#ifdef CONFIG_TLB_CONF_HANDLER
|
||||
static inline int qcom_scm_tlb_conf_handler(unsigned long addr) { return -ENODEV; }
|
||||
#endif
|
||||
static inline void qcom_scm_disable_sdi(void) {}
|
||||
static inline u32 qcom_scm_set_remote_state(u32 state, u32 id)
|
||||
{ return -ENODEV; }
|
||||
|
Loading…
Reference in New Issue
Block a user