1 1.11 riastrad /* $NetBSD: virtio_mmio_fdt.c,v 1.11 2025/01/14 16:46:38 riastradh Exp $ */ 2 1.1 jakllsch 3 1.1 jakllsch /* 4 1.1 jakllsch * Copyright (c) 2018 Jonathan A. Kollasch 5 1.1 jakllsch * All rights reserved. 6 1.1 jakllsch * 7 1.1 jakllsch * Redistribution and use in source and binary forms, with or without 8 1.1 jakllsch * modification, are permitted provided that the following conditions 9 1.1 jakllsch * are met: 10 1.1 jakllsch * 1. Redistributions of source code must retain the above copyright 11 1.1 jakllsch * notice, this list of conditions and the following disclaimer. 12 1.1 jakllsch * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jakllsch * notice, this list of conditions and the following disclaimer in the 14 1.1 jakllsch * documentation and/or other materials provided with the distribution. 15 1.1 jakllsch * 16 1.1 jakllsch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 1.1 jakllsch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jakllsch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jakllsch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20 1.1 jakllsch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 1.1 jakllsch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 1.1 jakllsch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 1.1 jakllsch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 1.1 jakllsch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 1.1 jakllsch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 1.1 jakllsch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 jakllsch */ 28 1.1 jakllsch 29 1.1 jakllsch #include <sys/cdefs.h> 30 1.11 riastrad __KERNEL_RCSID(0, "$NetBSD: virtio_mmio_fdt.c,v 1.11 2025/01/14 16:46:38 riastradh Exp $"); 31 1.1 jakllsch 32 1.1 jakllsch #include <sys/param.h> 33 1.1 jakllsch #include <sys/systm.h> 34 1.1 jakllsch 35 1.1 jakllsch #include <sys/device.h> 36 1.1 jakllsch 37 1.1 jakllsch #include <dev/fdt/fdtvar.h> 38 1.1 jakllsch 39 1.1 jakllsch #define VIRTIO_PRIVATE 40 1.1 jakllsch #include <dev/virtio/virtio_mmiovar.h> 41 1.1 jakllsch 42 1.1 jakllsch static int virtio_mmio_fdt_match(device_t, cfdata_t, void *); 43 1.1 jakllsch static void virtio_mmio_fdt_attach(device_t, device_t, void *); 44 1.1 jakllsch static int virtio_mmio_fdt_rescan(device_t, const char *, const int *); 45 1.1 jakllsch static int virtio_mmio_fdt_detach(device_t, int); 46 1.1 jakllsch 47 1.10 yamaguch static int virtio_mmio_fdt_alloc_interrupts(struct virtio_mmio_softc *); 48 1.1 jakllsch static void virtio_mmio_fdt_free_interrupts(struct virtio_mmio_softc *); 49 1.1 jakllsch 50 1.1 jakllsch struct virtio_mmio_fdt_softc { 51 1.1 jakllsch struct virtio_mmio_softc sc_msc; 52 1.1 jakllsch int sc_phandle; 53 1.1 jakllsch }; 54 1.1 jakllsch 55 1.1 jakllsch CFATTACH_DECL3_NEW(virtio_mmio_fdt, sizeof(struct virtio_mmio_fdt_softc), 56 1.1 jakllsch virtio_mmio_fdt_match, virtio_mmio_fdt_attach, virtio_mmio_fdt_detach, NULL, 57 1.11 riastrad virtio_mmio_fdt_rescan, NULL, 0); 58 1.1 jakllsch 59 1.7 thorpej static const struct device_compatible_entry compat_data[] = { 60 1.7 thorpej { .compat = "virtio,mmio" }, 61 1.7 thorpej DEVICE_COMPAT_EOL 62 1.1 jakllsch }; 63 1.1 jakllsch 64 1.1 jakllsch static int 65 1.1 jakllsch virtio_mmio_fdt_match(device_t parent, cfdata_t match, void *aux) 66 1.1 jakllsch { 67 1.1 jakllsch struct fdt_attach_args * const faa = aux; 68 1.1 jakllsch 69 1.7 thorpej return of_compatible_match(faa->faa_phandle, compat_data); 70 1.1 jakllsch } 71 1.1 jakllsch 72 1.1 jakllsch static void 73 1.1 jakllsch virtio_mmio_fdt_attach(device_t parent, device_t self, void *aux) 74 1.1 jakllsch { 75 1.1 jakllsch struct virtio_mmio_fdt_softc * const fsc = device_private(self); 76 1.1 jakllsch struct virtio_mmio_softc * const msc = &fsc->sc_msc; 77 1.1 jakllsch struct virtio_softc * const vsc = &msc->sc_sc; 78 1.1 jakllsch struct fdt_attach_args * const faa = aux; 79 1.1 jakllsch bus_addr_t addr; 80 1.1 jakllsch bus_size_t size; 81 1.1 jakllsch int error; 82 1.1 jakllsch 83 1.1 jakllsch aprint_normal("\n"); 84 1.1 jakllsch aprint_naive("\n"); 85 1.1 jakllsch 86 1.1 jakllsch if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { 87 1.1 jakllsch aprint_error_dev(self, "couldn't get registers\n"); 88 1.1 jakllsch return; 89 1.1 jakllsch } 90 1.1 jakllsch 91 1.1 jakllsch fsc->sc_phandle = faa->faa_phandle; 92 1.1 jakllsch msc->sc_iot = faa->faa_bst; 93 1.1 jakllsch vsc->sc_dev = self; 94 1.1 jakllsch vsc->sc_dmat = faa->faa_dmat; 95 1.1 jakllsch 96 1.1 jakllsch error = bus_space_map(msc->sc_iot, addr, size, 0, &msc->sc_ioh); 97 1.1 jakllsch if (error) { 98 1.3 jmcneill aprint_error_dev(self, "couldn't map %#" PRIx64 ": %d", 99 1.1 jakllsch (uint64_t)addr, error); 100 1.1 jakllsch return; 101 1.1 jakllsch } 102 1.1 jakllsch msc->sc_iosize = size; 103 1.1 jakllsch 104 1.10 yamaguch msc->sc_alloc_interrupts = virtio_mmio_fdt_alloc_interrupts; 105 1.1 jakllsch msc->sc_free_interrupts = virtio_mmio_fdt_free_interrupts; 106 1.1 jakllsch 107 1.1 jakllsch virtio_mmio_common_attach(msc); 108 1.8 thorpej virtio_mmio_fdt_rescan(self, NULL, NULL); 109 1.1 jakllsch } 110 1.1 jakllsch 111 1.1 jakllsch /* ARGSUSED */ 112 1.1 jakllsch static int 113 1.1 jakllsch virtio_mmio_fdt_rescan(device_t self, const char *attr, const int *scan_flags) 114 1.1 jakllsch { 115 1.1 jakllsch struct virtio_mmio_fdt_softc * const fsc = device_private(self); 116 1.1 jakllsch struct virtio_mmio_softc * const msc = &fsc->sc_msc; 117 1.1 jakllsch struct virtio_softc * const vsc = &msc->sc_sc; 118 1.1 jakllsch struct virtio_attach_args va; 119 1.1 jakllsch 120 1.1 jakllsch if (vsc->sc_child) /* Child already attached? */ 121 1.1 jakllsch return 0; 122 1.5 reinoud 123 1.1 jakllsch memset(&va, 0, sizeof(va)); 124 1.1 jakllsch va.sc_childdevid = vsc->sc_childdevid; 125 1.1 jakllsch 126 1.9 thorpej config_found(self, &va, NULL, CFARGS_NONE); 127 1.1 jakllsch 128 1.5 reinoud if (virtio_attach_failed(vsc)) 129 1.1 jakllsch return 0; 130 1.1 jakllsch 131 1.1 jakllsch return 0; 132 1.1 jakllsch } 133 1.1 jakllsch 134 1.1 jakllsch static int 135 1.1 jakllsch virtio_mmio_fdt_detach(device_t self, int flags) 136 1.1 jakllsch { 137 1.1 jakllsch struct virtio_mmio_fdt_softc * const fsc = device_private(self); 138 1.1 jakllsch struct virtio_mmio_softc * const msc = &fsc->sc_msc; 139 1.1 jakllsch 140 1.1 jakllsch return virtio_mmio_common_detach(msc, flags); 141 1.1 jakllsch } 142 1.1 jakllsch 143 1.1 jakllsch static int 144 1.10 yamaguch virtio_mmio_fdt_alloc_interrupts(struct virtio_mmio_softc *msc) 145 1.1 jakllsch { 146 1.1 jakllsch struct virtio_mmio_fdt_softc * const fsc = (void *)msc; 147 1.1 jakllsch struct virtio_softc * const vsc = &msc->sc_sc; 148 1.1 jakllsch char intrstr[128]; 149 1.1 jakllsch int flags = 0; 150 1.1 jakllsch 151 1.1 jakllsch if (!fdtbus_intr_str(fsc->sc_phandle, 0, intrstr, sizeof(intrstr))) { 152 1.1 jakllsch aprint_error_dev(vsc->sc_dev, "failed to decode interrupt\n"); 153 1.1 jakllsch return -1; 154 1.1 jakllsch } 155 1.1 jakllsch 156 1.5 reinoud if (vsc->sc_flags & VIRTIO_F_INTR_MPSAFE) 157 1.1 jakllsch flags |= FDT_INTR_MPSAFE; 158 1.1 jakllsch 159 1.4 jmcneill msc->sc_ih = fdtbus_intr_establish_xname(fsc->sc_phandle, 0, 160 1.4 jmcneill vsc->sc_ipl, flags, virtio_mmio_intr, msc, 161 1.4 jmcneill device_xname(vsc->sc_dev)); 162 1.1 jakllsch if (msc->sc_ih == NULL) { 163 1.1 jakllsch aprint_error_dev(vsc->sc_dev, 164 1.1 jakllsch "failed to establish interrupt on %s\n", intrstr); 165 1.1 jakllsch return -1; 166 1.1 jakllsch } 167 1.1 jakllsch aprint_normal_dev(vsc->sc_dev, "interrupting on %s\n", intrstr); 168 1.1 jakllsch 169 1.1 jakllsch return 0; 170 1.1 jakllsch } 171 1.1 jakllsch 172 1.1 jakllsch static void 173 1.1 jakllsch virtio_mmio_fdt_free_interrupts(struct virtio_mmio_softc *msc) 174 1.1 jakllsch { 175 1.1 jakllsch struct virtio_mmio_fdt_softc * const fsc = (void *)msc; 176 1.1 jakllsch 177 1.1 jakllsch if (msc->sc_ih != NULL) { 178 1.1 jakllsch fdtbus_intr_disestablish(fsc->sc_phandle, msc->sc_ih); 179 1.1 jakllsch msc->sc_ih = NULL; 180 1.1 jakllsch } 181 1.1 jakllsch } 182