1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com> 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory (Department of Computer Science and 8 * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 9 * DARPA SSITH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Intel Stratix 10 Service Layer 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/bus.h> 43 #include <sys/kernel.h> 44 #include <sys/module.h> 45 #include <sys/malloc.h> 46 #include <sys/rman.h> 47 #include <sys/timeet.h> 48 #include <sys/timetc.h> 49 #include <sys/conf.h> 50 #include <sys/uio.h> 51 #include <sys/vmem.h> 52 53 #include <vm/vm.h> 54 #include <vm/pmap.h> 55 56 #include <dev/fdt/simplebus.h> 57 #include <dev/ofw/openfirm.h> 58 #include <dev/ofw/ofw_bus.h> 59 #include <dev/ofw/ofw_bus_subr.h> 60 61 #include <arm64/intel/intel-smc.h> 62 #include <arm64/intel/stratix10-svc.h> 63 64 #include <machine/bus.h> 65 #include <machine/cpu.h> 66 #include <machine/intr.h> 67 68 struct s10_svc_softc { 69 device_t dev; 70 vmem_t *vmem; 71 intel_smc_callfn_t callfn; 72 }; 73 74 static int 75 s10_data_claim(struct s10_svc_softc *sc) 76 { 77 struct arm_smccc_res res; 78 register_t a0, a1, a2; 79 int ret; 80 81 ret = 0; 82 83 while (1) { 84 a0 = INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE; 85 a1 = 0; 86 a2 = 0; 87 88 ret = sc->callfn(a0, a1, a2, 0, 0, 0, 0, 0, &res); 89 if (ret == INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY) 90 continue; 91 92 break; 93 } 94 95 return (ret); 96 } 97 98 int 99 s10_svc_send(device_t dev, struct s10_svc_msg *msg) 100 { 101 struct s10_svc_softc *sc; 102 struct arm_smccc_res res; 103 register_t a0, a1, a2; 104 int ret; 105 106 sc = device_get_softc(dev); 107 108 a0 = 0; 109 a1 = 0; 110 a2 = 0; 111 112 switch (msg->command) { 113 case COMMAND_RECONFIG: 114 a0 = INTEL_SIP_SMC_FPGA_CONFIG_START; 115 a1 = msg->flags; 116 break; 117 case COMMAND_RECONFIG_DATA_SUBMIT: 118 a0 = INTEL_SIP_SMC_FPGA_CONFIG_WRITE; 119 a1 = (uint64_t)msg->payload; 120 a2 = (uint64_t)msg->payload_length; 121 break; 122 case COMMAND_RECONFIG_DATA_CLAIM: 123 ret = s10_data_claim(sc); 124 return (ret); 125 default: 126 return (-1); 127 } 128 129 ret = sc->callfn(a0, a1, a2, 0, 0, 0, 0, 0, &res); 130 131 return (ret); 132 } 133 134 int 135 s10_svc_allocate_memory(device_t dev, struct s10_svc_mem *mem, int size) 136 { 137 struct s10_svc_softc *sc; 138 139 sc = device_get_softc(dev); 140 141 if (size <= 0) 142 return (EINVAL); 143 144 if (vmem_alloc(sc->vmem, size, 145 M_FIRSTFIT | M_NOWAIT, &mem->paddr)) { 146 device_printf(dev, "Can't allocate memory\n"); 147 return (ENOMEM); 148 } 149 150 mem->size = size; 151 mem->fill = 0; 152 mem->vaddr = (vm_offset_t)pmap_mapdev(mem->paddr, mem->size); 153 154 return (0); 155 } 156 157 void 158 s10_svc_free_memory(device_t dev, struct s10_svc_mem *mem) 159 { 160 struct s10_svc_softc *sc; 161 162 sc = device_get_softc(dev); 163 164 vmem_free(sc->vmem, mem->paddr, mem->size); 165 } 166 167 static int 168 s10_get_memory(struct s10_svc_softc *sc) 169 { 170 struct arm_smccc_res res; 171 vmem_addr_t addr; 172 vmem_size_t size; 173 vmem_t *vmem; 174 175 sc->callfn(INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM, 176 0, 0, 0, 0, 0, 0, 0, &res); 177 if (res.a0 != INTEL_SIP_SMC_STATUS_OK) 178 return (ENXIO); 179 180 vmem = vmem_create("stratix10 vmem", 0, 0, PAGE_SIZE, 181 PAGE_SIZE, M_BESTFIT | M_WAITOK); 182 if (vmem == NULL) 183 return (ENXIO); 184 185 addr = res.a1; 186 size = res.a2; 187 188 device_printf(sc->dev, "Shared memory address 0x%lx size 0x%lx\n", 189 addr, size); 190 191 vmem_add(vmem, addr, size, 0); 192 193 sc->vmem = vmem; 194 195 return (0); 196 } 197 198 static intel_smc_callfn_t 199 s10_svc_get_callfn(struct s10_svc_softc *sc, phandle_t node) 200 { 201 char method[16]; 202 203 if ((OF_getprop(node, "method", method, sizeof(method))) > 0) { 204 if (strcmp(method, "hvc") == 0) 205 return (arm_smccc_hvc); 206 else if (strcmp(method, "smc") == 0) 207 return (arm_smccc_smc); 208 else 209 device_printf(sc->dev, 210 "Invalid method \"%s\"\n", method); 211 } else 212 device_printf(sc->dev, "SMC method not provided\n"); 213 214 return (NULL); 215 } 216 217 static int 218 s10_svc_probe(device_t dev) 219 { 220 221 if (!ofw_bus_status_okay(dev)) 222 return (ENXIO); 223 224 if (!ofw_bus_is_compatible(dev, "intel,stratix10-svc")) 225 return (ENXIO); 226 227 device_set_desc(dev, "Stratix 10 SVC"); 228 229 return (BUS_PROBE_DEFAULT); 230 } 231 232 static int 233 s10_svc_attach(device_t dev) 234 { 235 struct s10_svc_softc *sc; 236 phandle_t node; 237 238 node = ofw_bus_get_node(dev); 239 240 sc = device_get_softc(dev); 241 sc->dev = dev; 242 243 if (device_get_unit(dev) != 0) 244 return (ENXIO); 245 246 sc->callfn = s10_svc_get_callfn(sc, node); 247 if (sc->callfn == NULL) 248 return (ENXIO); 249 250 if (s10_get_memory(sc) != 0) 251 return (ENXIO); 252 253 return (0); 254 } 255 256 static device_method_t s10_svc_methods[] = { 257 DEVMETHOD(device_probe, s10_svc_probe), 258 DEVMETHOD(device_attach, s10_svc_attach), 259 { 0, 0 } 260 }; 261 262 static driver_t s10_svc_driver = { 263 "s10_svc", 264 s10_svc_methods, 265 sizeof(struct s10_svc_softc), 266 }; 267 268 static devclass_t s10_svc_devclass; 269 270 EARLY_DRIVER_MODULE(s10_svc, firmware, s10_svc_driver, 271 s10_svc_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 272