diff --git a/module/resource_perms/include/mod_resource_perms.h b/module/resource_perms/include/mod_resource_perms.h index 9d223651f944f3d2678a56a412564ab8a3c91907..8a3bd64a2f9b64da714f813f7c13d0cd0502a998 100644 --- a/module/resource_perms/include/mod_resource_perms.h +++ b/module/resource_perms/include/mod_resource_perms.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -45,6 +46,8 @@ enum mod_res_perms_permissions { MOD_RES_PERMS_ACCESS_DENIED = 1, }; +#define MOD_RES_PERMS_PERMISSIONS_MASK 0x1 + #define MOD_RES_PERMS_PROTOCOL_OFFSET MOD_SCMI_PROTOCOL_ID_BASE enum mod_res_perms_protocol_deny { @@ -266,6 +269,44 @@ enum mod_res_reset_domain_permissions_idx { MOD_SCMI_RESET_NOTIFY - MOD_RES_PERMS_RESET_DOMAIN_PERMS_OFFSET, }; +/*! + * \brief SCMI Domain Types + */ +enum mod_res_domain_device_types { + MOD_RES_POWER_DOMAIN_DEVICE = 0, + MOD_RES_PERF_DOMAIN_DEVICE, + MOD_RES_CLOCK_DOMAIN_DEVICE, + MOD_RES_SENSOR_DOMAIN_DEVICE, + MOD_RES_RESET_DOMAIN_DEVICE, + MOD_RES_PLATFORM_DOMAIN_DEVICE, + MOD_RES_DOMAIN_DEVICE_INVALID +}; + +/*! + * \brief Each device is made up multiple domain devices. + * The protocol is determined by the device type. + * The resource ID for a protocol is the element ID of the + * device_id. + */ +struct mod_res_domain_device { + /*! \brief Identifier of the domain device instance */ + fwk_id_t device_id; + + /*! \brief Type of the domain device instance */ + enum mod_res_domain_device_types type; +}; + +/*! + * \brief Device definition. + */ +struct mod_res_device { + /*! \brief Device Identifier */ + uint16_t device_id; + + /*! \brief List of domain devices in the device */ + struct mod_res_domain_device *domain_devices; +}; + /*! * \brief SCMI Agent Permissions * @@ -359,6 +400,52 @@ struct mod_res_permissions_api { uint32_t protocol_id, uint32_t message_id, uint32_t resource_id); + + /*! + * \brief Set device permissions for an agent + * + * \param agent_id identifier of the agent. + * \param device_id identifier of the device. + * \param flags permissions to set. + * + * \retval FWK_SUCCESS The operation has completed successfully. + * \retval FWK_E_ACCESS Unknown agent_id or device_id. + * \retval FWK_E_PARAM Invalid flags or protocol_ID. + */ + int (*agent_set_device_permission)( + uint32_t agent_id, + uint32_t device_id, + uint32_t flags); + + /*! + * \brief Set device protocol permissions for an agent + * + * \param agent_id identifier of the agent. + * \param device_id identifier of the device. + * \param device_id identifier of the protocol. + * \param flags permissions to set. + * + * \retval FWK_SUCCESS The operation has completed successfully. + * \retval FWK_E_ACCESS Unknown agent_id or device_id. + * \retval FWK_E_PARAM Invalid flags or protocol_ID. + */ + int (*agent_set_device_protocol_permission)( + uint32_t agent_id, + uint32_t device_id, + uint32_t protocol_id, + uint32_t flags); + + /*! + * \brief Reset permissions for an agent + * + * \param agent_id identifier of the agent. + * \param flags permissions to set. + * + * \retval FWK_SUCCESS The operation has completed successfully. + * \retval FWK_E_ACCESS Unknown agent_id. + * \retval FWK_E_PARAM Invalid flags. + */ + int (*agent_reset_config)(uint32_t agent_id, uint32_t flags); }; /*! @@ -377,22 +464,58 @@ struct mod_res_resource_perms_config { /*! \brief Number of clocks supported by the platform. */ uint32_t clock_count; + /*! \brief Number of clock commands supported by the platform. */ + uint32_t clock_cmd_count; + + /*! \brief Number of clock resources supported by the platform. */ + uint32_t clock_resource_count; + /*! \brief Number of sensors supported by the platform. */ uint32_t sensor_count; + /*! \brief Number of sensor commands supported by the platform. */ + uint32_t sensor_cmd_count; + + /*! \brief Number of sensor resources supported by the platform. */ + uint32_t sensor_resource_count; + /*! \brief Number of power domains supported by the platform. */ uint32_t pd_count; - /*! \brief Number of performance domains supported by the platform. */ + /*! \brief Number of power domain commands supported by the platform. */ + uint32_t pd_cmd_count; + + /*! \brief Number of power domain resources supported by the platform. */ + uint32_t pd_resource_count; + + /*! \brief Number of perf domains supported by the platform. */ uint32_t perf_count; + /*! \brief Number of perf domain commands supported by the platform. */ + uint32_t perf_cmd_count; + + /*! \brief Number of perf domain resources supported by the platform. */ + uint32_t perf_resource_count; + #ifdef BUILD_HAS_SCMI_RESET - /*! \brief Number of performance domains supported by the platform. */ + /*! \brief Number of reset domains supported by the platform. */ uint32_t reset_domain_count; + + /*! \brief Number of reset domain commands supported by the platform. */ + uint32_t reset_domain_cmd_count; + + /*! \brief Number of reset domain resources supported by the platform. */ + uint32_t reset_domain_resource_count; #endif + /*! \brief Number of devices supported by the platform. */ + uint32_t device_count; + /*! \brief Address of the permissions table */ uintptr_t agent_permissions; + + /*! \brief Address of the domain devices */ + uintptr_t domain_devices; }; /*! diff --git a/module/resource_perms/src/mod_resource_perms.c b/module/resource_perms/src/mod_resource_perms.c index 410f4d860b82626c0e35936b8791d2faeae21a8e..21628056d2d4773f52a6b850384f6af2746521cf 100644 --- a/module/resource_perms/src/mod_resource_perms.c +++ b/module/resource_perms/src/mod_resource_perms.c @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include #include @@ -21,6 +23,9 @@ #include struct res_perms_ctx { + /*! platform config data */ + struct mod_res_resource_perms_config *config; + /*! Number of agents for the platform. */ uint32_t agent_count; @@ -39,6 +44,9 @@ struct res_perms_ctx { /*! Number of performance domain resources for the platform. */ uint32_t perf_count; + /*! Number of devices for the platform. */ + uint32_t device_count; + #ifdef BUILD_HAS_SCMI_RESET /*! Number of reset domain resources for the platform. */ uint32_t reset_domain_count; @@ -61,9 +69,35 @@ struct res_perms_ctx { * memory. */ struct mod_res_agent_permission *agent_permissions; + + /*! + * The list of domain devices in the system. If this is not set then setting + * device permissions for an agent is not supported. + */ + struct mod_res_device *domain_devices; +}; + +struct res_perms_backup { + /*! \brief Power Domain:Resource permissions. */ + mod_res_perms_t *scmi_pd_perms; + + /*! Performance:Resource permissions. */ + mod_res_perms_t *scmi_perf_perms; + + /*! \brief Clock:Resource permissions. */ + mod_res_perms_t *scmi_clock_perms; + + /*! \brief Sensor:Resource permissions. */ + mod_res_perms_t *scmi_sensor_perms; + +#ifdef BUILD_HAS_SCMI_RESET + /*! \brief Reset Domain:Resource permissions. */ + mod_res_perms_t *scmi_reset_domain_perms; +#endif }; static struct res_perms_ctx res_perms_ctx; +static struct res_perms_backup res_perms_backup; /* * Map the agent-id to the corresponding index in the table. @@ -649,10 +683,601 @@ static enum mod_res_perms_permissions agent_resource_permissions( return MOD_RES_PERMS_ACCESS_ALLOWED; } +/* + * Set the permissions for an agent:device. + */ +static int set_agent_resource_message_perms( + uint32_t agent_id, + uint32_t protocol_id, + uint32_t message_idx, + uint32_t resource_id, + mod_res_perms_t *perms, + enum mod_res_perms_permissions flags) +{ + int status; + int32_t resource_idx; + mod_res_perms_t permissions; + + status = mod_res_resource_id_to_index( + agent_id, protocol_id, message_idx, resource_id, &resource_idx); + if (status != FWK_SUCCESS) + return status; + + permissions = perms[resource_idx]; + + flags = + ((flags == 0) ? MOD_RES_PERMS_ACCESS_DENIED : + MOD_RES_PERMS_ACCESS_ALLOWED); + + if (flags == MOD_RES_PERMS_ACCESS_ALLOWED) + permissions &= ~(1 << (MOD_RES_PERMS_RESOURCE_BIT(resource_id))); + else + permissions |= (1 << (MOD_RES_PERMS_RESOURCE_BIT(resource_id))); + + perms[resource_idx] = permissions; + + return FWK_SUCCESS; +} + +static int set_agent_resource_pd_permissions( + uint32_t agent_id, + uint32_t resource_id, + enum mod_res_perms_permissions flags) +{ + int status; + int32_t message_idx; + + if (res_perms_ctx.agent_permissions->scmi_pd_perms == NULL) + return FWK_SUCCESS; + if (resource_id >= res_perms_ctx.pd_count) + return FWK_E_ACCESS; + + /* Do a backup before making the changes if required */ + if ((res_perms_ctx.config->pd_cmd_count != 0) && + (res_perms_ctx.config->pd_resource_count != 0) && + (res_perms_backup.scmi_pd_perms == NULL)) { + res_perms_backup.scmi_pd_perms = (mod_res_perms_t *)fwk_mm_alloc( + res_perms_ctx.agent_count * res_perms_ctx.config->pd_cmd_count * + res_perms_ctx.config->pd_resource_count, + sizeof(mod_res_perms_t)); + memcpy( + res_perms_backup.scmi_pd_perms, + res_perms_ctx.agent_permissions->scmi_pd_perms, + res_perms_ctx.agent_count * res_perms_ctx.config->pd_cmd_count * + res_perms_ctx.config->pd_resource_count * + sizeof(mod_res_perms_t)); + } + + for (message_idx = MOD_SCMI_PD_POWER_DOMAIN_ATTRIBUTES; + message_idx <= MOD_SCMI_PD_POWER_STATE_NOTIFY; + message_idx++) { + status = set_agent_resource_message_perms( + agent_id, + MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN, + message_idx, + resource_id, + res_perms_ctx.agent_permissions->scmi_pd_perms, + flags); + + if (status != FWK_SUCCESS) + return status; + } + + return FWK_SUCCESS; +} + +static int set_agent_resource_perf_permissions( + uint32_t agent_id, + uint32_t resource_id, + enum mod_res_perms_permissions flags) +{ + int status; + int32_t message_idx; + + if (res_perms_ctx.agent_permissions->scmi_perf_perms == NULL) + return FWK_SUCCESS; + if (resource_id >= res_perms_ctx.perf_count) + return FWK_E_ACCESS; + + /* Do a backup before making the changes if required */ + if ((res_perms_ctx.config->perf_cmd_count != 0) && + (res_perms_ctx.config->perf_resource_count != 0) && + (res_perms_backup.scmi_perf_perms == NULL)) { + res_perms_backup.scmi_perf_perms = (mod_res_perms_t *)fwk_mm_alloc( + res_perms_ctx.agent_count * res_perms_ctx.config->perf_cmd_count * + res_perms_ctx.config->perf_resource_count, + sizeof(mod_res_perms_t)); + memcpy( + res_perms_backup.scmi_perf_perms, + res_perms_ctx.agent_permissions->scmi_perf_perms, + res_perms_ctx.agent_count * res_perms_ctx.config->perf_cmd_count * + res_perms_ctx.config->perf_resource_count * + sizeof(mod_res_perms_t)); + } + + for (message_idx = MOD_SCMI_PERF_DOMAIN_ATTRIBUTES; + message_idx <= MOD_SCMI_PERF_DESCRIBE_FAST_CHANNEL; + message_idx++) { + status = set_agent_resource_message_perms( + agent_id, + MOD_SCMI_PROTOCOL_ID_PERF, + message_idx, + resource_id, + res_perms_ctx.agent_permissions->scmi_perf_perms, + flags); + + if (status != FWK_SUCCESS) + return status; + } + + return FWK_SUCCESS; +} + +static int set_agent_resource_clock_permissions( + uint32_t agent_id, + uint32_t resource_id, + enum mod_res_perms_permissions flags) +{ + int status; + int32_t message_idx; + + if (res_perms_ctx.agent_permissions->scmi_clock_perms == NULL) + return FWK_SUCCESS; + if (resource_id >= res_perms_ctx.clock_count) + return FWK_E_ACCESS; + + /* Do a backup before making the changes if required */ + if ((res_perms_ctx.config->clock_cmd_count != 0) && + (res_perms_ctx.config->clock_resource_count != 0) && + (res_perms_backup.scmi_clock_perms == NULL)) { + res_perms_backup.scmi_clock_perms = (mod_res_perms_t *)fwk_mm_alloc( + res_perms_ctx.agent_count * res_perms_ctx.config->clock_cmd_count * + res_perms_ctx.config->clock_resource_count, + sizeof(mod_res_perms_t)); + memcpy( + res_perms_backup.scmi_clock_perms, + res_perms_ctx.agent_permissions->scmi_clock_perms, + res_perms_ctx.agent_count * res_perms_ctx.config->clock_cmd_count * + res_perms_ctx.config->clock_resource_count * + sizeof(mod_res_perms_t)); + } + + for (message_idx = MOD_SCMI_CLOCK_ATTRIBUTES; + message_idx <= MOD_SCMI_CLOCK_CONFIG_SET; + message_idx++) { + status = set_agent_resource_message_perms( + agent_id, + MOD_SCMI_PROTOCOL_ID_CLOCK, + message_idx, + resource_id, + res_perms_ctx.agent_permissions->scmi_clock_perms, + flags); + + if (status != FWK_SUCCESS) + return status; + } + + return FWK_SUCCESS; +} + +#ifdef BUILD_HAS_SCMI_RESET + +static int set_agent_resource_reset_permissions( + uint32_t agent_id, + uint32_t resource_id, + enum mod_res_perms_permissions flags) +{ + int status; + int32_t message_idx; + + if (res_perms_ctx.agent_permissions->scmi_reset_perms == NULL) + return FWK_SUCCESS; + if (resource_id >= res_perms_ctx.reset_domain_count) + return FWK_E_ACCESS; + + /* Do a backup before making the changes if required */ + if ((res_perms_ctx.config->reset_domain_cmd_count != 0) && + (res_perms_ctx.config->reset_domain_resource_count != 0) && + (res_perms_backup.scmi_reset_domain_perms == NULL)) { + res_perms_backup.scmi_reset_domain_perms = + (mod_res_perms_t *)fwk_mm_alloc( + res_perms_ctx.agent_count * + res_perms_ctx.config->reset_domain_cmd_count * + res_perms_ctx.config->reset_domain_resource_count, + sizeof(mod_res_perms_t)); + memcpy( + res_perms_backup.scmi_reset_domain_perms, + res_perms_ctx.agent_permissions->scmi_reset_domain_perms, + res_perms_ctx.agent_count * + res_perms_ctx.config->reset_domain_cmd_count * + res_perms_ctx.config->reset_domain_cmd_count * + sizeof(mod_res_perms_t)); + } + + for (message_idx = MOD_SCMI_RESET_DOMAIN_ATTRIBUTES; + message_idx <= MOD_SCMI_RESET_NOTIFY; + message_idx++) { + status = set_agent_resource_message_perms( + agent_id, + MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN, + message_idx, + resource_id, + res_perms_ctx.agent_permissions->scmi_reset_domain_perms, + flags); + + if (status != FWK_SUCCESS) + return status; + } + + return FWK_SUCCESS; +} + +#endif + +static int set_agent_resource_sensor_permissions( + uint32_t agent_id, + uint32_t resource_id, + enum mod_res_perms_permissions flags) +{ + int status; + int32_t message_idx; + + if (res_perms_ctx.agent_permissions->scmi_sensor_perms == NULL) + return FWK_SUCCESS; + if (resource_id >= res_perms_ctx.sensor_count) + return FWK_E_ACCESS; + + /* Do a backup before making the changes if required */ + if ((res_perms_ctx.config->sensor_cmd_count != 0) && + (res_perms_ctx.config->sensor_resource_count != 0) && + (res_perms_backup.scmi_sensor_perms == NULL)) { + res_perms_backup.scmi_sensor_perms = (mod_res_perms_t *)fwk_mm_alloc( + res_perms_ctx.agent_count * res_perms_ctx.config->sensor_cmd_count * + res_perms_ctx.config->sensor_resource_count, + sizeof(mod_res_perms_t)); + memcpy( + res_perms_backup.scmi_sensor_perms, + res_perms_ctx.agent_permissions->scmi_sensor_perms, + res_perms_ctx.agent_count * res_perms_ctx.config->sensor_cmd_count * + res_perms_ctx.config->sensor_resource_count * + sizeof(mod_res_perms_t)); + } + + for (message_idx = MOD_SCMI_SENSOR_DESCRIPTION_GET; + message_idx <= MOD_SCMI_SENSOR_READING_GET; + message_idx++) { + status = set_agent_resource_message_perms( + agent_id, + MOD_SCMI_PROTOCOL_ID_SENSOR, + message_idx, + resource_id, + res_perms_ctx.agent_permissions->scmi_sensor_perms, + flags); + + if (status != FWK_SUCCESS) + return status; + } + + return FWK_SUCCESS; +} + +static int mod_res_agent_set_permissions( + enum mod_res_domain_device_types type, + uint32_t agent_id, + uint32_t resource_id, + enum mod_res_perms_permissions flags) +{ + int status; + + switch (type) { + case MOD_RES_POWER_DOMAIN_DEVICE: + status = + set_agent_resource_pd_permissions(agent_id, resource_id, flags); + break; + + case MOD_RES_PERF_DOMAIN_DEVICE: + status = + set_agent_resource_perf_permissions(agent_id, resource_id, flags); + break; + + case MOD_RES_CLOCK_DOMAIN_DEVICE: + status = + set_agent_resource_clock_permissions(agent_id, resource_id, flags); + break; + + case MOD_RES_SENSOR_DOMAIN_DEVICE: + status = + set_agent_resource_sensor_permissions(agent_id, resource_id, flags); + break; + +#ifdef BUILD_HAS_SCMI_RESET + case MOD_RES_RESET_DOMAIN_DEVICE: + status = + set_agent_resource_reset_permissions(agent_id, resource_id, flags); + break; +#endif + + default: + status = FWK_E_ACCESS; + break; + } + + if (status != FWK_SUCCESS) + FWK_LOG_WARN( + "[perms] set_permissions for agent %d type %d device %d failed\n", + (int)agent_id, + (int)type, + (int)resource_id); + + return status; +} + +static int mod_res_agent_set_device_permission( + uint32_t agent_id, + uint32_t device_id, + uint32_t flags) +{ + struct mod_res_domain_device *dev; + uint32_t resource_id; + int status; + uint32_t i; + + /* No device permissons */ + if ((res_perms_ctx.device_count == 0) || + (res_perms_ctx.domain_devices == NULL)) + return FWK_E_ACCESS; + + if (device_id >= res_perms_ctx.device_count) + return FWK_E_PARAM; + + if ((flags != 0) && (flags != 1)) + return FWK_E_PARAM; + + /* Find device */ + for (i = 0; i < res_perms_ctx.device_count; i++) { + if (res_perms_ctx.domain_devices[i].device_id == device_id) + break; + } + + if (i == res_perms_ctx.device_count) + return FWK_E_ACCESS; + + dev = res_perms_ctx.domain_devices[i].domain_devices; + while (dev->type != MOD_RES_DOMAIN_DEVICE_INVALID) { + if (fwk_id_is_equal(dev->device_id, FWK_ID_NONE)) + return FWK_SUCCESS; + + resource_id = fwk_id_get_element_idx(dev->device_id); + + status = mod_res_agent_set_permissions( + dev->type, agent_id, resource_id, flags); + + if (status != FWK_SUCCESS) + FWK_LOG_WARN( + "[perms] set_permissions for agent %d device %d failed\n", + (int)agent_id, + (int)i); + + /* next domain device */ + dev++; + }; + + return FWK_SUCCESS; +} + +/* + * Set the permissions for an agent:device:protocol. + */ +static int mod_res_agent_set_device_protocol_permission( + uint32_t agent_id, + uint32_t device_id, + uint32_t protocol_id, + uint32_t flags) +{ + enum mod_res_domain_device_types dev_type; + struct mod_res_domain_device *dev; + uint32_t resource_id; + int status; + uint32_t i; + + /* No device permissons */ + if ((res_perms_ctx.device_count == 0) || + (res_perms_ctx.domain_devices == NULL)) + return FWK_E_ACCESS; + + if (device_id >= res_perms_ctx.device_count) + return FWK_E_PARAM; + + if ((flags != 0) && (flags != 1)) + return FWK_E_PARAM; + + /* Find device */ + for (i = 0; i < res_perms_ctx.device_count; i++) { + if (res_perms_ctx.domain_devices[i].device_id == device_id) + break; + } + + if (i == res_perms_ctx.device_count) + return FWK_E_ACCESS; + + switch (protocol_id) { + case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN: + dev_type = MOD_RES_POWER_DOMAIN_DEVICE; + break; + case MOD_SCMI_PROTOCOL_ID_PERF: + dev_type = MOD_RES_PERF_DOMAIN_DEVICE; + break; + case MOD_SCMI_PROTOCOL_ID_CLOCK: + dev_type = MOD_RES_CLOCK_DOMAIN_DEVICE; + break; + case MOD_SCMI_PROTOCOL_ID_SENSOR: + dev_type = MOD_RES_SENSOR_DOMAIN_DEVICE; + break; + case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN: + dev_type = MOD_RES_RESET_DOMAIN_DEVICE; + break; + default: + case MOD_SCMI_PROTOCOL_ID_BASE: + case MOD_SCMI_PROTOCOL_ID_SYS_POWER: + return FWK_E_ACCESS; + } + + dev = res_perms_ctx.domain_devices[i].domain_devices; + while (dev->type != MOD_RES_DOMAIN_DEVICE_INVALID) { + if (fwk_id_is_equal(dev->device_id, FWK_ID_NONE)) + return FWK_SUCCESS; + + if (dev->type != dev_type) { + dev++; + continue; + } + + resource_id = fwk_id_get_element_idx(dev->device_id); + + status = mod_res_agent_set_permissions( + dev->type, agent_id, resource_id, flags); + + if (status != FWK_SUCCESS) + FWK_LOG_WARN( + "[perms] set_permissions for agent %d device %d failed\n", + (int)agent_id, + (int)i); + + /* next domain device */ + dev++; + }; + + return FWK_SUCCESS; +} + +/* + * Reset the permissions for an agent to the default configuration. + * Note that we only save and restore the permissions for protocols + * which have set _cmd_count and _resource_count + * in the platform config data. Also, the backup copies of the + * permissions are not cleared after they are restored, the backup may + * be re-used for any future reset requests. + */ +static void mod_res_agent_copy_config( + uint32_t agent_id, + mod_res_perms_t *perms, + mod_res_perms_t *backup_perms, + uint32_t protocol_id) +{ + int cmd_count; + int resource_count; + int32_t resource_idx; + int i, j; + int status; + + switch (protocol_id) { + case MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN: + cmd_count = MOD_SCMI_PD_POWER_COMMAND_COUNT; + resource_count = res_perms_ctx.config->pd_resource_count; + break; + case MOD_SCMI_PROTOCOL_ID_PERF: + cmd_count = MOD_SCMI_PERF_COMMAND_COUNT; + resource_count = res_perms_ctx.config->perf_resource_count; + break; + case MOD_SCMI_PROTOCOL_ID_CLOCK: + cmd_count = MOD_SCMI_CLOCK_COMMAND_COUNT; + resource_count = res_perms_ctx.config->clock_resource_count; + break; + case MOD_SCMI_PROTOCOL_ID_SENSOR: + cmd_count = MOD_SCMI_SENSOR_COMMAND_COUNT; + resource_count = res_perms_ctx.config->sensor_resource_count; + break; +#ifdef BUILD_HAS_SCMI_RESET + case MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN: + cmd_count = MOD_SCMI_RESET_DOMAIN_COMMAND_COUNT; + resource_count = res_perms_ctx.config->reset_domainresource_count; + break; +#endif + default: + return; + } + + for (i = 3; i < cmd_count; i++) { /* commands < 3 are excluded */ + for (j = 0; j < resource_count; j++) { + status = mod_res_resource_id_to_index( + agent_id, + protocol_id, + i, /* message id */ + j, /* resource id */ + &resource_idx); + if ((status != FWK_SUCCESS) || (resource_idx < 0)) + continue; + perms[resource_idx] = backup_perms[resource_idx]; + } + } +} + +static int mod_res_agent_reset_config(uint32_t agent_id, uint32_t flags) +{ + /* No device permissons */ + if ((res_perms_ctx.device_count == 0) || + (res_perms_ctx.domain_devices == NULL)) + return FWK_E_ACCESS; + + if (flags == 0) + return FWK_SUCCESS; + + if (agent_id >= res_perms_ctx.agent_count) + return FWK_E_ACCESS; + + if (res_perms_backup.scmi_pd_perms != NULL) { + mod_res_agent_copy_config( + agent_id, + res_perms_ctx.agent_permissions->scmi_pd_perms, + res_perms_backup.scmi_pd_perms, + MOD_SCMI_PROTOCOL_ID_POWER_DOMAIN); + } + + if (res_perms_backup.scmi_perf_perms != NULL) { + mod_res_agent_copy_config( + agent_id, + res_perms_ctx.agent_permissions->scmi_perf_perms, + res_perms_backup.scmi_perf_perms, + MOD_SCMI_PROTOCOL_ID_PERF); + } + + if (res_perms_backup.scmi_clock_perms != NULL) { + mod_res_agent_copy_config( + agent_id, + res_perms_ctx.agent_permissions->scmi_clock_perms, + res_perms_backup.scmi_clock_perms, + MOD_SCMI_PROTOCOL_ID_CLOCK); + } + + if (res_perms_backup.scmi_sensor_perms != NULL) { + mod_res_agent_copy_config( + agent_id, + res_perms_ctx.agent_permissions->scmi_sensor_perms, + res_perms_backup.scmi_sensor_perms, + MOD_SCMI_PROTOCOL_ID_SENSOR); + } + +#ifdef BUILD_HAS_SCMI_RESET + if (res_perms_backup.scmi_reset_domain_perms != NULL) { + mod_res_agent_copy_config( + agent_id, + res_perms_ctx.agent_permissions->scmi_reset_domain_perms, + res_perms_backup.scmi_reset_domain_perms, + MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN); + } +#endif + + return FWK_SUCCESS; +} + static const struct mod_res_permissions_api res_perms_api = { .agent_has_protocol_permission = agent_protocol_permissions, .agent_has_message_permission = agent_message_permissions, .agent_has_resource_permission = agent_resource_permissions, + .agent_set_device_permission = mod_res_agent_set_device_permission, + .agent_set_device_protocol_permission = + mod_res_agent_set_device_protocol_permission, + .agent_reset_config = mod_res_agent_reset_config, }; /* @@ -691,11 +1316,14 @@ static int mod_res_perms_resources_init( res_perms_ctx.sensor_count = config->sensor_count; res_perms_ctx.pd_count = config->pd_count; res_perms_ctx.perf_count = config->perf_count; + res_perms_ctx.device_count = config->device_count; #ifdef BUILD_HAS_SCMI_RESET res_perms_ctx.reset_domain_count = config->reset_domain_count; #endif + res_perms_ctx.domain_devices = + (struct mod_res_device *)config->domain_devices; } - + res_perms_ctx.config = config; return FWK_SUCCESS; } diff --git a/module/scmi/include/internal/scmi_base.h b/module/scmi/include/internal/scmi_base.h index 07b414b54b2ba699d206893635bc1fe866da4c05..a89cf5807bbfefde6cfe051531ba8eea0067a8e0 100644 --- a/module/scmi/include/internal/scmi_base.h +++ b/module/scmi/include/internal/scmi_base.h @@ -76,4 +76,43 @@ struct __attribute((packed)) scmi_base_discover_agent_p2a { char name[16]; }; +/* + * BASE_SET_DEVICE_PERMISSIONS + */ +struct __attribute((packed)) scmi_base_set_device_permissions_a2p { + uint32_t agent_id; + uint32_t device_id; + uint32_t flags; +}; + +struct __attribute((packed)) scmi_base_set_device_permissions_p2a { + int32_t status; +}; + +/* + * BASE_SET_PROTOCOL_PERMISSIONS + */ +struct __attribute((packed)) scmi_base_set_protocol_permissions_a2p { + uint32_t agent_id; + uint32_t device_id; + uint32_t command_id; + uint32_t flags; +}; + +struct __attribute((packed)) scmi_base_set_protocol_permissions_p2a { + int32_t status; +}; + +/* + * BASE_RESET_AGENT_CONFIG + */ +struct __attribute((packed)) scmi_base_reset_agent_config_a2p { + uint32_t agent_id; + uint32_t flags; +}; + +struct __attribute((packed)) scmi_base_reset_agent_config_p2a { + int32_t status; +}; + #endif /* INTERNAL_SCMI_BASE_H */ diff --git a/module/scmi/include/mod_scmi_std.h b/module/scmi/include/mod_scmi_std.h index 3398e5fbc2e8a8a6c4f20566ef96731a6243ef76..9a05ddd65d83efc177686e25004197bb1a7cb030 100644 --- a/module/scmi/include/mod_scmi_std.h +++ b/module/scmi/include/mod_scmi_std.h @@ -88,6 +88,9 @@ enum scmi_base_command_id { MOD_SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x006, MOD_SCMI_BASE_DISCOVER_AGENT = 0x007, MOD_SCMI_BASE_NOTIFY_ERRORS = 0x008, + MOD_SCMI_BASE_SET_DEVICE_PERMISSIONS = 0x009, + MOD_SCMI_BASE_SET_PROTOCOL_PERMISSIONS = 0x00A, + MOD_SCMI_BASE_RESET_AGENT_CONFIG = 0x00B, MOD_SCMI_BASE_COMMAND_COUNT, }; diff --git a/module/scmi/src/mod_scmi.c b/module/scmi/src/mod_scmi.c index 6f382ee19cbce42844e231eb7185d656c6020f34..76e30eeabd46b06c9f9ddd016cd43c80de784b35 100644 --- a/module/scmi/src/mod_scmi.c +++ b/module/scmi/src/mod_scmi.c @@ -95,6 +95,17 @@ static int scmi_base_discover_list_protocols_handler( fwk_id_t service_id, const uint32_t *payload); static int scmi_base_discover_agent_handler( fwk_id_t service_id, const uint32_t *payload); +#ifdef BUILD_HAS_RESOURCE_PERMISSIONS +static int scmi_base_set_device_permissions( + fwk_id_t service_id, + const uint32_t *payload); +static int scmi_base_set_protocol_permissions( + fwk_id_t service_id, + const uint32_t *payload); +static int scmi_base_reset_agent_config( + fwk_id_t service_id, + const uint32_t *payload); +#endif static int (*const base_handler_table[])(fwk_id_t, const uint32_t *) = { [MOD_SCMI_PROTOCOL_VERSION] = scmi_base_protocol_version_handler, @@ -102,13 +113,18 @@ static int (*const base_handler_table[])(fwk_id_t, const uint32_t *) = { [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = scmi_base_protocol_message_attributes_handler, [MOD_SCMI_BASE_DISCOVER_VENDOR] = scmi_base_discover_vendor_handler, - [MOD_SCMI_BASE_DISCOVER_SUB_VENDOR] = - scmi_base_discover_sub_vendor_handler, + [MOD_SCMI_BASE_DISCOVER_SUB_VENDOR] = scmi_base_discover_sub_vendor_handler, [MOD_SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION] = scmi_base_discover_implementation_version_handler, [MOD_SCMI_BASE_DISCOVER_LIST_PROTOCOLS] = scmi_base_discover_list_protocols_handler, [MOD_SCMI_BASE_DISCOVER_AGENT] = scmi_base_discover_agent_handler, +#ifdef BUILD_HAS_RESOURCE_PERMISSIONS + [MOD_SCMI_BASE_SET_DEVICE_PERMISSIONS] = scmi_base_set_device_permissions, + [MOD_SCMI_BASE_SET_PROTOCOL_PERMISSIONS] = + scmi_base_set_protocol_permissions, + [MOD_SCMI_BASE_RESET_AGENT_CONFIG] = scmi_base_reset_agent_config, +#endif }; static const unsigned int base_payload_size_table[] = { @@ -123,6 +139,14 @@ static const unsigned int base_payload_size_table[] = { sizeof(struct scmi_base_discover_list_protocols_a2p), [MOD_SCMI_BASE_DISCOVER_AGENT] = sizeof(struct scmi_base_discover_agent_a2p), +#ifdef BUILD_HAS_RESOURCE_PERMISSIONS + [MOD_SCMI_BASE_SET_DEVICE_PERMISSIONS] = + sizeof(struct scmi_base_set_device_permissions_a2p), + [MOD_SCMI_BASE_SET_PROTOCOL_PERMISSIONS] = + sizeof(struct scmi_base_set_protocol_permissions_a2p), + [MOD_SCMI_BASE_RESET_AGENT_CONFIG] = + sizeof(struct scmi_base_reset_agent_config_a2p), +#endif }; static const char * const default_agent_names[] = { @@ -639,6 +663,189 @@ exit: } #ifdef BUILD_HAS_RESOURCE_PERMISSIONS + +/* + * BASE_SET_DEVICE_PERMISSIONS + */ +static int scmi_base_set_device_permissions( + fwk_id_t service_id, + const uint32_t *payload) +{ + const struct scmi_base_set_device_permissions_a2p *parameters; + struct scmi_base_set_device_permissions_p2a return_values = { + .status = SCMI_NOT_FOUND, + }; + int status = FWK_SUCCESS; + + parameters = (const struct scmi_base_set_device_permissions_a2p *)payload; + + if (parameters->agent_id > scmi_ctx.config->agent_count) { + status = FWK_E_ACCESS; + goto exit; + } + + if (parameters->agent_id == MOD_SCMI_PLATFORM_ID) { + return_values.status = SCMI_SUCCESS; + goto exit; + } + + if (parameters->flags & ~MOD_RES_PERMS_PERMISSIONS_MASK) { + return_values.status = SCMI_INVALID_PARAMETERS; + status = FWK_E_PARAM; + goto exit; + } + + status = scmi_ctx.res_perms_api->agent_set_device_permission( + parameters->agent_id, parameters->device_id, parameters->flags); + + switch (status) { + case FWK_SUCCESS: + return_values.status = SCMI_SUCCESS; + break; + case FWK_E_PARAM: + return_values.status = SCMI_INVALID_PARAMETERS; + break; + case FWK_E_ACCESS: + return_values.status = SCMI_NOT_FOUND; + break; + default: + return_values.status = SCMI_NOT_SUPPORTED; + break; + } + +exit: + respond( + service_id, + &return_values, + (return_values.status == SCMI_SUCCESS) ? sizeof(return_values) : + sizeof(return_values.status)); + + return status; +} + +/* + * BASE_SET_PROTOCOL_PERMISSIONS + */ +static int scmi_base_set_protocol_permissions( + fwk_id_t service_id, + const uint32_t *payload) +{ + const struct scmi_base_set_protocol_permissions_a2p *parameters; + struct scmi_base_set_protocol_permissions_p2a return_values = { + .status = SCMI_NOT_FOUND, + }; + int status = FWK_SUCCESS; + + parameters = (const struct scmi_base_set_protocol_permissions_a2p *)payload; + + if (parameters->agent_id > scmi_ctx.config->agent_count) { + status = FWK_E_ACCESS; + goto exit; + } + + if (parameters->agent_id == MOD_SCMI_PLATFORM_ID) { + return_values.status = SCMI_SUCCESS; + goto exit; + } + + if (parameters->flags & ~MOD_RES_PERMS_PERMISSIONS_MASK) { + status = FWK_E_PARAM; + return_values.status = SCMI_INVALID_PARAMETERS; + goto exit; + } + + if (parameters->command_id == MOD_SCMI_PROTOCOL_ID_BASE) { + return_values.status = SCMI_DENIED; + goto exit; + } + + status = scmi_ctx.res_perms_api->agent_set_device_protocol_permission( + parameters->agent_id, + parameters->device_id, + parameters->command_id, + parameters->flags); + + switch (status) { + case FWK_SUCCESS: + return_values.status = SCMI_SUCCESS; + break; + case FWK_E_PARAM: + return_values.status = SCMI_INVALID_PARAMETERS; + break; + case FWK_E_ACCESS: + return_values.status = SCMI_NOT_FOUND; + break; + default: + return_values.status = SCMI_NOT_SUPPORTED; + break; + } + +exit: + respond( + service_id, + &return_values, + (return_values.status == SCMI_SUCCESS) ? sizeof(return_values) : + sizeof(return_values.status)); + + return status; +} + +/* + * BASE_RESET_AGENT_CONFIG + */ +static int scmi_base_reset_agent_config( + fwk_id_t service_id, + const uint32_t *payload) +{ + const struct scmi_base_reset_agent_config_a2p *parameters; + struct scmi_base_reset_agent_config_p2a return_values = { + .status = SCMI_NOT_FOUND, + }; + int status; + + parameters = (const struct scmi_base_reset_agent_config_a2p *)payload; + + if (parameters->agent_id > scmi_ctx.config->agent_count) + goto exit; + + if (parameters->agent_id == MOD_SCMI_PLATFORM_ID) { + return_values.status = SCMI_SUCCESS; + goto exit; + } + + if (parameters->flags & ~MOD_RES_PERMS_PERMISSIONS_MASK) { + return_values.status = SCMI_INVALID_PARAMETERS; + goto exit; + } + + status = scmi_ctx.res_perms_api->agent_reset_config( + parameters->agent_id, parameters->flags); + + switch (status) { + case FWK_SUCCESS: + return_values.status = SCMI_SUCCESS; + break; + case FWK_E_PARAM: + return_values.status = SCMI_INVALID_PARAMETERS; + break; + case FWK_E_ACCESS: + return_values.status = SCMI_NOT_FOUND; + break; + default: + return_values.status = SCMI_NOT_SUPPORTED; + break; + } + +exit: + respond( + service_id, + &return_values, + (return_values.status == SCMI_SUCCESS) ? sizeof(return_values) : + sizeof(return_values.status)); + + return FWK_SUCCESS; +} + /* * SCMI Resource Permissions handler */ @@ -670,6 +877,7 @@ static int scmi_base_permissions_handler( else return FWK_E_ACCESS; } + #endif static int scmi_base_message_handler(fwk_id_t protocol_id, fwk_id_t service_id, diff --git a/product/juno/scp_ramfw/config_resource_perms.c b/product/juno/scp_ramfw/config_resource_perms.c index eaf984b491f89de9a299e96a502e4f98d816d7d9..03c51d6f02680cfd3ff843fbec49ac13a55a6ab9 100644 --- a/product/juno/scp_ramfw/config_resource_perms.c +++ b/product/juno/scp_ramfw/config_resource_perms.c @@ -7,6 +7,7 @@ #include "config_dvfs.h" #include "config_power_domain.h" +#include "config_resource_perms.h" #include "config_sensor.h" #include "juno_clock.h" #include "juno_scmi.h" @@ -325,6 +326,164 @@ static struct mod_res_agent_permission agent_permissions = { #endif }; +/* + * Juno Platform devices + * + * Note that a device must be terminated with + * {FWK_ID_NONE, MOD_RES_DOMAIN_DEVICE_INVALID} + * + */ +static struct mod_res_domain_device devices_cpu[] = { + { + .device_id = + FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SCMI_PERF, DVFS_ELEMENT_IDX_BIG), + .type = MOD_RES_PERF_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_CLOCK, + JUNO_CLOCK_IDX_BIGCLK), + .type = MOD_RES_CLOCK_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_BIG_CPU0), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_BIG_CPU1), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_BIG_SSTOP), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_PERF, + DVFS_ELEMENT_IDX_LITTLE), + .type = MOD_RES_PERF_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_CLOCK, + JUNO_CLOCK_IDX_LITTLECLK), + .type = MOD_RES_CLOCK_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_LITTLE_CPU0), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_LITTLE_CPU1), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_LITTLE_CPU2), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_LITTLE_CPU3), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_LITTLE_SSTOP), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_NONE_INIT, + .type = MOD_RES_DOMAIN_DEVICE_INVALID, + }, +}; + +static struct mod_res_domain_device devices_gpu[] = { + { + .device_id = + FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SCMI_PERF, DVFS_ELEMENT_IDX_GPU), + .type = MOD_RES_PERF_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_CLOCK, + JUNO_CLOCK_IDX_GPUCLK), + .type = MOD_RES_CLOCK_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_POWER_DOMAIN, + POWER_DOMAIN_IDX_GPUTOP), + .type = MOD_RES_POWER_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_NONE_INIT, + .type = MOD_RES_DOMAIN_DEVICE_INVALID, + }, +}; + +static struct mod_res_domain_device devices_io[] = { + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_CLOCK, + JUNO_CLOCK_IDX_HDLCD0), + .type = MOD_RES_CLOCK_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_CLOCK, + JUNO_CLOCK_IDX_HDLCD1), + .type = MOD_RES_CLOCK_DOMAIN_DEVICE, + }, + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_SCMI_CLOCK, + JUNO_CLOCK_IDX_I2SCLK), + .type = MOD_RES_CLOCK_DOMAIN_DEVICE, + }, +#ifdef BUILD_HAS_SCMI_RESET + { + .device_id = FWK_ID_ELEMENT_INIT( + FWK_MODULE_IDX_RESET_DOMAIN, + JUNO_RESET_DOMAIN_IDX_UART), + .type = MOD_RES_RESET_DOMAIN_DEVICE, + }, +#endif + { + .device_id = FWK_ID_NONE_INIT, + .type = MOD_RES_DOMAIN_DEVICE_INVALID, + }, +}; + +static struct mod_res_device juno_devices[] = { + { + .device_id = JUNO_RES_PERMS_DEVICES_CPU, + .domain_devices = devices_cpu, + }, + { + .device_id = JUNO_RES_PERMS_DEVICES_GPU, + .domain_devices = devices_gpu, + }, + { + .device_id = JUNO_RES_PERMS_DEVICES_IO, + .domain_devices = devices_io, + }, + { 0 }, +}; + struct fwk_module_config config_resource_perms = { .data = &(struct mod_res_resource_perms_config){ @@ -335,8 +494,12 @@ struct fwk_module_config config_resource_perms = { .sensor_count = MOD_JUNO_R0_SENSOR_IDX_COUNT, .pd_count = POWER_DOMAIN_IDX_COUNT, .perf_count = DVFS_ELEMENT_IDX_COUNT, + .perf_cmd_count = JUNO_PERF_RESOURCE_CMDS, + .perf_resource_count = JUNO_PERF_RESOURCE_ELEMENTS, + .device_count = JUNO_RES_PERMS_DEVICES_COUNT, #ifdef BUILD_HAS_SCMI_RESET .reset_domain_count = JUNO_RESET_DOMAIN_IDX_COUNT, #endif + .domain_devices = (uintptr_t)&juno_devices, }, }; diff --git a/product/juno/scp_ramfw/config_resource_perms.h b/product/juno/scp_ramfw/config_resource_perms.h new file mode 100644 index 0000000000000000000000000000000000000000..303687c20df70c97b8704dba766236616be63234 --- /dev/null +++ b/product/juno/scp_ramfw/config_resource_perms.h @@ -0,0 +1,18 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CONFIG_RESOURCE_PERMS_H +#define CONFIG_RESOURCE_PERMS_H + +enum juno_res_perms_devices { + JUNO_RES_PERMS_DEVICES_CPU = 0, + JUNO_RES_PERMS_DEVICES_GPU, + JUNO_RES_PERMS_DEVICES_IO, + JUNO_RES_PERMS_DEVICES_COUNT +}; + +#endif /* CONFIG_RESOURCE_PERMS_H */