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