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