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

firmware: stratix10-rsu: Migrate RSU driver to use stratix10 asynchronous framework.

* Add support for asynchronous communication to the RSU client channel.
* Migrate functions that communicate with the SDM to use the asynchronous
framework.

Signed-off-by: Mahesh Rao <mahesh.rao@altera.com>
Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>

authored by

Mahesh Rao and committed by
Dinh Nguyen
15847537 ec523793

+141 -129
+141 -129
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 ··· 621 597 if (ret) 622 598 return ret; 623 599 624 - ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, 625 - status, rsu_command_callback); 600 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL); 626 601 if (ret) { 627 602 dev_err(dev, "Error, RSU notify returned %i\n", ret); 628 603 return ret; 629 604 } 630 605 631 606 /* to get the updated state */ 632 - ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 633 - 0, rsu_status_callback); 607 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0, 608 + rsu_async_status_callback); 634 609 if (ret) { 635 610 dev_err(dev, "Error, getting RSU status %i\n", ret); 636 - return ret; 637 - } 638 - 639 - ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 640 - if (ret) { 641 - dev_err(dev, "Error, getting RSU retry %i\n", ret); 642 611 return ret; 643 612 } 644 613 ··· 754 737 return PTR_ERR(priv->chan); 755 738 } 756 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 + 757 747 init_completion(&priv->completion); 758 748 platform_set_drvdata(pdev, priv); 759 749 760 750 /* get the initial state from firmware */ 761 - ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 762 - 0, rsu_status_callback); 751 + ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0, 752 + rsu_async_status_callback); 763 753 if (ret) { 764 754 dev_err(dev, "Error, getting RSU status %i\n", ret); 765 755 stratix10_svc_free_channel(priv->chan); ··· 787 763 stratix10_svc_free_channel(priv->chan); 788 764 } 789 765 790 - ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 791 - if (ret) { 792 - dev_err(dev, "Error, getting RSU retry %i\n", ret); 793 - stratix10_svc_free_channel(priv->chan); 794 - } 795 - 796 766 ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0, 797 767 rsu_max_retry_callback); 798 768 if (ret) { ··· 794 776 stratix10_svc_free_channel(priv->chan); 795 777 } 796 778 797 - priv->get_spt_response_buf = 798 - stratix10_svc_allocate_memory(priv->chan, RSU_GET_SPT_RESP_LEN); 799 779 800 - if (IS_ERR(priv->get_spt_response_buf)) { 801 - dev_err(dev, "failed to allocate get spt buffer\n"); 802 - } else { 803 - ret = rsu_send_msg(priv, COMMAND_MBOX_SEND_CMD, 804 - RSU_GET_SPT_CMD, rsu_get_spt_callback); 805 - if (ret) { 806 - dev_err(dev, "Error, getting SPT table %i\n", ret); 807 - stratix10_svc_free_channel(priv->chan); 808 - } 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); 809 785 } 810 786 811 787 return ret;