xref: /dpdk/drivers/raw/ifpga/base/ifpga_sec_mgr.c (revision 20077edf5f09961c7b4434bdd4d48c4353d65507)
1a05bd1b4SWei Huang /* SPDX-License-Identifier: BSD-3-Clause
2a05bd1b4SWei Huang  * Copyright(c) 2020 Intel Corporation
3a05bd1b4SWei Huang  */
4a05bd1b4SWei Huang 
5a05bd1b4SWei Huang #include <fcntl.h>
6a05bd1b4SWei Huang #include <signal.h>
7a05bd1b4SWei Huang #include <unistd.h>
8a05bd1b4SWei Huang #include "ifpga_sec_mgr.h"
9a05bd1b4SWei Huang 
10a05bd1b4SWei Huang 
11a05bd1b4SWei Huang static const char * const rsu_prog[] = {"IDLE", "PREPARING", "SLEEPING",
12a05bd1b4SWei Huang 	"READY", "AUTHENTICATING", "COPYING", "CANCELLATION", "PROGRAMMING_KEY",
13a05bd1b4SWei Huang 	"DONE", "PKVL_DONE"};
14a05bd1b4SWei Huang static const char * const rsu_statl[] = {"NORMAL", "TIMEOUT", "AUTH_FAIL",
15a05bd1b4SWei Huang 	"COPY_FAIL", "FATAL", "PKVL_REJECT", "NON_INCR", "ERASE_FAIL",
16a05bd1b4SWei Huang 	"WEAROUT"};
17a05bd1b4SWei Huang static const char * const rsu_stath[] = {"NIOS_OK", "USER_OK", "FACTORY_OK",
18a05bd1b4SWei Huang 	"USER_FAIL", "FACTORY_FAIL", "NIOS_FLASH_ERR", "FPGA_FLASH_ERR"};
19a05bd1b4SWei Huang 
rsu_progress_name(uint32_t prog)20a05bd1b4SWei Huang static const char *rsu_progress_name(uint32_t prog)
21a05bd1b4SWei Huang {
22a05bd1b4SWei Huang 	if (prog > SEC_PROGRESS_PKVL_PROM_DONE)
23a05bd1b4SWei Huang 		return "UNKNOWN";
24a05bd1b4SWei Huang 	else
25a05bd1b4SWei Huang 		return rsu_prog[prog];
26a05bd1b4SWei Huang }
27a05bd1b4SWei Huang 
rsu_status_name(uint32_t stat)28a05bd1b4SWei Huang static const char *rsu_status_name(uint32_t stat)
29a05bd1b4SWei Huang {
30a05bd1b4SWei Huang 	if (stat >= SEC_STATUS_NIOS_OK) {
31a05bd1b4SWei Huang 		if (stat > SEC_STATUS_FPGA_FLASH_ERR)
32a05bd1b4SWei Huang 			return "UNKNOWN";
33a05bd1b4SWei Huang 		else
34a05bd1b4SWei Huang 			return rsu_stath[stat-SEC_STATUS_NIOS_OK];
35a05bd1b4SWei Huang 	} else {
36a05bd1b4SWei Huang 		if (stat > SEC_STATUS_WEAROUT)
37a05bd1b4SWei Huang 			return "UNKNOWN";
38a05bd1b4SWei Huang 		else
39a05bd1b4SWei Huang 			return rsu_statl[stat];
40a05bd1b4SWei Huang 	}
41a05bd1b4SWei Huang }
42a05bd1b4SWei Huang 
secure_start_done(uint32_t doorbell)43a05bd1b4SWei Huang static bool secure_start_done(uint32_t doorbell)
44a05bd1b4SWei Huang {
45a05bd1b4SWei Huang 	return (SEC_STATUS_G(doorbell) == SEC_STATUS_ERASE_FAIL ||
46a05bd1b4SWei Huang 		SEC_STATUS_G(doorbell) == SEC_STATUS_WEAROUT ||
47a05bd1b4SWei Huang 		(SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_IDLE &&
48a05bd1b4SWei Huang 		SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_RSU_DONE));
49a05bd1b4SWei Huang }
50a05bd1b4SWei Huang 
secure_prog_ready(uint32_t doorbell)51a05bd1b4SWei Huang static bool secure_prog_ready(uint32_t doorbell)
52a05bd1b4SWei Huang {
53a05bd1b4SWei Huang 	return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY);
54a05bd1b4SWei Huang }
55a05bd1b4SWei Huang 
poll_timeout(struct intel_max10_device * dev,uint32_t offset,bool (* cond)(uint32_t),uint32_t interval_ms,uint32_t timeout_ms)56a05bd1b4SWei Huang static int poll_timeout(struct intel_max10_device *dev, uint32_t offset,
57a05bd1b4SWei Huang 	bool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms)
58a05bd1b4SWei Huang {
59a05bd1b4SWei Huang 	uint32_t val = 0;
60a05bd1b4SWei Huang 	int ret = 0;
61a05bd1b4SWei Huang 
62a05bd1b4SWei Huang 	for (;;) {
63a05bd1b4SWei Huang 		ret = max10_sys_read(dev, offset, &val);
64a05bd1b4SWei Huang 		if (ret < 0) {
65a05bd1b4SWei Huang 			dev_err(dev,
66a05bd1b4SWei Huang 				"Failed to read max10 register 0x%x [e:%d]\n",
67a05bd1b4SWei Huang 				offset, ret);
68a05bd1b4SWei Huang 			break;
69a05bd1b4SWei Huang 		}
70a05bd1b4SWei Huang 
71a05bd1b4SWei Huang 		if (cond(val)) {
72a05bd1b4SWei Huang 			dev_debug(dev,
73a05bd1b4SWei Huang 				"Read 0x%08x from max10 register 0x%x "
74a05bd1b4SWei Huang 				"[poll success]\n", val, offset);
75a05bd1b4SWei Huang 			ret = 0;
76a05bd1b4SWei Huang 			break;
77a05bd1b4SWei Huang 		}
78a05bd1b4SWei Huang 		if (timeout_ms > interval_ms)
79a05bd1b4SWei Huang 			timeout_ms -= interval_ms;
80a05bd1b4SWei Huang 		else
81a05bd1b4SWei Huang 			timeout_ms = 0;
82a05bd1b4SWei Huang 		if (timeout_ms == 0) {
83a05bd1b4SWei Huang 			dev_debug(dev,
84a05bd1b4SWei Huang 				"Read 0x%08x from max10 register 0x%x "
85a05bd1b4SWei Huang 				"[poll timeout]\n", val, offset);
86a05bd1b4SWei Huang 			ret = -ETIMEDOUT;
87a05bd1b4SWei Huang 			break;
88a05bd1b4SWei Huang 		}
89a05bd1b4SWei Huang 		msleep(interval_ms);
90a05bd1b4SWei Huang 	}
91a05bd1b4SWei Huang 
92a05bd1b4SWei Huang 	return ret;
93a05bd1b4SWei Huang }
94a05bd1b4SWei Huang 
n3000_secure_update_start(struct intel_max10_device * dev)95a05bd1b4SWei Huang static int n3000_secure_update_start(struct intel_max10_device *dev)
96a05bd1b4SWei Huang {
97a05bd1b4SWei Huang 	uint32_t doorbell = 0;
98a05bd1b4SWei Huang 	uint32_t prog = 0;
99a05bd1b4SWei Huang 	uint32_t status = 0;
100a05bd1b4SWei Huang 	int ret = 0;
101a05bd1b4SWei Huang 
102a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
103a05bd1b4SWei Huang 	if (ret < 0) {
104a05bd1b4SWei Huang 		dev_err(dev,
105a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
106a05bd1b4SWei Huang 			ret);
107a05bd1b4SWei Huang 		return ret;
108a05bd1b4SWei Huang 	}
109a05bd1b4SWei Huang 
110a05bd1b4SWei Huang 	prog = SEC_PROGRESS_G(doorbell);
111a05bd1b4SWei Huang 	if ((prog != SEC_PROGRESS_IDLE) && (prog != SEC_PROGRESS_RSU_DONE)) {
112a05bd1b4SWei Huang 		dev_debug(dev, "Current RSU progress is %s\n",
113a05bd1b4SWei Huang 			rsu_progress_name(prog));
114a05bd1b4SWei Huang 		return -EBUSY;
115a05bd1b4SWei Huang 	}
116a05bd1b4SWei Huang 
117a05bd1b4SWei Huang 	ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
118a05bd1b4SWei Huang 		RSU_REQUEST | HOST_STATUS, RSU_REQUEST);
119a05bd1b4SWei Huang 	if (ret < 0) {
120a05bd1b4SWei Huang 		dev_err(dev,
121a05bd1b4SWei Huang 			"Failed to updt max10 doorbell register [e:%d]\n",
122a05bd1b4SWei Huang 			ret);
123a05bd1b4SWei Huang 		return ret;
124a05bd1b4SWei Huang 	}
125a05bd1b4SWei Huang 
126a05bd1b4SWei Huang 	ret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done,
127a05bd1b4SWei Huang 		IFPGA_SEC_START_INTERVAL_MS, IFPGA_SEC_START_TIMEOUT_MS);
128a05bd1b4SWei Huang 	if (ret < 0) {
129a05bd1b4SWei Huang 		dev_err(dev,
130a05bd1b4SWei Huang 			"Failed to poll max10 doorbell register [e:%d]\n",
131a05bd1b4SWei Huang 			ret);
132a05bd1b4SWei Huang 		return ret;
133a05bd1b4SWei Huang 	}
134a05bd1b4SWei Huang 
135a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
136a05bd1b4SWei Huang 	if (ret < 0) {
137a05bd1b4SWei Huang 		dev_err(dev,
138a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
139a05bd1b4SWei Huang 			ret);
140a05bd1b4SWei Huang 		return ret;
141a05bd1b4SWei Huang 	}
142a05bd1b4SWei Huang 
143a05bd1b4SWei Huang 	status = SEC_STATUS_G(doorbell);
144a05bd1b4SWei Huang 	if (status == SEC_STATUS_WEAROUT)
145a05bd1b4SWei Huang 		return -EAGAIN;
146a05bd1b4SWei Huang 
147a05bd1b4SWei Huang 	if (status == SEC_STATUS_ERASE_FAIL)
148a05bd1b4SWei Huang 		return -EIO;
149a05bd1b4SWei Huang 
150a05bd1b4SWei Huang 	return 0;
151a05bd1b4SWei Huang }
152a05bd1b4SWei Huang 
n3000_cancel(struct ifpga_sec_mgr * smgr)153a05bd1b4SWei Huang static int n3000_cancel(struct ifpga_sec_mgr *smgr)
154a05bd1b4SWei Huang {
155a05bd1b4SWei Huang 	struct intel_max10_device *dev = NULL;
156a05bd1b4SWei Huang 	uint32_t doorbell = 0;
157a05bd1b4SWei Huang 	uint32_t prog = 0;
158a05bd1b4SWei Huang 	int ret = 0;
159a05bd1b4SWei Huang 
160a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
161a05bd1b4SWei Huang 		return -ENODEV;
162a05bd1b4SWei Huang 	dev = (struct intel_max10_device *)smgr->max10_dev;
163a05bd1b4SWei Huang 
164a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
165a05bd1b4SWei Huang 	if (ret < 0) {
166a05bd1b4SWei Huang 		dev_err(dev,
167a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
168a05bd1b4SWei Huang 			ret);
169a05bd1b4SWei Huang 		return ret;
170a05bd1b4SWei Huang 	}
171a05bd1b4SWei Huang 
172a05bd1b4SWei Huang 	prog = SEC_PROGRESS_G(doorbell);
173a05bd1b4SWei Huang 	if (prog == SEC_PROGRESS_IDLE)
174a05bd1b4SWei Huang 		return 0;
175a05bd1b4SWei Huang 	if (prog != SEC_PROGRESS_READY)
176a05bd1b4SWei Huang 		return -EBUSY;
177a05bd1b4SWei Huang 
178a05bd1b4SWei Huang 	return max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
179a05bd1b4SWei Huang 		HOST_STATUS_S(HOST_STATUS_ABORT_RSU));
180a05bd1b4SWei Huang }
181a05bd1b4SWei Huang 
n3000_prepare(struct ifpga_sec_mgr * smgr)182a05bd1b4SWei Huang static int n3000_prepare(struct ifpga_sec_mgr *smgr)
183a05bd1b4SWei Huang {
184a05bd1b4SWei Huang 	struct intel_max10_device *dev = NULL;
185a05bd1b4SWei Huang 	int retry = 0;
186a05bd1b4SWei Huang 	int ret = 0;
187a05bd1b4SWei Huang 
188a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
189a05bd1b4SWei Huang 		return -ENODEV;
190a05bd1b4SWei Huang 	dev = (struct intel_max10_device *)smgr->max10_dev;
191a05bd1b4SWei Huang 
192a05bd1b4SWei Huang 	ret = n3000_secure_update_start(dev);
193a05bd1b4SWei Huang 	if (ret == -EBUSY)
194a05bd1b4SWei Huang 		n3000_cancel(smgr);
195a05bd1b4SWei Huang 
196a05bd1b4SWei Huang 	while (ret) {
197a05bd1b4SWei Huang 		if (++retry > IFPGA_RSU_START_RETRY)
198a05bd1b4SWei Huang 			break;
199a05bd1b4SWei Huang 		msleep(1000);
200a05bd1b4SWei Huang 		ret = n3000_secure_update_start(dev);
201a05bd1b4SWei Huang 	}
202a05bd1b4SWei Huang 	if (retry > IFPGA_RSU_START_RETRY) {
203a05bd1b4SWei Huang 		dev_err(dev, "Failed to start secure flash update\n");
204a05bd1b4SWei Huang 		ret = -EAGAIN;
205a05bd1b4SWei Huang 	}
206a05bd1b4SWei Huang 
207a05bd1b4SWei Huang 	return ret;
208a05bd1b4SWei Huang }
209a05bd1b4SWei Huang 
n3000_bulk_write(struct intel_max10_device * dev,uint32_t addr,char * buf,uint32_t len)210a05bd1b4SWei Huang static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr,
211a05bd1b4SWei Huang 	char *buf, uint32_t len)
212a05bd1b4SWei Huang {
213a05bd1b4SWei Huang 	uint32_t i = 0;
214a05bd1b4SWei Huang 	uint32_t n = 0;
215a05bd1b4SWei Huang 	uint32_t v = 0;
216a05bd1b4SWei Huang 	uint32_t p = 0;
217a05bd1b4SWei Huang 	int ret = 0;
218a05bd1b4SWei Huang 
219a05bd1b4SWei Huang 	if (len & 0x3) {
220a05bd1b4SWei Huang 		dev_err(dev,
221a05bd1b4SWei Huang 			"Length of data block is not 4 bytes aligned [e:%u]\n",
222a05bd1b4SWei Huang 			len);
223a05bd1b4SWei Huang 		return -EINVAL;
224a05bd1b4SWei Huang 	}
225a05bd1b4SWei Huang 
226a05bd1b4SWei Huang 	n = len >> 2;
227a05bd1b4SWei Huang 	for (i = 0; i < n; i++) {
228a05bd1b4SWei Huang 		p = i << 2;
229a05bd1b4SWei Huang 		v = *(uint32_t *)(buf + p);
230a05bd1b4SWei Huang 		ret = max10_reg_write(dev, addr + p, v);
231a05bd1b4SWei Huang 		if (ret < 0) {
232a05bd1b4SWei Huang 			dev_err(dev,
233a05bd1b4SWei Huang 				"Failed to write to staging area 0x%08x [e:%d]\n",
234a05bd1b4SWei Huang 				addr + p, ret);
235a05bd1b4SWei Huang 			return ret;
236a05bd1b4SWei Huang 		}
237a05bd1b4SWei Huang 		usleep(1);
238a05bd1b4SWei Huang 	}
239a05bd1b4SWei Huang 
240a05bd1b4SWei Huang 	return 0;
241a05bd1b4SWei Huang }
242a05bd1b4SWei Huang 
n3000_write_blk(struct ifpga_sec_mgr * smgr,char * buf,uint32_t offset,uint32_t len)243a05bd1b4SWei Huang static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf,
244a05bd1b4SWei Huang 	uint32_t offset, uint32_t len)
245a05bd1b4SWei Huang {
246a05bd1b4SWei Huang 	struct intel_max10_device *dev = NULL;
247a05bd1b4SWei Huang 	uint32_t doorbell = 0;
248a05bd1b4SWei Huang 	uint32_t prog = 0;
249a05bd1b4SWei Huang 	uint32_t m = 0;
250a05bd1b4SWei Huang 	int ret = 0;
251a05bd1b4SWei Huang 
252a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
253a05bd1b4SWei Huang 		return -ENODEV;
254a05bd1b4SWei Huang 	dev = (struct intel_max10_device *)smgr->max10_dev;
255a05bd1b4SWei Huang 
256a05bd1b4SWei Huang 	if (offset + len > dev->staging_area_size) {
257a05bd1b4SWei Huang 		dev_err(dev,
258a05bd1b4SWei Huang 			"Write position would be out of staging area [e:%u]\n",
259a05bd1b4SWei Huang 			dev->staging_area_size);
260a05bd1b4SWei Huang 		return -ENOMEM;
261a05bd1b4SWei Huang 	}
262a05bd1b4SWei Huang 
263a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
264a05bd1b4SWei Huang 	if (ret < 0) {
265a05bd1b4SWei Huang 		dev_err(dev,
266a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
267a05bd1b4SWei Huang 			ret);
268a05bd1b4SWei Huang 		return ret;
269a05bd1b4SWei Huang 	}
270a05bd1b4SWei Huang 
271a05bd1b4SWei Huang 	prog = SEC_PROGRESS_G(doorbell);
272a05bd1b4SWei Huang 	if (prog == SEC_PROGRESS_PREPARE)
273a05bd1b4SWei Huang 		return -EAGAIN;
274a05bd1b4SWei Huang 	else if (prog != SEC_PROGRESS_READY)
275a05bd1b4SWei Huang 		return -EBUSY;
276a05bd1b4SWei Huang 
277a05bd1b4SWei Huang 	m = len & 0x3;
278a05bd1b4SWei Huang 	if (m != 0)
279a05bd1b4SWei Huang 		len += 4 - m;   /* make length to 4 bytes align */
280a05bd1b4SWei Huang 
281a05bd1b4SWei Huang 	return n3000_bulk_write(dev, dev->staging_area_base + offset, buf, len);
282a05bd1b4SWei Huang }
283a05bd1b4SWei Huang 
n3000_write_done(struct ifpga_sec_mgr * smgr)284a05bd1b4SWei Huang static int n3000_write_done(struct ifpga_sec_mgr *smgr)
285a05bd1b4SWei Huang {
286a05bd1b4SWei Huang 	struct intel_max10_device *dev = NULL;
287a05bd1b4SWei Huang 	uint32_t doorbell = 0;
288a05bd1b4SWei Huang 	uint32_t prog = 0;
289a05bd1b4SWei Huang 	uint32_t status = 0;
290a05bd1b4SWei Huang 	int ret = 0;
291a05bd1b4SWei Huang 
292a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
293a05bd1b4SWei Huang 		return -ENODEV;
294a05bd1b4SWei Huang 	dev = (struct intel_max10_device *)smgr->max10_dev;
295a05bd1b4SWei Huang 
296a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
297a05bd1b4SWei Huang 	if (ret < 0) {
298a05bd1b4SWei Huang 		dev_err(dev,
299a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
300a05bd1b4SWei Huang 			ret);
301a05bd1b4SWei Huang 		return ret;
302a05bd1b4SWei Huang 	}
303a05bd1b4SWei Huang 
304a05bd1b4SWei Huang 	prog = SEC_PROGRESS_G(doorbell);
305a05bd1b4SWei Huang 	if (prog != SEC_PROGRESS_READY)
306a05bd1b4SWei Huang 		return -EBUSY;
307a05bd1b4SWei Huang 
308a05bd1b4SWei Huang 	ret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
309a05bd1b4SWei Huang 		HOST_STATUS_S(HOST_STATUS_WRITE_DONE));
310a05bd1b4SWei Huang 	if (ret < 0) {
311a05bd1b4SWei Huang 		dev_err(dev,
312a05bd1b4SWei Huang 			"Failed to update max10 doorbell register [e:%d]\n",
313a05bd1b4SWei Huang 			ret);
314a05bd1b4SWei Huang 		return ret;
315a05bd1b4SWei Huang 	}
316a05bd1b4SWei Huang 
317a05bd1b4SWei Huang 	ret = poll_timeout(dev, MAX10_DOORBELL, secure_prog_ready,
318a05bd1b4SWei Huang 		IFPGA_NIOS_HANDSHAKE_INTERVAL_MS,
319a05bd1b4SWei Huang 		IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS);
320a05bd1b4SWei Huang 	if (ret < 0) {
321a05bd1b4SWei Huang 		dev_err(dev,
322a05bd1b4SWei Huang 			"Failed to poll max10 doorbell register [e:%d]\n",
323a05bd1b4SWei Huang 			ret);
324a05bd1b4SWei Huang 		return ret;
325a05bd1b4SWei Huang 	}
326a05bd1b4SWei Huang 
327a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
328a05bd1b4SWei Huang 	if (ret < 0) {
329a05bd1b4SWei Huang 		dev_err(dev,
330a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
331a05bd1b4SWei Huang 			ret);
332a05bd1b4SWei Huang 		return ret;
333a05bd1b4SWei Huang 	}
334a05bd1b4SWei Huang 
335a05bd1b4SWei Huang 	status = SEC_STATUS_G(doorbell);
336a05bd1b4SWei Huang 	switch (status) {
337a05bd1b4SWei Huang 	case SEC_STATUS_NORMAL:
338a05bd1b4SWei Huang 	case SEC_STATUS_NIOS_OK:
339a05bd1b4SWei Huang 	case SEC_STATUS_USER_OK:
340a05bd1b4SWei Huang 	case SEC_STATUS_FACTORY_OK:
341a05bd1b4SWei Huang 		ret = 0;
342a05bd1b4SWei Huang 		break;
343a05bd1b4SWei Huang 	default:
344a05bd1b4SWei Huang 		ret = -EIO;
345a05bd1b4SWei Huang 		break;
346a05bd1b4SWei Huang 	}
347a05bd1b4SWei Huang 
348a05bd1b4SWei Huang 	return ret;
349a05bd1b4SWei Huang }
350a05bd1b4SWei Huang 
n3000_check_complete(struct ifpga_sec_mgr * smgr)351a05bd1b4SWei Huang static int n3000_check_complete(struct ifpga_sec_mgr *smgr)
352a05bd1b4SWei Huang {
353a05bd1b4SWei Huang 	struct intel_max10_device *dev = NULL;
354a05bd1b4SWei Huang 	uint32_t doorbell = 0;
355a05bd1b4SWei Huang 	uint32_t status = 0;
356a05bd1b4SWei Huang 	uint32_t prog = 0;
357a05bd1b4SWei Huang 	int ret = 0;
358a05bd1b4SWei Huang 
359a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
360a05bd1b4SWei Huang 		return -ENODEV;
361a05bd1b4SWei Huang 	dev = (struct intel_max10_device *)smgr->max10_dev;
362a05bd1b4SWei Huang 
363a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
364a05bd1b4SWei Huang 	if (ret < 0) {
365a05bd1b4SWei Huang 		dev_err(dev,
366a05bd1b4SWei Huang 			"Failed to read max10 doorbell register [e:%d]\n",
367a05bd1b4SWei Huang 			ret);
368a05bd1b4SWei Huang 		return ret;
369a05bd1b4SWei Huang 	}
370a05bd1b4SWei Huang 
371a05bd1b4SWei Huang 	status = SEC_STATUS_G(doorbell);
372a05bd1b4SWei Huang 	switch (status) {
373a05bd1b4SWei Huang 	case SEC_STATUS_NORMAL:
374a05bd1b4SWei Huang 	case SEC_STATUS_NIOS_OK:
375a05bd1b4SWei Huang 	case SEC_STATUS_USER_OK:
376a05bd1b4SWei Huang 	case SEC_STATUS_FACTORY_OK:
377a05bd1b4SWei Huang 	case SEC_STATUS_WEAROUT:
378a05bd1b4SWei Huang 		break;
379a05bd1b4SWei Huang 	default:
380a05bd1b4SWei Huang 		return -EIO;
381a05bd1b4SWei Huang 	}
382a05bd1b4SWei Huang 
383a05bd1b4SWei Huang 	prog = SEC_PROGRESS_G(doorbell);
384a05bd1b4SWei Huang 	switch (prog) {
385a05bd1b4SWei Huang 	case SEC_PROGRESS_IDLE:
386a05bd1b4SWei Huang 	case SEC_PROGRESS_RSU_DONE:
387a05bd1b4SWei Huang 		return 0;
388a05bd1b4SWei Huang 	case SEC_PROGRESS_AUTHENTICATING:
389a05bd1b4SWei Huang 	case SEC_PROGRESS_COPYING:
390a05bd1b4SWei Huang 	case SEC_PROGRESS_UPDATE_CANCEL:
391a05bd1b4SWei Huang 	case SEC_PROGRESS_PROGRAM_KEY_HASH:
392a05bd1b4SWei Huang 		return -EAGAIN;
393a05bd1b4SWei Huang 	case SEC_PROGRESS_PREPARE:
394a05bd1b4SWei Huang 	case SEC_PROGRESS_READY:
395a05bd1b4SWei Huang 		return -EBUSY;
396a05bd1b4SWei Huang 	default:
397a05bd1b4SWei Huang 		return -EIO;
398a05bd1b4SWei Huang 	}
399a05bd1b4SWei Huang 
400a05bd1b4SWei Huang 	return 0;
401a05bd1b4SWei Huang }
402a05bd1b4SWei Huang 
n3000_reload_fpga(struct intel_max10_device * dev,int page)403a05bd1b4SWei Huang static int n3000_reload_fpga(struct intel_max10_device *dev, int page)
404a05bd1b4SWei Huang {
405a05bd1b4SWei Huang 	int ret = 0;
406a05bd1b4SWei Huang 
407a05bd1b4SWei Huang 	dev_info(dev, "Reload FPGA\n");
408a05bd1b4SWei Huang 
409a05bd1b4SWei Huang 	if (!dev || ((page != 0) && (page != 1))) {
410a05bd1b4SWei Huang 		dev_err(dev, "Input parameter of %s is invalid\n", __func__);
411a05bd1b4SWei Huang 		ret = -EINVAL;
412a05bd1b4SWei Huang 		goto end;
413a05bd1b4SWei Huang 	}
414a05bd1b4SWei Huang 
415a05bd1b4SWei Huang 	if (dev->flags & MAX10_FLAGS_SECURE) {
416a05bd1b4SWei Huang 		ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
417a05bd1b4SWei Huang 			SFPGA_RP_LOAD, 0);
418a05bd1b4SWei Huang 		if (ret < 0) {
419a05bd1b4SWei Huang 			dev_err(dev,
420a05bd1b4SWei Huang 				"Failed to update max10 reconfig register [e:%d]\n",
421a05bd1b4SWei Huang 				ret);
422a05bd1b4SWei Huang 			goto end;
423a05bd1b4SWei Huang 		}
424a05bd1b4SWei Huang 		ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
425a05bd1b4SWei Huang 			SFPGA_RP_LOAD | SFPGA_RECONF_PAGE,
426a05bd1b4SWei Huang 			SFPGA_RP_LOAD | SFPGA_PAGE(page));
427a05bd1b4SWei Huang 		if (ret < 0) {
428a05bd1b4SWei Huang 			dev_err(dev,
429a05bd1b4SWei Huang 				"Failed to update max10 reconfig register [e:%d]\n",
430a05bd1b4SWei Huang 				ret);
431a05bd1b4SWei Huang 			goto end;
432a05bd1b4SWei Huang 		}
433a05bd1b4SWei Huang 	} else {
434a05bd1b4SWei Huang 		ret = max10_sys_update_bits(dev, RSU_REG, FPGA_RP_LOAD, 0);
435a05bd1b4SWei Huang 		if (ret < 0) {
436a05bd1b4SWei Huang 			dev_err(dev,
437a05bd1b4SWei Huang 				"Failed to update max10 rsu register [e:%d]\n",
438a05bd1b4SWei Huang 				ret);
439a05bd1b4SWei Huang 			goto end;
440a05bd1b4SWei Huang 		}
441a05bd1b4SWei Huang 		ret = max10_sys_update_bits(dev, RSU_REG,
442a05bd1b4SWei Huang 			FPGA_RP_LOAD | FPGA_RECONF_PAGE,
443a05bd1b4SWei Huang 			FPGA_RP_LOAD | FPGA_PAGE(page));
444a05bd1b4SWei Huang 		if (ret < 0) {
445a05bd1b4SWei Huang 			dev_err(dev,
446a05bd1b4SWei Huang 				"Failed to update max10 rsu register [e:%d]\n",
447a05bd1b4SWei Huang 				ret);
448a05bd1b4SWei Huang 			goto end;
449a05bd1b4SWei Huang 		}
450a05bd1b4SWei Huang 	}
451a05bd1b4SWei Huang 
452a05bd1b4SWei Huang 	ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, COUNTDOWN_START, 0);
453a05bd1b4SWei Huang 	if (ret < 0) {
454a05bd1b4SWei Huang 		dev_err(dev,
455a05bd1b4SWei Huang 			"Failed to update max10 reconfig register [e:%d]\n",
456a05bd1b4SWei Huang 			ret);
457a05bd1b4SWei Huang 		goto end;
458a05bd1b4SWei Huang 	}
459a05bd1b4SWei Huang 
460a05bd1b4SWei Huang 	ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, COUNTDOWN_START,
461a05bd1b4SWei Huang 		COUNTDOWN_START);
462a05bd1b4SWei Huang 	if (ret < 0) {
463a05bd1b4SWei Huang 		dev_err(dev,
464a05bd1b4SWei Huang 			"Failed to update max10 reconfig register [e:%d]\n",
465a05bd1b4SWei Huang 			ret);
466a05bd1b4SWei Huang 	}
467a05bd1b4SWei Huang end:
468a05bd1b4SWei Huang 	if (ret < 0)
469a05bd1b4SWei Huang 		dev_err(dev, "Failed to reload FPGA\n");
470a05bd1b4SWei Huang 
471a05bd1b4SWei Huang 	return ret;
472a05bd1b4SWei Huang }
473a05bd1b4SWei Huang 
n3000_reload_bmc(struct intel_max10_device * dev,int page)474a05bd1b4SWei Huang static int n3000_reload_bmc(struct intel_max10_device *dev, int page)
475a05bd1b4SWei Huang {
476a05bd1b4SWei Huang 	uint32_t val = 0;
477a05bd1b4SWei Huang 	int ret = 0;
478a05bd1b4SWei Huang 
479a05bd1b4SWei Huang 	dev_info(dev, "Reload BMC\n");
480a05bd1b4SWei Huang 
481a05bd1b4SWei Huang 	if (!dev || ((page != 0) && (page != 1))) {
482a05bd1b4SWei Huang 		dev_err(dev, "Input parameter of %s is invalid\n", __func__);
483a05bd1b4SWei Huang 		ret = -EINVAL;
484a05bd1b4SWei Huang 		goto end;
485a05bd1b4SWei Huang 	}
486a05bd1b4SWei Huang 
487a05bd1b4SWei Huang 	if (dev->flags & MAX10_FLAGS_SECURE) {
488a05bd1b4SWei Huang 		ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
489a05bd1b4SWei Huang 			CONFIG_SEL | REBOOT_REQ,
490a05bd1b4SWei Huang 			CONFIG_SEL_S(page) | REBOOT_REQ);
491a05bd1b4SWei Huang 	} else {
492a05bd1b4SWei Huang 		val = (page == 0) ? 0x1 : 0x3;
493a05bd1b4SWei Huang 		ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL1, val);
494a05bd1b4SWei Huang 		if (ret < 0) {
495a05bd1b4SWei Huang 			dev_err(dev,
496a05bd1b4SWei Huang 				"Failed to write to dual config1 register [e:%d]\n",
497a05bd1b4SWei Huang 				ret);
498a05bd1b4SWei Huang 			goto end;
499a05bd1b4SWei Huang 		}
500a05bd1b4SWei Huang 
501a05bd1b4SWei Huang 		ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1);
502a05bd1b4SWei Huang 		if (ret < 0) {
503a05bd1b4SWei Huang 			if (ret == -EIO) {
504a05bd1b4SWei Huang 				ret = 0;
505a05bd1b4SWei Huang 				goto end;
506a05bd1b4SWei Huang 			}
507a05bd1b4SWei Huang 			dev_err(dev,
508a05bd1b4SWei Huang 				"Failed to write to dual config0 register [e:%d]\n",
509a05bd1b4SWei Huang 				ret);
510a05bd1b4SWei Huang 		}
511a05bd1b4SWei Huang 	}
512a05bd1b4SWei Huang 
513a05bd1b4SWei Huang end:
514a05bd1b4SWei Huang 	if (ret < 0)
515a05bd1b4SWei Huang 		dev_err(dev, "Failed to reload BMC\n");
516a05bd1b4SWei Huang 
517a05bd1b4SWei Huang 	return ret;
518a05bd1b4SWei Huang }
519a05bd1b4SWei Huang 
n3000_reload(struct ifpga_sec_mgr * smgr,int type,int page)520a05bd1b4SWei Huang static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page)
521a05bd1b4SWei Huang {
522a05bd1b4SWei Huang 	int psel = 0;
523a05bd1b4SWei Huang 	int ret = 0;
524a05bd1b4SWei Huang 
525a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
526a05bd1b4SWei Huang 		return -ENODEV;
527a05bd1b4SWei Huang 
528a05bd1b4SWei Huang 	if (type == IFPGA_BOOT_TYPE_FPGA) {
529a05bd1b4SWei Huang 		psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 0 : 1);
530a05bd1b4SWei Huang 		ret = n3000_reload_fpga(smgr->max10_dev, psel);
531a05bd1b4SWei Huang 	} else if (type == IFPGA_BOOT_TYPE_BMC) {
532a05bd1b4SWei Huang 		psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 1 : 0);
533a05bd1b4SWei Huang 		ret = n3000_reload_bmc(smgr->max10_dev, psel);
534a05bd1b4SWei Huang 	} else {
535a05bd1b4SWei Huang 		ret = -EINVAL;
536a05bd1b4SWei Huang 	}
537a05bd1b4SWei Huang 
538a05bd1b4SWei Huang 	return ret;
539a05bd1b4SWei Huang }
540a05bd1b4SWei Huang 
n3000_get_hw_errinfo(struct ifpga_sec_mgr * smgr)541a05bd1b4SWei Huang static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr)
542a05bd1b4SWei Huang {
543a05bd1b4SWei Huang 	struct intel_max10_device *dev = NULL;
544a05bd1b4SWei Huang 	uint32_t doorbell = 0;
545a05bd1b4SWei Huang 	uint32_t stat = 0;
546a05bd1b4SWei Huang 	uint32_t prog = 0;
547a05bd1b4SWei Huang 	uint32_t auth_result = 0;
548a05bd1b4SWei Huang 	int ret = 0;
549a05bd1b4SWei Huang 
550a05bd1b4SWei Huang 	if (!smgr || !smgr->max10_dev)
551a05bd1b4SWei Huang 		return -ENODEV;
552a05bd1b4SWei Huang 	dev = (struct intel_max10_device *)smgr->max10_dev;
553a05bd1b4SWei Huang 
554a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
555a05bd1b4SWei Huang 	if (ret < 0) {
556a05bd1b4SWei Huang 		dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n",
557a05bd1b4SWei Huang 			ret);
558a05bd1b4SWei Huang 		return -1;
559a05bd1b4SWei Huang 	}
560a05bd1b4SWei Huang 	stat = SEC_STATUS_G(doorbell);
561a05bd1b4SWei Huang 	prog = SEC_PROGRESS_G(doorbell);
562a05bd1b4SWei Huang 	dev_debug(dev, "Current RSU status is %s, progress is %s\n",
563a05bd1b4SWei Huang 		rsu_status_name(stat), rsu_progress_name(prog));
564a05bd1b4SWei Huang 
565a05bd1b4SWei Huang 	ret = max10_sys_read(dev, MAX10_AUTH_RESULT, &auth_result);
566a05bd1b4SWei Huang 	if (ret < 0) {
567a05bd1b4SWei Huang 		dev_err(dev,
568a05bd1b4SWei Huang 			"Failed to read authenticate result register [e:%d]\n",
569a05bd1b4SWei Huang 			ret);
570a05bd1b4SWei Huang 		return -1;
571a05bd1b4SWei Huang 	}
572a05bd1b4SWei Huang 
573a05bd1b4SWei Huang 	return (uint64_t)doorbell << 32 | (uint64_t)auth_result;
574a05bd1b4SWei Huang }
575a05bd1b4SWei Huang 
576a05bd1b4SWei Huang static const struct ifpga_sec_ops n3000_sec_ops = {
577a05bd1b4SWei Huang 	.prepare = n3000_prepare,
578a05bd1b4SWei Huang 	.write_blk = n3000_write_blk,
579a05bd1b4SWei Huang 	.write_done = n3000_write_done,
580a05bd1b4SWei Huang 	.check_complete = n3000_check_complete,
581a05bd1b4SWei Huang 	.reload = n3000_reload,
582a05bd1b4SWei Huang 	.cancel = n3000_cancel,
583a05bd1b4SWei Huang 	.cleanup = NULL,
584a05bd1b4SWei Huang 	.get_hw_errinfo = n3000_get_hw_errinfo,
585a05bd1b4SWei Huang };
586a05bd1b4SWei Huang 
init_sec_mgr(struct ifpga_fme_hw * fme)587a05bd1b4SWei Huang int init_sec_mgr(struct ifpga_fme_hw *fme)
588a05bd1b4SWei Huang {
589a05bd1b4SWei Huang 	struct ifpga_hw *hw = NULL;
590a05bd1b4SWei Huang 	opae_share_data *sd = NULL;
591a05bd1b4SWei Huang 	struct ifpga_sec_mgr *smgr = NULL;
592a05bd1b4SWei Huang 
593a05bd1b4SWei Huang 	if (!fme || !fme->max10_dev)
594a05bd1b4SWei Huang 		return -ENODEV;
595a05bd1b4SWei Huang 
596a05bd1b4SWei Huang 	smgr = (struct ifpga_sec_mgr *)malloc(sizeof(*smgr));
597a05bd1b4SWei Huang 	if (!smgr) {
598a05bd1b4SWei Huang 		dev_err(NULL, "Failed to allocate memory for security manager\n");
599a05bd1b4SWei Huang 		return -ENOMEM;
600a05bd1b4SWei Huang 	}
601a05bd1b4SWei Huang 	fme->sec_mgr = smgr;
602a05bd1b4SWei Huang 
603a05bd1b4SWei Huang 	hw = (struct ifpga_hw *)fme->parent;
604a05bd1b4SWei Huang 	if (hw && hw->adapter && hw->adapter->shm.ptr) {
605a05bd1b4SWei Huang 		sd = (opae_share_data *)hw->adapter->shm.ptr;
606a05bd1b4SWei Huang 		smgr->rsu_control = &sd->rsu_ctrl;
607a05bd1b4SWei Huang 		smgr->rsu_status = &sd->rsu_stat;
608a05bd1b4SWei Huang 	} else {
609a05bd1b4SWei Huang 		smgr->rsu_control = NULL;
610a05bd1b4SWei Huang 		smgr->rsu_status = NULL;
611a05bd1b4SWei Huang 	}
612a05bd1b4SWei Huang 
613*20077edfSWei Huang 	if (hw && (hw->pci_data->device_id == IFPGA_N3000_DID) &&
614a05bd1b4SWei Huang 		(hw->pci_data->vendor_id == IFPGA_N3000_VID)) {
615a05bd1b4SWei Huang 		smgr->ops = &n3000_sec_ops;
616a05bd1b4SWei Huang 		smgr->copy_speed = IFPGA_N3000_COPY_SPEED;
617a05bd1b4SWei Huang 	} else {
618a05bd1b4SWei Huang 		dev_err(NULL, "No operation for security manager\n");
619a05bd1b4SWei Huang 		smgr->ops = NULL;
620a05bd1b4SWei Huang 	}
621a05bd1b4SWei Huang 
622a05bd1b4SWei Huang 	smgr->fme = fme;
623a05bd1b4SWei Huang 	smgr->max10_dev = fme->max10_dev;
624a05bd1b4SWei Huang 
625a05bd1b4SWei Huang 	return 0;
626a05bd1b4SWei Huang }
627a05bd1b4SWei Huang 
release_sec_mgr(struct ifpga_fme_hw * fme)628a05bd1b4SWei Huang void release_sec_mgr(struct ifpga_fme_hw *fme)
629a05bd1b4SWei Huang {
630a05bd1b4SWei Huang 	struct ifpga_sec_mgr *smgr = NULL;
631a05bd1b4SWei Huang 
632a05bd1b4SWei Huang 	if (fme) {
633a05bd1b4SWei Huang 		smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
634a05bd1b4SWei Huang 		if (smgr) {
635a05bd1b4SWei Huang 			fme->sec_mgr = NULL;
636a05bd1b4SWei Huang 			free(smgr);
637a05bd1b4SWei Huang 		}
638a05bd1b4SWei Huang 	}
639a05bd1b4SWei Huang }
640