Home | History | Annotate | Line # | Download | only in pci
      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