xref: /openbmc/linux/drivers/firmware/stratix10-rsu.c (revision 4526ebbc77732bcae965ee374cf3e8d86436b2ad)
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