Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'socfpga_firmware_updates_for_v6.19' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux into char-misc-next

Dinh writes:

SoCFPGA firmware updates for v6.19
- Add support for voltage and temperature sensor
- Add a mutex to memory operations on Stratix10 service driver
- Add support for asynchronous communications in the service driver
- Replace scnprintf() with sysfs_emit()

* tag 'socfpga_firmware_updates_for_v6.19' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux:
firmware: stratix10-rsu: replace scnprintf() with sysfs_emit() in *_show() functions
firmware: stratix10-rsu: Migrate RSU driver to use stratix10 asynchronous framework.
firmware: stratix10-svc: Add support for RSU commands in asynchronous framework
firmware: stratix10-svc: Add support for async communication
firmware: stratix10-svc: Add mutex in stratix10 memory management
firmware: stratix10-svc: Add definition for voltage and temperature sensor

+1108 -140
+144 -133
drivers/firmware/stratix10-rsu.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 3 * Copyright (C) 2018-2019, Intel Corporation 4 + * Copyright (C) 2025, Altera Corporation 4 5 */ 5 6 6 7 #include <linux/arm-smccc.h> ··· 15 14 #include <linux/firmware/intel/stratix10-svc-client.h> 16 15 #include <linux/string.h> 17 16 #include <linux/sysfs.h> 17 + #include <linux/delay.h> 18 18 19 - #define RSU_STATE_MASK GENMASK_ULL(31, 0) 20 - #define RSU_VERSION_MASK GENMASK_ULL(63, 32) 21 - #define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0) 22 - #define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32) 19 + #define RSU_ERASE_SIZE_MASK GENMASK_ULL(63, 32) 23 20 #define RSU_DCMF0_MASK GENMASK_ULL(31, 0) 24 21 #define RSU_DCMF1_MASK GENMASK_ULL(63, 32) 25 22 #define RSU_DCMF2_MASK GENMASK_ULL(31, 0) ··· 34 35 #define INVALID_DCMF_STATUS 0xFFFFFFFF 35 36 #define INVALID_SPT_ADDRESS 0x0 36 37 37 - #define RSU_GET_SPT_CMD 0x5A 38 + #define RSU_RETRY_SLEEP_MS (1U) 39 + #define RSU_ASYNC_MSG_RETRY (3U) 38 40 #define RSU_GET_SPT_RESP_LEN (4 * sizeof(unsigned int)) 39 41 40 42 typedef void (*rsu_callback)(struct stratix10_svc_client *client, ··· 64 64 * @max_retry: the preset max retry value 65 65 * @spt0_address: address of spt0 66 66 * @spt1_address: address of spt1 67 - * @get_spt_response_buf: response from sdm for get_spt command 68 67 */ 69 68 struct stratix10_rsu_priv { 70 69 struct stratix10_svc_chan *chan; ··· 98 99 99 100 unsigned long spt0_address; 100 101 unsigned long spt1_address; 101 - 102 - unsigned int *get_spt_response_buf; 103 102 }; 104 103 104 + typedef void (*rsu_async_callback)(struct device *dev, 105 + struct stratix10_rsu_priv *priv, struct stratix10_svc_cb_data *data); 106 + 105 107 /** 106 - * rsu_status_callback() - Status callback from Intel Service Layer 107 - * @client: pointer to service client 108 + * rsu_async_status_callback() - Status callback from rsu_async_send() 109 + * @dev: pointer to device object 110 + * @priv: pointer to priv object 108 111 * @data: pointer to callback data structure 109 112 * 110 - * Callback from Intel service layer for RSU status request. Status is 111 - * only updated after a system reboot, so a get updated status call is 112 - * made during driver probe. 113 + * Callback from rsu_async_send() to get the system rsu error status. 113 114 */ 114 - static void rsu_status_callback(struct stratix10_svc_client *client, 115 - struct stratix10_svc_cb_data *data) 115 + static void rsu_async_status_callback(struct device *dev, 116 + struct stratix10_rsu_priv *priv, 117 + struct stratix10_svc_cb_data *data) 116 118 { 117 - struct stratix10_rsu_priv *priv = client->priv; 118 - struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1; 119 + struct arm_smccc_1_2_regs *res = (struct arm_smccc_1_2_regs *)data->kaddr1; 119 120 120 - if (data->status == BIT(SVC_STATUS_OK)) { 121 - priv->status.version = FIELD_GET(RSU_VERSION_MASK, 122 - res->a2); 123 - priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2); 124 - priv->status.fail_image = res->a1; 125 - priv->status.current_image = res->a0; 126 - priv->status.error_location = 127 - FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3); 128 - priv->status.error_details = 129 - FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3); 130 - } else { 131 - dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n", 132 - res->a0); 133 - priv->status.version = 0; 134 - priv->status.state = 0; 135 - priv->status.fail_image = 0; 136 - priv->status.current_image = 0; 137 - priv->status.error_location = 0; 138 - priv->status.error_details = 0; 139 - } 140 - 141 - complete(&priv->completion); 121 + priv->status.current_image = res->a2; 122 + priv->status.fail_image = res->a3; 123 + priv->status.state = res->a4; 124 + priv->status.version = res->a5; 125 + priv->status.error_location = res->a7; 126 + priv->status.error_details = res->a8; 127 + priv->retry_counter = res->a9; 142 128 } 143 129 144 130 /** ··· 147 163 complete(&priv->completion); 148 164 } 149 165 150 - /** 151 - * rsu_retry_callback() - Callback from Intel service layer for getting 152 - * the current image's retry counter from the firmware 153 - * @client: pointer to client 154 - * @data: pointer to callback data structure 155 - * 156 - * Callback from Intel service layer for retry counter, which is used by 157 - * user to know how many times the images is still allowed to reload 158 - * itself before giving up and starting RSU fail-over flow. 159 - */ 160 - static void rsu_retry_callback(struct stratix10_svc_client *client, 161 - struct stratix10_svc_cb_data *data) 162 - { 163 - struct stratix10_rsu_priv *priv = client->priv; 164 - unsigned int *counter = (unsigned int *)data->kaddr1; 165 - 166 - if (data->status == BIT(SVC_STATUS_OK)) 167 - priv->retry_counter = *counter; 168 - else if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 169 - dev_warn(client->dev, "Secure FW doesn't support retry\n"); 170 - else 171 - dev_err(client->dev, "Failed to get retry counter %lu\n", 172 - BIT(data->status)); 173 - 174 - complete(&priv->completion); 175 - } 176 166 177 167 /** 178 168 * rsu_max_retry_callback() - Callback from Intel service layer for getting ··· 228 270 complete(&priv->completion); 229 271 } 230 272 231 - static void rsu_get_spt_callback(struct stratix10_svc_client *client, 232 - struct stratix10_svc_cb_data *data) 273 + /** 274 + * rsu_async_get_spt_table_callback() - Callback to be used by the rsu_async_send() 275 + * to retrieve the SPT table information. 276 + * @dev: pointer to device object 277 + * @priv: pointer to priv object 278 + * @data: pointer to callback data structure 279 + */ 280 + static void rsu_async_get_spt_table_callback(struct device *dev, 281 + struct stratix10_rsu_priv *priv, 282 + struct stratix10_svc_cb_data *data) 233 283 { 234 - struct stratix10_rsu_priv *priv = client->priv; 235 - unsigned long *mbox_err = (unsigned long *)data->kaddr1; 236 - unsigned long *resp_len = (unsigned long *)data->kaddr2; 237 - 238 - if (data->status != BIT(SVC_STATUS_OK) || (*mbox_err) || 239 - (*resp_len != RSU_GET_SPT_RESP_LEN)) 240 - goto error; 241 - 242 - priv->spt0_address = priv->get_spt_response_buf[0]; 243 - priv->spt0_address <<= 32; 244 - priv->spt0_address |= priv->get_spt_response_buf[1]; 245 - 246 - priv->spt1_address = priv->get_spt_response_buf[2]; 247 - priv->spt1_address <<= 32; 248 - priv->spt1_address |= priv->get_spt_response_buf[3]; 249 - 250 - goto complete; 251 - 252 - error: 253 - dev_err(client->dev, "failed to get SPTs\n"); 254 - 255 - complete: 256 - stratix10_svc_free_memory(priv->chan, priv->get_spt_response_buf); 257 - priv->get_spt_response_buf = NULL; 258 - complete(&priv->completion); 284 + priv->spt0_address = *((unsigned long *)data->kaddr1); 285 + priv->spt1_address = *((unsigned long *)data->kaddr2); 259 286 } 260 287 261 288 /** ··· 272 329 if (arg) 273 330 msg.arg[0] = arg; 274 331 275 - if (command == COMMAND_MBOX_SEND_CMD) { 276 - msg.arg[1] = 0; 277 - msg.payload = NULL; 278 - msg.payload_length = 0; 279 - msg.payload_output = priv->get_spt_response_buf; 280 - msg.payload_length_output = RSU_GET_SPT_RESP_LEN; 281 - } 282 - 283 332 ret = stratix10_svc_send(priv->chan, &msg); 284 333 if (ret < 0) 285 334 goto status_done; ··· 294 359 status_done: 295 360 stratix10_svc_done(priv->chan); 296 361 mutex_unlock(&priv->lock); 362 + return ret; 363 + } 364 + 365 + /** 366 + * soc64_async_callback() - Callback from Intel service layer for async requests 367 + * @ptr: pointer to the completion object 368 + */ 369 + static void soc64_async_callback(void *ptr) 370 + { 371 + if (ptr) 372 + complete(ptr); 373 + } 374 + 375 + /** 376 + * rsu_send_async_msg() - send an async message to Intel service layer 377 + * @dev: pointer to device object 378 + * @priv: pointer to rsu private data 379 + * @command: RSU status or update command 380 + * @arg: the request argument, notify status 381 + * @callback: function pointer for the callback (status or update) 382 + */ 383 + static int rsu_send_async_msg(struct device *dev, struct stratix10_rsu_priv *priv, 384 + enum stratix10_svc_command_code command, 385 + unsigned long arg, 386 + rsu_async_callback callback) 387 + { 388 + struct stratix10_svc_client_msg msg = {0}; 389 + struct stratix10_svc_cb_data data = {0}; 390 + struct completion completion; 391 + int status, index, ret; 392 + void *handle = NULL; 393 + 394 + msg.command = command; 395 + msg.arg[0] = arg; 396 + 397 + init_completion(&completion); 398 + 399 + for (index = 0; index < RSU_ASYNC_MSG_RETRY; index++) { 400 + status = stratix10_svc_async_send(priv->chan, &msg, 401 + &handle, soc64_async_callback, 402 + &completion); 403 + if (status == 0) 404 + break; 405 + dev_warn(dev, "Failed to send async message\n"); 406 + msleep(RSU_RETRY_SLEEP_MS); 407 + } 408 + 409 + if (status && !handle) { 410 + dev_err(dev, "Failed to send async message\n"); 411 + return -ETIMEDOUT; 412 + } 413 + 414 + ret = wait_for_completion_io_timeout(&completion, RSU_TIMEOUT); 415 + if (ret > 0) 416 + dev_dbg(dev, "Received async interrupt\n"); 417 + else if (ret == 0) 418 + dev_dbg(dev, "Timeout occurred. Trying to poll the response\n"); 419 + 420 + for (index = 0; index < RSU_ASYNC_MSG_RETRY; index++) { 421 + status = stratix10_svc_async_poll(priv->chan, handle, &data); 422 + if (status == -EAGAIN) { 423 + dev_dbg(dev, "Async message is still in progress\n"); 424 + } else if (status < 0) { 425 + dev_alert(dev, "Failed to poll async message\n"); 426 + ret = -ETIMEDOUT; 427 + } else if (status == 0) { 428 + ret = 0; 429 + break; 430 + } 431 + msleep(RSU_RETRY_SLEEP_MS); 432 + } 433 + 434 + if (ret) { 435 + dev_err(dev, "Failed to get async response\n"); 436 + goto status_done; 437 + } 438 + 439 + if (data.status == 0) { 440 + ret = 0; 441 + if (callback) 442 + callback(dev, priv, &data); 443 + } else { 444 + dev_err(dev, "%s returned 0x%x from SDM\n", __func__, 445 + data.status); 446 + ret = -EFAULT; 447 + } 448 + 449 + status_done: 450 + stratix10_svc_async_done(priv->chan, handle); 297 451 return ret; 298 452 } 299 453 ··· 478 454 if (!priv) 479 455 return -ENODEV; 480 456 481 - return scnprintf(buf, sizeof(priv->max_retry), 482 - "0x%08x\n", priv->max_retry); 457 + return sysfs_emit(buf, "0x%08x\n", priv->max_retry); 483 458 } 484 459 485 460 static ssize_t dcmf0_show(struct device *dev, ··· 620 597 if (ret) 621 598 return ret; 622 599 623 - ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, 624 - status, rsu_command_callback); 600 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL); 625 601 if (ret) { 626 602 dev_err(dev, "Error, RSU notify returned %i\n", ret); 627 603 return ret; 628 604 } 629 605 630 606 /* to get the updated state */ 631 - ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 632 - 0, rsu_status_callback); 607 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0, 608 + rsu_async_status_callback); 633 609 if (ret) { 634 610 dev_err(dev, "Error, getting RSU status %i\n", ret); 635 - return ret; 636 - } 637 - 638 - ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 639 - if (ret) { 640 - dev_err(dev, "Error, getting RSU retry %i\n", ret); 641 611 return ret; 642 612 } 643 613 ··· 648 632 if (priv->spt0_address == INVALID_SPT_ADDRESS) 649 633 return -EIO; 650 634 651 - return scnprintf(buf, PAGE_SIZE, "0x%08lx\n", priv->spt0_address); 635 + return sysfs_emit(buf, "0x%08lx\n", priv->spt0_address); 652 636 } 653 637 654 638 static ssize_t spt1_address_show(struct device *dev, ··· 662 646 if (priv->spt1_address == INVALID_SPT_ADDRESS) 663 647 return -EIO; 664 648 665 - return scnprintf(buf, PAGE_SIZE, "0x%08lx\n", priv->spt1_address); 649 + return sysfs_emit(buf, "0x%08lx\n", priv->spt1_address); 666 650 } 667 651 668 652 static DEVICE_ATTR_RO(current_image); ··· 753 737 return PTR_ERR(priv->chan); 754 738 } 755 739 740 + ret = stratix10_svc_add_async_client(priv->chan, false); 741 + if (ret) { 742 + dev_err(dev, "failed to add async client\n"); 743 + stratix10_svc_free_channel(priv->chan); 744 + return ret; 745 + } 746 + 756 747 init_completion(&priv->completion); 757 748 platform_set_drvdata(pdev, priv); 758 749 759 750 /* get the initial state from firmware */ 760 - ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 761 - 0, rsu_status_callback); 751 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0, 752 + rsu_async_status_callback); 762 753 if (ret) { 763 754 dev_err(dev, "Error, getting RSU status %i\n", ret); 764 755 stratix10_svc_free_channel(priv->chan); ··· 786 763 stratix10_svc_free_channel(priv->chan); 787 764 } 788 765 789 - ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 790 - if (ret) { 791 - dev_err(dev, "Error, getting RSU retry %i\n", ret); 792 - stratix10_svc_free_channel(priv->chan); 793 - } 794 - 795 766 ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0, 796 767 rsu_max_retry_callback); 797 768 if (ret) { ··· 793 776 stratix10_svc_free_channel(priv->chan); 794 777 } 795 778 796 - priv->get_spt_response_buf = 797 - stratix10_svc_allocate_memory(priv->chan, RSU_GET_SPT_RESP_LEN); 798 779 799 - if (IS_ERR(priv->get_spt_response_buf)) { 800 - dev_err(dev, "failed to allocate get spt buffer\n"); 801 - } else { 802 - ret = rsu_send_msg(priv, COMMAND_MBOX_SEND_CMD, 803 - RSU_GET_SPT_CMD, rsu_get_spt_callback); 804 - if (ret) { 805 - dev_err(dev, "Error, getting SPT table %i\n", ret); 806 - stratix10_svc_free_channel(priv->chan); 807 - } 780 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE, 0, 781 + rsu_async_get_spt_table_callback); 782 + if (ret) { 783 + dev_err(dev, "Error, getting SPT table %i\n", ret); 784 + stratix10_svc_free_channel(priv->chan); 808 785 } 809 786 810 787 return ret;
+754 -6
drivers/firmware/stratix10-svc.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 3 * Copyright (C) 2017-2018, Intel Corporation 4 + * Copyright (C) 2025, Altera Corporation 4 5 */ 5 6 7 + #include <linux/atomic.h> 6 8 #include <linux/completion.h> 7 9 #include <linux/delay.h> 8 10 #include <linux/genalloc.h> 11 + #include <linux/hashtable.h> 12 + #include <linux/idr.h> 9 13 #include <linux/io.h> 10 14 #include <linux/kfifo.h> 11 15 #include <linux/kthread.h> ··· 38 34 * timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC. 39 35 */ 40 36 #define SVC_NUM_DATA_IN_FIFO 32 41 - #define SVC_NUM_CHANNEL 3 37 + #define SVC_NUM_CHANNEL 4 42 38 #define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200 43 39 #define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30 44 40 #define BYTE_TO_WORD_SIZE 4 ··· 46 42 /* stratix10 service layer clients */ 47 43 #define STRATIX10_RSU "stratix10-rsu" 48 44 #define INTEL_FCS "intel-fcs" 45 + 46 + /* Maximum number of SDM client IDs. */ 47 + #define MAX_SDM_CLIENT_IDS 16 48 + /* Client ID for SIP Service Version 1. */ 49 + #define SIP_SVC_V1_CLIENT_ID 0x1 50 + /* Maximum number of SDM job IDs. */ 51 + #define MAX_SDM_JOB_IDS 16 52 + /* Number of bits used for asynchronous transaction hashing. */ 53 + #define ASYNC_TRX_HASH_BITS 3 54 + /** 55 + * Total number of transaction IDs, which is a combination of 56 + * client ID and job ID. 57 + */ 58 + #define TOTAL_TRANSACTION_IDS \ 59 + (MAX_SDM_CLIENT_IDS * MAX_SDM_JOB_IDS) 60 + 61 + /* Minimum major version of the ATF for Asynchronous transactions. */ 62 + #define ASYNC_ATF_MINIMUM_MAJOR_VERSION 0x3 63 + /* Minimum minor version of the ATF for Asynchronous transactions.*/ 64 + #define ASYNC_ATF_MINIMUM_MINOR_VERSION 0x0 65 + 66 + /* Job ID field in the transaction ID */ 67 + #define STRATIX10_JOB_FIELD GENMASK(3, 0) 68 + /* Client ID field in the transaction ID */ 69 + #define STRATIX10_CLIENT_FIELD GENMASK(7, 4) 70 + /* Transaction ID mask for Stratix10 service layer */ 71 + #define STRATIX10_TRANS_ID_FIELD GENMASK(7, 0) 72 + 73 + /* Macro to extract the job ID from a transaction ID. */ 74 + #define STRATIX10_GET_JOBID(transaction_id) \ 75 + (FIELD_GET(STRATIX10_JOB_FIELD, transaction_id)) 76 + /* Macro to set the job ID in a transaction ID. */ 77 + #define STRATIX10_SET_JOBID(jobid) \ 78 + (FIELD_PREP(STRATIX10_JOB_FIELD, jobid)) 79 + /* Macro to set the client ID in a transaction ID. */ 80 + #define STRATIX10_SET_CLIENTID(clientid) \ 81 + (FIELD_PREP(STRATIX10_CLIENT_FIELD, clientid)) 82 + /* Macro to set a transaction ID using a client ID and a job ID. */ 83 + #define STRATIX10_SET_TRANSACTIONID(clientid, jobid) \ 84 + (STRATIX10_SET_CLIENTID(clientid) | STRATIX10_SET_JOBID(jobid)) 85 + /* Macro to set a transaction ID for SIP SMC Async transactions */ 86 + #define STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(transaction_id) \ 87 + (FIELD_PREP(STRATIX10_TRANS_ID_FIELD, transaction_id)) 88 + 89 + /* 10-bit mask for extracting the SDM status code */ 90 + #define STRATIX10_SDM_STATUS_MASK GENMASK(9, 0) 91 + /* Macro to get the SDM mailbox error status */ 92 + #define STRATIX10_GET_SDM_STATUS_CODE(status) \ 93 + (FIELD_GET(STRATIX10_SDM_STATUS_MASK, status)) 49 94 50 95 typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long, 51 96 unsigned long, unsigned long, unsigned long, ··· 116 63 * @sync_complete: state for a completion 117 64 * @addr: physical address of shared memory block 118 65 * @size: size of shared memory block 119 - * @invoke_fn: function to issue secure monitor or hypervisor call 66 + * @invoke_fn: service clients to handle secure monitor or hypervisor calls 120 67 * 121 68 * This struct is used to save physical address and size of shared memory 122 69 * block. The shared memory blocked is allocated by secure monitor software ··· 175 122 }; 176 123 177 124 /** 125 + * struct stratix10_svc_async_handler - Asynchronous handler for Stratix10 126 + * service layer 127 + * @transaction_id: Unique identifier for the transaction 128 + * @achan: Pointer to the asynchronous channel structure 129 + * @cb_arg: Argument to be passed to the callback function 130 + * @cb: Callback function to be called upon completion 131 + * @msg: Pointer to the client message structure 132 + * @next: Node in the hash list 133 + * @res: Response structure to store result from the secure firmware 134 + * 135 + * This structure is used to handle asynchronous transactions in the 136 + * Stratix10 service layer. It maintains the necessary information 137 + * for processing and completing asynchronous requests. 138 + */ 139 + 140 + struct stratix10_svc_async_handler { 141 + u8 transaction_id; 142 + struct stratix10_async_chan *achan; 143 + void *cb_arg; 144 + async_callback_t cb; 145 + struct stratix10_svc_client_msg *msg; 146 + struct hlist_node next; 147 + struct arm_smccc_1_2_regs res; 148 + }; 149 + 150 + /** 151 + * struct stratix10_async_chan - Structure representing an asynchronous channel 152 + * @async_client_id: Unique client identifier for the asynchronous operation 153 + * @job_id_pool: Pointer to the job ID pool associated with this channel 154 + */ 155 + 156 + struct stratix10_async_chan { 157 + unsigned long async_client_id; 158 + struct ida job_id_pool; 159 + }; 160 + 161 + /** 162 + * struct stratix10_async_ctrl - Control structure for Stratix10 163 + * asynchronous operations 164 + * @initialized: Flag indicating whether the control structure has 165 + * been initialized 166 + * @invoke_fn: Function pointer for invoking Stratix10 service calls 167 + * to EL3 secure firmware 168 + * @async_id_pool: Pointer to the ID pool used for asynchronous 169 + * operations 170 + * @common_achan_refcount: Atomic reference count for the common 171 + * asynchronous channel usage 172 + * @common_async_chan: Pointer to the common asynchronous channel 173 + * structure 174 + * @trx_list_lock: Spinlock for protecting the transaction list 175 + * operations 176 + * @trx_list: Hash table for managing asynchronous transactions 177 + */ 178 + 179 + struct stratix10_async_ctrl { 180 + bool initialized; 181 + void (*invoke_fn)(struct stratix10_async_ctrl *actrl, 182 + const struct arm_smccc_1_2_regs *args, 183 + struct arm_smccc_1_2_regs *res); 184 + struct ida async_id_pool; 185 + atomic_t common_achan_refcount; 186 + struct stratix10_async_chan *common_async_chan; 187 + /* spinlock to protect trx_list hash table */ 188 + spinlock_t trx_list_lock; 189 + DECLARE_HASHTABLE(trx_list, ASYNC_TRX_HASH_BITS); 190 + }; 191 + 192 + /** 178 193 * struct stratix10_svc_controller - service controller 179 194 * @dev: device 180 195 * @chans: array of service channels ··· 255 134 * @complete_status: state for completion 256 135 * @svc_fifo_lock: protect access to service message data queue 257 136 * @invoke_fn: function to issue secure monitor call or hypervisor call 137 + * @actrl: async control structure 258 138 * 259 139 * This struct is used to create communication channels for service clients, to 260 140 * handle secure monitor or hypervisor call. ··· 272 150 struct completion complete_status; 273 151 spinlock_t svc_fifo_lock; 274 152 svc_invoke_fn *invoke_fn; 153 + struct stratix10_async_ctrl actrl; 275 154 }; 276 155 277 156 /** ··· 281 158 * @scl: pointer to service client which owns the channel 282 159 * @name: service client name associated with the channel 283 160 * @lock: protect access to the channel 161 + * @async_chan: reference to asynchronous channel object for this channel 284 162 * 285 - * This struct is used by service client to communicate with service layer, each 286 - * service client has its own channel created by service controller. 163 + * This struct is used by service client to communicate with service layer. 164 + * Each service client has its own channel created by service controller. 287 165 */ 288 166 struct stratix10_svc_chan { 289 167 struct stratix10_svc_controller *ctrl; 290 168 struct stratix10_svc_client *scl; 291 169 char *name; 292 170 spinlock_t lock; 171 + struct stratix10_async_chan *async_chan; 293 172 }; 294 173 295 174 static LIST_HEAD(svc_ctrl); 296 175 static LIST_HEAD(svc_data_mem); 176 + 177 + /** 178 + * svc_mem_lock protects access to the svc_data_mem list for 179 + * concurrent multi-client operations 180 + */ 181 + static DEFINE_MUTEX(svc_mem_lock); 297 182 298 183 /** 299 184 * svc_pa_to_va() - translate physical address to virtual address ··· 315 184 struct stratix10_svc_data_mem *pmem; 316 185 317 186 pr_debug("claim back P-addr=0x%016x\n", (unsigned int)addr); 187 + guard(mutex)(&svc_mem_lock); 318 188 list_for_each_entry(pmem, &svc_data_mem, node) 319 189 if (pmem->paddr == addr) 320 190 return pmem->vaddr; ··· 473 341 case COMMAND_RSU_MAX_RETRY: 474 342 case COMMAND_RSU_DCMF_STATUS: 475 343 case COMMAND_FIRMWARE_VERSION: 344 + case COMMAND_HWMON_READTEMP: 345 + case COMMAND_HWMON_READVOLT: 476 346 cb_data->status = BIT(SVC_STATUS_OK); 477 347 cb_data->kaddr1 = &res.a1; 478 348 break; ··· 659 525 a1 = (unsigned long)pdata->paddr; 660 526 a2 = 0; 661 527 break; 662 - 528 + /* for HWMON */ 529 + case COMMAND_HWMON_READTEMP: 530 + a0 = INTEL_SIP_SMC_HWMON_READTEMP; 531 + a1 = pdata->arg[0]; 532 + a2 = 0; 533 + break; 534 + case COMMAND_HWMON_READVOLT: 535 + a0 = INTEL_SIP_SMC_HWMON_READVOLT; 536 + a1 = pdata->arg[0]; 537 + a2 = 0; 538 + break; 663 539 /* for polling */ 664 540 case COMMAND_POLL_SERVICE_STATUS: 665 541 a0 = INTEL_SIP_SMC_SERVICE_COMPLETED; ··· 1067 923 EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname); 1068 924 1069 925 /** 926 + * stratix10_svc_add_async_client - Add an asynchronous client to the 927 + * Stratix10 service channel. 928 + * @chan: Pointer to the Stratix10 service channel structure. 929 + * @use_unique_clientid: Boolean flag indicating whether to use a 930 + * unique client ID. 931 + * 932 + * This function adds an asynchronous client to the specified 933 + * Stratix10 service channel. If the `use_unique_clientid` flag is 934 + * set to true, a unique client ID is allocated for the asynchronous 935 + * channel. Otherwise, a common asynchronous channel is used. 936 + * 937 + * Return: 0 on success, or a negative error code on failure: 938 + * -EINVAL if the channel is NULL or the async controller is 939 + * not initialized. 940 + * -EALREADY if the async channel is already allocated. 941 + * -ENOMEM if memory allocation fails. 942 + * Other negative values if ID allocation fails. 943 + */ 944 + int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan, 945 + bool use_unique_clientid) 946 + { 947 + struct stratix10_svc_controller *ctrl; 948 + struct stratix10_async_ctrl *actrl; 949 + struct stratix10_async_chan *achan; 950 + int ret = 0; 951 + 952 + if (!chan) 953 + return -EINVAL; 954 + 955 + ctrl = chan->ctrl; 956 + actrl = &ctrl->actrl; 957 + 958 + if (!actrl->initialized) { 959 + dev_err(ctrl->dev, "Async controller not initialized\n"); 960 + return -EINVAL; 961 + } 962 + 963 + if (chan->async_chan) { 964 + dev_err(ctrl->dev, "async channel already allocated\n"); 965 + return -EALREADY; 966 + } 967 + 968 + if (use_unique_clientid && 969 + atomic_read(&actrl->common_achan_refcount) > 0) { 970 + chan->async_chan = actrl->common_async_chan; 971 + atomic_inc(&actrl->common_achan_refcount); 972 + return 0; 973 + } 974 + 975 + achan = kzalloc(sizeof(*achan), GFP_KERNEL); 976 + if (!achan) 977 + return -ENOMEM; 978 + 979 + ida_init(&achan->job_id_pool); 980 + 981 + ret = ida_alloc_max(&actrl->async_id_pool, MAX_SDM_CLIENT_IDS, 982 + GFP_KERNEL); 983 + if (ret < 0) { 984 + dev_err(ctrl->dev, 985 + "Failed to allocate async client id\n"); 986 + ida_destroy(&achan->job_id_pool); 987 + kfree(achan); 988 + return ret; 989 + } 990 + 991 + achan->async_client_id = ret; 992 + chan->async_chan = achan; 993 + 994 + if (use_unique_clientid && 995 + atomic_read(&actrl->common_achan_refcount) == 0) { 996 + actrl->common_async_chan = achan; 997 + atomic_inc(&actrl->common_achan_refcount); 998 + } 999 + 1000 + return 0; 1001 + } 1002 + EXPORT_SYMBOL_GPL(stratix10_svc_add_async_client); 1003 + 1004 + /** 1005 + * stratix10_svc_remove_async_client - Remove an asynchronous client 1006 + * from the Stratix10 service 1007 + * channel. 1008 + * @chan: Pointer to the Stratix10 service channel structure. 1009 + * 1010 + * This function removes an asynchronous client associated with the 1011 + * given service channel. It checks if the channel and the 1012 + * asynchronous channel are valid, and then proceeds to decrement 1013 + * the reference count for the common asynchronous channel if 1014 + * applicable. If the reference count reaches zero, it destroys the 1015 + * job ID pool and deallocates the asynchronous client ID. For 1016 + * non-common asynchronous channels, it directly destroys the job ID 1017 + * pool, deallocates the asynchronous client ID, and frees the 1018 + * memory allocated for the asynchronous channel. 1019 + * 1020 + * Return: 0 on success, -EINVAL if the channel or asynchronous 1021 + * channel is invalid. 1022 + */ 1023 + int stratix10_svc_remove_async_client(struct stratix10_svc_chan *chan) 1024 + { 1025 + struct stratix10_svc_controller *ctrl; 1026 + struct stratix10_async_ctrl *actrl; 1027 + struct stratix10_async_chan *achan; 1028 + 1029 + if (!chan) 1030 + return -EINVAL; 1031 + 1032 + ctrl = chan->ctrl; 1033 + actrl = &ctrl->actrl; 1034 + achan = chan->async_chan; 1035 + 1036 + if (!achan) { 1037 + dev_err(ctrl->dev, "async channel not allocated\n"); 1038 + return -EINVAL; 1039 + } 1040 + 1041 + if (achan == actrl->common_async_chan) { 1042 + atomic_dec(&actrl->common_achan_refcount); 1043 + if (atomic_read(&actrl->common_achan_refcount) == 0) { 1044 + ida_destroy(&achan->job_id_pool); 1045 + ida_free(&actrl->async_id_pool, 1046 + achan->async_client_id); 1047 + kfree(achan); 1048 + actrl->common_async_chan = NULL; 1049 + } 1050 + } else { 1051 + ida_destroy(&achan->job_id_pool); 1052 + ida_free(&actrl->async_id_pool, achan->async_client_id); 1053 + kfree(achan); 1054 + } 1055 + chan->async_chan = NULL; 1056 + 1057 + return 0; 1058 + } 1059 + EXPORT_SYMBOL_GPL(stratix10_svc_remove_async_client); 1060 + 1061 + /** 1062 + * stratix10_svc_async_send - Send an asynchronous message to the 1063 + * Stratix10 service 1064 + * @chan: Pointer to the service channel structure 1065 + * @msg: Pointer to the message to be sent 1066 + * @handler: Pointer to the handler for the asynchronous message 1067 + * used by caller for later reference. 1068 + * @cb: Callback function to be called upon completion 1069 + * @cb_arg: Argument to be passed to the callback function 1070 + * 1071 + * This function sends an asynchronous message to the SDM mailbox in 1072 + * EL3 secure firmware. It performs various checks and setups, 1073 + * including allocating a job ID, setting up the transaction ID and 1074 + * packaging it to El3 firmware. The function handles different 1075 + * commands by setting up the appropriate arguments for the SMC call. 1076 + * If the SMC call is successful, the handler is set up and the 1077 + * function returns 0. If the SMC call fails, appropriate error 1078 + * handling is performed along with cleanup of resources. 1079 + * 1080 + * Return: 0 on success, -EINVAL for invalid argument, -ENOMEM if 1081 + * memory is not available, -EAGAIN if EL3 firmware is busy, -EBADF 1082 + * if the message is rejected by EL3 firmware and -EIO on other 1083 + * errors from EL3 firmware. 1084 + */ 1085 + int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg, 1086 + void **handler, async_callback_t cb, void *cb_arg) 1087 + { 1088 + struct arm_smccc_1_2_regs args = { 0 }, res = { 0 }; 1089 + struct stratix10_svc_async_handler *handle = NULL; 1090 + struct stratix10_svc_client_msg *p_msg = 1091 + (struct stratix10_svc_client_msg *)msg; 1092 + struct stratix10_svc_controller *ctrl; 1093 + struct stratix10_async_ctrl *actrl; 1094 + struct stratix10_async_chan *achan; 1095 + int ret = 0; 1096 + 1097 + if (!chan || !msg || !handler) 1098 + return -EINVAL; 1099 + 1100 + achan = chan->async_chan; 1101 + ctrl = chan->ctrl; 1102 + actrl = &ctrl->actrl; 1103 + 1104 + if (!actrl->initialized) { 1105 + dev_err(ctrl->dev, "Async controller not initialized\n"); 1106 + return -EINVAL; 1107 + } 1108 + 1109 + if (!achan) { 1110 + dev_err(ctrl->dev, "Async channel not allocated\n"); 1111 + return -EINVAL; 1112 + } 1113 + 1114 + handle = kzalloc(sizeof(*handle), GFP_KERNEL); 1115 + if (!handle) 1116 + return -ENOMEM; 1117 + 1118 + ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS, 1119 + GFP_KERNEL); 1120 + if (ret < 0) { 1121 + dev_err(ctrl->dev, "Failed to allocate job id\n"); 1122 + kfree(handle); 1123 + return -ENOMEM; 1124 + } 1125 + 1126 + handle->transaction_id = 1127 + STRATIX10_SET_TRANSACTIONID(achan->async_client_id, ret); 1128 + handle->cb = cb; 1129 + handle->msg = p_msg; 1130 + handle->cb_arg = cb_arg; 1131 + handle->achan = achan; 1132 + 1133 + /*set the transaction jobid in args.a1*/ 1134 + args.a1 = 1135 + STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id); 1136 + 1137 + switch (p_msg->command) { 1138 + case COMMAND_RSU_GET_SPT_TABLE: 1139 + args.a0 = INTEL_SIP_SMC_ASYNC_RSU_GET_SPT; 1140 + break; 1141 + case COMMAND_RSU_STATUS: 1142 + args.a0 = INTEL_SIP_SMC_ASYNC_RSU_GET_ERROR_STATUS; 1143 + break; 1144 + case COMMAND_RSU_NOTIFY: 1145 + args.a0 = INTEL_SIP_SMC_ASYNC_RSU_NOTIFY; 1146 + args.a2 = p_msg->arg[0]; 1147 + break; 1148 + default: 1149 + dev_err(ctrl->dev, "Invalid command ,%d\n", p_msg->command); 1150 + ret = -EINVAL; 1151 + goto deallocate_id; 1152 + } 1153 + 1154 + /** 1155 + * There is a chance that during the execution of async_send() 1156 + * in one core, an interrupt might be received in another core; 1157 + * to mitigate this we are adding the handle to the DB and then 1158 + * send the smc call. If the smc call is rejected or busy then 1159 + * we will deallocate the handle for the client to retry again. 1160 + */ 1161 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1162 + hash_add(actrl->trx_list, &handle->next, 1163 + handle->transaction_id); 1164 + } 1165 + 1166 + actrl->invoke_fn(actrl, &args, &res); 1167 + 1168 + switch (res.a0) { 1169 + case INTEL_SIP_SMC_STATUS_OK: 1170 + dev_dbg(ctrl->dev, 1171 + "Async message sent with transaction_id 0x%02x\n", 1172 + handle->transaction_id); 1173 + *handler = handle; 1174 + return 0; 1175 + case INTEL_SIP_SMC_STATUS_BUSY: 1176 + dev_warn(ctrl->dev, "Mailbox is busy, try after some time\n"); 1177 + ret = -EAGAIN; 1178 + break; 1179 + case INTEL_SIP_SMC_STATUS_REJECTED: 1180 + dev_err(ctrl->dev, "Async message rejected\n"); 1181 + ret = -EBADF; 1182 + break; 1183 + default: 1184 + dev_err(ctrl->dev, 1185 + "Failed to send async message ,got status as %ld\n", 1186 + res.a0); 1187 + ret = -EIO; 1188 + } 1189 + 1190 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1191 + hash_del(&handle->next); 1192 + } 1193 + 1194 + deallocate_id: 1195 + ida_free(&achan->job_id_pool, 1196 + STRATIX10_GET_JOBID(handle->transaction_id)); 1197 + kfree(handle); 1198 + return ret; 1199 + } 1200 + EXPORT_SYMBOL_GPL(stratix10_svc_async_send); 1201 + 1202 + /** 1203 + * stratix10_svc_async_prepare_response - Prepare the response data for 1204 + * an asynchronous transaction. 1205 + * @chan: Pointer to the service channel structure. 1206 + * @handle: Pointer to the asynchronous handler structure. 1207 + * @data: Pointer to the callback data structure. 1208 + * 1209 + * This function prepares the response data for an asynchronous transaction. It 1210 + * extracts the response data from the SMC response structure and stores it in 1211 + * the callback data structure. The function also logs the completion of the 1212 + * asynchronous transaction. 1213 + * 1214 + * Return: 0 on success, -ENOENT if the command is invalid 1215 + */ 1216 + static int stratix10_svc_async_prepare_response(struct stratix10_svc_chan *chan, 1217 + struct stratix10_svc_async_handler *handle, 1218 + struct stratix10_svc_cb_data *data) 1219 + { 1220 + struct stratix10_svc_client_msg *p_msg = 1221 + (struct stratix10_svc_client_msg *)handle->msg; 1222 + struct stratix10_svc_controller *ctrl = chan->ctrl; 1223 + 1224 + data->status = STRATIX10_GET_SDM_STATUS_CODE(handle->res.a1); 1225 + 1226 + switch (p_msg->command) { 1227 + case COMMAND_RSU_NOTIFY: 1228 + break; 1229 + case COMMAND_RSU_GET_SPT_TABLE: 1230 + data->kaddr1 = (void *)&handle->res.a2; 1231 + data->kaddr2 = (void *)&handle->res.a3; 1232 + break; 1233 + case COMMAND_RSU_STATUS: 1234 + /* COMMAND_RSU_STATUS has more elements than the cb_data 1235 + * can acomodate, so passing the response structure to the 1236 + * response function to be handled before done command is 1237 + * executed by the client. 1238 + */ 1239 + data->kaddr1 = (void *)&handle->res; 1240 + break; 1241 + 1242 + default: 1243 + dev_alert(ctrl->dev, "Invalid command\n ,%d", p_msg->command); 1244 + return -ENOENT; 1245 + } 1246 + dev_dbg(ctrl->dev, "Async message completed transaction_id 0x%02x\n", 1247 + handle->transaction_id); 1248 + return 0; 1249 + } 1250 + 1251 + /** 1252 + * stratix10_svc_async_poll - Polls the status of an asynchronous 1253 + * transaction. 1254 + * @chan: Pointer to the service channel structure. 1255 + * @tx_handle: Handle to the transaction being polled. 1256 + * @data: Pointer to the callback data structure. 1257 + * 1258 + * This function polls the status of an asynchronous transaction 1259 + * identified by the given transaction handle. It ensures that the 1260 + * necessary structures are initialized and valid before proceeding 1261 + * with the poll operation. The function sets up the necessary 1262 + * arguments for the SMC call, invokes the call, and prepares the 1263 + * response data if the call is successful. If the call fails, the 1264 + * function returns the error mapped to the SVC status error. 1265 + * 1266 + * Return: 0 on success, -EINVAL if any input parameter is invalid, 1267 + * -EAGAIN if the transaction is still in progress, 1268 + * -EPERM if the command is invalid, or other negative 1269 + * error codes on failure. 1270 + */ 1271 + int stratix10_svc_async_poll(struct stratix10_svc_chan *chan, 1272 + void *tx_handle, 1273 + struct stratix10_svc_cb_data *data) 1274 + { 1275 + struct stratix10_svc_async_handler *handle; 1276 + struct arm_smccc_1_2_regs args = { 0 }; 1277 + struct stratix10_svc_controller *ctrl; 1278 + struct stratix10_async_ctrl *actrl; 1279 + struct stratix10_async_chan *achan; 1280 + int ret; 1281 + 1282 + if (!chan || !tx_handle || !data) 1283 + return -EINVAL; 1284 + 1285 + ctrl = chan->ctrl; 1286 + actrl = &ctrl->actrl; 1287 + achan = chan->async_chan; 1288 + 1289 + if (!achan) { 1290 + dev_err(ctrl->dev, "Async channel not allocated\n"); 1291 + return -EINVAL; 1292 + } 1293 + 1294 + handle = (struct stratix10_svc_async_handler *)tx_handle; 1295 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1296 + if (!hash_hashed(&handle->next)) { 1297 + dev_err(ctrl->dev, "Invalid transaction handler"); 1298 + return -EINVAL; 1299 + } 1300 + } 1301 + 1302 + args.a0 = INTEL_SIP_SMC_ASYNC_POLL; 1303 + args.a1 = 1304 + STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id); 1305 + 1306 + actrl->invoke_fn(actrl, &args, &handle->res); 1307 + 1308 + /*clear data for response*/ 1309 + memset(data, 0, sizeof(*data)); 1310 + 1311 + if (handle->res.a0 == INTEL_SIP_SMC_STATUS_OK) { 1312 + ret = stratix10_svc_async_prepare_response(chan, handle, data); 1313 + if (ret) { 1314 + dev_err(ctrl->dev, "Error in preparation of response,%d\n", ret); 1315 + WARN_ON_ONCE(1); 1316 + } 1317 + return 0; 1318 + } else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY) { 1319 + dev_dbg(ctrl->dev, "async message is still in progress\n"); 1320 + return -EAGAIN; 1321 + } 1322 + 1323 + dev_err(ctrl->dev, 1324 + "Failed to poll async message ,got status as %ld\n", 1325 + handle->res.a0); 1326 + return -EINVAL; 1327 + } 1328 + EXPORT_SYMBOL_GPL(stratix10_svc_async_poll); 1329 + 1330 + /** 1331 + * stratix10_svc_async_done - Completes an asynchronous transaction. 1332 + * @chan: Pointer to the service channel structure. 1333 + * @tx_handle: Handle to the transaction being completed. 1334 + * 1335 + * This function completes an asynchronous transaction identified by 1336 + * the given transaction handle. It ensures that the necessary 1337 + * structures are initialized and valid before proceeding with the 1338 + * completion operation. The function deallocates the transaction ID, 1339 + * frees the memory allocated for the handler, and removes the handler 1340 + * from the transaction list. 1341 + * 1342 + * Return: 0 on success, -EINVAL if any input parameter is invalid, 1343 + * or other negative error codes on failure. 1344 + */ 1345 + int stratix10_svc_async_done(struct stratix10_svc_chan *chan, void *tx_handle) 1346 + { 1347 + struct stratix10_svc_async_handler *handle; 1348 + struct stratix10_svc_controller *ctrl; 1349 + struct stratix10_async_chan *achan; 1350 + struct stratix10_async_ctrl *actrl; 1351 + 1352 + if (!chan || !tx_handle) 1353 + return -EINVAL; 1354 + 1355 + ctrl = chan->ctrl; 1356 + achan = chan->async_chan; 1357 + actrl = &ctrl->actrl; 1358 + 1359 + if (!achan) { 1360 + dev_err(ctrl->dev, "async channel not allocated\n"); 1361 + return -EINVAL; 1362 + } 1363 + 1364 + handle = (struct stratix10_svc_async_handler *)tx_handle; 1365 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1366 + if (!hash_hashed(&handle->next)) { 1367 + dev_err(ctrl->dev, "Invalid transaction handle"); 1368 + return -EINVAL; 1369 + } 1370 + hash_del(&handle->next); 1371 + } 1372 + ida_free(&achan->job_id_pool, 1373 + STRATIX10_GET_JOBID(handle->transaction_id)); 1374 + kfree(handle); 1375 + return 0; 1376 + } 1377 + EXPORT_SYMBOL_GPL(stratix10_svc_async_done); 1378 + 1379 + static inline void stratix10_smc_1_2(struct stratix10_async_ctrl *actrl, 1380 + const struct arm_smccc_1_2_regs *args, 1381 + struct arm_smccc_1_2_regs *res) 1382 + { 1383 + arm_smccc_1_2_smc(args, res); 1384 + } 1385 + 1386 + /** 1387 + * stratix10_svc_async_init - Initialize the Stratix10 service 1388 + * controller for asynchronous operations. 1389 + * @controller: Pointer to the Stratix10 service controller structure. 1390 + * 1391 + * This function initializes the asynchronous service controller by 1392 + * setting up the necessary data structures and initializing the 1393 + * transaction list. 1394 + * 1395 + * Return: 0 on success, -EINVAL if the controller is NULL or already 1396 + * initialized, -ENOMEM if memory allocation fails, 1397 + * -EADDRINUSE if the client ID is already reserved, or other 1398 + * negative error codes on failure. 1399 + */ 1400 + static int stratix10_svc_async_init(struct stratix10_svc_controller *controller) 1401 + { 1402 + struct stratix10_async_ctrl *actrl; 1403 + struct arm_smccc_res res; 1404 + struct device *dev; 1405 + int ret; 1406 + 1407 + if (!controller) 1408 + return -EINVAL; 1409 + 1410 + actrl = &controller->actrl; 1411 + 1412 + if (actrl->initialized) 1413 + return -EINVAL; 1414 + 1415 + dev = controller->dev; 1416 + 1417 + controller->invoke_fn(INTEL_SIP_SMC_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); 1418 + if (res.a0 != INTEL_SIP_SMC_STATUS_OK || 1419 + !(res.a1 > ASYNC_ATF_MINIMUM_MAJOR_VERSION || 1420 + (res.a1 == ASYNC_ATF_MINIMUM_MAJOR_VERSION && 1421 + res.a2 >= ASYNC_ATF_MINIMUM_MINOR_VERSION))) { 1422 + dev_err(dev, 1423 + "Intel Service Layer Driver: ATF version is not compatible for async operation\n"); 1424 + return -EINVAL; 1425 + } 1426 + 1427 + actrl->invoke_fn = stratix10_smc_1_2; 1428 + 1429 + ida_init(&actrl->async_id_pool); 1430 + 1431 + /** 1432 + * SIP_SVC_V1_CLIENT_ID is used by V1/stratix10_svc_send() clients 1433 + * for communicating with SDM synchronously. We need to restrict 1434 + * this in V3/stratix10_svc_async_send() usage to distinguish 1435 + * between V1 and V3 messages in El3 firmware. 1436 + */ 1437 + ret = ida_alloc_range(&actrl->async_id_pool, SIP_SVC_V1_CLIENT_ID, 1438 + SIP_SVC_V1_CLIENT_ID, GFP_KERNEL); 1439 + if (ret < 0) { 1440 + dev_err(dev, 1441 + "Intel Service Layer Driver: Error on reserving SIP_SVC_V1_CLIENT_ID\n"); 1442 + ida_destroy(&actrl->async_id_pool); 1443 + actrl->invoke_fn = NULL; 1444 + return -EADDRINUSE; 1445 + } 1446 + 1447 + spin_lock_init(&actrl->trx_list_lock); 1448 + hash_init(actrl->trx_list); 1449 + atomic_set(&actrl->common_achan_refcount, 0); 1450 + 1451 + actrl->initialized = true; 1452 + return 0; 1453 + } 1454 + 1455 + /** 1456 + * stratix10_svc_async_exit - Clean up and exit the asynchronous 1457 + * service controller 1458 + * @ctrl: Pointer to the stratix10_svc_controller structure 1459 + * 1460 + * This function performs the necessary cleanup for the asynchronous 1461 + * service controller. It checks if the controller is valid and if it 1462 + * has been initialized. It then locks the transaction list and safely 1463 + * removes and deallocates each handler in the list. The function also 1464 + * removes any asynchronous clients associated with the controller's 1465 + * channels and destroys the asynchronous ID pool. Finally, it resets 1466 + * the asynchronous ID pool and invoke function pointers to NULL. 1467 + * 1468 + * Return: 0 on success, -EINVAL if the controller is invalid or not 1469 + * initialized. 1470 + */ 1471 + static int stratix10_svc_async_exit(struct stratix10_svc_controller *ctrl) 1472 + { 1473 + struct stratix10_svc_async_handler *handler; 1474 + struct stratix10_async_ctrl *actrl; 1475 + struct hlist_node *tmp; 1476 + int i; 1477 + 1478 + if (!ctrl) 1479 + return -EINVAL; 1480 + 1481 + actrl = &ctrl->actrl; 1482 + 1483 + if (!actrl->initialized) 1484 + return -EINVAL; 1485 + 1486 + actrl->initialized = false; 1487 + 1488 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1489 + hash_for_each_safe(actrl->trx_list, i, tmp, handler, next) { 1490 + ida_free(&handler->achan->job_id_pool, 1491 + STRATIX10_GET_JOBID(handler->transaction_id)); 1492 + hash_del(&handler->next); 1493 + kfree(handler); 1494 + } 1495 + } 1496 + 1497 + for (i = 0; i < SVC_NUM_CHANNEL; i++) { 1498 + if (ctrl->chans[i].async_chan) { 1499 + stratix10_svc_remove_async_client(&ctrl->chans[i]); 1500 + ctrl->chans[i].async_chan = NULL; 1501 + } 1502 + } 1503 + 1504 + ida_destroy(&actrl->async_id_pool); 1505 + actrl->invoke_fn = NULL; 1506 + 1507 + return 0; 1508 + } 1509 + 1510 + /** 1070 1511 * stratix10_svc_free_channel() - free service channel 1071 1512 * @chan: service channel to be freed 1072 1513 * ··· 1719 990 p_data->flag = ct->flags; 1720 991 } 1721 992 } else { 993 + guard(mutex)(&svc_mem_lock); 1722 994 list_for_each_entry(p_mem, &svc_data_mem, node) 1723 995 if (p_mem->vaddr == p_msg->payload) { 1724 996 p_data->paddr = p_mem->paddr; ··· 1802 1072 if (!pmem) 1803 1073 return ERR_PTR(-ENOMEM); 1804 1074 1075 + guard(mutex)(&svc_mem_lock); 1805 1076 va = gen_pool_alloc(genpool, s); 1806 1077 if (!va) 1807 1078 return ERR_PTR(-ENOMEM); ··· 1831 1100 void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) 1832 1101 { 1833 1102 struct stratix10_svc_data_mem *pmem; 1103 + guard(mutex)(&svc_mem_lock); 1834 1104 1835 1105 list_for_each_entry(pmem, &svc_data_mem, node) 1836 1106 if (pmem->vaddr == kaddr) { ··· 1906 1174 controller->invoke_fn = invoke_fn; 1907 1175 init_completion(&controller->complete_status); 1908 1176 1177 + ret = stratix10_svc_async_init(controller); 1178 + if (ret) { 1179 + dev_dbg(dev, "Intel Service Layer Driver: Error on stratix10_svc_async_init %d\n", 1180 + ret); 1181 + goto err_destroy_pool; 1182 + } 1183 + 1909 1184 fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO; 1910 1185 ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL); 1911 1186 if (ret) { 1912 1187 dev_err(dev, "failed to allocate FIFO\n"); 1913 - goto err_destroy_pool; 1188 + goto err_async_exit; 1914 1189 } 1915 1190 spin_lock_init(&controller->svc_fifo_lock); 1916 1191 ··· 1935 1196 chans[2].ctrl = controller; 1936 1197 chans[2].name = SVC_CLIENT_FCS; 1937 1198 spin_lock_init(&chans[2].lock); 1199 + 1200 + chans[3].scl = NULL; 1201 + chans[3].ctrl = controller; 1202 + chans[3].name = SVC_CLIENT_HWMON; 1203 + spin_lock_init(&chans[3].lock); 1938 1204 1939 1205 list_add_tail(&controller->node, &svc_ctrl); 1940 1206 platform_set_drvdata(pdev, controller); ··· 1993 1249 platform_device_unregister(svc->stratix10_svc_rsu); 1994 1250 err_free_kfifo: 1995 1251 kfifo_free(&controller->svc_fifo); 1252 + err_async_exit: 1253 + stratix10_svc_async_exit(controller); 1996 1254 err_destroy_pool: 1997 1255 gen_pool_destroy(genpool); 1998 1256 return ret; ··· 2004 1258 { 2005 1259 struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev); 2006 1260 struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev); 1261 + 1262 + stratix10_svc_async_exit(ctrl); 2007 1263 2008 1264 of_platform_depopulate(ctrl->dev); 2009 1265
+111
include/linux/firmware/intel/stratix10-smc.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * Copyright (C) 2017-2018, Intel Corporation 4 + * Copyright (C) 2025, Altera Corporation 4 5 */ 5 6 6 7 #ifndef __STRATIX10_SMC_H ··· 47 46 #define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ 48 47 ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ 49 48 ARM_SMCCC_OWNER_SIP, (func_num)) 49 + 50 + #define INTEL_SIP_SMC_ASYNC_VAL(func_name) \ 51 + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ 52 + ARM_SMCCC_OWNER_SIP, (func_name)) 50 53 51 54 /** 52 55 * Return values in INTEL_SIP_SMC_* call ··· 625 620 #define INTEL_SIP_SMC_FCS_GET_PROVISION_DATA \ 626 621 INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FCS_GET_PROVISION_DATA) 627 622 623 + /** 624 + * Request INTEL_SIP_SMC_HWMON_READTEMP 625 + * Sync call to request temperature 626 + * 627 + * Call register usage: 628 + * a0 Temperature Channel 629 + * a1-a7 not used 630 + * 631 + * Return status 632 + * a0 INTEL_SIP_SMC_STATUS_OK 633 + * a1 Temperature Value 634 + * a2-a3 not used 635 + */ 636 + #define INTEL_SIP_SMC_FUNCID_HWMON_READTEMP 32 637 + #define INTEL_SIP_SMC_HWMON_READTEMP \ 638 + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_HWMON_READTEMP) 639 + 640 + /** 641 + * Request INTEL_SIP_SMC_HWMON_READVOLT 642 + * Sync call to request voltage 643 + * 644 + * Call register usage: 645 + * a0 Voltage Channel 646 + * a1-a7 not used 647 + * 648 + * Return status 649 + * a0 INTEL_SIP_SMC_STATUS_OK 650 + * a1 Voltage Value 651 + * a2-a3 not used 652 + */ 653 + #define INTEL_SIP_SMC_FUNCID_HWMON_READVOLT 33 654 + #define INTEL_SIP_SMC_HWMON_READVOLT \ 655 + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_HWMON_READVOLT) 656 + 657 + /** 658 + * Request INTEL_SIP_SMC_ASYNC_POLL 659 + * Async call used by service driver at EL1 to query mailbox response from SDM. 660 + * 661 + * Call register usage: 662 + * a0 INTEL_SIP_SMC_ASYNC_POLL 663 + * a1 transaction job id 664 + * a2-17 will be used to return the response data 665 + * 666 + * Return status 667 + * a0 INTEL_SIP_SMC_STATUS_OK 668 + * a1-17 will contain the response values from mailbox for the previous send 669 + * transaction 670 + * Or 671 + * a0 INTEL_SIP_SMC_STATUS_NO_RESPONSE 672 + * a1-17 not used 673 + */ 674 + #define INTEL_SIP_SMC_ASYNC_FUNC_ID_POLL (0xC8) 675 + #define INTEL_SIP_SMC_ASYNC_POLL \ 676 + INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_POLL) 677 + 678 + /** 679 + * Request INTEL_SIP_SMC_ASYNC_RSU_GET_SPT 680 + * Async call to get RSU SPT from SDM. 681 + * Call register usage: 682 + * a0 INTEL_SIP_SMC_ASYNC_RSU_GET_SPT 683 + * a1 transaction job id 684 + * a2-a17 not used 685 + * 686 + * Return status: 687 + * a0 INTEL_SIP_SMC_STATUS_OK ,INTEL_SIP_SMC_STATUS_REJECTED 688 + * or INTEL_SIP_SMC_STATUS_BUSY 689 + * a1-a17 not used 690 + */ 691 + #define INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_GET_SPT (0xEA) 692 + #define INTEL_SIP_SMC_ASYNC_RSU_GET_SPT \ 693 + INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_GET_SPT) 694 + 695 + /** 696 + * Request INTEL_SIP_SMC_ASYNC_RSU_GET_ERROR_STATUS 697 + * Async call to get RSU error status from SDM. 698 + * Call register usage: 699 + * a0 INTEL_SIP_SMC_ASYNC_RSU_GET_ERROR_STATUS 700 + * a1 transaction job id 701 + * a2-a17 not used 702 + * 703 + * Return status: 704 + * a0 INTEL_SIP_SMC_STATUS_OK ,INTEL_SIP_SMC_STATUS_REJECTED 705 + * or INTEL_SIP_SMC_STATUS_BUSY 706 + * a1-a17 not used 707 + */ 708 + #define INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_GET_ERROR_STATUS (0xEB) 709 + #define INTEL_SIP_SMC_ASYNC_RSU_GET_ERROR_STATUS \ 710 + INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_GET_ERROR_STATUS) 711 + 712 + /** 713 + * Request INTEL_SIP_SMC_ASYNC_RSU_NOTIFY 714 + * Async call to send NOTIFY value to SDM. 715 + * Call register usage: 716 + * a0 INTEL_SIP_SMC_ASYNC_RSU_NOTIFY 717 + * a1 transaction job id 718 + * a2 notify value 719 + * a3-a17 not used 720 + * 721 + * Return status: 722 + * a0 INTEL_SIP_SMC_STATUS_OK ,INTEL_SIP_SMC_STATUS_REJECTED 723 + * or INTEL_SIP_SMC_STATUS_BUSY 724 + * a1-a17 not used 725 + */ 726 + #define INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_NOTIFY (0xEC) 727 + #define INTEL_SIP_SMC_ASYNC_RSU_NOTIFY \ 728 + INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_NOTIFY) 628 729 #endif
+99 -1
include/linux/firmware/intel/stratix10-svc-client.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * Copyright (C) 2017-2018, Intel Corporation 4 + * Copyright (C) 2025, Altera Corporation 4 5 */ 5 6 6 7 #ifndef __STRATIX10_SVC_CLIENT_H ··· 12 11 * 13 12 * fpga: for FPGA configuration 14 13 * rsu: for remote status update 14 + * hwmon: for hardware monitoring (voltage and temperature) 15 15 */ 16 16 #define SVC_CLIENT_FPGA "fpga" 17 17 #define SVC_CLIENT_RSU "rsu" 18 18 #define SVC_CLIENT_FCS "fcs" 19 + #define SVC_CLIENT_HWMON "hwmon" 19 20 20 - /* 21 + /** 21 22 * Status of the sent command, in bit number 22 23 * 23 24 * SVC_STATUS_OK: ··· 73 70 #define SVC_RSU_REQUEST_TIMEOUT_MS 300 74 71 #define SVC_FCS_REQUEST_TIMEOUT_MS 2000 75 72 #define SVC_COMPLETED_TIMEOUT_MS 30000 73 + #define SVC_HWMON_REQUEST_TIMEOUT_MS 300 76 74 77 75 struct stratix10_svc_chan; 78 76 ··· 128 124 * @COMMAND_RSU_DCMF_STATUS: query firmware for the DCMF status 129 125 * return status is SVC_STATUS_OK or SVC_STATUS_ERROR 130 126 * 127 + * @COMMAND_RSU_GET_SPT_TABLE: query firmware for SPT table 128 + * return status is SVC_STATUS_OK or SVC_STATUS_ERROR 129 + * 131 130 * @COMMAND_FCS_REQUEST_SERVICE: request validation of image from firmware, 132 131 * return status is SVC_STATUS_OK, SVC_STATUS_INVALID_PARAM 133 132 * ··· 165 158 COMMAND_RSU_DCMF_VERSION, 166 159 COMMAND_RSU_DCMF_STATUS, 167 160 COMMAND_FIRMWARE_VERSION, 161 + COMMAND_RSU_GET_SPT_TABLE, 168 162 /* for FCS */ 169 163 COMMAND_FCS_REQUEST_SERVICE = 20, 170 164 COMMAND_FCS_SEND_CERTIFICATE, ··· 179 171 COMMAND_MBOX_SEND_CMD = 100, 180 172 /* Non-mailbox SMC Call */ 181 173 COMMAND_SMC_SVC_VERSION = 200, 174 + /* for HWMON */ 175 + COMMAND_HWMON_READTEMP, 176 + COMMAND_HWMON_READVOLT 182 177 }; 183 178 184 179 /** ··· 295 284 * request process. 296 285 */ 297 286 void stratix10_svc_done(struct stratix10_svc_chan *chan); 287 + 288 + /** 289 + * typedef async_callback_t - A type definition for an asynchronous callback function. 290 + * 291 + * This type defines a function pointer for an asynchronous callback. 292 + * The callback function takes a single argument, which is a pointer to 293 + * user-defined data. 294 + * 295 + * @param cb_arg A pointer to user-defined data passed to the callback function. 296 + */ 297 + typedef void (*async_callback_t)(void *cb_arg); 298 + 299 + /** 300 + * stratix10_svc_add_async_client - Add an asynchronous client to a Stratix 10 301 + * service channel. 302 + * @chan: Pointer to the Stratix 10 service channel structure. 303 + * @use_unique_clientid: Boolean flag indicating whether to use a unique client ID. 304 + * 305 + * This function registers an asynchronous client with the specified Stratix 10 306 + * service channel. If the use_unique_clientid flag is set to true, a unique client 307 + * ID will be assigned to the client. 308 + * 309 + * Return: 0 on success, or a negative error code on failure: 310 + * -EINVAL if the channel is NULL or the async controller is not initialized. 311 + * -EALREADY if the async channel is already allocated. 312 + * -ENOMEM if memory allocation fails. 313 + * Other negative values if ID allocation fails 314 + */ 315 + int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan, bool use_unique_clientid); 316 + 317 + /** 318 + * stratix10_svc_remove_async_client - Remove an asynchronous client from the Stratix 10 319 + * service channel. 320 + * @chan: Pointer to the Stratix 10 service channel structure. 321 + * 322 + * This function removes an asynchronous client from the specified Stratix 10 service channel. 323 + * It is typically used to clean up and release resources associated with the client. 324 + * 325 + * Return: 0 on success, -EINVAL if the channel or asynchronous channel is invalid. 326 + */ 327 + int stratix10_svc_remove_async_client(struct stratix10_svc_chan *chan); 328 + 329 + /** 330 + * stratix10_svc_async_send - Send an asynchronous message to the SDM mailbox 331 + * in EL3 secure firmware. 332 + * @chan: Pointer to the service channel structure. 333 + * @msg: Pointer to the message to be sent. 334 + * @handler: Pointer to the handler object used by caller to track the transaction. 335 + * @cb: Callback function to be called upon completion. 336 + * @cb_arg: Argument to be passed to the callback function. 337 + * 338 + * This function sends a message asynchronously to the SDM mailbox in EL3 secure firmware. 339 + * and registers a callback function to be invoked when the operation completes. 340 + * 341 + * Return: 0 on success,and negative error codes on failure. 342 + */ 343 + int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg, void **handler, 344 + async_callback_t cb, void *cb_arg); 345 + 346 + /** 347 + * stratix10_svc_async_poll - Polls the status of an asynchronous service request. 348 + * @chan: Pointer to the service channel structure. 349 + * @tx_handle: Handle to the transaction being polled. 350 + * @data: Pointer to the callback data structure to be filled with the result. 351 + * 352 + * This function checks the status of an asynchronous service request 353 + * and fills the provided callback data structure with the result. 354 + * 355 + * Return: 0 on success, -EINVAL if any input parameter is invalid or if the 356 + * async controller is not initialized, -EAGAIN if the transaction is 357 + * still in progress, or other negative error codes on failure. 358 + */ 359 + int stratix10_svc_async_poll(struct stratix10_svc_chan *chan, void *tx_handle, 360 + struct stratix10_svc_cb_data *data); 361 + 362 + /** 363 + * stratix10_svc_async_done - Complete an asynchronous transaction 364 + * @chan: Pointer to the service channel structure 365 + * @tx_handle: Pointer to the transaction handle 366 + * 367 + * This function completes an asynchronous transaction by removing the 368 + * transaction from the hash table and deallocating the associated resources. 369 + * 370 + * Return: 0 on success, -EINVAL on invalid input or errors. 371 + */ 372 + int stratix10_svc_async_done(struct stratix10_svc_chan *chan, void *tx_handle); 373 + 298 374 #endif 299 375