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