1 /* $NetBSD: virtio_mainbus.c,v 1.2 2024/03/09 11:16:31 isaki Exp $ */ 2 3 /* 4 * Copyright (c) 2021, 2024 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Reinoud Zandijk and by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: virtio_mainbus.c,v 1.2 2024/03/09 11:16:31 isaki Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 38 #include <sys/device.h> 39 40 #include <virt68k/dev/mainbusvar.h> 41 42 #define VIRTIO_PRIVATE 43 #include <dev/virtio/virtio_mmiovar.h> 44 45 46 static int virtio_mainbus_match(device_t, cfdata_t, void *); 47 static void virtio_mainbus_attach(device_t, device_t, void *); 48 static int virtio_mainbus_rescan(device_t, const char *, const int *); 49 static int virtio_mainbus_detach(device_t, int); 50 51 static int virtio_mainbus_alloc_interrupts(struct virtio_mmio_softc *); 52 static void virtio_mainbus_free_interrupts(struct virtio_mmio_softc *); 53 54 struct virtio_mainbus_softc { 55 struct virtio_mmio_softc sc_msc; 56 57 int sc_irq; 58 }; 59 60 61 CFATTACH_DECL3_NEW(virtio_mainbus, sizeof(struct virtio_mainbus_softc), 62 virtio_mainbus_match, virtio_mainbus_attach, 63 virtio_mainbus_detach, NULL, 64 virtio_mainbus_rescan, (void *)voidop, 0); 65 66 67 static const struct device_compatible_entry compat_data[] = { 68 { .compat = "virtio,mmio" }, 69 DEVICE_COMPAT_EOL 70 }; 71 72 73 static int 74 virtio_mainbus_match(device_t parent, cfdata_t match, void *aux) 75 { 76 struct mainbus_attach_args *ma = aux; 77 78 return mainbus_compatible_match(ma, compat_data); 79 } 80 81 82 void 83 virtio_mainbus_attach(device_t parent, device_t self, void *aux) 84 { 85 struct virtio_mainbus_softc *sc = device_private(self); 86 struct virtio_mmio_softc *msc = &sc->sc_msc; 87 struct virtio_softc *vsc = &msc->sc_sc; 88 struct mainbus_attach_args *ma = aux; 89 bus_space_handle_t bsh; 90 91 if (bus_space_map(ma->ma_st, ma->ma_addr, ma->ma_size, 0, &bsh) != 0) { 92 aprint_error(": can't map i/o space\n"); 93 return; 94 } 95 96 aprint_normal("\n"); 97 aprint_naive("\n"); 98 99 sc->sc_irq = ma->ma_irq; 100 101 msc->sc_iot = ma->ma_st; 102 msc->sc_ioh = bsh; 103 msc->sc_iosize = ma->ma_size; 104 msc->sc_alloc_interrupts = virtio_mainbus_alloc_interrupts; 105 msc->sc_free_interrupts = virtio_mainbus_free_interrupts; 106 107 vsc->sc_dev = self; 108 vsc->sc_dmat = ma->ma_dmat; 109 virtio_mmio_common_attach(msc); 110 111 virtio_mainbus_rescan(self, NULL, NULL); 112 } 113 114 115 /* ARGSUSED */ 116 static int 117 virtio_mainbus_rescan(device_t self, const char *ifattr, const int *locs) 118 { 119 struct virtio_mainbus_softc *sc = device_private(self); 120 struct virtio_mmio_softc *msc = &sc->sc_msc; 121 struct virtio_softc *vsc = &msc->sc_sc; 122 struct virtio_attach_args va; 123 124 if (vsc->sc_child) /* child already attached? */ 125 return 0; 126 127 memset(&va, 0, sizeof(va)); 128 va.sc_childdevid = vsc->sc_childdevid; 129 130 config_found(self, &va, NULL, CFARGS_NONE); 131 132 if (virtio_attach_failed(vsc)) 133 return 0; 134 return 0; 135 } 136 137 138 static int 139 virtio_mainbus_detach(device_t self, int flags) 140 { 141 struct virtio_mainbus_softc *sc = device_private(self); 142 struct virtio_mmio_softc * const msc = &sc->sc_msc; 143 144 return virtio_mmio_common_detach(msc, flags); 145 } 146 147 148 static int 149 virtio_mainbus_alloc_interrupts(struct virtio_mmio_softc *msc) 150 { 151 struct virtio_mainbus_softc *sc = (struct virtio_mainbus_softc *) msc; 152 struct virtio_softc * const vsc = &msc->sc_sc; 153 char strbuf[INTR_STRING_BUFSIZE]; 154 155 msc->sc_ih = intr_establish(virtio_mmio_intr, msc, 156 sc->sc_irq, IPL_VM/*XXX*/, 0); 157 if (msc->sc_ih == NULL) { 158 aprint_error_dev(vsc->sc_dev, 159 "couldn't install interrupt handler\n"); 160 return -1; 161 } 162 163 aprint_normal_dev(vsc->sc_dev, "interrupting at %s\n", 164 intr_string(msc->sc_ih, strbuf, sizeof(strbuf))); 165 166 return 0; 167 } 168 169 170 static void 171 virtio_mainbus_free_interrupts(struct virtio_mmio_softc *msc) 172 { 173 if (msc->sc_ih) { 174 intr_disestablish(msc->sc_ih); 175 msc->sc_ih = NULL; 176 } 177 } 178