Commit a2cc220a authored by Rajan Vaja's avatar Rajan Vaja Committed by Greg Kroah-Hartman

firmware: xilinx: Add sysfs and API to set boot health status

Add sysfs interface to set boot health status from user space.
Add API used by this interface to communicate with firmware.

If PMUFW is compiled with CHECK_HEALTHY_BOOT, it will check the
healthy bit on FPD WDT expiration. If healthy bit is set by a user
application running in Linux, PMUFW will do APU only restart. If
healthy bit is not set during FPD WDT expiration, PMUFW will do
system restart.
Signed-off-by: default avatarRajan Vaja <rajan.vaja@xilinx.com>
Signed-off-by: default avatarMichal Simek <michal.simek@xilinx.com>
Signed-off-by: default avatarTejas Patel <tejas.patel@xilinx.com>
Signed-off-by: default avatarJolly Shah <jolly.shah@xilinx.com>
Link: https://lore.kernel.org/r/1587761887-4279-26-git-send-email-jolly.shah@xilinx.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b3ae24c4
...@@ -80,3 +80,24 @@ Description: ...@@ -80,3 +80,24 @@ Description:
# echo "subsystem" > /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope # echo "subsystem" > /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope
Users: Xilinx Users: Xilinx
What: /sys/devices/platform/firmware\:zynqmp-firmware/health_status
Date: March 2020
KernelVersion: 5.6
Contact: "Jolly Shah" <jollys@xilinx.com>
Description:
This sysfs interface allows to set the health status. If PMUFW
is compiled with CHECK_HEALTHY_BOOT, it will check the healthy
bit on FPD WDT expiration. If healthy bit is set by a user
application running in Linux, PMUFW will do APU only restart. If
healthy bit is not set during FPD WDT expiration, PMUFW will do
system restart.
Usage:
Set healthy bit
# echo 1 > /sys/devices/platform/firmware\:zynqmp-firmware/health_status
Unset healthy bit
# echo 0 > /sys/devices/platform/firmware\:zynqmp-firmware/health_status
Users: Xilinx
...@@ -683,6 +683,21 @@ int zynqmp_pm_read_pggs(u32 index, u32 *value) ...@@ -683,6 +683,21 @@ int zynqmp_pm_read_pggs(u32 index, u32 *value)
} }
EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs); EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
/**
* zynqmp_pm_set_boot_health_status() - PM API for setting healthy boot status
* @value Status value to be written
*
* This function sets healthy bit value to indicate boot health status
* to firmware.
*
* @return Returns status, either success or error+reason
*/
int zynqmp_pm_set_boot_health_status(u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_BOOT_HEALTH_STATUS,
value, 0, NULL);
}
/** /**
* zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release) * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)
* @reset: Reset to be configured * @reset: Reset to be configured
...@@ -984,6 +999,29 @@ static ssize_t shutdown_scope_store(struct device *device, ...@@ -984,6 +999,29 @@ static ssize_t shutdown_scope_store(struct device *device,
static DEVICE_ATTR_RW(shutdown_scope); static DEVICE_ATTR_RW(shutdown_scope);
static ssize_t health_status_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
unsigned int value;
ret = kstrtouint(buf, 10, &value);
if (ret)
return ret;
ret = zynqmp_pm_set_boot_health_status(value);
if (ret) {
dev_err(device, "unable to set healthy bit value to %u\n",
value);
return ret;
}
return count;
}
static DEVICE_ATTR_WO(health_status);
static ssize_t ggs_show(struct device *device, static ssize_t ggs_show(struct device *device,
struct device_attribute *attr, struct device_attribute *attr,
char *buf, char *buf,
...@@ -1143,6 +1181,7 @@ static struct attribute *zynqmp_firmware_attrs[] = { ...@@ -1143,6 +1181,7 @@ static struct attribute *zynqmp_firmware_attrs[] = {
&dev_attr_pggs2.attr, &dev_attr_pggs2.attr,
&dev_attr_pggs3.attr, &dev_attr_pggs3.attr,
&dev_attr_shutdown_scope.attr, &dev_attr_shutdown_scope.attr,
&dev_attr_health_status.attr,
NULL, NULL,
}; };
......
...@@ -114,6 +114,8 @@ enum pm_ioctl_id { ...@@ -114,6 +114,8 @@ enum pm_ioctl_id {
IOCTL_READ_GGS = 13, IOCTL_READ_GGS = 13,
IOCTL_WRITE_PGGS = 14, IOCTL_WRITE_PGGS = 14,
IOCTL_READ_PGGS = 15, IOCTL_READ_PGGS = 15,
/* Set healthy bit value */
IOCTL_SET_BOOT_HEALTH_STATUS = 17,
}; };
enum pm_query_id { enum pm_query_id {
...@@ -354,6 +356,7 @@ int zynqmp_pm_read_ggs(u32 index, u32 *value); ...@@ -354,6 +356,7 @@ int zynqmp_pm_read_ggs(u32 index, u32 *value);
int zynqmp_pm_write_pggs(u32 index, u32 value); int zynqmp_pm_write_pggs(u32 index, u32 value);
int zynqmp_pm_read_pggs(u32 index, u32 *value); int zynqmp_pm_read_pggs(u32 index, u32 *value);
int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype); int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype);
int zynqmp_pm_set_boot_health_status(u32 value);
#else #else
static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
{ {
...@@ -500,6 +503,10 @@ static inline int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype) ...@@ -500,6 +503,10 @@ static inline int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int zynqmp_pm_set_boot_health_status(u32 value)
{
return -ENODEV;
}
#endif #endif
#endif /* __FIRMWARE_ZYNQMP_H__ */ #endif /* __FIRMWARE_ZYNQMP_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment