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