Message ID | 1575502159-11327-5-git-send-email-jolly.shah@xilinx.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | firmware: xilinx: Add xilinx specific sysfs interface | expand |
On 05. 12. 19 0:29, Jolly Shah wrote: > From: Rajan Vaja <rajan.vaja@xilinx.com> > > The Linux shutdown functionality implemented via PSCI system_off does > not include an option to set a scope, i.e. which parts of the system to > shut down. > > This patch creates sysfs that allows to set the shutdown scope for the > next shutdown request. When the next shutdown is performed, the platform > specific portion of PSCI-system_off can use the chosen shutdown scope. > > Signed-off-by: Stefan Krsmanovic <stefan.krsmanovic@aggios.com> > Signed-off-by: Michal Simek <michal.simek@xilinx.com> > Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com> > Signed-off-by: Jolly Shah <jolly.shah@xilinx.com> > --- > Documentation/ABI/stable/sysfs-firmware-zynqmp | 32 ++++++ > drivers/firmware/xilinx/zynqmp.c | 141 +++++++++++++++++++++++++ > include/linux/firmware/xlnx-zynqmp.h | 12 +++ > 3 files changed, 185 insertions(+) > > diff --git a/Documentation/ABI/stable/sysfs-firmware-zynqmp b/Documentation/ABI/stable/sysfs-firmware-zynqmp > index 0a75812..13e4fd2 100644 > --- a/Documentation/ABI/stable/sysfs-firmware-zynqmp > +++ b/Documentation/ABI/stable/sysfs-firmware-zynqmp > @@ -48,3 +48,35 @@ Description: > # echo 0xFFFFFFFF 0x1234ABCD > /sys/firmware/zynqmp/pggs0 > > Users: Xilinx > + > +What: /sys/firmware/zynqmp/shutdown_scope > +Date: February 2018 > +KernelVersion: 4.15.6 ditto. > +Contact: "Jolly Shah" <jollys@xilinx.com> > +Description: > + This sysfs interface allows to set the shutdown scope for the > + next shutdown request. When the next shutdown is performed, the > + platform specific portion of PSCI-system_off can use the chosen > + shutdown scope. > + > + Following are available shutdown scopes(subtypes): > + > + subsystem: Only the APU along with all of its peripherals > + not used by other processing units will be > + shut down. This may result in the FPD power > + domain being shut down provided that no other > + processing unit uses FPD peripherals or DRAM. > + ps_only: The complete PS will be shut down, including the > + RPU, PMU, etc. Only the PL domain (FPGA) > + remains untouched. > + system: The complete system/device is shut down. > + > + Usage: > + # cat /sys/firmware/zynqmp/shutdown_scope > + # echo <scope> > /sys/firmware/zynqmp/shutdown_scope > + > + Example: > + # cat /sys/firmware/zynqmp/shutdown_scope > + # echo "subsystem" > /sys/firmware/zynqmp/shutdown_scope > + > +Users: Xilinx > diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c > index 8dcf5a4..b23bda4 100644 > --- a/drivers/firmware/xilinx/zynqmp.c > +++ b/drivers/firmware/xilinx/zynqmp.c > @@ -746,6 +746,146 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) > EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); > > /** > + * struct zynqmp_pm_shutdown_scope - Struct for shutdown scope > + * @subtype: Shutdown subtype > + * @name: Matching string for scope argument > + * > + * This struct encapsulates mapping between shutdown scope ID and string. > + */ > +struct zynqmp_pm_shutdown_scope { > + const enum zynqmp_pm_shutdown_subtype subtype; > + const char *name; > +}; > + > +static struct zynqmp_pm_shutdown_scope shutdown_scopes[] = { > + [ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM] = { > + .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM, > + .name = "subsystem", > + }, > + [ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY] = { > + .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY, > + .name = "ps_only", > + }, > + [ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM] = { > + .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM, > + .name = "system", > + }, > +}; > + > +static struct zynqmp_pm_shutdown_scope *selected_scope = > + &shutdown_scopes[ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM]; > + > +/** > + * zynqmp_pm_is_shutdown_scope_valid - Check if shutdown scope string is valid > + * @scope_string: Shutdown scope string > + * > + * Return: Return pointer to matching shutdown scope struct from > + * array of available options in system if string is valid, > + * otherwise returns NULL. > + */ > +static struct zynqmp_pm_shutdown_scope* > + zynqmp_pm_is_shutdown_scope_valid(const char *scope_string) > +{ > + int count; > + > + for (count = 0; count < ARRAY_SIZE(shutdown_scopes); count++) > + if (sysfs_streq(scope_string, shutdown_scopes[count].name)) > + return &shutdown_scopes[count]; > + > + return NULL; > +} > + > +/** > + * shutdown_scope_show - Show shutdown_scope sysfs attribute > + * @kobj: Kobject structure > + * @attr: Kobject attribute structure > + * @buf: Requested available shutdown_scope attributes string > + * > + * User-space interface for viewing the available scope options for system > + * shutdown. Scope option for next shutdown call is marked with []. > + * > + * Usage: cat /sys/firmware/zynqmp/shutdown_scope > + * > + * Return: Number of bytes printed into the buffer. > + */ > +static ssize_t shutdown_scope_show(struct kobject *kobj, > + struct kobj_attribute *attr, > + char *buf) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(shutdown_scopes); i++) { > + if (&shutdown_scopes[i] == selected_scope) { > + strcat(buf, "["); > + strcat(buf, shutdown_scopes[i].name); > + strcat(buf, "]"); > + } else { > + strcat(buf, shutdown_scopes[i].name); > + } > + strcat(buf, " "); > + } > + strcat(buf, "\n"); > + > + return strlen(buf); > +} > + > +/** > + * shutdown_scope_store - Store shutdown_scope sysfs attribute > + * @kobj: Kobject structure > + * @attr: Kobject attribute structure > + * @buf: User entered shutdown_scope attribute string > + * @count: Buffer size > + * > + * User-space interface for setting the scope for the next system shutdown. > + * Usage: echo <scope> > /sys/firmware/zynqmp/shutdown_scope > + * > + * The Linux shutdown functionality implemented via PSCI system_off does not > + * include an option to set a scope, i.e. which parts of the system to shut > + * down. > + * > + * This API function allows to set the shutdown scope for the next shutdown > + * request by passing it to the ATF running in EL3. When the next shutdown > + * is performed, the platform specific portion of PSCI-system_off can use > + * the chosen shutdown scope. > + * > + * subsystem: Only the APU along with all of its peripherals not used by other > + * processing units will be shut down. This may result in the FPD > + * power domain being shut down provided that no other processing > + * unit uses FPD peripherals or DRAM. > + * ps_only: The complete PS will be shut down, including the RPU, PMU, etc. > + * Only the PL domain (FPGA) remains untouched. > + * system: The complete system/device is shut down. > + * > + * Return: count argument if request succeeds, the corresponding error > + * code otherwise > + */ > +static ssize_t shutdown_scope_store(struct kobject *kobj, > + struct kobj_attribute *attr, > + const char *buf, size_t count) > +{ > + int ret; > + struct zynqmp_pm_shutdown_scope *scope; > + > + scope = zynqmp_pm_is_shutdown_scope_valid(buf); > + if (!scope) > + return -EINVAL; > + > + ret = zynqmp_pm_system_shutdown(ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY, > + scope->subtype); > + if (ret) { > + pr_err("unable to set shutdown scope %s\n", buf); > + return ret; > + } > + > + selected_scope = scope; > + > + return count; > +} > + > +static struct kobj_attribute zynqmp_attr_shutdown_scope = > + __ATTR_RW(shutdown_scope); the same as was in 1/5. > + > +/** > * config_reg_store - Write config_reg sysfs attribute > * @kobj: Kobject structure > * @attr: Kobject attribute structure > @@ -870,6 +1010,7 @@ static struct kobj_attribute zynqmp_attr_config_reg = > __ATTR_RW(config_reg); > > static struct attribute *attrs[] = { > + &zynqmp_attr_shutdown_scope.attr, > &zynqmp_attr_config_reg.attr, > NULL, > }; > diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h > index b96ea5d..54061de 100644 > --- a/include/linux/firmware/xlnx-zynqmp.h > +++ b/include/linux/firmware/xlnx-zynqmp.h > @@ -277,6 +277,18 @@ enum pm_register_access_id { > CONFIG_REG_READ, > }; > > +enum zynqmp_pm_shutdown_type { > + ZYNQMP_PM_SHUTDOWN_TYPE_SHUTDOWN, > + ZYNQMP_PM_SHUTDOWN_TYPE_RESET, > + ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY, > +}; > + > +enum zynqmp_pm_shutdown_subtype { > + ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM, > + ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY, > + ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM, > +}; > + > /** > * struct zynqmp_pm_query_data - PM query data > * @qid: query ID > M
diff --git a/Documentation/ABI/stable/sysfs-firmware-zynqmp b/Documentation/ABI/stable/sysfs-firmware-zynqmp index 0a75812..13e4fd2 100644 --- a/Documentation/ABI/stable/sysfs-firmware-zynqmp +++ b/Documentation/ABI/stable/sysfs-firmware-zynqmp @@ -48,3 +48,35 @@ Description: # echo 0xFFFFFFFF 0x1234ABCD > /sys/firmware/zynqmp/pggs0 Users: Xilinx + +What: /sys/firmware/zynqmp/shutdown_scope +Date: February 2018 +KernelVersion: 4.15.6 +Contact: "Jolly Shah" <jollys@xilinx.com> +Description: + This sysfs interface allows to set the shutdown scope for the + next shutdown request. When the next shutdown is performed, the + platform specific portion of PSCI-system_off can use the chosen + shutdown scope. + + Following are available shutdown scopes(subtypes): + + subsystem: Only the APU along with all of its peripherals + not used by other processing units will be + shut down. This may result in the FPD power + domain being shut down provided that no other + processing unit uses FPD peripherals or DRAM. + ps_only: The complete PS will be shut down, including the + RPU, PMU, etc. Only the PL domain (FPGA) + remains untouched. + system: The complete system/device is shut down. + + Usage: + # cat /sys/firmware/zynqmp/shutdown_scope + # echo <scope> > /sys/firmware/zynqmp/shutdown_scope + + Example: + # cat /sys/firmware/zynqmp/shutdown_scope + # echo "subsystem" > /sys/firmware/zynqmp/shutdown_scope + +Users: Xilinx diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 8dcf5a4..b23bda4 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -746,6 +746,146 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); /** + * struct zynqmp_pm_shutdown_scope - Struct for shutdown scope + * @subtype: Shutdown subtype + * @name: Matching string for scope argument + * + * This struct encapsulates mapping between shutdown scope ID and string. + */ +struct zynqmp_pm_shutdown_scope { + const enum zynqmp_pm_shutdown_subtype subtype; + const char *name; +}; + +static struct zynqmp_pm_shutdown_scope shutdown_scopes[] = { + [ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM] = { + .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM, + .name = "subsystem", + }, + [ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY] = { + .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY, + .name = "ps_only", + }, + [ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM] = { + .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM, + .name = "system", + }, +}; + +static struct zynqmp_pm_shutdown_scope *selected_scope = + &shutdown_scopes[ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM]; + +/** + * zynqmp_pm_is_shutdown_scope_valid - Check if shutdown scope string is valid + * @scope_string: Shutdown scope string + * + * Return: Return pointer to matching shutdown scope struct from + * array of available options in system if string is valid, + * otherwise returns NULL. + */ +static struct zynqmp_pm_shutdown_scope* + zynqmp_pm_is_shutdown_scope_valid(const char *scope_string) +{ + int count; + + for (count = 0; count < ARRAY_SIZE(shutdown_scopes); count++) + if (sysfs_streq(scope_string, shutdown_scopes[count].name)) + return &shutdown_scopes[count]; + + return NULL; +} + +/** + * shutdown_scope_show - Show shutdown_scope sysfs attribute + * @kobj: Kobject structure + * @attr: Kobject attribute structure + * @buf: Requested available shutdown_scope attributes string + * + * User-space interface for viewing the available scope options for system + * shutdown. Scope option for next shutdown call is marked with []. + * + * Usage: cat /sys/firmware/zynqmp/shutdown_scope + * + * Return: Number of bytes printed into the buffer. + */ +static ssize_t shutdown_scope_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(shutdown_scopes); i++) { + if (&shutdown_scopes[i] == selected_scope) { + strcat(buf, "["); + strcat(buf, shutdown_scopes[i].name); + strcat(buf, "]"); + } else { + strcat(buf, shutdown_scopes[i].name); + } + strcat(buf, " "); + } + strcat(buf, "\n"); + + return strlen(buf); +} + +/** + * shutdown_scope_store - Store shutdown_scope sysfs attribute + * @kobj: Kobject structure + * @attr: Kobject attribute structure + * @buf: User entered shutdown_scope attribute string + * @count: Buffer size + * + * User-space interface for setting the scope for the next system shutdown. + * Usage: echo <scope> > /sys/firmware/zynqmp/shutdown_scope + * + * The Linux shutdown functionality implemented via PSCI system_off does not + * include an option to set a scope, i.e. which parts of the system to shut + * down. + * + * This API function allows to set the shutdown scope for the next shutdown + * request by passing it to the ATF running in EL3. When the next shutdown + * is performed, the platform specific portion of PSCI-system_off can use + * the chosen shutdown scope. + * + * subsystem: Only the APU along with all of its peripherals not used by other + * processing units will be shut down. This may result in the FPD + * power domain being shut down provided that no other processing + * unit uses FPD peripherals or DRAM. + * ps_only: The complete PS will be shut down, including the RPU, PMU, etc. + * Only the PL domain (FPGA) remains untouched. + * system: The complete system/device is shut down. + * + * Return: count argument if request succeeds, the corresponding error + * code otherwise + */ +static ssize_t shutdown_scope_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct zynqmp_pm_shutdown_scope *scope; + + scope = zynqmp_pm_is_shutdown_scope_valid(buf); + if (!scope) + return -EINVAL; + + ret = zynqmp_pm_system_shutdown(ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY, + scope->subtype); + if (ret) { + pr_err("unable to set shutdown scope %s\n", buf); + return ret; + } + + selected_scope = scope; + + return count; +} + +static struct kobj_attribute zynqmp_attr_shutdown_scope = + __ATTR_RW(shutdown_scope); + +/** * config_reg_store - Write config_reg sysfs attribute * @kobj: Kobject structure * @attr: Kobject attribute structure @@ -870,6 +1010,7 @@ static struct kobj_attribute zynqmp_attr_config_reg = __ATTR_RW(config_reg); static struct attribute *attrs[] = { + &zynqmp_attr_shutdown_scope.attr, &zynqmp_attr_config_reg.attr, NULL, }; diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index b96ea5d..54061de 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -277,6 +277,18 @@ enum pm_register_access_id { CONFIG_REG_READ, }; +enum zynqmp_pm_shutdown_type { + ZYNQMP_PM_SHUTDOWN_TYPE_SHUTDOWN, + ZYNQMP_PM_SHUTDOWN_TYPE_RESET, + ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY, +}; + +enum zynqmp_pm_shutdown_subtype { + ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM, + ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY, + ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM, +}; + /** * struct zynqmp_pm_query_data - PM query data * @qid: query ID