From 32ca8ffd5b282da8f4767680ac8b440f73ad41b5 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 12 Apr 2019 12:54:43 -0400 Subject: [PATCH] firmware: ti_sci: Add support for firewall management TI-SCI message protocol provides support for controlling the firewall configurations available in SoC. Introduce support for the set of TI-SCI message protocol APIs that provide us with this capability of controlling firewalls. Signed-off-by: Andrew F. Davis Reviewed-by: Tom Rini Reviewed-by: Andreas Dannenberg --- drivers/firmware/ti_sci.c | 177 +++++++++++++++++++++++++++++++++ drivers/firmware/ti_sci.h | 121 ++++++++++++++++++++++ include/linux/soc/ti/ti_sci_protocol.h | 64 ++++++++++++ 3 files changed, 362 insertions(+) diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index d47d22f..44bbeb6 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -2428,6 +2428,178 @@ fail: return ret; } +/** + * ti_sci_cmd_set_fwl_region() - Request for configuring a firewall region + * @handle: pointer to TI SCI handle + * @region: region configuration parameters + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_set_fwl_region(const struct ti_sci_handle *handle, + const struct ti_sci_msg_fwl_region *region) +{ + struct ti_sci_msg_fwl_set_firewall_region_req req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + + xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_SET, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + (u32 *)&req, sizeof(req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(info->dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + req.fwl_id = region->fwl_id; + req.region = region->region; + req.n_permission_regs = region->n_permission_regs; + req.control = region->control; + req.permissions[0] = region->permissions[0]; + req.permissions[1] = region->permissions[1]; + req.permissions[2] = region->permissions[2]; + req.start_address = region->start_address; + req.end_address = region->end_address; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(info->dev, "Mbox send fail %d\n", ret); + return ret; + } + + resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; + + if (!ti_sci_is_response_ack(resp)) + return -ENODEV; + + return 0; +} + +/** + * ti_sci_cmd_get_fwl_region() - Request for getting a firewall region + * @handle: pointer to TI SCI handle + * @region: region configuration parameters + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_get_fwl_region(const struct ti_sci_handle *handle, + struct ti_sci_msg_fwl_region *region) +{ + struct ti_sci_msg_fwl_get_firewall_region_req req; + struct ti_sci_msg_fwl_get_firewall_region_resp *resp; + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + + xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_GET, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + (u32 *)&req, sizeof(req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(info->dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + req.fwl_id = region->fwl_id; + req.region = region->region; + req.n_permission_regs = region->n_permission_regs; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(info->dev, "Mbox send fail %d\n", ret); + return ret; + } + + resp = (struct ti_sci_msg_fwl_get_firewall_region_resp *)xfer->tx_message.buf; + + if (!ti_sci_is_response_ack(resp)) + return -ENODEV; + + region->fwl_id = resp->fwl_id; + region->region = resp->region; + region->n_permission_regs = resp->n_permission_regs; + region->control = resp->control; + region->permissions[0] = resp->permissions[0]; + region->permissions[1] = resp->permissions[1]; + region->permissions[2] = resp->permissions[2]; + region->start_address = resp->start_address; + region->end_address = resp->end_address; + + return 0; +} + +/** + * ti_sci_cmd_change_fwl_owner() - Request for changing a firewall owner + * @handle: pointer to TI SCI handle + * @region: region configuration parameters + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_change_fwl_owner(const struct ti_sci_handle *handle, + struct ti_sci_msg_fwl_owner *owner) +{ + struct ti_sci_msg_fwl_change_owner_info_req req; + struct ti_sci_msg_fwl_change_owner_info_resp *resp; + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + + xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_GET, + TISCI_MSG_FWL_CHANGE_OWNER, + (u32 *)&req, sizeof(req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(info->dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + req.fwl_id = owner->fwl_id; + req.region = owner->region; + req.owner_index = owner->owner_index; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(info->dev, "Mbox send fail %d\n", ret); + return ret; + } + + resp = (struct ti_sci_msg_fwl_change_owner_info_resp *)xfer->tx_message.buf; + + if (!ti_sci_is_response_ack(resp)) + return -ENODEV; + + owner->fwl_id = resp->fwl_id; + owner->region = resp->region; + owner->owner_index = resp->owner_index; + owner->owner_privid = resp->owner_privid; + owner->owner_permission_bits = resp->owner_permission_bits; + + return ret; +} + /* * ti_sci_setup_ops() - Setup the operations structures * @info: pointer to TISCI pointer @@ -2444,6 +2616,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops; struct ti_sci_rm_psil_ops *psilops = &ops->rm_psil_ops; struct ti_sci_rm_udmap_ops *udmap_ops = &ops->rm_udmap_ops; + struct ti_sci_fwl_ops *fwl_ops = &ops->fwl_ops; bops->board_config = ti_sci_cmd_set_board_config; bops->board_config_rm = ti_sci_cmd_set_board_config_rm; @@ -2501,6 +2674,10 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) udmap_ops->tx_ch_cfg = ti_sci_cmd_rm_udmap_tx_ch_cfg; udmap_ops->rx_ch_cfg = ti_sci_cmd_rm_udmap_rx_ch_cfg; udmap_ops->rx_flow_cfg = ti_sci_cmd_rm_udmap_rx_flow_cfg; + + fwl_ops->set_fwl_region = ti_sci_cmd_set_fwl_region; + fwl_ops->get_fwl_region = ti_sci_cmd_get_fwl_region; + fwl_ops->change_fwl_owner = ti_sci_cmd_change_fwl_owner; } /** diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 2d87cdd..1b601ff 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -79,6 +79,10 @@ #define TISCI_MSG_RM_UDMAP_FLOW_GET_CFG 0x1232 #define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_GET_CFG 0x1233 +#define TISCI_MSG_FWL_SET 0x9000 +#define TISCI_MSG_FWL_GET 0x9001 +#define TISCI_MSG_FWL_CHANGE_OWNER 0x9002 + /** * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses * @type: Type of messages: One of TI_SCI_MSG* values @@ -1338,4 +1342,121 @@ struct ti_sci_msg_rm_udmap_flow_cfg_resp { struct ti_sci_msg_hdr hdr; } __packed; +#define FWL_MAX_PRIVID_SLOTS 3U + +/** + * struct ti_sci_msg_fwl_set_firewall_region_req - Request for configuring the firewall permissions. + * + * @hdr: Generic Header + * + * @fwl_id: Firewall ID in question + * @region: Region or channel number to set config info + * This field is unused in case of a simple firewall and must be initialized + * to zero. In case of a region based firewall, this field indicates the + * region in question. (index starting from 0) In case of a channel based + * firewall, this field indicates the channel in question (index starting + * from 0) + * @n_permission_regs: Number of permission registers to set + * @control: Contents of the firewall CONTROL register to set + * @permissions: Contents of the firewall PERMISSION register to set + * @start_address: Contents of the firewall START_ADDRESS register to set + * @end_address: Contents of the firewall END_ADDRESS register to set + */ + +struct ti_sci_msg_fwl_set_firewall_region_req { + struct ti_sci_msg_hdr hdr; + u16 fwl_id; + u16 region; + u32 n_permission_regs; + u32 control; + u32 permissions[FWL_MAX_PRIVID_SLOTS]; + u64 start_address; + u64 end_address; +} __packed; + +/** + * struct ti_sci_msg_fwl_get_firewall_region_req - Request for retrieving the firewall permissions + * + * @hdr: Generic Header + * + * @fwl_id: Firewall ID in question + * @region: Region or channel number to get config info + * This field is unused in case of a simple firewall and must be initialized + * to zero. In case of a region based firewall, this field indicates the + * region in question (index starting from 0). In case of a channel based + * firewall, this field indicates the channel in question (index starting + * from 0). + * @n_permission_regs: Number of permission registers to retrieve + */ +struct ti_sci_msg_fwl_get_firewall_region_req { + struct ti_sci_msg_hdr hdr; + u16 fwl_id; + u16 region; + u32 n_permission_regs; +} __packed; + +/** + * struct ti_sci_msg_fwl_get_firewall_region_resp - Response for retrieving the firewall permissions + * + * @hdr: Generic Header + * + * @fwl_id: Firewall ID in question + * @region: Region or channel number to set config info This field is + * unused in case of a simple firewall and must be initialized to zero. In + * case of a region based firewall, this field indicates the region in + * question. (index starting from 0) In case of a channel based firewall, this + * field indicates the channel in question (index starting from 0) + * @n_permission_regs: Number of permission registers retrieved + * @control: Contents of the firewall CONTROL register + * @permissions: Contents of the firewall PERMISSION registers + * @start_address: Contents of the firewall START_ADDRESS register This is not applicable for channelized firewalls. + * @end_address: Contents of the firewall END_ADDRESS register This is not applicable for channelized firewalls. + */ +struct ti_sci_msg_fwl_get_firewall_region_resp { + struct ti_sci_msg_hdr hdr; + u16 fwl_id; + u16 region; + u32 n_permission_regs; + u32 control; + u32 permissions[FWL_MAX_PRIVID_SLOTS]; + u64 start_address; + u64 end_address; +} __packed; + +/** + * struct ti_sci_msg_fwl_change_owner_info_req - Request for a firewall owner change + * + * @hdr: Generic Header + * + * @fwl_id: Firewall ID in question + * @region: Region or channel number if applicable + * @owner_index: New owner index to transfer ownership to + */ +struct ti_sci_msg_fwl_change_owner_info_req { + struct ti_sci_msg_hdr hdr; + u16 fwl_id; + u16 region; + u8 owner_index; +} __packed; + +/** + * struct ti_sci_msg_fwl_change_owner_info_resp - Response for a firewall owner change + * + * @hdr: Generic Header + * + * @fwl_id: Firewall ID specified in request + * @region: Region or channel number specified in request + * @owner_index: Owner index specified in request + * @owner_privid: New owner priv-ID returned by DMSC. + * @owner_permission_bits: New owner permission bits returned by DMSC. + */ +struct ti_sci_msg_fwl_change_owner_info_resp { + struct ti_sci_msg_hdr hdr; + u16 fwl_id; + u16 region; + u8 owner_index; + u8 owner_privid; + u16 owner_permission_bits; +} __packed; + #endif /* __TI_SCI_H */ diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index 222cf66..895cb1b 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -511,6 +511,68 @@ struct ti_sci_rm_udmap_ops { }; /** + * struct ti_sci_msg_fwl_region_cfg - Request and Response for firewalls settings + * + * @fwl_id: Firewall ID in question + * @region: Region or channel number to set config info + * This field is unused in case of a simple firewall and must be initialized + * to zero. In case of a region based firewall, this field indicates the + * region in question. (index starting from 0) In case of a channel based + * firewall, this field indicates the channel in question (index starting + * from 0) + * @n_permission_regs: Number of permission registers to set + * @control: Contents of the firewall CONTROL register to set + * @permissions: Contents of the firewall PERMISSION register to set + * @start_address: Contents of the firewall START_ADDRESS register to set + * @end_address: Contents of the firewall END_ADDRESS register to set + */ +struct ti_sci_msg_fwl_region { + u16 fwl_id; + u16 region; + u32 n_permission_regs; + u32 control; + u32 permissions[3]; + u64 start_address; + u64 end_address; +} __packed; + +/** + * \brief Request and Response for firewall owner change + * + * @fwl_id: Firewall ID in question + * @region: Region or channel number to set config info + * This field is unused in case of a simple firewall and must be initialized + * to zero. In case of a region based firewall, this field indicates the + * region in question. (index starting from 0) In case of a channel based + * firewall, this field indicates the channel in question (index starting + * from 0) + * @n_permission_regs: Number of permission registers <= 3 + * @control: Control register value for this region + * @owner_index: New owner index to change to. Owner indexes are setup in DMSC firmware boot configuration data + * @owner_privid: New owner priv-id, used to lookup owner_index is not known, must be set to zero otherwise + * @owner_permission_bits: New owner permission bits + */ +struct ti_sci_msg_fwl_owner { + u16 fwl_id; + u16 region; + u8 owner_index; + u8 owner_privid; + u16 owner_permission_bits; +} __packed; + +/** + * struct ti_sci_fwl_ops - Firewall specific operations + * @set_fwl_region: Request for configuring the firewall permissions. + * @get_fwl_region: Request for retrieving the firewall permissions. + * @change_fwl_owner: Request for a change of firewall owner. + */ +struct ti_sci_fwl_ops { + int (*set_fwl_region)(const struct ti_sci_handle *handle, const struct ti_sci_msg_fwl_region *region); + int (*get_fwl_region)(const struct ti_sci_handle *handle, struct ti_sci_msg_fwl_region *region); + int (*change_fwl_owner)(const struct ti_sci_handle *handle, struct ti_sci_msg_fwl_owner *owner); +}; + +/** * struct ti_sci_ops - Function support for TI SCI * @board_ops: Miscellaneous operations * @dev_ops: Device specific operations @@ -518,6 +580,7 @@ struct ti_sci_rm_udmap_ops { * @core_ops: Core specific operations * @proc_ops: Processor specific operations * @ring_ops: Ring Accelerator Management operations + * @fw_ops: Firewall specific operations */ struct ti_sci_ops { struct ti_sci_board_ops board_ops; @@ -529,6 +592,7 @@ struct ti_sci_ops { struct ti_sci_rm_ringacc_ops rm_ring_ops; struct ti_sci_rm_psil_ops rm_psil_ops; struct ti_sci_rm_udmap_ops rm_udmap_ops; + struct ti_sci_fwl_ops fwl_ops; }; /** -- 2.7.4