xref: /freebsd/sys/arm64/intel/stratix10-svc.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1ee41e38dSRuslan Bukin /*-
2ee41e38dSRuslan Bukin  * SPDX-License-Identifier: BSD-2-Clause
3ee41e38dSRuslan Bukin  *
4ee41e38dSRuslan Bukin  * Copyright (c) 2019 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 Service Layer
35ee41e38dSRuslan Bukin  */
36ee41e38dSRuslan Bukin 
37ee41e38dSRuslan Bukin #include <sys/param.h>
38ee41e38dSRuslan Bukin #include <sys/systm.h>
39ee41e38dSRuslan Bukin #include <sys/bus.h>
40ee41e38dSRuslan Bukin #include <sys/kernel.h>
41ee41e38dSRuslan Bukin #include <sys/module.h>
42ee41e38dSRuslan Bukin #include <sys/malloc.h>
43ee41e38dSRuslan Bukin #include <sys/rman.h>
44ee41e38dSRuslan Bukin #include <sys/timeet.h>
45ee41e38dSRuslan Bukin #include <sys/timetc.h>
46ee41e38dSRuslan Bukin #include <sys/conf.h>
47ee41e38dSRuslan Bukin #include <sys/uio.h>
48ee41e38dSRuslan Bukin #include <sys/vmem.h>
49ee41e38dSRuslan Bukin 
50ee41e38dSRuslan Bukin #include <vm/vm.h>
51ee41e38dSRuslan Bukin #include <vm/pmap.h>
52ee41e38dSRuslan Bukin 
53ee41e38dSRuslan Bukin #include <dev/fdt/simplebus.h>
54ee41e38dSRuslan Bukin #include <dev/ofw/openfirm.h>
55ee41e38dSRuslan Bukin #include <dev/ofw/ofw_bus.h>
56ee41e38dSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
57ee41e38dSRuslan Bukin 
58ee41e38dSRuslan Bukin #include <arm64/intel/intel-smc.h>
59ee41e38dSRuslan Bukin #include <arm64/intel/stratix10-svc.h>
60ee41e38dSRuslan Bukin 
61ee41e38dSRuslan Bukin #include <machine/bus.h>
62ee41e38dSRuslan Bukin #include <machine/cpu.h>
63ee41e38dSRuslan Bukin #include <machine/intr.h>
64ee41e38dSRuslan Bukin 
65ee41e38dSRuslan Bukin struct s10_svc_softc {
66ee41e38dSRuslan Bukin 	device_t		dev;
67ee41e38dSRuslan Bukin 	vmem_t			*vmem;
68ee41e38dSRuslan Bukin 	intel_smc_callfn_t	callfn;
69ee41e38dSRuslan Bukin };
70ee41e38dSRuslan Bukin 
71ee41e38dSRuslan Bukin static int
s10_data_claim(struct s10_svc_softc * sc)72ee41e38dSRuslan Bukin s10_data_claim(struct s10_svc_softc *sc)
73ee41e38dSRuslan Bukin {
74ee41e38dSRuslan Bukin 	struct arm_smccc_res res;
75ee41e38dSRuslan Bukin 	register_t a0, a1, a2;
76ee41e38dSRuslan Bukin 	int ret;
77ee41e38dSRuslan Bukin 
78ee41e38dSRuslan Bukin 	ret = 0;
79ee41e38dSRuslan Bukin 
80ee41e38dSRuslan Bukin 	while (1) {
81ee41e38dSRuslan Bukin 		a0 = INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE;
82ee41e38dSRuslan Bukin 		a1 = 0;
83ee41e38dSRuslan Bukin 		a2 = 0;
84ee41e38dSRuslan Bukin 
85ee41e38dSRuslan Bukin 		ret = sc->callfn(a0, a1, a2, 0, 0, 0, 0, 0, &res);
86ee41e38dSRuslan Bukin 		if (ret == INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY)
87ee41e38dSRuslan Bukin 			continue;
88ee41e38dSRuslan Bukin 
89ee41e38dSRuslan Bukin 		break;
90ee41e38dSRuslan Bukin 	}
91ee41e38dSRuslan Bukin 
92ee41e38dSRuslan Bukin 	return (ret);
93ee41e38dSRuslan Bukin }
94ee41e38dSRuslan Bukin 
95ee41e38dSRuslan Bukin int
s10_svc_send(device_t dev,struct s10_svc_msg * msg)96ee41e38dSRuslan Bukin s10_svc_send(device_t dev, struct s10_svc_msg *msg)
97ee41e38dSRuslan Bukin {
98ee41e38dSRuslan Bukin 	struct s10_svc_softc *sc;
99ee41e38dSRuslan Bukin 	struct arm_smccc_res res;
100ee41e38dSRuslan Bukin 	register_t a0, a1, a2;
101ee41e38dSRuslan Bukin 	int ret;
102ee41e38dSRuslan Bukin 
103ee41e38dSRuslan Bukin 	sc = device_get_softc(dev);
104ee41e38dSRuslan Bukin 
105ee41e38dSRuslan Bukin 	a0 = 0;
106ee41e38dSRuslan Bukin 	a1 = 0;
107ee41e38dSRuslan Bukin 	a2 = 0;
108ee41e38dSRuslan Bukin 
109ee41e38dSRuslan Bukin 	switch (msg->command) {
110ee41e38dSRuslan Bukin 	case COMMAND_RECONFIG:
111ee41e38dSRuslan Bukin 		a0 = INTEL_SIP_SMC_FPGA_CONFIG_START;
112ee41e38dSRuslan Bukin 		a1 = msg->flags;
113ee41e38dSRuslan Bukin 		break;
114ee41e38dSRuslan Bukin 	case COMMAND_RECONFIG_DATA_SUBMIT:
115ee41e38dSRuslan Bukin 		a0 = INTEL_SIP_SMC_FPGA_CONFIG_WRITE;
116ee41e38dSRuslan Bukin 		a1 = (uint64_t)msg->payload;
117ee41e38dSRuslan Bukin 		a2 = (uint64_t)msg->payload_length;
118ee41e38dSRuslan Bukin 		break;
119ee41e38dSRuslan Bukin 	case COMMAND_RECONFIG_DATA_CLAIM:
120ee41e38dSRuslan Bukin 		ret = s10_data_claim(sc);
121ee41e38dSRuslan Bukin 		return (ret);
122ee41e38dSRuslan Bukin 	default:
123ee41e38dSRuslan Bukin 		return (-1);
124ee41e38dSRuslan Bukin 	}
125ee41e38dSRuslan Bukin 
126ee41e38dSRuslan Bukin 	ret = sc->callfn(a0, a1, a2, 0, 0, 0, 0, 0, &res);
127ee41e38dSRuslan Bukin 
128ee41e38dSRuslan Bukin 	return (ret);
129ee41e38dSRuslan Bukin }
130ee41e38dSRuslan Bukin 
131ee41e38dSRuslan Bukin int
s10_svc_allocate_memory(device_t dev,struct s10_svc_mem * mem,int size)132ee41e38dSRuslan Bukin s10_svc_allocate_memory(device_t dev, struct s10_svc_mem *mem, int size)
133ee41e38dSRuslan Bukin {
134ee41e38dSRuslan Bukin 	struct s10_svc_softc *sc;
135ee41e38dSRuslan Bukin 
136ee41e38dSRuslan Bukin 	sc = device_get_softc(dev);
137ee41e38dSRuslan Bukin 
138ee41e38dSRuslan Bukin 	if (size <= 0)
139ee41e38dSRuslan Bukin 		return (EINVAL);
140ee41e38dSRuslan Bukin 
141ee41e38dSRuslan Bukin 	if (vmem_alloc(sc->vmem, size,
142ee41e38dSRuslan Bukin 	    M_FIRSTFIT | M_NOWAIT, &mem->paddr)) {
143ee41e38dSRuslan Bukin 		device_printf(dev, "Can't allocate memory\n");
144ee41e38dSRuslan Bukin 		return (ENOMEM);
145ee41e38dSRuslan Bukin 	}
146ee41e38dSRuslan Bukin 
147ee41e38dSRuslan Bukin 	mem->size = size;
148ee41e38dSRuslan Bukin 	mem->fill = 0;
149ee41e38dSRuslan Bukin 	mem->vaddr = (vm_offset_t)pmap_mapdev(mem->paddr, mem->size);
150ee41e38dSRuslan Bukin 
151ee41e38dSRuslan Bukin 	return (0);
152ee41e38dSRuslan Bukin }
153ee41e38dSRuslan Bukin 
154ee41e38dSRuslan Bukin void
s10_svc_free_memory(device_t dev,struct s10_svc_mem * mem)155ee41e38dSRuslan Bukin s10_svc_free_memory(device_t dev, struct s10_svc_mem *mem)
156ee41e38dSRuslan Bukin {
157ee41e38dSRuslan Bukin 	struct s10_svc_softc *sc;
158ee41e38dSRuslan Bukin 
159ee41e38dSRuslan Bukin 	sc = device_get_softc(dev);
160ee41e38dSRuslan Bukin 
161ee41e38dSRuslan Bukin 	vmem_free(sc->vmem, mem->paddr, mem->size);
162ee41e38dSRuslan Bukin }
163ee41e38dSRuslan Bukin 
164ee41e38dSRuslan Bukin static int
s10_get_memory(struct s10_svc_softc * sc)165ee41e38dSRuslan Bukin s10_get_memory(struct s10_svc_softc *sc)
166ee41e38dSRuslan Bukin {
167ee41e38dSRuslan Bukin 	struct arm_smccc_res res;
168ee41e38dSRuslan Bukin 	vmem_addr_t addr;
169ee41e38dSRuslan Bukin 	vmem_size_t size;
170ee41e38dSRuslan Bukin 	vmem_t *vmem;
171ee41e38dSRuslan Bukin 
172ee41e38dSRuslan Bukin 	sc->callfn(INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM,
173ee41e38dSRuslan Bukin 	    0, 0, 0, 0, 0, 0, 0, &res);
174ee41e38dSRuslan Bukin 	if (res.a0 != INTEL_SIP_SMC_STATUS_OK)
175ee41e38dSRuslan Bukin 		return (ENXIO);
176ee41e38dSRuslan Bukin 
177ee41e38dSRuslan Bukin 	vmem = vmem_create("stratix10 vmem", 0, 0, PAGE_SIZE,
178ee41e38dSRuslan Bukin 	    PAGE_SIZE, M_BESTFIT | M_WAITOK);
179ee41e38dSRuslan Bukin 	if (vmem == NULL)
180ee41e38dSRuslan Bukin 		return (ENXIO);
181ee41e38dSRuslan Bukin 
182ee41e38dSRuslan Bukin 	addr = res.a1;
183ee41e38dSRuslan Bukin 	size = res.a2;
184ee41e38dSRuslan Bukin 
185ee41e38dSRuslan Bukin 	device_printf(sc->dev, "Shared memory address 0x%lx size 0x%lx\n",
186ee41e38dSRuslan Bukin 	    addr, size);
187ee41e38dSRuslan Bukin 
188ee41e38dSRuslan Bukin 	vmem_add(vmem, addr, size, 0);
189ee41e38dSRuslan Bukin 
190ee41e38dSRuslan Bukin 	sc->vmem = vmem;
191ee41e38dSRuslan Bukin 
192ee41e38dSRuslan Bukin 	return (0);
193ee41e38dSRuslan Bukin }
194ee41e38dSRuslan Bukin 
195ee41e38dSRuslan Bukin static intel_smc_callfn_t
s10_svc_get_callfn(struct s10_svc_softc * sc,phandle_t node)196ee41e38dSRuslan Bukin s10_svc_get_callfn(struct s10_svc_softc *sc, phandle_t node)
197ee41e38dSRuslan Bukin {
198ee41e38dSRuslan Bukin 	char method[16];
199ee41e38dSRuslan Bukin 
200ee41e38dSRuslan Bukin 	if ((OF_getprop(node, "method", method, sizeof(method))) > 0) {
201ee41e38dSRuslan Bukin 		if (strcmp(method, "hvc") == 0)
202ee41e38dSRuslan Bukin 			return (arm_smccc_hvc);
203ee41e38dSRuslan Bukin 		else if (strcmp(method, "smc") == 0)
204ee41e38dSRuslan Bukin 			return (arm_smccc_smc);
205ee41e38dSRuslan Bukin 		else
206ee41e38dSRuslan Bukin 			device_printf(sc->dev,
207ee41e38dSRuslan Bukin 			    "Invalid method \"%s\"\n", method);
208ee41e38dSRuslan Bukin 	} else
209ee41e38dSRuslan Bukin 		device_printf(sc->dev, "SMC method not provided\n");
210ee41e38dSRuslan Bukin 
211ee41e38dSRuslan Bukin 	return (NULL);
212ee41e38dSRuslan Bukin }
213ee41e38dSRuslan Bukin 
214ee41e38dSRuslan Bukin static int
s10_svc_probe(device_t dev)215ee41e38dSRuslan Bukin s10_svc_probe(device_t dev)
216ee41e38dSRuslan Bukin {
217ee41e38dSRuslan Bukin 
218ee41e38dSRuslan Bukin 	if (!ofw_bus_status_okay(dev))
219ee41e38dSRuslan Bukin 		return (ENXIO);
220ee41e38dSRuslan Bukin 
221ee41e38dSRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "intel,stratix10-svc"))
222ee41e38dSRuslan Bukin 		return (ENXIO);
223ee41e38dSRuslan Bukin 
224ee41e38dSRuslan Bukin 	device_set_desc(dev, "Stratix 10 SVC");
225ee41e38dSRuslan Bukin 
226ee41e38dSRuslan Bukin 	return (BUS_PROBE_DEFAULT);
227ee41e38dSRuslan Bukin }
228ee41e38dSRuslan Bukin 
229ee41e38dSRuslan Bukin static int
s10_svc_attach(device_t dev)230ee41e38dSRuslan Bukin s10_svc_attach(device_t dev)
231ee41e38dSRuslan Bukin {
232ee41e38dSRuslan Bukin 	struct s10_svc_softc *sc;
233ee41e38dSRuslan Bukin 	phandle_t node;
234ee41e38dSRuslan Bukin 
235ee41e38dSRuslan Bukin 	node = ofw_bus_get_node(dev);
236ee41e38dSRuslan Bukin 
237ee41e38dSRuslan Bukin 	sc = device_get_softc(dev);
238ee41e38dSRuslan Bukin 	sc->dev = dev;
239ee41e38dSRuslan Bukin 
240ee41e38dSRuslan Bukin 	if (device_get_unit(dev) != 0)
241ee41e38dSRuslan Bukin 		return (ENXIO);
242ee41e38dSRuslan Bukin 
243ee41e38dSRuslan Bukin 	sc->callfn = s10_svc_get_callfn(sc, node);
244ee41e38dSRuslan Bukin 	if (sc->callfn == NULL)
245ee41e38dSRuslan Bukin 		return (ENXIO);
246ee41e38dSRuslan Bukin 
247ee41e38dSRuslan Bukin 	if (s10_get_memory(sc) != 0)
248ee41e38dSRuslan Bukin 		return (ENXIO);
249ee41e38dSRuslan Bukin 
250ee41e38dSRuslan Bukin 	return (0);
251ee41e38dSRuslan Bukin }
252ee41e38dSRuslan Bukin 
253ee41e38dSRuslan Bukin static device_method_t s10_svc_methods[] = {
254ee41e38dSRuslan Bukin 	DEVMETHOD(device_probe,		s10_svc_probe),
255ee41e38dSRuslan Bukin 	DEVMETHOD(device_attach,	s10_svc_attach),
256ee41e38dSRuslan Bukin 	{ 0, 0 }
257ee41e38dSRuslan Bukin };
258ee41e38dSRuslan Bukin 
259ee41e38dSRuslan Bukin static driver_t s10_svc_driver = {
260ee41e38dSRuslan Bukin 	"s10_svc",
261ee41e38dSRuslan Bukin 	s10_svc_methods,
262ee41e38dSRuslan Bukin 	sizeof(struct s10_svc_softc),
263ee41e38dSRuslan Bukin };
264ee41e38dSRuslan Bukin 
265*4b5f5fe7SEmmanuel Vadot EARLY_DRIVER_MODULE(s10_svc, simplebus, s10_svc_driver, 0, 0,
2663d2549ceSJohn Baldwin     BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
267