1 1.28 thorpej /* $NetBSD: btvmeii.c,v 1.28 2024/04/24 02:31:26 thorpej Exp $ */ 2 1.1 drochner 3 1.1 drochner /* 4 1.1 drochner * Copyright (c) 1999 5 1.1 drochner * Matthias Drochner. All rights reserved. 6 1.1 drochner * 7 1.1 drochner * Redistribution and use in source and binary forms, with or without 8 1.1 drochner * modification, are permitted provided that the following conditions 9 1.1 drochner * are met: 10 1.1 drochner * 1. Redistributions of source code must retain the above copyright 11 1.1 drochner * notice, this list of conditions, and the following disclaimer. 12 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 drochner * notice, this list of conditions and the following disclaimer in the 14 1.1 drochner * documentation and/or other materials provided with the distribution. 15 1.1 drochner * 16 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 drochner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 drochner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 drochner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 drochner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 drochner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 drochner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 drochner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 drochner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 drochner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 drochner * SUCH DAMAGE. 27 1.1 drochner */ 28 1.1 drochner 29 1.1 drochner /* 30 1.1 drochner * Driver for the Bit3/SBS PCI-VME adapter Model 2706. 31 1.1 drochner * Uses the common Tundra Universe code. 32 1.1 drochner */ 33 1.4 lukem 34 1.4 lukem #include <sys/cdefs.h> 35 1.28 thorpej __KERNEL_RCSID(0, "$NetBSD: btvmeii.c,v 1.28 2024/04/24 02:31:26 thorpej Exp $"); 36 1.1 drochner 37 1.1 drochner #include <sys/param.h> 38 1.1 drochner #include <sys/systm.h> 39 1.5 simonb #include <sys/kernel.h> 40 1.1 drochner #include <sys/device.h> 41 1.1 drochner 42 1.1 drochner #include <dev/pci/pcireg.h> 43 1.1 drochner #include <dev/pci/pcivar.h> 44 1.1 drochner #include <dev/pci/pcidevs.h> 45 1.1 drochner 46 1.13 ad #include <sys/bus.h> 47 1.27 thorpej #include <sys/kmem.h> 48 1.27 thorpej #include <sys/vmem.h> 49 1.1 drochner 50 1.1 drochner #include <dev/pci/ppbreg.h> 51 1.1 drochner 52 1.1 drochner #include <dev/vme/vmereg.h> 53 1.1 drochner #include <dev/vme/vmevar.h> 54 1.1 drochner 55 1.1 drochner #include <dev/pci/universe_pci_var.h> 56 1.1 drochner 57 1.19 cegger static int b3_2706_match(device_t, cfdata_t, void *); 58 1.19 cegger static void b3_2706_attach(device_t, device_t, void *); 59 1.1 drochner 60 1.1 drochner /* exported via tag structs */ 61 1.10 perry int b3_2706_map_vme(void *, vme_addr_t, vme_size_t, 62 1.1 drochner vme_am_t, vme_datasize_t, vme_swap_t, 63 1.10 perry bus_space_tag_t *, bus_space_handle_t *, vme_mapresc_t*); 64 1.10 perry void b3_2706_unmap_vme(void *, vme_mapresc_t); 65 1.1 drochner 66 1.10 perry int b3_2706_vme_probe(void *, vme_addr_t, vme_size_t, vme_am_t, 67 1.1 drochner vme_datasize_t, 68 1.1 drochner int (*)(void *, bus_space_tag_t, bus_space_handle_t), 69 1.10 perry void *); 70 1.1 drochner 71 1.10 perry int b3_2706_map_vmeint(void *, int, int, vme_intr_handle_t *); 72 1.10 perry void *b3_2706_establish_vmeint(void *, vme_intr_handle_t, int, 73 1.10 perry int (*)(void *), void *); 74 1.10 perry void b3_2706_disestablish_vmeint(void *, void *); 75 1.10 perry void b3_2706_vmeint(void *, int, int); 76 1.1 drochner 77 1.10 perry int b3_2706_dmamap_create(void *, vme_size_t, 78 1.1 drochner vme_am_t, vme_datasize_t, vme_swap_t, 79 1.1 drochner int, vme_size_t, vme_addr_t, 80 1.10 perry int, bus_dmamap_t *); 81 1.10 perry void b3_2706_dmamap_destroy(void *, bus_dmamap_t); 82 1.1 drochner 83 1.10 perry int b3_2706_dmamem_alloc(void *, vme_size_t, 84 1.1 drochner vme_am_t, vme_datasize_t, vme_swap_t, 85 1.10 perry bus_dma_segment_t *, int, int *, int); 86 1.10 perry void b3_2706_dmamem_free(void *, bus_dma_segment_t *, int); 87 1.1 drochner 88 1.1 drochner struct b3_2706_vmemaprescs { 89 1.1 drochner int wnd; 90 1.1 drochner unsigned long pcibase, maplen; 91 1.1 drochner bus_space_handle_t handle; 92 1.1 drochner u_int32_t len; 93 1.1 drochner }; 94 1.1 drochner 95 1.2 drochner struct b3_2706_vmeintrhand { 96 1.2 drochner TAILQ_ENTRY(b3_2706_vmeintrhand) ih_next; 97 1.10 perry int (*ih_fun)(void*); 98 1.2 drochner void *ih_arg; 99 1.2 drochner int ih_level; 100 1.2 drochner int ih_vector; 101 1.2 drochner int ih_prior; 102 1.2 drochner u_long ih_count; 103 1.2 drochner }; 104 1.2 drochner 105 1.1 drochner struct b3_2706_softc { 106 1.1 drochner struct univ_pci_data univdata; 107 1.1 drochner bus_space_tag_t swapt, vmet; 108 1.1 drochner bus_space_handle_t swaph; 109 1.1 drochner bus_addr_t vmepbase; 110 1.1 drochner 111 1.1 drochner int windowused[8]; 112 1.1 drochner struct b3_2706_vmemaprescs vmemaprescs[8]; 113 1.27 thorpej vmem_t *vme_arena; 114 1.1 drochner 115 1.1 drochner struct vme_chipset_tag sc_vct; 116 1.2 drochner 117 1.2 drochner /* list of VME interrupt handlers */ 118 1.2 drochner TAILQ_HEAD(, b3_2706_vmeintrhand) intrhdls; 119 1.2 drochner int strayintrs; 120 1.1 drochner }; 121 1.1 drochner 122 1.22 chs CFATTACH_DECL_NEW(btvmeii, sizeof(struct b3_2706_softc), 123 1.8 thorpej b3_2706_match, b3_2706_attach, NULL, NULL); 124 1.1 drochner 125 1.1 drochner /* 126 1.1 drochner * The adapter consists of a DEC PCI-PCI-bridge with two 127 1.1 drochner * PCI devices behind it: A Tundra Universe as device 4 and 128 1.1 drochner * some FPGA with glue logics as device 8. 129 1.1 drochner * As long as the autoconf code doesn't provide more support 130 1.21 wiz * for dependent devices, we have to duplicate a part of the 131 1.1 drochner * "ppb" functions here. 132 1.1 drochner */ 133 1.1 drochner 134 1.1 drochner static int 135 1.19 cegger b3_2706_match(device_t parent, cfdata_t match, void *aux) 136 1.1 drochner { 137 1.1 drochner struct pci_attach_args *pa = aux; 138 1.1 drochner pci_chipset_tag_t pc = pa->pa_pc; 139 1.1 drochner int secbus; 140 1.1 drochner pcitag_t tag; 141 1.1 drochner pcireg_t id; 142 1.1 drochner 143 1.1 drochner if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR_DEC) 144 1.1 drochner || (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_DEC_21152)) 145 1.1 drochner return (0); 146 1.1 drochner 147 1.23 msaitoh secbus = PCI_BRIDGE_BUS_NUM_SECONDARY(pci_conf_read(pc, pa->pa_tag, 148 1.23 msaitoh PCI_BRIDGE_BUS_REG)); 149 1.1 drochner if (secbus == 0) { 150 1.1 drochner printf("b3_2706_match: ppb not configured\n"); 151 1.1 drochner return (0); 152 1.1 drochner } 153 1.1 drochner 154 1.1 drochner tag = pci_make_tag(pc, secbus, 4, 0); 155 1.1 drochner id = pci_conf_read(pc, tag, PCI_ID_REG); 156 1.1 drochner 157 1.1 drochner if ((PCI_VENDOR(id) != PCI_VENDOR_NEWBRIDGE) 158 1.1 drochner || (PCI_PRODUCT(id) != PCI_PRODUCT_NEWBRIDGE_CA91CX42)) { 159 1.1 drochner #ifdef DEBUG 160 1.1 drochner printf("b3_2706_match: no tundra\n"); 161 1.1 drochner #endif 162 1.1 drochner return (0); 163 1.1 drochner } 164 1.1 drochner 165 1.1 drochner tag = pci_make_tag(pc, secbus, 8, 0); 166 1.1 drochner id = pci_conf_read(pc, tag, PCI_ID_REG); 167 1.1 drochner 168 1.1 drochner if ((PCI_VENDOR(id) != PCI_VENDOR_BIT3) 169 1.1 drochner || (PCI_PRODUCT(id) != PCI_PRODUCT_BIT3_PCIVME2706)) { 170 1.1 drochner #ifdef DEBUG 171 1.1 drochner printf("b3_2706_match: no bit3 chip\n"); 172 1.1 drochner #endif 173 1.1 drochner return (0); 174 1.1 drochner } 175 1.1 drochner 176 1.1 drochner return (5); /* beat "ppb" */ 177 1.1 drochner } 178 1.1 drochner 179 1.1 drochner static void 180 1.19 cegger b3_2706_attach(device_t parent, device_t self, void *aux) 181 1.1 drochner { 182 1.20 cegger struct b3_2706_softc *sc = device_private(self); 183 1.1 drochner struct pci_attach_args *pa = aux; 184 1.1 drochner pci_chipset_tag_t pc = pa->pa_pc; 185 1.1 drochner struct pci_attach_args aa; 186 1.1 drochner int secbus; 187 1.1 drochner pcireg_t intr; 188 1.1 drochner pcitag_t tag; 189 1.1 drochner bus_addr_t swappbase; 190 1.1 drochner int i; 191 1.1 drochner 192 1.1 drochner struct vmebus_attach_args vaa; 193 1.1 drochner 194 1.9 thorpej aprint_naive(": VME bus adapter\n"); 195 1.9 thorpej aprint_normal("\n"); 196 1.1 drochner 197 1.23 msaitoh secbus = PCI_BRIDGE_BUS_NUM_SECONDARY(pci_conf_read(pc, pa->pa_tag, 198 1.23 msaitoh PCI_BRIDGE_BUS_REG)); 199 1.1 drochner 200 1.3 thorpej memcpy(&aa, pa, sizeof(struct pci_attach_args)); 201 1.1 drochner aa.pa_device = 4; 202 1.1 drochner aa.pa_function = 0; 203 1.1 drochner aa.pa_tag = pci_make_tag(pc, secbus, 4, 0); 204 1.1 drochner aa.pa_intrswiz += 4; 205 1.1 drochner intr = pci_conf_read(pc, aa.pa_tag, PCI_INTERRUPT_REG); 206 1.1 drochner /* 207 1.1 drochner * swizzle it based on the number of 208 1.1 drochner * busses we're behind and our device 209 1.1 drochner * number. 210 1.1 drochner */ 211 1.1 drochner aa.pa_intrpin = ((1 + aa.pa_intrswiz - 1) % 4) + 1; 212 1.1 drochner aa.pa_intrline = PCI_INTERRUPT_LINE(intr); 213 1.1 drochner 214 1.14 cegger if (univ_pci_attach(&sc->univdata, &aa, device_xname(self), 215 1.2 drochner b3_2706_vmeint, sc)) { 216 1.14 cegger aprint_error_dev(self, "error initializing universe chip\n"); 217 1.1 drochner return; 218 1.1 drochner } 219 1.1 drochner 220 1.2 drochner /* 221 1.2 drochner * don't waste KVM - the byteswap register is aliased in 222 1.2 drochner * a 512k window, we need it only once 223 1.2 drochner */ 224 1.1 drochner tag = pci_make_tag(pc, secbus, 8, 0); 225 1.1 drochner sc->swapt = pa->pa_memt; 226 1.1 drochner if (pci_mapreg_info(pc, tag, 0x10, 227 1.1 drochner PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 228 1.1 drochner &swappbase, 0, 0) || 229 1.1 drochner bus_space_map(sc->swapt, swappbase, 4, 0, &sc->swaph)) { 230 1.14 cegger aprint_error_dev(self, "can't map byteswap register\n"); 231 1.1 drochner return; 232 1.1 drochner } 233 1.2 drochner /* 234 1.2 drochner * Set up cycle specific byteswap mode. 235 1.2 drochner * XXX Readback yields "all-ones" for me, and it doesn't seem 236 1.2 drochner * to matter what I write into the register - the data don't 237 1.2 drochner * get swapped. Adapter fault or documentation bug? 238 1.2 drochner */ 239 1.2 drochner bus_space_write_4(sc->swapt, sc->swaph, 0, 0x00000490); 240 1.2 drochner 241 1.2 drochner /* VME space is mapped as needed */ 242 1.1 drochner sc->vmet = pa->pa_memt; 243 1.1 drochner if (pci_mapreg_info(pc, tag, 0x14, 244 1.1 drochner PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 245 1.1 drochner &sc->vmepbase, 0, 0)) { 246 1.14 cegger aprint_error_dev(self, "VME range not assigned\n"); 247 1.1 drochner return; 248 1.1 drochner } 249 1.2 drochner #ifdef BIT3DEBUG 250 1.14 cegger aprint_debug_dev(self, "VME window @%lx\n", 251 1.9 thorpej (long)sc->vmepbase); 252 1.2 drochner #endif 253 1.1 drochner 254 1.1 drochner for (i = 0; i < 8; i++) { 255 1.1 drochner sc->windowused[i] = 0; 256 1.1 drochner } 257 1.27 thorpej sc->vme_arena = vmem_create("pcivme", 258 1.27 thorpej sc->vmepbase, /* base */ 259 1.27 thorpej 32*1024*1024, /* size */ 260 1.27 thorpej 1, /* quantum */ 261 1.27 thorpej NULL, /* allocfn */ 262 1.27 thorpej NULL, /* releasefn */ 263 1.27 thorpej NULL, /* source */ 264 1.27 thorpej 0, /* qcache_max */ 265 1.27 thorpej VM_SLEEP, 266 1.27 thorpej IPL_NONE); 267 1.1 drochner 268 1.1 drochner sc->sc_vct.cookie = self; 269 1.1 drochner sc->sc_vct.vct_probe = b3_2706_vme_probe; 270 1.1 drochner sc->sc_vct.vct_map = b3_2706_map_vme; 271 1.1 drochner sc->sc_vct.vct_unmap = b3_2706_unmap_vme; 272 1.1 drochner sc->sc_vct.vct_int_map = b3_2706_map_vmeint; 273 1.1 drochner sc->sc_vct.vct_int_establish = b3_2706_establish_vmeint; 274 1.1 drochner sc->sc_vct.vct_int_disestablish = b3_2706_disestablish_vmeint; 275 1.1 drochner sc->sc_vct.vct_dmamap_create = b3_2706_dmamap_create; 276 1.1 drochner sc->sc_vct.vct_dmamap_destroy = b3_2706_dmamap_destroy; 277 1.1 drochner sc->sc_vct.vct_dmamem_alloc = b3_2706_dmamem_alloc; 278 1.1 drochner sc->sc_vct.vct_dmamem_free = b3_2706_dmamem_free; 279 1.1 drochner 280 1.1 drochner vaa.va_vct = &(sc->sc_vct); 281 1.1 drochner vaa.va_bdt = pa->pa_dmat; /* XXX */ 282 1.2 drochner vaa.va_slaveconfig = 0; /* XXX CSR window? */ 283 1.1 drochner 284 1.26 thorpej config_found(self, &vaa, 0, CFARGS_NONE); 285 1.1 drochner } 286 1.1 drochner 287 1.1 drochner #define sc ((struct b3_2706_softc*)vsc) 288 1.1 drochner 289 1.1 drochner int 290 1.15 dsl b3_2706_map_vme(void *vsc, vme_addr_t vmeaddr, vme_size_t len, vme_am_t am, vme_datasize_t datasizes, vme_swap_t swap, bus_space_tag_t *tag, bus_space_handle_t *handle, vme_mapresc_t *resc) 291 1.1 drochner { 292 1.1 drochner int idx, i, wnd, res; 293 1.27 thorpej unsigned long boundary, maplen; 294 1.1 drochner vme_addr_t vmebase, vmeend; 295 1.27 thorpej vmem_addr_t pcibase; 296 1.1 drochner static int windoworder[8] = {1, 2, 3, 5, 6, 7, 0, 4}; 297 1.1 drochner 298 1.1 drochner /* prefer windows with fine granularity for small mappings */ 299 1.1 drochner wnd = -1; 300 1.1 drochner if (len <= 32*1024) 301 1.1 drochner idx = 6; 302 1.1 drochner else 303 1.1 drochner idx = 0; 304 1.1 drochner for (i = 0; i < 8; i++) { 305 1.1 drochner if (!sc->windowused[windoworder[idx]]) { 306 1.1 drochner wnd = windoworder[idx]; 307 1.1 drochner sc->windowused[wnd] = 1; 308 1.1 drochner break; 309 1.1 drochner } 310 1.1 drochner idx = (idx + 1) % 8; 311 1.1 drochner } 312 1.1 drochner if (wnd == -1) 313 1.1 drochner return (ENOSPC); 314 1.1 drochner 315 1.1 drochner boundary = (wnd & 3) ? 64*1024 : 4*1024; 316 1.1 drochner 317 1.1 drochner /* first mapped address */ 318 1.1 drochner vmebase = vmeaddr & ~(boundary - 1); 319 1.1 drochner /* base of last mapped page */ 320 1.1 drochner vmeend = (vmeaddr + len - 1) & ~(boundary - 1); 321 1.1 drochner /* bytes in outgoing window required */ 322 1.1 drochner maplen = vmeend - vmebase + boundary; 323 1.1 drochner 324 1.27 thorpej if (vmem_xalloc(sc->vme_arena, 325 1.27 thorpej maplen, /* size */ 326 1.27 thorpej boundary, /* align */ 327 1.27 thorpej 0, /* phase */ 328 1.27 thorpej 0, /* boundary */ 329 1.27 thorpej VMEM_ADDR_MIN, /* minaddr */ 330 1.27 thorpej VMEM_ADDR_MAX, /* maxaddr */ 331 1.28 thorpej VM_BESTFIT | VM_NOSLEEP, 332 1.27 thorpej &pcibase)) { 333 1.2 drochner sc->windowused[wnd] = 0; 334 1.1 drochner return (ENOMEM); 335 1.2 drochner } 336 1.1 drochner 337 1.1 drochner res = univ_pci_mapvme(&sc->univdata, wnd, vmebase, maplen, 338 1.1 drochner am, datasizes, pcibase); 339 1.1 drochner if (res) { 340 1.27 thorpej vmem_xfree(sc->vme_arena, pcibase, maplen); 341 1.2 drochner sc->windowused[wnd] = 0; 342 1.1 drochner return (res); 343 1.1 drochner } 344 1.1 drochner 345 1.1 drochner res = bus_space_map(sc->vmet, pcibase + (vmeaddr - vmebase), len, 346 1.1 drochner 0, handle); 347 1.1 drochner if (res) { 348 1.1 drochner univ_pci_unmapvme(&sc->univdata, wnd); 349 1.27 thorpej vmem_xfree(sc->vme_arena, pcibase, maplen); 350 1.2 drochner sc->windowused[wnd] = 0; 351 1.1 drochner return (res); 352 1.1 drochner } 353 1.1 drochner 354 1.1 drochner *tag = sc->vmet; 355 1.1 drochner 356 1.1 drochner /* 357 1.1 drochner * save all data needed for later unmapping 358 1.1 drochner */ 359 1.1 drochner sc->vmemaprescs[wnd].wnd = wnd; 360 1.1 drochner sc->vmemaprescs[wnd].pcibase = pcibase; 361 1.1 drochner sc->vmemaprescs[wnd].maplen = maplen; 362 1.1 drochner sc->vmemaprescs[wnd].handle = *handle; 363 1.1 drochner sc->vmemaprescs[wnd].len = len; 364 1.1 drochner *resc = &sc->vmemaprescs[wnd]; 365 1.1 drochner return (0); 366 1.1 drochner } 367 1.1 drochner 368 1.1 drochner void 369 1.15 dsl b3_2706_unmap_vme(void *vsc, vme_mapresc_t resc) 370 1.1 drochner { 371 1.1 drochner struct b3_2706_vmemaprescs *r = resc; 372 1.1 drochner 373 1.1 drochner bus_space_unmap(sc->vmet, r->handle, r->len); 374 1.27 thorpej vmem_xfree(sc->vme_arena, r->pcibase, r->maplen); 375 1.1 drochner 376 1.1 drochner if (!sc->windowused[r->wnd]) 377 1.1 drochner panic("b3_2706_unmap_vme: bad window"); 378 1.1 drochner univ_pci_unmapvme(&sc->univdata, r->wnd); 379 1.1 drochner sc->windowused[r->wnd] = 0; 380 1.1 drochner } 381 1.1 drochner 382 1.1 drochner int 383 1.17 dsl b3_2706_vme_probe(void *vsc, vme_addr_t addr, vme_size_t len, vme_am_t am, vme_datasize_t datasize, int (*callback)(void *, bus_space_tag_t, bus_space_handle_t), void *cbarg) 384 1.1 drochner { 385 1.2 drochner bus_space_tag_t tag; 386 1.2 drochner bus_space_handle_t handle; 387 1.2 drochner vme_mapresc_t resc; 388 1.2 drochner int res, i; 389 1.2 drochner volatile u_int32_t dummy; 390 1.2 drochner 391 1.2 drochner res = b3_2706_map_vme(vsc, addr, len, am, datasize, 0, 392 1.2 drochner &tag, &handle, &resc); 393 1.2 drochner if (res) 394 1.2 drochner return (res); 395 1.2 drochner 396 1.2 drochner if (univ_pci_vmebuserr(&sc->univdata, 1)) 397 1.2 drochner printf("b3_2706_vme_badaddr: TA bit not clean - reset\n"); 398 1.2 drochner 399 1.2 drochner if (callback) 400 1.2 drochner res = (*callback)(cbarg, tag, handle); 401 1.2 drochner else { 402 1.2 drochner for (i = 0; i < len;) { 403 1.2 drochner switch (datasize) { 404 1.2 drochner case VME_D8: 405 1.2 drochner dummy = bus_space_read_1(tag, handle, i); 406 1.27 thorpej (void)dummy; 407 1.2 drochner i++; 408 1.2 drochner break; 409 1.2 drochner case VME_D16: 410 1.2 drochner dummy = bus_space_read_2(tag, handle, i); 411 1.27 thorpej (void)dummy; 412 1.2 drochner i += 2; 413 1.2 drochner break; 414 1.2 drochner case VME_D32: 415 1.2 drochner dummy = bus_space_read_4(tag, handle, i); 416 1.27 thorpej (void)dummy; 417 1.2 drochner i += 4; 418 1.2 drochner break; 419 1.2 drochner default: 420 1.2 drochner panic("b3_2706_vme_probe: invalid datasize %x", 421 1.2 drochner datasize); 422 1.2 drochner } 423 1.2 drochner } 424 1.2 drochner } 425 1.2 drochner 426 1.2 drochner if (univ_pci_vmebuserr(&sc->univdata, 0)) { 427 1.2 drochner #ifdef BIT3DEBUG 428 1.2 drochner printf("b3_2706_vme_badaddr: caught TA\n"); 429 1.2 drochner #endif 430 1.2 drochner univ_pci_vmebuserr(&sc->univdata, 1); 431 1.2 drochner res = EIO; 432 1.2 drochner } 433 1.2 drochner 434 1.2 drochner b3_2706_unmap_vme(vsc, resc); 435 1.2 drochner return (res); 436 1.1 drochner } 437 1.1 drochner 438 1.1 drochner int 439 1.16 dsl b3_2706_map_vmeint(void *vsc, int level, int vector, vme_intr_handle_t *handlep) 440 1.1 drochner { 441 1.2 drochner 442 1.2 drochner *handlep = (void *)(long)((level << 8) | vector); /* XXX */ 443 1.2 drochner return (0); 444 1.1 drochner } 445 1.1 drochner 446 1.1 drochner void * 447 1.17 dsl b3_2706_establish_vmeint(void *vsc, vme_intr_handle_t handle, int prior, int (*func)(void *), void *arg) 448 1.1 drochner { 449 1.2 drochner struct b3_2706_vmeintrhand *ih; 450 1.2 drochner long lv; 451 1.2 drochner int s; 452 1.2 drochner 453 1.27 thorpej ih = kmem_alloc(sizeof *ih, KM_SLEEP); 454 1.2 drochner 455 1.2 drochner lv = (long)handle; /* XXX */ 456 1.2 drochner 457 1.2 drochner ih->ih_fun = func; 458 1.2 drochner ih->ih_arg = arg; 459 1.2 drochner ih->ih_level = lv >> 8; 460 1.2 drochner ih->ih_vector = lv & 0xff; 461 1.2 drochner ih->ih_prior = prior; 462 1.2 drochner ih->ih_count = 0; 463 1.2 drochner 464 1.2 drochner s = splhigh(); 465 1.2 drochner TAILQ_INSERT_TAIL(&(sc->intrhdls), ih, ih_next); 466 1.2 drochner splx(s); 467 1.2 drochner 468 1.2 drochner return (ih); 469 1.1 drochner } 470 1.1 drochner 471 1.1 drochner void 472 1.15 dsl b3_2706_disestablish_vmeint(void *vsc, void *cookie) 473 1.1 drochner { 474 1.2 drochner struct b3_2706_vmeintrhand *ih = cookie; 475 1.2 drochner int s; 476 1.2 drochner 477 1.2 drochner if (!ih) { 478 1.2 drochner printf("b3_2706_unmap_vmeint: NULL arg\n"); 479 1.2 drochner return; 480 1.2 drochner } 481 1.2 drochner 482 1.2 drochner s = splhigh(); 483 1.2 drochner TAILQ_REMOVE(&(sc->intrhdls), ih, ih_next); 484 1.2 drochner splx(s); 485 1.2 drochner 486 1.27 thorpej kmem_free(ih, sizeof(*ih)); 487 1.2 drochner } 488 1.2 drochner 489 1.2 drochner void 490 1.16 dsl b3_2706_vmeint(void *vsc, int level, int vector) 491 1.2 drochner { 492 1.2 drochner struct b3_2706_vmeintrhand *ih; 493 1.2 drochner int found; 494 1.2 drochner 495 1.2 drochner #ifdef BIT3DEBUG 496 1.2 drochner printf("b3_2706_vmeint: VME IRQ %d, vec %x\n", level, vector); 497 1.2 drochner #endif 498 1.2 drochner found = 0; 499 1.2 drochner 500 1.2 drochner for (ih = sc->intrhdls.tqh_first; ih; 501 1.2 drochner ih = ih->ih_next.tqe_next) { 502 1.2 drochner if ((ih->ih_level == level) && 503 1.2 drochner ((ih->ih_vector == -1) || 504 1.2 drochner (ih->ih_vector == vector))) { 505 1.2 drochner int s, res; 506 1.2 drochner /* 507 1.2 drochner * We should raise the interrupt level 508 1.2 drochner * to ih->ih_prior here. How to do this 509 1.12 wiz * machine-independently? 510 1.2 drochner * To be safe, raise to the maximum. 511 1.2 drochner */ 512 1.2 drochner s = splhigh(); 513 1.2 drochner found |= (res = (*(ih->ih_fun))(ih->ih_arg)); 514 1.2 drochner splx(s); 515 1.2 drochner if (res) 516 1.2 drochner ih->ih_count++; 517 1.2 drochner if (res == 1) 518 1.2 drochner break; 519 1.2 drochner } 520 1.2 drochner } 521 1.2 drochner if (!found) 522 1.2 drochner sc->strayintrs++; 523 1.1 drochner } 524 1.1 drochner 525 1.1 drochner int 526 1.27 thorpej b3_2706_dmamap_create(void *vsc, vme_size_t len, vme_am_t am, 527 1.27 thorpej vme_datasize_t datasize, vme_swap_t swap, int nsegs, vme_size_t segsz, 528 1.27 thorpej vme_addr_t bound, int flags, bus_dmamap_t *mapp) 529 1.1 drochner { 530 1.1 drochner return (EINVAL); 531 1.1 drochner } 532 1.1 drochner 533 1.1 drochner void 534 1.15 dsl b3_2706_dmamap_destroy(void *vsc, bus_dmamap_t map) 535 1.1 drochner { 536 1.1 drochner } 537 1.1 drochner 538 1.1 drochner int 539 1.15 dsl b3_2706_dmamem_alloc(void *vsc, vme_size_t len, vme_am_t am, vme_datasize_t datasizes, vme_swap_t swap, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags) 540 1.1 drochner { 541 1.1 drochner return (EINVAL); 542 1.1 drochner } 543 1.1 drochner 544 1.1 drochner void 545 1.15 dsl b3_2706_dmamem_free(void *vsc, bus_dma_segment_t *segs, int nsegs) 546 1.1 drochner { 547 1.1 drochner } 548 1.1 drochner 549 1.1 drochner #undef sc 550