xref: /freebsd/sys/arm64/intel/stratix10-soc-fpga-mgr.c (revision ddf7fbbb57e271b392d1aea4866bf5df800a7cf9)
1ee41e38dSRuslan Bukin /*-
2ee41e38dSRuslan Bukin  * SPDX-License-Identifier: BSD-2-Clause
3ee41e38dSRuslan Bukin  *
4*ddf7fbbbSRuslan Bukin  * Copyright (c) 2019-2024 Ruslan Bukin <br@bsdpad.com>
5ee41e38dSRuslan Bukin  *
6ee41e38dSRuslan Bukin  * This software was developed by SRI International and the University of
7ee41e38dSRuslan Bukin  * Cambridge Computer Laboratory (Department of Computer Science and
8ee41e38dSRuslan Bukin  * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
9ee41e38dSRuslan Bukin  * DARPA SSITH research programme.
10ee41e38dSRuslan Bukin  *
11ee41e38dSRuslan Bukin  * Redistribution and use in source and binary forms, with or without
12ee41e38dSRuslan Bukin  * modification, are permitted provided that the following conditions
13ee41e38dSRuslan Bukin  * are met:
14ee41e38dSRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
15ee41e38dSRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
16ee41e38dSRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
17ee41e38dSRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
18ee41e38dSRuslan Bukin  *    documentation and/or other materials provided with the distribution.
19ee41e38dSRuslan Bukin  *
20ee41e38dSRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21ee41e38dSRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22ee41e38dSRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23ee41e38dSRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24ee41e38dSRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25ee41e38dSRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26ee41e38dSRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27ee41e38dSRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28ee41e38dSRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29ee41e38dSRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30ee41e38dSRuslan Bukin  * SUCH DAMAGE.
31ee41e38dSRuslan Bukin  */
32ee41e38dSRuslan Bukin 
33ee41e38dSRuslan Bukin /*
34ee41e38dSRuslan Bukin  * Intel Stratix 10 FPGA Manager.
35*ddf7fbbbSRuslan Bukin  *
36*ddf7fbbbSRuslan Bukin  * FPGA Programming Example:
37*ddf7fbbbSRuslan Bukin  *  dd if=cheri.core.rbf of=/dev/fpga_partial0 bs=512k
38ee41e38dSRuslan Bukin  */
39ee41e38dSRuslan Bukin 
40ee41e38dSRuslan Bukin #include <sys/param.h>
41ee41e38dSRuslan Bukin #include <sys/systm.h>
42ee41e38dSRuslan Bukin #include <sys/bus.h>
43ee41e38dSRuslan Bukin #include <sys/kernel.h>
44ee41e38dSRuslan Bukin #include <sys/module.h>
45ee41e38dSRuslan Bukin #include <sys/malloc.h>
46ee41e38dSRuslan Bukin #include <sys/rman.h>
47ee41e38dSRuslan Bukin #include <sys/timeet.h>
48ee41e38dSRuslan Bukin #include <sys/timetc.h>
49ee41e38dSRuslan Bukin #include <sys/conf.h>
50ee41e38dSRuslan Bukin #include <sys/uio.h>
51ee41e38dSRuslan Bukin #include <sys/sx.h>
52ee41e38dSRuslan Bukin 
53ee41e38dSRuslan Bukin #include <dev/ofw/openfirm.h>
54ee41e38dSRuslan Bukin #include <dev/ofw/ofw_bus.h>
55ee41e38dSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
56ee41e38dSRuslan Bukin 
57ee41e38dSRuslan Bukin #include <arm64/intel/stratix10-svc.h>
58ee41e38dSRuslan Bukin 
59ee41e38dSRuslan Bukin #include <machine/bus.h>
60ee41e38dSRuslan Bukin #include <machine/cpu.h>
61ee41e38dSRuslan Bukin #include <machine/intr.h>
62ee41e38dSRuslan Bukin 
63*ddf7fbbbSRuslan Bukin #define	SVC_BUF_SIZE	(512 * 1024)
64ee41e38dSRuslan Bukin 
65ee41e38dSRuslan Bukin struct fpgamgr_s10_softc {
66ee41e38dSRuslan Bukin 	struct cdev		*mgr_cdev;
67ee41e38dSRuslan Bukin 	struct cdev		*mgr_cdev_partial;
68ee41e38dSRuslan Bukin 	device_t		dev;
69ee41e38dSRuslan Bukin 	device_t		s10_svc_dev;
70ee41e38dSRuslan Bukin 	struct s10_svc_mem	mem;
71ee41e38dSRuslan Bukin 	struct sx		sx;
72ee41e38dSRuslan Bukin 	int			opened;
73ee41e38dSRuslan Bukin };
74ee41e38dSRuslan Bukin 
75ee41e38dSRuslan Bukin static int
fpga_open(struct cdev * dev,int flags __unused,int fmt __unused,struct thread * td __unused)76ee41e38dSRuslan Bukin fpga_open(struct cdev *dev, int flags __unused,
77ee41e38dSRuslan Bukin     int fmt __unused, struct thread *td __unused)
78ee41e38dSRuslan Bukin {
79ee41e38dSRuslan Bukin 	struct fpgamgr_s10_softc *sc;
80ee41e38dSRuslan Bukin 	struct s10_svc_msg msg;
81ee41e38dSRuslan Bukin 	int ret;
82ee41e38dSRuslan Bukin 	int err;
83ee41e38dSRuslan Bukin 
84ee41e38dSRuslan Bukin 	sc = dev->si_drv1;
85ee41e38dSRuslan Bukin 
86ee41e38dSRuslan Bukin 	sx_xlock(&sc->sx);
87ee41e38dSRuslan Bukin 	if (sc->opened) {
88ee41e38dSRuslan Bukin 		sx_xunlock(&sc->sx);
89ee41e38dSRuslan Bukin 		return (EBUSY);
90ee41e38dSRuslan Bukin 	}
91ee41e38dSRuslan Bukin 
92ee41e38dSRuslan Bukin 	err = s10_svc_allocate_memory(sc->s10_svc_dev,
93ee41e38dSRuslan Bukin 	    &sc->mem, SVC_BUF_SIZE);
94ee41e38dSRuslan Bukin 	if (err != 0) {
95ee41e38dSRuslan Bukin 		sx_xunlock(&sc->sx);
96ee41e38dSRuslan Bukin 		return (ENXIO);
97ee41e38dSRuslan Bukin 	}
98ee41e38dSRuslan Bukin 
99ee41e38dSRuslan Bukin 	bzero(&msg, sizeof(struct s10_svc_msg));
100ee41e38dSRuslan Bukin 	msg.command = COMMAND_RECONFIG;
101ee41e38dSRuslan Bukin 	if (dev == sc->mgr_cdev_partial)
102ee41e38dSRuslan Bukin 		msg.flags |= COMMAND_RECONFIG_FLAG_PARTIAL;
103ee41e38dSRuslan Bukin 	ret = s10_svc_send(sc->s10_svc_dev, &msg);
104ee41e38dSRuslan Bukin 	if (ret != 0) {
105ee41e38dSRuslan Bukin 		sx_xunlock(&sc->sx);
106ee41e38dSRuslan Bukin 		return (ENXIO);
107ee41e38dSRuslan Bukin 	}
108ee41e38dSRuslan Bukin 
109ee41e38dSRuslan Bukin 	sc->opened = 1;
110ee41e38dSRuslan Bukin 	sx_xunlock(&sc->sx);
111ee41e38dSRuslan Bukin 
112ee41e38dSRuslan Bukin 	return (0);
113ee41e38dSRuslan Bukin }
114ee41e38dSRuslan Bukin 
115ee41e38dSRuslan Bukin static int
fpga_submit(struct cdev * dev)116*ddf7fbbbSRuslan Bukin fpga_submit(struct cdev *dev)
117*ddf7fbbbSRuslan Bukin {
118*ddf7fbbbSRuslan Bukin 	struct fpgamgr_s10_softc *sc;
119*ddf7fbbbSRuslan Bukin 	struct s10_svc_msg msg;
120*ddf7fbbbSRuslan Bukin 	int ret;
121*ddf7fbbbSRuslan Bukin 
122*ddf7fbbbSRuslan Bukin 	sc = dev->si_drv1;
123*ddf7fbbbSRuslan Bukin 
124*ddf7fbbbSRuslan Bukin 	bzero(&msg, sizeof(struct s10_svc_msg));
125*ddf7fbbbSRuslan Bukin 	msg.command = COMMAND_RECONFIG_DATA_SUBMIT;
126*ddf7fbbbSRuslan Bukin 	msg.payload = (void *)sc->mem.paddr;
127*ddf7fbbbSRuslan Bukin 	msg.payload_length = sc->mem.fill;
128*ddf7fbbbSRuslan Bukin 	ret = s10_svc_send(sc->s10_svc_dev, &msg);
129*ddf7fbbbSRuslan Bukin 	if (ret != 0) {
130*ddf7fbbbSRuslan Bukin 		device_printf(sc->dev, "Failed to submit data\n");
131*ddf7fbbbSRuslan Bukin 		s10_svc_free_memory(sc->s10_svc_dev, &sc->mem);
132*ddf7fbbbSRuslan Bukin 		sc->opened = 0;
133*ddf7fbbbSRuslan Bukin 		return (ENXIO);
134*ddf7fbbbSRuslan Bukin 	}
135*ddf7fbbbSRuslan Bukin 
136*ddf7fbbbSRuslan Bukin 	/* Claim memory buffer back. */
137*ddf7fbbbSRuslan Bukin 	bzero(&msg, sizeof(struct s10_svc_msg));
138*ddf7fbbbSRuslan Bukin 	msg.command = COMMAND_RECONFIG_DATA_CLAIM;
139*ddf7fbbbSRuslan Bukin 	ret = s10_svc_send(sc->s10_svc_dev, &msg);
140*ddf7fbbbSRuslan Bukin 	if (ret)
141*ddf7fbbbSRuslan Bukin 		device_printf(sc->dev, "Can't claim buffer back.\n");
142*ddf7fbbbSRuslan Bukin 
143*ddf7fbbbSRuslan Bukin 	return (ret);
144*ddf7fbbbSRuslan Bukin }
145*ddf7fbbbSRuslan Bukin 
146*ddf7fbbbSRuslan Bukin static int
fpga_write(struct cdev * dev,struct uio * uio,int ioflag)147ee41e38dSRuslan Bukin fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
148ee41e38dSRuslan Bukin {
149ee41e38dSRuslan Bukin 	struct fpgamgr_s10_softc *sc;
150ee41e38dSRuslan Bukin 	vm_offset_t addr;
151*ddf7fbbbSRuslan Bukin 	int error;
152ee41e38dSRuslan Bukin 	int amnt;
153*ddf7fbbbSRuslan Bukin 	int ret;
154ee41e38dSRuslan Bukin 
155ee41e38dSRuslan Bukin 	sc = dev->si_drv1;
156ee41e38dSRuslan Bukin 
157ee41e38dSRuslan Bukin 	sx_xlock(&sc->sx);
158ee41e38dSRuslan Bukin 	if (sc->opened == 0) {
159ee41e38dSRuslan Bukin 		/* Device closed. */
160ee41e38dSRuslan Bukin 		sx_xunlock(&sc->sx);
161ee41e38dSRuslan Bukin 		return (ENXIO);
162ee41e38dSRuslan Bukin 	}
163ee41e38dSRuslan Bukin 
164ee41e38dSRuslan Bukin 	while (uio->uio_resid > 0) {
165ee41e38dSRuslan Bukin 		addr = sc->mem.vaddr + sc->mem.fill;
166ee41e38dSRuslan Bukin 		amnt = MIN(uio->uio_resid, (SVC_BUF_SIZE - sc->mem.fill));
167*ddf7fbbbSRuslan Bukin 		error = uiomove((void *)addr, amnt, uio);
168*ddf7fbbbSRuslan Bukin 		if (error) {
169*ddf7fbbbSRuslan Bukin 			device_printf(sc->dev, "uiomove returned error %d\n",
170*ddf7fbbbSRuslan Bukin 			    error);
171*ddf7fbbbSRuslan Bukin 			break;
172*ddf7fbbbSRuslan Bukin 		}
173ee41e38dSRuslan Bukin 		sc->mem.fill += amnt;
174*ddf7fbbbSRuslan Bukin 		if (sc->mem.fill == SVC_BUF_SIZE) {
175*ddf7fbbbSRuslan Bukin 			ret = fpga_submit(dev);
176*ddf7fbbbSRuslan Bukin 			if (ret) {
177*ddf7fbbbSRuslan Bukin 				sx_xunlock(&sc->sx);
178*ddf7fbbbSRuslan Bukin 				return (ret);
179*ddf7fbbbSRuslan Bukin 			}
180*ddf7fbbbSRuslan Bukin 			sc->mem.fill = 0;
181*ddf7fbbbSRuslan Bukin 		}
182ee41e38dSRuslan Bukin 	}
183ee41e38dSRuslan Bukin 
184ee41e38dSRuslan Bukin 	sx_xunlock(&sc->sx);
185ee41e38dSRuslan Bukin 
186ee41e38dSRuslan Bukin 	return (0);
187ee41e38dSRuslan Bukin }
188ee41e38dSRuslan Bukin 
189ee41e38dSRuslan Bukin static int
fpga_close(struct cdev * dev,int flags __unused,int fmt __unused,struct thread * td __unused)190ee41e38dSRuslan Bukin fpga_close(struct cdev *dev, int flags __unused,
191ee41e38dSRuslan Bukin     int fmt __unused, struct thread *td __unused)
192ee41e38dSRuslan Bukin {
193ee41e38dSRuslan Bukin 	struct fpgamgr_s10_softc *sc;
194ee41e38dSRuslan Bukin 	int ret;
195ee41e38dSRuslan Bukin 
196ee41e38dSRuslan Bukin 	sc = dev->si_drv1;
197ee41e38dSRuslan Bukin 
198ee41e38dSRuslan Bukin 	sx_xlock(&sc->sx);
199ee41e38dSRuslan Bukin 	if (sc->opened == 0) {
200ee41e38dSRuslan Bukin 		/* Device closed. */
201ee41e38dSRuslan Bukin 		sx_xunlock(&sc->sx);
202ee41e38dSRuslan Bukin 		return (ENXIO);
203ee41e38dSRuslan Bukin 	}
204ee41e38dSRuslan Bukin 
205*ddf7fbbbSRuslan Bukin 	if (sc->mem.fill > 0) {
206*ddf7fbbbSRuslan Bukin 		ret = fpga_submit(dev);
207*ddf7fbbbSRuslan Bukin 		if (ret) {
208ee41e38dSRuslan Bukin 			sx_xunlock(&sc->sx);
209*ddf7fbbbSRuslan Bukin 			return (ret);
210ee41e38dSRuslan Bukin 		}
211*ddf7fbbbSRuslan Bukin 		sc->mem.fill = 0;
212*ddf7fbbbSRuslan Bukin 	}
213ee41e38dSRuslan Bukin 
214ee41e38dSRuslan Bukin 	s10_svc_free_memory(sc->s10_svc_dev, &sc->mem);
215ee41e38dSRuslan Bukin 	sc->opened = 0;
216ee41e38dSRuslan Bukin 	sx_xunlock(&sc->sx);
217ee41e38dSRuslan Bukin 
218ee41e38dSRuslan Bukin 	return (0);
219ee41e38dSRuslan Bukin }
220ee41e38dSRuslan Bukin 
221ee41e38dSRuslan Bukin static int
fpga_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flags,struct thread * td)222ee41e38dSRuslan Bukin fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
223ee41e38dSRuslan Bukin     struct thread *td)
224ee41e38dSRuslan Bukin {
225ee41e38dSRuslan Bukin 
226ee41e38dSRuslan Bukin 	return (0);
227ee41e38dSRuslan Bukin }
228ee41e38dSRuslan Bukin 
229ee41e38dSRuslan Bukin static struct cdevsw fpga_cdevsw = {
230ee41e38dSRuslan Bukin 	.d_version =	D_VERSION,
231ee41e38dSRuslan Bukin 	.d_open =	fpga_open,
232ee41e38dSRuslan Bukin 	.d_close =	fpga_close,
233ee41e38dSRuslan Bukin 	.d_write =	fpga_write,
234ee41e38dSRuslan Bukin 	.d_ioctl =	fpga_ioctl,
235ee41e38dSRuslan Bukin 	.d_name =	"FPGA Manager",
236ee41e38dSRuslan Bukin };
237ee41e38dSRuslan Bukin 
238ee41e38dSRuslan Bukin static int
fpgamgr_s10_probe(device_t dev)239ee41e38dSRuslan Bukin fpgamgr_s10_probe(device_t dev)
240ee41e38dSRuslan Bukin {
241ee41e38dSRuslan Bukin 
242ee41e38dSRuslan Bukin 	if (!ofw_bus_status_okay(dev))
243ee41e38dSRuslan Bukin 		return (ENXIO);
244ee41e38dSRuslan Bukin 
245ee41e38dSRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "intel,stratix10-soc-fpga-mgr"))
246ee41e38dSRuslan Bukin 		return (ENXIO);
247ee41e38dSRuslan Bukin 
248ee41e38dSRuslan Bukin 	device_set_desc(dev, "Stratix 10 SOC FPGA Manager");
249ee41e38dSRuslan Bukin 
250ee41e38dSRuslan Bukin 	return (BUS_PROBE_DEFAULT);
251ee41e38dSRuslan Bukin }
252ee41e38dSRuslan Bukin 
253ee41e38dSRuslan Bukin static int
fpgamgr_s10_attach(device_t dev)254ee41e38dSRuslan Bukin fpgamgr_s10_attach(device_t dev)
255ee41e38dSRuslan Bukin {
256ee41e38dSRuslan Bukin 	struct fpgamgr_s10_softc *sc;
257ee41e38dSRuslan Bukin 	devclass_t dc;
258ee41e38dSRuslan Bukin 
259ee41e38dSRuslan Bukin 	sc = device_get_softc(dev);
260ee41e38dSRuslan Bukin 	sc->dev = dev;
261ee41e38dSRuslan Bukin 
262ee41e38dSRuslan Bukin 	dc = devclass_find("s10_svc");
263ee41e38dSRuslan Bukin 	if (dc == NULL)
264ee41e38dSRuslan Bukin 		return (ENXIO);
265ee41e38dSRuslan Bukin 
266ee41e38dSRuslan Bukin 	sc->s10_svc_dev = devclass_get_device(dc, 0);
267ee41e38dSRuslan Bukin 	if (sc->s10_svc_dev == NULL)
268ee41e38dSRuslan Bukin 		return (ENXIO);
269ee41e38dSRuslan Bukin 
270ee41e38dSRuslan Bukin 	sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
271ee41e38dSRuslan Bukin 	    0600, "fpga%d", device_get_unit(sc->dev));
272ee41e38dSRuslan Bukin 	if (sc->mgr_cdev == NULL) {
273ee41e38dSRuslan Bukin 		device_printf(dev, "Failed to create character device.\n");
274ee41e38dSRuslan Bukin 		return (ENXIO);
275ee41e38dSRuslan Bukin 	}
276ee41e38dSRuslan Bukin 
277ee41e38dSRuslan Bukin 	sc->mgr_cdev_partial = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
278ee41e38dSRuslan Bukin 	    0600, "fpga_partial%d", device_get_unit(sc->dev));
279ee41e38dSRuslan Bukin 	if (sc->mgr_cdev_partial == NULL) {
280ee41e38dSRuslan Bukin 		device_printf(dev, "Failed to create character device.\n");
281ee41e38dSRuslan Bukin 		return (ENXIO);
282ee41e38dSRuslan Bukin 	}
283ee41e38dSRuslan Bukin 
284ee41e38dSRuslan Bukin 	sx_init(&sc->sx, "s10 fpga");
285ee41e38dSRuslan Bukin 
286ee41e38dSRuslan Bukin 	sc->mgr_cdev->si_drv1 = sc;
287ee41e38dSRuslan Bukin 	sc->mgr_cdev_partial->si_drv1 = sc;
288ee41e38dSRuslan Bukin 
289ee41e38dSRuslan Bukin 	return (0);
290ee41e38dSRuslan Bukin }
291ee41e38dSRuslan Bukin 
292ee41e38dSRuslan Bukin static int
fpgamgr_s10_detach(device_t dev)293ee41e38dSRuslan Bukin fpgamgr_s10_detach(device_t dev)
294ee41e38dSRuslan Bukin {
295ee41e38dSRuslan Bukin 	struct fpgamgr_s10_softc *sc;
296ee41e38dSRuslan Bukin 
297ee41e38dSRuslan Bukin 	sc = device_get_softc(dev);
298ee41e38dSRuslan Bukin 
299ee41e38dSRuslan Bukin 	destroy_dev(sc->mgr_cdev);
300ee41e38dSRuslan Bukin 	destroy_dev(sc->mgr_cdev_partial);
301ee41e38dSRuslan Bukin 
302ee41e38dSRuslan Bukin 	sx_destroy(&sc->sx);
303ee41e38dSRuslan Bukin 
304ee41e38dSRuslan Bukin 	return (0);
305ee41e38dSRuslan Bukin }
306ee41e38dSRuslan Bukin 
307ee41e38dSRuslan Bukin static device_method_t fpgamgr_s10_methods[] = {
308ee41e38dSRuslan Bukin 	DEVMETHOD(device_probe,		fpgamgr_s10_probe),
309ee41e38dSRuslan Bukin 	DEVMETHOD(device_attach,	fpgamgr_s10_attach),
310ee41e38dSRuslan Bukin 	DEVMETHOD(device_detach,	fpgamgr_s10_detach),
311ee41e38dSRuslan Bukin 	{ 0, 0 }
312ee41e38dSRuslan Bukin };
313ee41e38dSRuslan Bukin 
314ee41e38dSRuslan Bukin static driver_t fpgamgr_s10_driver = {
315ee41e38dSRuslan Bukin 	"fpgamgr_s10",
316ee41e38dSRuslan Bukin 	fpgamgr_s10_methods,
317ee41e38dSRuslan Bukin 	sizeof(struct fpgamgr_s10_softc),
318ee41e38dSRuslan Bukin };
319ee41e38dSRuslan Bukin 
3203d2549ceSJohn Baldwin DRIVER_MODULE(fpgamgr_s10, simplebus, fpgamgr_s10_driver, 0, 0);
321