stratix10-rsu.c (16558B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018-2019, Intel Corporation 4 */ 5 6#include <linux/arm-smccc.h> 7#include <linux/bitfield.h> 8#include <linux/completion.h> 9#include <linux/kobject.h> 10#include <linux/module.h> 11#include <linux/mutex.h> 12#include <linux/of.h> 13#include <linux/of_platform.h> 14#include <linux/platform_device.h> 15#include <linux/firmware/intel/stratix10-svc-client.h> 16#include <linux/string.h> 17#include <linux/sysfs.h> 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) 23#define RSU_DCMF0_MASK GENMASK_ULL(31, 0) 24#define RSU_DCMF1_MASK GENMASK_ULL(63, 32) 25#define RSU_DCMF2_MASK GENMASK_ULL(31, 0) 26#define RSU_DCMF3_MASK GENMASK_ULL(63, 32) 27 28#define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS)) 29 30#define INVALID_RETRY_COUNTER 0xFF 31#define INVALID_DCMF_VERSION 0xFF 32 33 34typedef void (*rsu_callback)(struct stratix10_svc_client *client, 35 struct stratix10_svc_cb_data *data); 36/** 37 * struct stratix10_rsu_priv - rsu data structure 38 * @chan: pointer to the allocated service channel 39 * @client: active service client 40 * @completion: state for callback completion 41 * @lock: a mutex to protect callback completion state 42 * @status.current_image: address of image currently running in flash 43 * @status.fail_image: address of failed image in flash 44 * @status.version: the interface version number of RSU firmware 45 * @status.state: the state of RSU system 46 * @status.error_details: error code 47 * @status.error_location: the error offset inside the image that failed 48 * @dcmf_version.dcmf0: Quartus dcmf0 version 49 * @dcmf_version.dcmf1: Quartus dcmf1 version 50 * @dcmf_version.dcmf2: Quartus dcmf2 version 51 * @dcmf_version.dcmf3: Quartus dcmf3 version 52 * @retry_counter: the current image's retry counter 53 * @max_retry: the preset max retry value 54 */ 55struct stratix10_rsu_priv { 56 struct stratix10_svc_chan *chan; 57 struct stratix10_svc_client client; 58 struct completion completion; 59 struct mutex lock; 60 struct { 61 unsigned long current_image; 62 unsigned long fail_image; 63 unsigned int version; 64 unsigned int state; 65 unsigned int error_details; 66 unsigned int error_location; 67 } status; 68 69 struct { 70 unsigned int dcmf0; 71 unsigned int dcmf1; 72 unsigned int dcmf2; 73 unsigned int dcmf3; 74 } dcmf_version; 75 76 unsigned int retry_counter; 77 unsigned int max_retry; 78}; 79 80/** 81 * rsu_status_callback() - Status callback from Intel Service Layer 82 * @client: pointer to service client 83 * @data: pointer to callback data structure 84 * 85 * Callback from Intel service layer for RSU status request. Status is 86 * only updated after a system reboot, so a get updated status call is 87 * made during driver probe. 88 */ 89static void rsu_status_callback(struct stratix10_svc_client *client, 90 struct stratix10_svc_cb_data *data) 91{ 92 struct stratix10_rsu_priv *priv = client->priv; 93 struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1; 94 95 if (data->status == BIT(SVC_STATUS_OK)) { 96 priv->status.version = FIELD_GET(RSU_VERSION_MASK, 97 res->a2); 98 priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2); 99 priv->status.fail_image = res->a1; 100 priv->status.current_image = res->a0; 101 priv->status.error_location = 102 FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3); 103 priv->status.error_details = 104 FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3); 105 } else { 106 dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n", 107 res->a0); 108 priv->status.version = 0; 109 priv->status.state = 0; 110 priv->status.fail_image = 0; 111 priv->status.current_image = 0; 112 priv->status.error_location = 0; 113 priv->status.error_details = 0; 114 } 115 116 complete(&priv->completion); 117} 118 119/** 120 * rsu_command_callback() - Update callback from Intel Service Layer 121 * @client: pointer to client 122 * @data: pointer to callback data structure 123 * 124 * Callback from Intel service layer for RSU commands. 125 */ 126static void rsu_command_callback(struct stratix10_svc_client *client, 127 struct stratix10_svc_cb_data *data) 128{ 129 struct stratix10_rsu_priv *priv = client->priv; 130 131 if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 132 dev_warn(client->dev, "FW doesn't support notify\n"); 133 else if (data->status == BIT(SVC_STATUS_ERROR)) 134 dev_err(client->dev, "Failure, returned status is %lu\n", 135 BIT(data->status)); 136 137 complete(&priv->completion); 138} 139 140/** 141 * rsu_retry_callback() - Callback from Intel service layer for getting 142 * the current image's retry counter from the firmware 143 * @client: pointer to client 144 * @data: pointer to callback data structure 145 * 146 * Callback from Intel service layer for retry counter, which is used by 147 * user to know how many times the images is still allowed to reload 148 * itself before giving up and starting RSU fail-over flow. 149 */ 150static void rsu_retry_callback(struct stratix10_svc_client *client, 151 struct stratix10_svc_cb_data *data) 152{ 153 struct stratix10_rsu_priv *priv = client->priv; 154 unsigned int *counter = (unsigned int *)data->kaddr1; 155 156 if (data->status == BIT(SVC_STATUS_OK)) 157 priv->retry_counter = *counter; 158 else if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 159 dev_warn(client->dev, "FW doesn't support retry\n"); 160 else 161 dev_err(client->dev, "Failed to get retry counter %lu\n", 162 BIT(data->status)); 163 164 complete(&priv->completion); 165} 166 167/** 168 * rsu_max_retry_callback() - Callback from Intel service layer for getting 169 * the max retry value from the firmware 170 * @client: pointer to client 171 * @data: pointer to callback data structure 172 * 173 * Callback from Intel service layer for max retry. 174 */ 175static void rsu_max_retry_callback(struct stratix10_svc_client *client, 176 struct stratix10_svc_cb_data *data) 177{ 178 struct stratix10_rsu_priv *priv = client->priv; 179 unsigned int *max_retry = (unsigned int *)data->kaddr1; 180 181 if (data->status == BIT(SVC_STATUS_OK)) 182 priv->max_retry = *max_retry; 183 else if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 184 dev_warn(client->dev, "FW doesn't support max retry\n"); 185 else 186 dev_err(client->dev, "Failed to get max retry %lu\n", 187 BIT(data->status)); 188 189 complete(&priv->completion); 190} 191 192/** 193 * rsu_dcmf_version_callback() - Callback from Intel service layer for getting 194 * the DCMF version 195 * @client: pointer to client 196 * @data: pointer to callback data structure 197 * 198 * Callback from Intel service layer for DCMF version number 199 */ 200static void rsu_dcmf_version_callback(struct stratix10_svc_client *client, 201 struct stratix10_svc_cb_data *data) 202{ 203 struct stratix10_rsu_priv *priv = client->priv; 204 unsigned long long *value1 = (unsigned long long *)data->kaddr1; 205 unsigned long long *value2 = (unsigned long long *)data->kaddr2; 206 207 if (data->status == BIT(SVC_STATUS_OK)) { 208 priv->dcmf_version.dcmf0 = FIELD_GET(RSU_DCMF0_MASK, *value1); 209 priv->dcmf_version.dcmf1 = FIELD_GET(RSU_DCMF1_MASK, *value1); 210 priv->dcmf_version.dcmf2 = FIELD_GET(RSU_DCMF2_MASK, *value2); 211 priv->dcmf_version.dcmf3 = FIELD_GET(RSU_DCMF3_MASK, *value2); 212 } else 213 dev_err(client->dev, "failed to get DCMF version\n"); 214 215 complete(&priv->completion); 216} 217 218/** 219 * rsu_send_msg() - send a message to Intel service layer 220 * @priv: pointer to rsu private data 221 * @command: RSU status or update command 222 * @arg: the request argument, the bitstream address or notify status 223 * @callback: function pointer for the callback (status or update) 224 * 225 * Start an Intel service layer transaction to perform the SMC call that 226 * is necessary to get RSU boot log or set the address of bitstream to 227 * boot after reboot. 228 * 229 * Returns 0 on success or -ETIMEDOUT on error. 230 */ 231static int rsu_send_msg(struct stratix10_rsu_priv *priv, 232 enum stratix10_svc_command_code command, 233 unsigned long arg, 234 rsu_callback callback) 235{ 236 struct stratix10_svc_client_msg msg; 237 int ret; 238 239 mutex_lock(&priv->lock); 240 reinit_completion(&priv->completion); 241 priv->client.receive_cb = callback; 242 243 msg.command = command; 244 if (arg) 245 msg.arg[0] = arg; 246 247 ret = stratix10_svc_send(priv->chan, &msg); 248 if (ret < 0) 249 goto status_done; 250 251 ret = wait_for_completion_interruptible_timeout(&priv->completion, 252 RSU_TIMEOUT); 253 if (!ret) { 254 dev_err(priv->client.dev, 255 "timeout waiting for SMC call\n"); 256 ret = -ETIMEDOUT; 257 goto status_done; 258 } else if (ret < 0) { 259 dev_err(priv->client.dev, 260 "error %d waiting for SMC call\n", ret); 261 goto status_done; 262 } else { 263 ret = 0; 264 } 265 266status_done: 267 stratix10_svc_done(priv->chan); 268 mutex_unlock(&priv->lock); 269 return ret; 270} 271 272/* 273 * This driver exposes some optional features of the Intel Stratix 10 SoC FPGA. 274 * The sysfs interfaces exposed here are FPGA Remote System Update (RSU) 275 * related. They allow user space software to query the configuration system 276 * status and to request optional reboot behavior specific to Intel FPGAs. 277 */ 278 279static ssize_t current_image_show(struct device *dev, 280 struct device_attribute *attr, char *buf) 281{ 282 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 283 284 if (!priv) 285 return -ENODEV; 286 287 return sprintf(buf, "0x%08lx\n", priv->status.current_image); 288} 289 290static ssize_t fail_image_show(struct device *dev, 291 struct device_attribute *attr, char *buf) 292{ 293 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 294 295 if (!priv) 296 return -ENODEV; 297 298 return sprintf(buf, "0x%08lx\n", priv->status.fail_image); 299} 300 301static ssize_t version_show(struct device *dev, struct device_attribute *attr, 302 char *buf) 303{ 304 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 305 306 if (!priv) 307 return -ENODEV; 308 309 return sprintf(buf, "0x%08x\n", priv->status.version); 310} 311 312static ssize_t state_show(struct device *dev, struct device_attribute *attr, 313 char *buf) 314{ 315 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 316 317 if (!priv) 318 return -ENODEV; 319 320 return sprintf(buf, "0x%08x\n", priv->status.state); 321} 322 323static ssize_t error_location_show(struct device *dev, 324 struct device_attribute *attr, char *buf) 325{ 326 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 327 328 if (!priv) 329 return -ENODEV; 330 331 return sprintf(buf, "0x%08x\n", priv->status.error_location); 332} 333 334static ssize_t error_details_show(struct device *dev, 335 struct device_attribute *attr, char *buf) 336{ 337 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 338 339 if (!priv) 340 return -ENODEV; 341 342 return sprintf(buf, "0x%08x\n", priv->status.error_details); 343} 344 345static ssize_t retry_counter_show(struct device *dev, 346 struct device_attribute *attr, char *buf) 347{ 348 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 349 350 if (!priv) 351 return -ENODEV; 352 353 return sprintf(buf, "0x%08x\n", priv->retry_counter); 354} 355 356static ssize_t max_retry_show(struct device *dev, 357 struct device_attribute *attr, char *buf) 358{ 359 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 360 361 if (!priv) 362 return -ENODEV; 363 364 return sprintf(buf, "0x%08x\n", priv->max_retry); 365} 366 367static ssize_t dcmf0_show(struct device *dev, 368 struct device_attribute *attr, char *buf) 369{ 370 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 371 372 if (!priv) 373 return -ENODEV; 374 375 return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf0); 376} 377 378static ssize_t dcmf1_show(struct device *dev, 379 struct device_attribute *attr, char *buf) 380{ 381 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 382 383 if (!priv) 384 return -ENODEV; 385 386 return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf1); 387} 388 389static ssize_t dcmf2_show(struct device *dev, 390 struct device_attribute *attr, char *buf) 391{ 392 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 393 394 if (!priv) 395 return -ENODEV; 396 397 return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf2); 398} 399 400static ssize_t dcmf3_show(struct device *dev, 401 struct device_attribute *attr, char *buf) 402{ 403 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 404 405 if (!priv) 406 return -ENODEV; 407 408 return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf3); 409} 410 411static ssize_t reboot_image_store(struct device *dev, 412 struct device_attribute *attr, 413 const char *buf, size_t count) 414{ 415 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 416 unsigned long address; 417 int ret; 418 419 if (!priv) 420 return -ENODEV; 421 422 ret = kstrtoul(buf, 0, &address); 423 if (ret) 424 return ret; 425 426 ret = rsu_send_msg(priv, COMMAND_RSU_UPDATE, 427 address, rsu_command_callback); 428 if (ret) { 429 dev_err(dev, "Error, RSU update returned %i\n", ret); 430 return ret; 431 } 432 433 return count; 434} 435 436static ssize_t notify_store(struct device *dev, 437 struct device_attribute *attr, 438 const char *buf, size_t count) 439{ 440 struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 441 unsigned long status; 442 int ret; 443 444 if (!priv) 445 return -ENODEV; 446 447 ret = kstrtoul(buf, 0, &status); 448 if (ret) 449 return ret; 450 451 ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, 452 status, rsu_command_callback); 453 if (ret) { 454 dev_err(dev, "Error, RSU notify returned %i\n", ret); 455 return ret; 456 } 457 458 /* to get the updated state */ 459 ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 460 0, rsu_status_callback); 461 if (ret) { 462 dev_err(dev, "Error, getting RSU status %i\n", ret); 463 return ret; 464 } 465 466 ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 467 if (ret) { 468 dev_err(dev, "Error, getting RSU retry %i\n", ret); 469 return ret; 470 } 471 472 return count; 473} 474 475static DEVICE_ATTR_RO(current_image); 476static DEVICE_ATTR_RO(fail_image); 477static DEVICE_ATTR_RO(state); 478static DEVICE_ATTR_RO(version); 479static DEVICE_ATTR_RO(error_location); 480static DEVICE_ATTR_RO(error_details); 481static DEVICE_ATTR_RO(retry_counter); 482static DEVICE_ATTR_RO(max_retry); 483static DEVICE_ATTR_RO(dcmf0); 484static DEVICE_ATTR_RO(dcmf1); 485static DEVICE_ATTR_RO(dcmf2); 486static DEVICE_ATTR_RO(dcmf3); 487static DEVICE_ATTR_WO(reboot_image); 488static DEVICE_ATTR_WO(notify); 489 490static struct attribute *rsu_attrs[] = { 491 &dev_attr_current_image.attr, 492 &dev_attr_fail_image.attr, 493 &dev_attr_state.attr, 494 &dev_attr_version.attr, 495 &dev_attr_error_location.attr, 496 &dev_attr_error_details.attr, 497 &dev_attr_retry_counter.attr, 498 &dev_attr_max_retry.attr, 499 &dev_attr_dcmf0.attr, 500 &dev_attr_dcmf1.attr, 501 &dev_attr_dcmf2.attr, 502 &dev_attr_dcmf3.attr, 503 &dev_attr_reboot_image.attr, 504 &dev_attr_notify.attr, 505 NULL 506}; 507 508ATTRIBUTE_GROUPS(rsu); 509 510static int stratix10_rsu_probe(struct platform_device *pdev) 511{ 512 struct device *dev = &pdev->dev; 513 struct stratix10_rsu_priv *priv; 514 int ret; 515 516 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 517 if (!priv) 518 return -ENOMEM; 519 520 priv->client.dev = dev; 521 priv->client.receive_cb = NULL; 522 priv->client.priv = priv; 523 priv->status.current_image = 0; 524 priv->status.fail_image = 0; 525 priv->status.error_location = 0; 526 priv->status.error_details = 0; 527 priv->status.version = 0; 528 priv->status.state = 0; 529 priv->retry_counter = INVALID_RETRY_COUNTER; 530 priv->dcmf_version.dcmf0 = INVALID_DCMF_VERSION; 531 priv->dcmf_version.dcmf1 = INVALID_DCMF_VERSION; 532 priv->dcmf_version.dcmf2 = INVALID_DCMF_VERSION; 533 priv->dcmf_version.dcmf3 = INVALID_DCMF_VERSION; 534 priv->max_retry = INVALID_RETRY_COUNTER; 535 536 mutex_init(&priv->lock); 537 priv->chan = stratix10_svc_request_channel_byname(&priv->client, 538 SVC_CLIENT_RSU); 539 if (IS_ERR(priv->chan)) { 540 dev_err(dev, "couldn't get service channel %s\n", 541 SVC_CLIENT_RSU); 542 return PTR_ERR(priv->chan); 543 } 544 545 init_completion(&priv->completion); 546 platform_set_drvdata(pdev, priv); 547 548 /* get the initial state from firmware */ 549 ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 550 0, rsu_status_callback); 551 if (ret) { 552 dev_err(dev, "Error, getting RSU status %i\n", ret); 553 stratix10_svc_free_channel(priv->chan); 554 } 555 556 /* get DCMF version from firmware */ 557 ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION, 558 0, rsu_dcmf_version_callback); 559 if (ret) { 560 dev_err(dev, "Error, getting DCMF version %i\n", ret); 561 stratix10_svc_free_channel(priv->chan); 562 } 563 564 ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 565 if (ret) { 566 dev_err(dev, "Error, getting RSU retry %i\n", ret); 567 stratix10_svc_free_channel(priv->chan); 568 } 569 570 ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0, 571 rsu_max_retry_callback); 572 if (ret) { 573 dev_err(dev, "Error, getting RSU max retry %i\n", ret); 574 stratix10_svc_free_channel(priv->chan); 575 } 576 577 return ret; 578} 579 580static int stratix10_rsu_remove(struct platform_device *pdev) 581{ 582 struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev); 583 584 stratix10_svc_free_channel(priv->chan); 585 return 0; 586} 587 588static struct platform_driver stratix10_rsu_driver = { 589 .probe = stratix10_rsu_probe, 590 .remove = stratix10_rsu_remove, 591 .driver = { 592 .name = "stratix10-rsu", 593 .dev_groups = rsu_groups, 594 }, 595}; 596 597module_platform_driver(stratix10_rsu_driver); 598 599MODULE_LICENSE("GPL v2"); 600MODULE_DESCRIPTION("Intel Remote System Update Driver"); 601MODULE_AUTHOR("Richard Gong <richard.gong@intel.com>");