root/drivers/firmware/stratix10-rsu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rsu_status_callback
  2. rsu_command_callback
  3. rsu_retry_callback
  4. rsu_send_msg
  5. current_image_show
  6. fail_image_show
  7. version_show
  8. state_show
  9. error_location_show
  10. error_details_show
  11. retry_counter_show
  12. reboot_image_store
  13. notify_store
  14. stratix10_rsu_probe
  15. stratix10_rsu_remove

   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_FW_VERSION_MASK             GENMASK_ULL(15, 0)
  24 
  25 #define RSU_TIMEOUT     (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS))
  26 
  27 #define INVALID_RETRY_COUNTER           0xFFFFFFFF
  28 
  29 typedef void (*rsu_callback)(struct stratix10_svc_client *client,
  30                              struct stratix10_svc_cb_data *data);
  31 /**
  32  * struct stratix10_rsu_priv - rsu data structure
  33  * @chan: pointer to the allocated service channel
  34  * @client: active service client
  35  * @completion: state for callback completion
  36  * @lock: a mutex to protect callback completion state
  37  * @status.current_image: address of image currently running in flash
  38  * @status.fail_image: address of failed image in flash
  39  * @status.version: the version number of RSU firmware
  40  * @status.state: the state of RSU system
  41  * @status.error_details: error code
  42  * @status.error_location: the error offset inside the image that failed
  43  * @retry_counter: the current image's retry counter
  44  */
  45 struct stratix10_rsu_priv {
  46         struct stratix10_svc_chan *chan;
  47         struct stratix10_svc_client client;
  48         struct completion completion;
  49         struct mutex lock;
  50         struct {
  51                 unsigned long current_image;
  52                 unsigned long fail_image;
  53                 unsigned int version;
  54                 unsigned int state;
  55                 unsigned int error_details;
  56                 unsigned int error_location;
  57         } status;
  58         unsigned int retry_counter;
  59 };
  60 
  61 /**
  62  * rsu_status_callback() - Status callback from Intel Service Layer
  63  * @client: pointer to service client
  64  * @data: pointer to callback data structure
  65  *
  66  * Callback from Intel service layer for RSU status request. Status is
  67  * only updated after a system reboot, so a get updated status call is
  68  * made during driver probe.
  69  */
  70 static void rsu_status_callback(struct stratix10_svc_client *client,
  71                                 struct stratix10_svc_cb_data *data)
  72 {
  73         struct stratix10_rsu_priv *priv = client->priv;
  74         struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1;
  75 
  76         if (data->status == BIT(SVC_STATUS_RSU_OK)) {
  77                 priv->status.version = FIELD_GET(RSU_VERSION_MASK,
  78                                                  res->a2);
  79                 priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2);
  80                 priv->status.fail_image = res->a1;
  81                 priv->status.current_image = res->a0;
  82                 priv->status.error_location =
  83                         FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3);
  84                 priv->status.error_details =
  85                         FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3);
  86         } else {
  87                 dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n",
  88                         res->a0);
  89                 priv->status.version = 0;
  90                 priv->status.state = 0;
  91                 priv->status.fail_image = 0;
  92                 priv->status.current_image = 0;
  93                 priv->status.error_location = 0;
  94                 priv->status.error_details = 0;
  95         }
  96 
  97         complete(&priv->completion);
  98 }
  99 
 100 /**
 101  * rsu_command_callback() - Update callback from Intel Service Layer
 102  * @client: pointer to client
 103  * @data: pointer to callback data structure
 104  *
 105  * Callback from Intel service layer for RSU commands.
 106  */
 107 static void rsu_command_callback(struct stratix10_svc_client *client,
 108                                  struct stratix10_svc_cb_data *data)
 109 {
 110         struct stratix10_rsu_priv *priv = client->priv;
 111 
 112         if (data->status != BIT(SVC_STATUS_RSU_OK))
 113                 dev_err(client->dev, "RSU returned status is %i\n",
 114                         data->status);
 115         complete(&priv->completion);
 116 }
 117 
 118 /**
 119  * rsu_retry_callback() - Callback from Intel service layer for getting
 120  * the current image's retry counter from firmware
 121  * @client: pointer to client
 122  * @data: pointer to callback data structure
 123  *
 124  * Callback from Intel service layer for retry counter, which is used by
 125  * user to know how many times the images is still allowed to reload
 126  * itself before giving up and starting RSU fail-over flow.
 127  */
 128 static void rsu_retry_callback(struct stratix10_svc_client *client,
 129                                struct stratix10_svc_cb_data *data)
 130 {
 131         struct stratix10_rsu_priv *priv = client->priv;
 132         unsigned int *counter = (unsigned int *)data->kaddr1;
 133 
 134         if (data->status == BIT(SVC_STATUS_RSU_OK))
 135                 priv->retry_counter = *counter;
 136         else
 137                 dev_err(client->dev, "Failed to get retry counter %i\n",
 138                         data->status);
 139 
 140         complete(&priv->completion);
 141 }
 142 
 143 /**
 144  * rsu_send_msg() - send a message to Intel service layer
 145  * @priv: pointer to rsu private data
 146  * @command: RSU status or update command
 147  * @arg: the request argument, the bitstream address or notify status
 148  * @callback: function pointer for the callback (status or update)
 149  *
 150  * Start an Intel service layer transaction to perform the SMC call that
 151  * is necessary to get RSU boot log or set the address of bitstream to
 152  * boot after reboot.
 153  *
 154  * Returns 0 on success or -ETIMEDOUT on error.
 155  */
 156 static int rsu_send_msg(struct stratix10_rsu_priv *priv,
 157                         enum stratix10_svc_command_code command,
 158                         unsigned long arg,
 159                         rsu_callback callback)
 160 {
 161         struct stratix10_svc_client_msg msg;
 162         int ret;
 163 
 164         mutex_lock(&priv->lock);
 165         reinit_completion(&priv->completion);
 166         priv->client.receive_cb = callback;
 167 
 168         msg.command = command;
 169         if (arg)
 170                 msg.arg[0] = arg;
 171 
 172         ret = stratix10_svc_send(priv->chan, &msg);
 173         if (ret < 0)
 174                 goto status_done;
 175 
 176         ret = wait_for_completion_interruptible_timeout(&priv->completion,
 177                                                         RSU_TIMEOUT);
 178         if (!ret) {
 179                 dev_err(priv->client.dev,
 180                         "timeout waiting for SMC call\n");
 181                 ret = -ETIMEDOUT;
 182                 goto status_done;
 183         } else if (ret < 0) {
 184                 dev_err(priv->client.dev,
 185                         "error %d waiting for SMC call\n", ret);
 186                 goto status_done;
 187         } else {
 188                 ret = 0;
 189         }
 190 
 191 status_done:
 192         stratix10_svc_done(priv->chan);
 193         mutex_unlock(&priv->lock);
 194         return ret;
 195 }
 196 
 197 /*
 198  * This driver exposes some optional features of the Intel Stratix 10 SoC FPGA.
 199  * The sysfs interfaces exposed here are FPGA Remote System Update (RSU)
 200  * related. They allow user space software to query the configuration system
 201  * status and to request optional reboot behavior specific to Intel FPGAs.
 202  */
 203 
 204 static ssize_t current_image_show(struct device *dev,
 205                                   struct device_attribute *attr, char *buf)
 206 {
 207         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 208 
 209         if (!priv)
 210                 return -ENODEV;
 211 
 212         return sprintf(buf, "0x%08lx\n", priv->status.current_image);
 213 }
 214 
 215 static ssize_t fail_image_show(struct device *dev,
 216                                struct device_attribute *attr, char *buf)
 217 {
 218         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 219 
 220         if (!priv)
 221                 return -ENODEV;
 222 
 223         return sprintf(buf, "0x%08lx\n", priv->status.fail_image);
 224 }
 225 
 226 static ssize_t version_show(struct device *dev, struct device_attribute *attr,
 227                             char *buf)
 228 {
 229         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 230 
 231         if (!priv)
 232                 return -ENODEV;
 233 
 234         return sprintf(buf, "0x%08x\n", priv->status.version);
 235 }
 236 
 237 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
 238                           char *buf)
 239 {
 240         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 241 
 242         if (!priv)
 243                 return -ENODEV;
 244 
 245         return sprintf(buf, "0x%08x\n", priv->status.state);
 246 }
 247 
 248 static ssize_t error_location_show(struct device *dev,
 249                                    struct device_attribute *attr, char *buf)
 250 {
 251         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 252 
 253         if (!priv)
 254                 return -ENODEV;
 255 
 256         return sprintf(buf, "0x%08x\n", priv->status.error_location);
 257 }
 258 
 259 static ssize_t error_details_show(struct device *dev,
 260                                   struct device_attribute *attr, char *buf)
 261 {
 262         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 263 
 264         if (!priv)
 265                 return -ENODEV;
 266 
 267         return sprintf(buf, "0x%08x\n", priv->status.error_details);
 268 }
 269 
 270 static ssize_t retry_counter_show(struct device *dev,
 271                                   struct device_attribute *attr, char *buf)
 272 {
 273         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 274 
 275         if (!priv)
 276                 return -ENODEV;
 277 
 278         return sprintf(buf, "0x%08x\n", priv->retry_counter);
 279 }
 280 
 281 static ssize_t reboot_image_store(struct device *dev,
 282                                   struct device_attribute *attr,
 283                                   const char *buf, size_t count)
 284 {
 285         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 286         unsigned long address;
 287         int ret;
 288 
 289         if (priv == 0)
 290                 return -ENODEV;
 291 
 292         ret = kstrtoul(buf, 0, &address);
 293         if (ret)
 294                 return ret;
 295 
 296         ret = rsu_send_msg(priv, COMMAND_RSU_UPDATE,
 297                            address, rsu_command_callback);
 298         if (ret) {
 299                 dev_err(dev, "Error, RSU update returned %i\n", ret);
 300                 return ret;
 301         }
 302 
 303         return count;
 304 }
 305 
 306 static ssize_t notify_store(struct device *dev,
 307                             struct device_attribute *attr,
 308                             const char *buf, size_t count)
 309 {
 310         struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
 311         unsigned long status;
 312         int ret;
 313 
 314         if (priv == 0)
 315                 return -ENODEV;
 316 
 317         ret = kstrtoul(buf, 0, &status);
 318         if (ret)
 319                 return ret;
 320 
 321         ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY,
 322                            status, rsu_command_callback);
 323         if (ret) {
 324                 dev_err(dev, "Error, RSU notify returned %i\n", ret);
 325                 return ret;
 326         }
 327 
 328         /* to get the updated state */
 329         ret = rsu_send_msg(priv, COMMAND_RSU_STATUS,
 330                            0, rsu_status_callback);
 331         if (ret) {
 332                 dev_err(dev, "Error, getting RSU status %i\n", ret);
 333                 return ret;
 334         }
 335 
 336         /* only 19.3 or late version FW supports retry counter feature */
 337         if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) {
 338                 ret = rsu_send_msg(priv, COMMAND_RSU_RETRY,
 339                                    0, rsu_retry_callback);
 340                 if (ret) {
 341                         dev_err(dev,
 342                                 "Error, getting RSU retry %i\n", ret);
 343                         return ret;
 344                 }
 345         }
 346 
 347         return count;
 348 }
 349 
 350 static DEVICE_ATTR_RO(current_image);
 351 static DEVICE_ATTR_RO(fail_image);
 352 static DEVICE_ATTR_RO(state);
 353 static DEVICE_ATTR_RO(version);
 354 static DEVICE_ATTR_RO(error_location);
 355 static DEVICE_ATTR_RO(error_details);
 356 static DEVICE_ATTR_RO(retry_counter);
 357 static DEVICE_ATTR_WO(reboot_image);
 358 static DEVICE_ATTR_WO(notify);
 359 
 360 static struct attribute *rsu_attrs[] = {
 361         &dev_attr_current_image.attr,
 362         &dev_attr_fail_image.attr,
 363         &dev_attr_state.attr,
 364         &dev_attr_version.attr,
 365         &dev_attr_error_location.attr,
 366         &dev_attr_error_details.attr,
 367         &dev_attr_retry_counter.attr,
 368         &dev_attr_reboot_image.attr,
 369         &dev_attr_notify.attr,
 370         NULL
 371 };
 372 
 373 ATTRIBUTE_GROUPS(rsu);
 374 
 375 static int stratix10_rsu_probe(struct platform_device *pdev)
 376 {
 377         struct device *dev = &pdev->dev;
 378         struct stratix10_rsu_priv *priv;
 379         int ret;
 380 
 381         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 382         if (!priv)
 383                 return -ENOMEM;
 384 
 385         priv->client.dev = dev;
 386         priv->client.receive_cb = NULL;
 387         priv->client.priv = priv;
 388         priv->status.current_image = 0;
 389         priv->status.fail_image = 0;
 390         priv->status.error_location = 0;
 391         priv->status.error_details = 0;
 392         priv->status.version = 0;
 393         priv->status.state = 0;
 394         priv->retry_counter = INVALID_RETRY_COUNTER;
 395 
 396         mutex_init(&priv->lock);
 397         priv->chan = stratix10_svc_request_channel_byname(&priv->client,
 398                                                           SVC_CLIENT_RSU);
 399         if (IS_ERR(priv->chan)) {
 400                 dev_err(dev, "couldn't get service channel %s\n",
 401                         SVC_CLIENT_RSU);
 402                 return PTR_ERR(priv->chan);
 403         }
 404 
 405         init_completion(&priv->completion);
 406         platform_set_drvdata(pdev, priv);
 407 
 408         /* get the initial state from firmware */
 409         ret = rsu_send_msg(priv, COMMAND_RSU_STATUS,
 410                            0, rsu_status_callback);
 411         if (ret) {
 412                 dev_err(dev, "Error, getting RSU status %i\n", ret);
 413                 stratix10_svc_free_channel(priv->chan);
 414         }
 415 
 416         /* only 19.3 or late version FW supports retry counter feature */
 417         if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) {
 418                 ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0,
 419                                    rsu_retry_callback);
 420                 if (ret) {
 421                         dev_err(dev,
 422                                 "Error, getting RSU retry %i\n", ret);
 423                         stratix10_svc_free_channel(priv->chan);
 424                 }
 425         }
 426 
 427         return ret;
 428 }
 429 
 430 static int stratix10_rsu_remove(struct platform_device *pdev)
 431 {
 432         struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev);
 433 
 434         stratix10_svc_free_channel(priv->chan);
 435         return 0;
 436 }
 437 
 438 static struct platform_driver stratix10_rsu_driver = {
 439         .probe = stratix10_rsu_probe,
 440         .remove = stratix10_rsu_remove,
 441         .driver = {
 442                 .name = "stratix10-rsu",
 443                 .dev_groups = rsu_groups,
 444         },
 445 };
 446 
 447 module_platform_driver(stratix10_rsu_driver);
 448 
 449 MODULE_LICENSE("GPL v2");
 450 MODULE_DESCRIPTION("Intel Remote System Update Driver");
 451 MODULE_AUTHOR("Richard Gong <richard.gong@intel.com>");

/* [<][>][^][v][top][bottom][index][help] */