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>"); 452