diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-06-08 21:37:14 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-06-08 21:37:14 +0200 |
| commit | 579f9786b7cd3b73eb99fe2c17c67bc03c1f14d8 (patch) | |
| tree | a66c8ed7dcce1c8f067017dd4a11d2ba6e5999b9 | |
| parent | 8b98f9f42e80f5ba7eded99bd72faea437ec7c56 (diff) | |
| parent | 71e6a19fe2669faf7dcb96ba8a4fde927485e60e (diff) | |
| download | lwn-579f9786b7cd3b73eb99fe2c17c67bc03c1f14d8.tar.gz lwn-579f9786b7cd3b73eb99fe2c17c67bc03c1f14d8.zip | |
Merge tag 'svc_updates_for_v7.2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux into char-misc-next
Dinh writes:
SoCFPGA firmware updates for v7.2
- Simplify service driver memory management by using a flexible array
- Change FCS call to get provision data to asynchronous
- Avoid blocking the call the reboot_image sysfs when busy
- Add support to query the ATF version
* tag 'svc_updates_for_v7.2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux:
firmware: stratix10-svc: Add support to query Arm Trusted Firmware (ATF) version
firmware: stratix10-rsu: avoid blocking reboot_image sysfs when busy
firmware: stratix10-svc: change get provision data to async SMC call
firmware: stratix10-svc: kmalloc_array + kzalloc to flex
| -rw-r--r-- | drivers/firmware/stratix10-rsu.c | 85 | ||||
| -rw-r--r-- | drivers/firmware/stratix10-svc.c | 98 | ||||
| -rw-r--r-- | include/linux/firmware/intel/stratix10-smc.h | 31 | ||||
| -rw-r--r-- | include/linux/firmware/intel/stratix10-svc-client.h | 7 |
4 files changed, 153 insertions, 68 deletions
diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c index e1912108a0fe..018a933943fb 100644 --- a/drivers/firmware/stratix10-rsu.c +++ b/drivers/firmware/stratix10-rsu.c @@ -244,27 +244,26 @@ static void rsu_async_get_spt_table_callback(struct device *dev, } /** - * rsu_send_msg() - send a message to Intel service layer + * __rsu_send_msg_locked() - send a message to Intel service layer * @priv: pointer to rsu private data * @command: RSU status or update command * @arg: the request argument, the bitstream address or notify status * @callback: function pointer for the callback (status or update) * - * Start an Intel service layer transaction to perform the SMC call that - * is necessary to get RSU boot log or set the address of bitstream to - * boot after reboot. + * Perform the actual SMC transaction. The caller must hold @priv->lock. * - * Returns 0 on success or -ETIMEDOUT on error. + * Returns 0 on success or a negative errno on failure. */ -static int rsu_send_msg(struct stratix10_rsu_priv *priv, - enum stratix10_svc_command_code command, - unsigned long arg, - rsu_callback callback) +static int __rsu_send_msg_locked(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) { struct stratix10_svc_client_msg msg; int ret; - mutex_lock(&priv->lock); + lockdep_assert_held(&priv->lock); + reinit_completion(&priv->completion); priv->client.receive_cb = callback; @@ -293,6 +292,59 @@ static int rsu_send_msg(struct stratix10_rsu_priv *priv, status_done: stratix10_svc_done(priv->chan); + return ret; +} + +/** + * rsu_send_msg() - send a message to Intel service layer + * @priv: pointer to rsu private data + * @command: RSU status or update command + * @arg: the request argument, the bitstream address or notify status + * @callback: function pointer for the callback (status or update) + * + * Start an Intel service layer transaction to perform the SMC call that + * is necessary to get RSU boot log or set the address of bitstream to + * boot after reboot. This call will block until the RSU lock can be + * acquired. + * + * Returns 0 on success or a negative errno on failure. + */ +static int rsu_send_msg(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) +{ + int ret; + + mutex_lock(&priv->lock); + ret = __rsu_send_msg_locked(priv, command, arg, callback); + mutex_unlock(&priv->lock); + return ret; +} + +/** + * rsu_try_send_msg() - non-blocking variant of rsu_send_msg() + * @priv: pointer to rsu private data + * @command: RSU status or update command + * @arg: the request argument, the bitstream address or notify status + * @callback: function pointer for the callback (status or update) + * + * Same as rsu_send_msg() but returns -EBUSY immediately when another + * RSU operation is already in flight, instead of waiting for the lock. + * + * Returns 0 on success, -EBUSY if the RSU is busy, or another negative + * errno on failure. + */ +static int rsu_try_send_msg(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) +{ + int ret; + + if (!mutex_trylock(&priv->lock)) + return -EBUSY; + ret = __rsu_send_msg_locked(priv, command, arg, callback); mutex_unlock(&priv->lock); return ret; } @@ -595,8 +647,17 @@ static ssize_t reboot_image_store(struct device *dev, if (ret) return ret; - ret = rsu_send_msg(priv, COMMAND_RSU_UPDATE, - address, rsu_command_callback); + /* + * Use the non-blocking variant so a write to this sysfs attribute + * does not stall the caller while another RSU operation is in + * flight. Userspace can retry on -EBUSY. + */ + ret = rsu_try_send_msg(priv, COMMAND_RSU_UPDATE, + address, rsu_command_callback); + if (ret == -EBUSY) { + dev_dbg(dev, "RSU busy, reboot_image write rejected\n"); + return ret; + } if (ret) { dev_err(dev, "Error, RSU update returned %i\n", ret); return ret; diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index e9e35d67ef96..00e134e663c8 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -241,9 +241,33 @@ struct stratix10_async_ctrl { }; /** + * struct stratix10_svc_chan - service communication channel + * @ctrl: pointer to service controller which is the provider of this channel + * @scl: pointer to service client which owns the channel + * @name: service client name associated with the channel + * @task: pointer to the thread task which handles SMC or HVC call + * @svc_fifo: a queue for storing service message data (separate fifo for every channel) + * @svc_fifo_lock: protect access to service message data queue (locking pending fifo) + * @lock: protect access to the channel + * @async_chan: reference to asynchronous channel object for this channel + * + * This struct is used by service client to communicate with service layer. + * Each service client has its own channel created by service controller. + */ +struct stratix10_svc_chan { + struct stratix10_svc_controller *ctrl; + struct stratix10_svc_client *scl; + char *name; + struct task_struct *task; + struct kfifo svc_fifo; + spinlock_t svc_fifo_lock; + spinlock_t lock; + struct stratix10_async_chan *async_chan; +}; + +/** * struct stratix10_svc_controller - service controller * @dev: device - * @chans: array of service channels * @num_chans: number of channels in 'chans' array * @num_active_client: number of active service client * @node: list management @@ -253,13 +277,13 @@ struct stratix10_async_ctrl { * @svc: manages the list of client svc drivers * @sdm_lock: only allows a single command single response to SDM * @actrl: async control structure + * @chans: array of service channels * * This struct is used to create communication channels for service clients, to * handle secure monitor or hypervisor call. */ struct stratix10_svc_controller { struct device *dev; - struct stratix10_svc_chan *chans; int num_chans; int num_active_client; struct list_head node; @@ -269,31 +293,7 @@ struct stratix10_svc_controller { struct stratix10_svc *svc; struct mutex sdm_lock; struct stratix10_async_ctrl actrl; -}; - -/** - * struct stratix10_svc_chan - service communication channel - * @ctrl: pointer to service controller which is the provider of this channel - * @scl: pointer to service client which owns the channel - * @name: service client name associated with the channel - * @task: pointer to the thread task which handles SMC or HVC call - * @svc_fifo: a queue for storing service message data (separate fifo for every channel) - * @svc_fifo_lock: protect access to service message data queue (locking pending fifo) - * @lock: protect access to the channel - * @async_chan: reference to asynchronous channel object for this channel - * - * This struct is used by service client to communicate with service layer. - * Each service client has its own channel created by service controller. - */ -struct stratix10_svc_chan { - struct stratix10_svc_controller *ctrl; - struct stratix10_svc_client *scl; - char *name; - struct task_struct *task; - struct kfifo svc_fifo; - spinlock_t svc_fifo_lock; - spinlock_t lock; - struct stratix10_async_chan *async_chan; + struct stratix10_svc_chan chans[] __counted_by(num_chans); }; static LIST_HEAD(svc_ctrl); @@ -463,6 +463,7 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data, case COMMAND_FCS_SEND_CERTIFICATE: case COMMAND_FCS_DATA_ENCRYPTION: case COMMAND_FCS_DATA_DECRYPTION: + case COMMAND_FCS_GET_PROVISION_DATA: cb_data->status = BIT(SVC_STATUS_OK); break; case COMMAND_RECONFIG_DATA_SUBMIT: @@ -485,13 +486,18 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data, cb_data->kaddr1 = &res.a1; cb_data->kaddr2 = &res.a2; break; + case COMMAND_SMC_ATF_BUILD_VER: + cb_data->status = BIT(SVC_STATUS_OK); + cb_data->kaddr1 = &res.a1; + cb_data->kaddr2 = &res.a2; + cb_data->kaddr3 = &res.a3; + break; case COMMAND_RSU_DCMF_VERSION: cb_data->status = BIT(SVC_STATUS_OK); cb_data->kaddr1 = &res.a1; cb_data->kaddr2 = &res.a2; break; case COMMAND_FCS_RANDOM_NUMBER_GEN: - case COMMAND_FCS_GET_PROVISION_DATA: case COMMAND_POLL_SERVICE_STATUS: cb_data->status = BIT(SVC_STATUS_OK); cb_data->kaddr1 = &res.a1; @@ -674,7 +680,7 @@ static int svc_normal_to_secure_thread(void *data) break; case COMMAND_FCS_GET_PROVISION_DATA: a0 = INTEL_SIP_SMC_FCS_GET_PROVISION_DATA; - a1 = (unsigned long)pdata->paddr; + a1 = 0; a2 = 0; break; /* for HWMON */ @@ -704,6 +710,12 @@ static int svc_normal_to_secure_thread(void *data) a1 = 0; a2 = 0; break; + case COMMAND_SMC_ATF_BUILD_VER: + a0 = INTEL_SIP_SMC_ATF_BUILD_VER; + a1 = 0; + a2 = 0; + a3 = 0; + break; case COMMAND_MBOX_SEND_CMD: a0 = INTEL_SIP_SMC_MBOX_SEND_CMD; a1 = pdata->arg[0]; @@ -1901,7 +1913,6 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct stratix10_svc_controller *controller; - struct stratix10_svc_chan *chans; struct gen_pool *genpool; struct stratix10_svc_sh_memory *sh_memory; struct stratix10_svc *svc = NULL; @@ -1929,23 +1940,16 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) return PTR_ERR(genpool); /* allocate service controller and supporting channel */ - controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL); + controller = devm_kzalloc(dev, struct_size(controller, chans, SVC_NUM_CHANNEL), + GFP_KERNEL); if (!controller) { ret = -ENOMEM; goto err_destroy_pool; } - chans = devm_kmalloc_array(dev, SVC_NUM_CHANNEL, - sizeof(*chans), GFP_KERNEL | __GFP_ZERO); - if (!chans) { - ret = -ENOMEM; - goto err_destroy_pool; - } - - controller->dev = dev; controller->num_chans = SVC_NUM_CHANNEL; + controller->dev = dev; controller->num_active_client = 0; - controller->chans = chans; controller->genpool = genpool; controller->invoke_fn = invoke_fn; INIT_LIST_HEAD(&controller->node); @@ -1962,16 +1966,16 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) mutex_init(&controller->sdm_lock); for (i = 0; i < SVC_NUM_CHANNEL; i++) { - chans[i].scl = NULL; - chans[i].ctrl = controller; - chans[i].name = (char *)chan_names[i]; - spin_lock_init(&chans[i].lock); - ret = kfifo_alloc(&chans[i].svc_fifo, fifo_size, GFP_KERNEL); + controller->chans[i].scl = NULL; + controller->chans[i].ctrl = controller; + controller->chans[i].name = (char *)chan_names[i]; + spin_lock_init(&controller->chans[i].lock); + ret = kfifo_alloc(&controller->chans[i].svc_fifo, fifo_size, GFP_KERNEL); if (ret) { dev_err(dev, "failed to allocate FIFO %d\n", i); goto err_free_fifos; } - spin_lock_init(&chans[i].svc_fifo_lock); + spin_lock_init(&controller->chans[i].svc_fifo_lock); } list_add_tail(&controller->node, &svc_ctrl); @@ -2015,7 +2019,7 @@ err_free_fifos: list_del(&controller->node); /* free only the FIFOs that were successfully allocated */ while (i--) - kfifo_free(&chans[i].svc_fifo); + kfifo_free(&controller->chans[i].svc_fifo); stratix10_svc_async_exit(controller); err_destroy_pool: gen_pool_destroy(genpool); diff --git a/include/linux/firmware/intel/stratix10-smc.h b/include/linux/firmware/intel/stratix10-smc.h index 935dba3633b5..9116512169dc 100644 --- a/include/linux/firmware/intel/stratix10-smc.h +++ b/include/linux/firmware/intel/stratix10-smc.h @@ -515,6 +515,25 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE) INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_SVC_FUNCID_VERSION) /** + * Request INTEL_SIP_SMC_ATF_BUILD_VER + * + * Sync call used to query the ATF Build Version + * + * Call register usage: + * a0 INTEL_SIP_SMC_ATF_BUILD_VER + * a1-a7 not used + * + * Return status: + * a0 INTEL_SIP_SMC_STATUS_OK + * a1 Major + * a2 Minor + * a3 Patch + */ +#define INTEL_SIP_SMC_ATF_BUILD_VERSION 155 +#define INTEL_SIP_SMC_ATF_BUILD_VER \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_ATF_BUILD_VERSION) + +/** * SMC call protocol for FPGA Crypto Service (FCS) * FUNCID starts from 90 */ @@ -605,25 +624,21 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE) /** * Request INTEL_SIP_SMC_FCS_GET_PROVISION_DATA - * Sync call to dump all the fuses and key hashes + * Async call to dump all the fuses and key hashes * * Call register usage: * a0 INTEL_SIP_SMC_FCS_GET_PROVISION_DATA - * a1 the physical address for firmware to write structure of fuse and - * key hashes - * a2-a7 not used + * a1-a7 not used * * Return status: * a0 INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FCS_ERROR or * INTEL_SIP_SMC_FCS_REJECTED - * a1 mailbox error - * a2 physical address for the structure of fuse and key hashes - * a3 the size of structure + * a1-a3 not used * */ #define INTEL_SIP_SMC_FUNCID_FCS_GET_PROVISION_DATA 94 #define INTEL_SIP_SMC_FCS_GET_PROVISION_DATA \ - INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FCS_GET_PROVISION_DATA) + INTEL_SIP_SMC_STD_CALL_VAL(INTEL_SIP_SMC_FUNCID_FCS_GET_PROVISION_DATA) /** * Request INTEL_SIP_SMC_HWMON_READTEMP diff --git a/include/linux/firmware/intel/stratix10-svc-client.h b/include/linux/firmware/intel/stratix10-svc-client.h index 91013161e9db..3edd93502bf8 100644 --- a/include/linux/firmware/intel/stratix10-svc-client.h +++ b/include/linux/firmware/intel/stratix10-svc-client.h @@ -154,6 +154,10 @@ struct stratix10_svc_chan; * * @COMMAND_HWMON_READVOLT: query the voltage from the hardware monitor, * return status is SVC_STATUS_OK or SVC_STATUS_ERROR + * + * @COMMAND_SMC_ATF_BUILD_VER: Non-mailbox SMC ATF Build Version, + * return status is SVC_STATUS_OK + * */ enum stratix10_svc_command_code { /* for FPGA */ @@ -187,7 +191,8 @@ enum stratix10_svc_command_code { COMMAND_SMC_SVC_VERSION = 200, /* for HWMON */ COMMAND_HWMON_READTEMP, - COMMAND_HWMON_READVOLT + COMMAND_HWMON_READVOLT, + COMMAND_SMC_ATF_BUILD_VER }; /** |
