linux/drivers/firmware/stratix10-rsu.c
<<
>>
Prefs
   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>");
 602