soc: tegra: add t21x panic handler
Some t21x bootloaders like cboot read PMC_SCRATCH37 to check if a reboot was due to a kernel panic. Support this functionality with a panic notifier. Original implementation relied on single bit 24 but a specific magic was chosen in later improvement to prevent false positive from random data in scratch register during reboot. Based on: - https://gitlab.com/nvidia/nv-tegra/linux-4.9/-/commit/31b412a5fc80ed0fe33f3ad4e7cc779ce66446a2 - https://github.com/CTCaer/switch-l4t-kernel-4.9/commit/b74fee3edf8053b0b954643d3bd065596cee8aca Co-developed-by: Nat Pettipaw <npettipaw@nvidia.com> Co-developed-by: CTCaer <ctcaer@gmail.com>
This commit is contained in:
1 parent
4d226a839b
commit
33b21c2d6c
1 file changed
+28
@@ -35,6 +35,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/panic_notifier.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
@@ -111,6 +112,8 @@
|
||||
|
||||
#define PMC_PWR_DET_VALUE 0xe4
|
||||
|
||||
#define KERNEL_PANIC_MAGIC 0x4E415054
|
||||
|
||||
#define PMC_USB_DEBOUNCE_DEL 0xec
|
||||
#define PMC_USB_AO 0xf0
|
||||
|
||||
@@ -419,6 +422,7 @@ struct tegra_pmc_soc {
|
||||
bool has_usb_sleepwalk;
|
||||
bool supports_core_domain;
|
||||
bool has_single_mmio_aperture;
|
||||
bool has_panic_notifier;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -505,6 +509,7 @@ struct tegra_pmc {
|
||||
unsigned long *wake_cntrl_level_map;
|
||||
|
||||
struct notifier_block reboot_notifier;
|
||||
struct notifier_block panic_notifier;
|
||||
struct syscore syscore;
|
||||
|
||||
/* Pending wake IRQ processing */
|
||||
@@ -1310,6 +1315,13 @@ static int tegra_pmc_restart_handler(struct sys_off_data *data)
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int tegra_pmc_panic_handler(struct notifier_block *this,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
tegra_pmc_writel(pmc, KERNEL_PANIC_MAGIC, PMC_SCRATCH37);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int tegra_pmc_power_off_handler(struct sys_off_data *data)
|
||||
{
|
||||
struct tegra_pmc *pmc = data->cb_data;
|
||||
@@ -3199,6 +3211,20 @@ static int tegra_pmc_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
if (pmc->soc->has_panic_notifier) {
|
||||
pmc->panic_notifier.notifier_call = tegra_pmc_panic_handler;
|
||||
pmc->panic_notifier.priority = INT_MAX-1;
|
||||
|
||||
err = atomic_notifier_chain_register(&panic_notifier_list,
|
||||
&pmc->panic_notifier);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to register panic notifier, %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = devm_register_sys_off_handler(&pdev->dev,
|
||||
SYS_OFF_MODE_RESTART,
|
||||
SYS_OFF_PRIO_LOW,
|
||||
@@ -4018,6 +4044,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
|
||||
.has_blink_output = true,
|
||||
.has_usb_sleepwalk = true,
|
||||
.has_single_mmio_aperture = true,
|
||||
.has_panic_notifier = true,
|
||||
};
|
||||
|
||||
static const char * const tegra210b01_powergates[] = {
|
||||
@@ -4079,6 +4106,7 @@ static const struct tegra_pmc_soc tegra210b01_pmc_soc = {
|
||||
.has_blink_output = true,
|
||||
.has_usb_sleepwalk = true,
|
||||
.has_single_mmio_aperture = true,
|
||||
.has_panic_notifier = true,
|
||||
};
|
||||
|
||||
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
|
||||
|
||||
Reference in new issue
Block a user