diff options
author | dfr <dfr@FreeBSD.org> | 1999-06-05 13:30:13 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1999-06-05 13:30:13 +0000 |
commit | 5d698a672d010c9c1953515f78b626af1f2b23c8 (patch) | |
tree | 2c54ebf6283cdabc63a25afd53742d93bbe5eba8 /sys | |
parent | b5f25689234ab13b40ae7c1bfdd723ac8c3dc9d3 (diff) | |
download | FreeBSD-src-5d698a672d010c9c1953515f78b626af1f2b23c8.zip FreeBSD-src-5d698a672d010c9c1953515f78b626af1f2b23c8.tar.gz |
* Implement ISA dma (only for CIA now but more chipsets to follow).
* Port the fd driver to alpha.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/alpha/alpha/busdma_machdep.c | 59 | ||||
-rw-r--r-- | sys/alpha/alpha/sgmap.c | 196 | ||||
-rw-r--r-- | sys/alpha/conf/GENERIC | 6 | ||||
-rw-r--r-- | sys/alpha/conf/NOTES | 6 | ||||
-rw-r--r-- | sys/alpha/conf/files.alpha | 5 | ||||
-rw-r--r-- | sys/alpha/include/bus.h | 6 | ||||
-rw-r--r-- | sys/alpha/include/chipset.h | 9 | ||||
-rw-r--r-- | sys/alpha/include/ioctl_fd.h | 126 | ||||
-rw-r--r-- | sys/alpha/include/sgmap.h | 49 | ||||
-rw-r--r-- | sys/alpha/isa/isa.c | 36 | ||||
-rw-r--r-- | sys/alpha/isa/isa_dma.c | 487 | ||||
-rw-r--r-- | sys/alpha/pci/cia.c | 145 | ||||
-rw-r--r-- | sys/conf/files.alpha | 5 |
13 files changed, 1115 insertions, 20 deletions
diff --git a/sys/alpha/alpha/busdma_machdep.c b/sys/alpha/alpha/busdma_machdep.c index 5deba06..60d9bcf 100644 --- a/sys/alpha/alpha/busdma_machdep.c +++ b/sys/alpha/alpha/busdma_machdep.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: busdma_machdep.c,v 1.1 1998/09/16 08:20:45 dfr Exp $ + * $Id: busdma_machdep.c,v 1.2 1999/05/26 23:01:36 gallatin Exp $ */ #include <sys/param.h> @@ -35,6 +35,7 @@ #include <vm/vm_page.h> #include <machine/bus.h> +#include <machine/sgmap.h> #include <machine/md_var.h> #define MAX(a,b) (((a) > (b)) ? (a) : (b)) @@ -81,8 +82,10 @@ struct bus_dmamap { bus_dma_tag_t dmat; void *buf; /* unmapped buffer pointer */ bus_size_t buflen; /* unmapped buffer length */ + vm_offset_t busaddress; /* address in bus space */ bus_dmamap_callback_t *callback; void *callback_arg; + void *sgmaphandle; /* handle into sgmap */ STAILQ_ENTRY(bus_dmamap) links; }; @@ -237,6 +240,25 @@ bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) error = 0; + if (dmat->flags & BUS_DMA_ISA) { + bus_dmamap_t map; + map = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF, + M_NOWAIT); + if (map == NULL) { + return (ENOMEM); + } else { + bzero(map, sizeof(*map)); + map->busaddress = + sgmap_alloc_region(chipset.sgmap, + dmat->maxsize, + dmat->boundary, + &map->sgmaphandle); + dmat->map_count++; + *mapp = map; + return (0); + } + } + if (dmat->lowaddr < ptoa(Maxmem)) { /* Must bounce */ int maxpages; @@ -294,6 +316,10 @@ bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) { + if (dmat->flags & BUS_DMA_ISA) { + sgmap_free_region(chipset.sgmap, map->sgmaphandle); + } + if (map != NULL) { if (STAILQ_FIRST(&map->bpages) != NULL) return (EBUSY); @@ -376,6 +402,28 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, int error; error = 0; + + if (dmat->flags & BUS_DMA_ISA) { + /* + * For ISA dma, we use the chipset's scatter-gather + * map to map the tranfer into the ISA reachable range + * of the bus address space. + */ + vaddr = trunc_page((vm_offset_t) buf); + dm_segments[0].ds_addr = + map->busaddress + (vm_offset_t) buf - vaddr; + dm_segments[0].ds_len = buflen; + buflen = round_page((vm_offset_t) buf + buflen) - vaddr; + sgmap_load_region(chipset.sgmap, + map->busaddress, + vaddr, + buflen); + map->buflen = buflen; + (*callback)(callback_arg, dm_segments, 1, error); + + return (0); + } + /* * If we are being called during a callback, pagesneeded will * be non-zero, so we can avoid doing the work twice. @@ -479,6 +527,13 @@ _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) { struct bounce_page *bpage; + if (dmat->flags & BUS_DMA_ISA) { + sgmap_unload_region(chipset.sgmap, + map->busaddress, + map->buflen); + return; + } + while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { STAILQ_REMOVE_HEAD(&map->bpages, links); free_bounce_page(dmat, bpage); @@ -637,7 +692,7 @@ free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) } void -busdma_swi() +busdma_swi(void) { int s; struct bus_dmamap *map; diff --git a/sys/alpha/alpha/sgmap.c b/sys/alpha/alpha/sgmap.c new file mode 100644 index 0000000..493a2b1 --- /dev/null +++ b/sys/alpha/alpha/sgmap.c @@ -0,0 +1,196 @@ +/*- + * Copyright (c) 1998 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <machine/bus.h> +#include <sys/malloc.h> +#include <sys/rman.h> +#include <sys/lock.h> +#include <machine/sgmap.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_prot.h> +#include <vm/vm_map.h> + +MALLOC_DEFINE(M_SGMAP, "sgmap", "Scatter Gather mapping"); + +struct sgmap { + struct rman rm; /* manage range of bus addresses */ + sgmap_map_callback *map; /* map one page in the sgmap */ + void *arg; /* argument to map function */ + bus_addr_t sba; + bus_addr_t eba; +}; + +void *overflow_page = 0; +vm_offset_t overflow_page_pa; + +vm_offset_t +sgmap_overflow_page(void) +{ + /* + * Allocate the overflow page if necessary. + */ + if (!overflow_page) { + overflow_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + if (!overflow_page) + panic("sgmap_alloc_region: can't allocate overflow page"); + overflow_page_pa = pmap_kextract((vm_offset_t) overflow_page); + } + + return overflow_page_pa; +} + +/* + * Create an sgmap to manage a range of bus addresses which map + * physical memory using a scatter-gather map. + */ +struct sgmap * +sgmap_map_create(bus_addr_t sba, bus_addr_t eba, + sgmap_map_callback *map, void *arg) +{ + struct sgmap *sgmap; + + sgmap = malloc(sizeof *sgmap, M_SGMAP, M_NOWAIT); + if (!sgmap) + return 0; + + + sgmap->rm.rm_start = sba; + sgmap->rm.rm_end = eba; + sgmap->rm.rm_type = RMAN_ARRAY; + sgmap->rm.rm_descr = "Scatter Gather Bus Addresses"; + rman_init(&sgmap->rm); + rman_manage_region(&sgmap->rm, sba, eba); + sgmap->map = map; + sgmap->arg = arg; + sgmap->sba = sba; + sgmap->eba = eba; + + return sgmap; +} + +/* + * Destroy an sgmap created with sgmap_map_create(). + */ +void +sgmap_map_destroy(struct sgmap *sgmap) +{ + rman_fini(&sgmap->rm); + free(sgmap, M_SGMAP); +} + +/* + * Map a range of virtual addresses using the sgmap and return the bus + * address of the mapped region. An opaque handle for the mapped + * region is also returned in *mhp. This handle should be passed to + * sgmap_free_region() when the mapping is no longer required. + */ +bus_addr_t +sgmap_alloc_region(struct sgmap *sgmap, + bus_size_t size, + bus_size_t boundary, + void **mhp) +{ + struct resource *res; + bus_addr_t ba, nba; + + /* + * This ensures allocations are on page boundaries. The extra + * page is used as a guard page since dma prefetching can + * generate accesses to addresses outside the transfer range. + */ + size = round_page(size); + + /* + * Attempt to allocate within each boundary delimited region. + */ + res = 0; + for (ba = sgmap->sba; ba < sgmap->eba; ba = nba) { + nba = (ba + boundary) & ~(boundary - 1); + res = rman_reserve_resource(&sgmap->rm, + ba, nba - 1, size + PAGE_SIZE, + RF_ACTIVE, 0); + if (res) + break; + } + + if (res == 0) + return 0; + + *mhp = (void *) res; + return rman_get_start(res); +} + +void +sgmap_load_region(struct sgmap *sgmap, + bus_addr_t sba, + vm_offset_t va, + bus_size_t size) +{ + bus_addr_t ba, eba; + + /* + * Call the chipset to map each page in the mapped range to + * the correct physical page. + */ + for (ba = sba, eba = sba + size; ba < eba; + ba += PAGE_SIZE, va += PAGE_SIZE) { + vm_offset_t pa = pmap_kextract(va); + sgmap->map(sgmap->arg, ba, pa); + } + sgmap->map(sgmap->arg, ba, overflow_page_pa); +} + +void +sgmap_unload_region(struct sgmap *sgmap, + bus_addr_t sba, + bus_size_t size) +{ + bus_addr_t ba, eba; + + /* + * Call the chipset to unmap each page. + */ + for (ba = sba, eba = sba + size; ba < eba; ba += PAGE_SIZE) { + sgmap->map(sgmap->arg, ba, 0); + } + sgmap->map(sgmap->arg, ba, 0); +} + +/* + * Free a region allocated using sgmap_alloc_region(). + */ +void +sgmap_free_region(struct sgmap *sgmap, void *mh) +{ + struct resource *res = mh; + rman_release_resource(res); +} diff --git a/sys/alpha/conf/GENERIC b/sys/alpha/conf/GENERIC index 865313b..8497209 100644 --- a/sys/alpha/conf/GENERIC +++ b/sys/alpha/conf/GENERIC @@ -11,7 +11,7 @@ # device lines is present in the ./LINT configuration file. If you are # in doubt as to the purpose or necessity of a line, check first in LINT. # -# $Id: GENERIC,v 1.22 1999/05/10 13:30:51 dfr Exp $ +# $Id: GENERIC,v 1.23 1999/05/26 23:22:14 gallatin Exp $ machine "alpha" cpu "EV4" @@ -91,6 +91,10 @@ device cd0 # real time clock device mcclock0 at isa0 port 0x70 +# Not enabled since it only works on CIA chipsets +#controller fdc0 at isa? port IO_FD1 irq 6 drq 2 +#disk fd0 at fdc0 drive 0 + controller atkbdc0 at isa? port IO_KBD device atkbd0 at atkbdc? irq 1 device psm0 at atkbdc? irq 12 diff --git a/sys/alpha/conf/NOTES b/sys/alpha/conf/NOTES index 865313b..8497209 100644 --- a/sys/alpha/conf/NOTES +++ b/sys/alpha/conf/NOTES @@ -11,7 +11,7 @@ # device lines is present in the ./LINT configuration file. If you are # in doubt as to the purpose or necessity of a line, check first in LINT. # -# $Id: GENERIC,v 1.22 1999/05/10 13:30:51 dfr Exp $ +# $Id: GENERIC,v 1.23 1999/05/26 23:22:14 gallatin Exp $ machine "alpha" cpu "EV4" @@ -91,6 +91,10 @@ device cd0 # real time clock device mcclock0 at isa0 port 0x70 +# Not enabled since it only works on CIA chipsets +#controller fdc0 at isa? port IO_FD1 irq 6 drq 2 +#disk fd0 at fdc0 drive 0 + controller atkbdc0 at isa? port IO_KBD device atkbd0 at atkbdc? irq 1 device psm0 at atkbdc? irq 12 diff --git a/sys/alpha/conf/files.alpha b/sys/alpha/conf/files.alpha index b589354..6b3f3e8 100644 --- a/sys/alpha/conf/files.alpha +++ b/sys/alpha/conf/files.alpha @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.alpha,v 1.18 1999/04/16 21:21:34 peter Exp $ +# $Id: files.alpha,v 1.19 1999/05/26 23:22:13 gallatin Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -35,6 +35,7 @@ alpha/alpha/mountroot.c optional slice alpha/alpha/ipl_funcs.c standard alpha/alpha/pal.s standard alpha/alpha/busdma_machdep.c standard +alpha/alpha/sgmap.c standard alpha/alpha/cons.c standard alpha/alpha/prom.c standard alpha/alpha/promcons.c standard @@ -124,6 +125,7 @@ alpha/pci/tsunami.c optional tsunami alpha/pci/tsunami_pci.c optional tsunami alpha/pci/pcibus.c optional pci alpha/isa/isa.c optional isa +alpha/isa/isa_dma.c optional isa alpha/isa/mcclock_isa.c optional isa alpha/alpha/elf_machdep.c standard libkern/bcd.c standard @@ -163,6 +165,7 @@ dev/syscons/syscons.c optional sc device-driver dev/syscons/scvidctl.c optional sc device-driver isa/syscons_isa.c optional sc device-driver isa/psm.c optional psm device-driver +isa/fd.c optional fd device-driver dev/ata/ata-all.c optional ata device-driver dev/ata/ata-dma.c optional ata device-driver dev/ata/atapi-all.c optional ata device-driver diff --git a/sys/alpha/include/bus.h b/sys/alpha/include/bus.h index f515b71..86f80ea 100644 --- a/sys/alpha/include/bus.h +++ b/sys/alpha/include/bus.h @@ -67,7 +67,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* $Id$ */ +/* $Id: bus.h,v 1.2 1998/09/16 08:22:57 dfr Exp $ */ #ifndef _ALPHA_BUS_H_ #define _ALPHA_BUS_H_ @@ -1025,8 +1025,8 @@ bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, #define BUS_DMA_NOWAIT 0x01 /* not safe to sleep */ #define BUS_DMA_ALLOCNOW 0x02 /* perform resource allocation now */ #define BUS_DMAMEM_NOSYNC 0x04 /* map memory to not require sync */ -#define BUS_DMA_BUS1 0x10 /* placeholders for bus functions... */ -#define BUS_DMA_BUS2 0x20 +#define BUS_DMA_ISA 0x10 /* map memory for ISA dma */ +#define BUS_DMA_BUS2 0x20 /* placeholders for bus functions... */ #define BUS_DMA_BUS3 0x40 #define BUS_DMA_BUS4 0x80 diff --git a/sys/alpha/include/chipset.h b/sys/alpha/include/chipset.h index ec34810..e9dbe87 100644 --- a/sys/alpha/include/chipset.h +++ b/sys/alpha/include/chipset.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: chipset.h,v 1.7 1999/04/16 21:21:35 peter Exp $ + * $Id: chipset.h,v 1.8 1999/05/20 15:33:16 gallatin Exp $ */ #ifndef _MACHINE_CHIPSET_H_ @@ -57,6 +57,8 @@ typedef vm_offset_t alpha_chipset_addrcvt_t(vm_offset_t); typedef u_int64_t alpha_chipset_read_hae_t(void); typedef void alpha_chipset_write_hae_t(u_int64_t); +struct sgmap; + typedef struct alpha_chipset { /* * I/O port access @@ -100,6 +102,11 @@ typedef struct alpha_chipset { */ alpha_chipset_read_hae_t* read_hae; alpha_chipset_write_hae_t* write_hae; + + /* + * Scatter-Gather map for ISA dma. + */ + struct sgmap* sgmap; } alpha_chipset_t; extern alpha_chipset_t chipset; diff --git a/sys/alpha/include/ioctl_fd.h b/sys/alpha/include/ioctl_fd.h new file mode 100644 index 0000000..970d247 --- /dev/null +++ b/sys/alpha/include/ioctl_fd.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * $Id$ + * from: ioctl_fd.h,v 1.11 + */ + +#ifndef _MACHINE_IOCTL_FD_H_ +#define _MACHINE_IOCTL_FD_H_ + +#ifndef KERNEL +#include <sys/types.h> +#endif +#include <sys/ioccom.h> + +#define FD_FORMAT_VERSION 110 /* used to validate before formatting */ +#define FD_MAX_NSEC 36 /* highest known number of spt - allow for */ + /* 2.88 MB drives */ + +struct fd_formb { + int format_version; /* == FD_FORMAT_VERSION */ + int cyl, head; + int transfer_rate; /* fdreg.h: FDC_???KBPS */ + + union { + struct fd_form_data { + /* + * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS + * it is hardware-dependent since it exactly + * matches the byte sequence to write to FDC + * during its `format track' operation + */ + u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */ + u_char nsecs; /* must be <= FD_MAX_NSEC */ + u_char gaplen; /* GAP 3 length; usually 84 */ + u_char fillbyte; /* usually 0xf6 */ + struct fd_idfield_data { + /* + * data to write into id fields; + * for obscure formats, they mustn't match + * the real values (but mostly do) + */ + u_char cylno; /* 0 thru 79 (or 39) */ + u_char headno; /* 0, or 1 */ + u_char secno; /* starting at 1! */ + u_char secsize; /* usually 2 */ + } idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */ + } structured; + u_char raw[1]; /* to have continuous indexed access */ + } format_info; +}; + +/* make life easier */ +# define fd_formb_secshift format_info.structured.secshift +# define fd_formb_nsecs format_info.structured.nsecs +# define fd_formb_gaplen format_info.structured.gaplen +# define fd_formb_fillbyte format_info.structured.fillbyte +/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */ +# define fd_formb_cylno(i) format_info.structured.idfields[i].cylno +# define fd_formb_headno(i) format_info.structured.idfields[i].headno +# define fd_formb_secno(i) format_info.structured.idfields[i].secno +# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize + +struct fd_type { + int sectrac; /* sectors per track */ + int secsize; /* size code for sectors */ + int datalen; /* data len when secsize = 0 */ + int gap; /* gap len between sectors */ + int tracks; /* total num of tracks */ + int size; /* size of disk in sectors */ + int steptrac; /* steps per cylinder */ + int trans; /* transfer speed code */ + int heads; /* number of heads */ + int f_gap; /* format gap len */ + int f_inter; /* format interleave factor */ +}; + +#define FD_FORM _IOW('F', 61, struct fd_formb) /* format a track */ +#define FD_GTYPE _IOR('F', 62, struct fd_type) /* get drive type */ +#define FD_STYPE _IOW('F', 63, struct fd_type) /* set drive type */ + +#define FD_GOPTS _IOR('F', 64, int) /* drive options, see below */ +#define FD_SOPTS _IOW('F', 65, int) + +#define FD_DEBUG _IOW('F', 66, int) + +#define FDOPT_NORETRY 0x0001 /* no retries on failure (cleared on close) */ + +/* + * The following definitions duplicate those in sys/i386/isa/fdreg.h + * They are here since their values are to be used in the above + * structure when formatting a floppy. For very obvious reasons, both + * definitions must match ;-) + */ +#ifndef FDC_500KBPS +#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */ +#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */ +#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */ +#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */ + /* for some controllers 1MPBS instead */ +#endif /* FDC_500KBPS */ + +#endif /* !_MACHINE_IOCTL_FD_H_ */ diff --git a/sys/alpha/include/sgmap.h b/sys/alpha/include/sgmap.h new file mode 100644 index 0000000..65299c7 --- /dev/null +++ b/sys/alpha/include/sgmap.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 1998 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#ifndef _MACHINE_SGMAP_H_ +#define _MACHINE_SGMAP_H_ + +struct sgmap; + +typedef void sgmap_map_callback(void *arg, bus_addr_t ba, vm_offset_t pa); + +vm_offset_t sgmap_overflow_page(void); +struct sgmap *sgmap_map_create(bus_addr_t sba, bus_addr_t eba, + sgmap_map_callback *map, void *arg); +void sgmap_map_destroy(struct sgmap *sgmap); +bus_addr_t sgmap_alloc_region(struct sgmap *sgmap, + bus_size_t size, bus_size_t boundary, + void **mhp); +void sgmap_load_region(struct sgmap *sgmap, bus_addr_t sba, + vm_offset_t va, bus_size_t size); +void sgmap_unload_region(struct sgmap *sgmap, + bus_addr_t sba, bus_size_t size); +void sgmap_free_region(struct sgmap *sgmap, void *mh); + +#endif /* !_MACHINE_SGMAP_H_ */ diff --git a/sys/alpha/isa/isa.c b/sys/alpha/isa/isa.c index 3878e6a..920751f 100644 --- a/sys/alpha/isa/isa.c +++ b/sys/alpha/isa/isa.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: isa.c,v 1.15 1999/05/18 20:43:49 dfr Exp $ + * $Id: isa.c,v 1.16 1999/05/22 15:18:15 dfr Exp $ */ #include <sys/param.h> @@ -44,6 +44,7 @@ #include <machine/resource.h> static struct rman isa_irq_rman; +static struct rman isa_drq_rman; static void isa_intr_enable(int irq) @@ -112,6 +113,14 @@ isa_init_intr(void) || rman_manage_region(&isa_irq_rman, 3, 15)) panic("isa_probe isa_irq_rman"); + isa_drq_rman.rm_start = 0; + isa_drq_rman.rm_end = 7; + isa_drq_rman.rm_type = RMAN_ARRAY; + isa_drq_rman.rm_descr = "ISA DMA request lines"; + if (rman_init(&isa_drq_rman) + || rman_manage_region(&isa_drq_rman, 0, 7)) + panic("isa_probe isa_drq_rman"); + /* mask all isa interrupts */ outb(IO_ICU1+1, 0xff); outb(IO_ICU2+1, 0xff); @@ -150,8 +159,8 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, { /* * Consider adding a resource definition. We allow rid 0-1 for - * irq, drq and memory and rid 0-7 for ports which is sufficient for - * isapnp. + * irq and drq, 0-3 for memory and 0-7 for ports which is + * sufficient for isapnp. */ int passthrough = (device_get_parent(child) != bus); int isdefault = (start == 0UL && end == ~0UL); @@ -165,7 +174,11 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, if (!rle) { if (*rid < 0) return 0; - if (type != SYS_RES_IOPORT && *rid > 1) + if (type == SYS_RES_IRQ && *rid > 1) + return 0; + if (type == SYS_RES_DRQ && *rid > 1) + return 0; + if (type != SYS_RES_MEMORY && *rid > 3) return 0; if (type == SYS_RES_IOPORT && *rid > 7) return 0; @@ -173,13 +186,13 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, } } - if (type != SYS_RES_IRQ) + if (type != SYS_RES_IRQ && type != SYS_RES_DRQ) return resource_list_alloc(bus, child, type, rid, start, end, count, flags); if (!passthrough) { rl = device_get_ivars(child); - rle = resource_list_find(rl, SYS_RES_IRQ, *rid); + rle = resource_list_find(rl, type, *rid); if (!rle) return 0; if (rle->res) @@ -190,11 +203,16 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid, } } - res = isa_alloc_intr(bus, child, start); - + if (type == SYS_RES_IRQ) + res = rman_reserve_resource(&isa_irq_rman, start, start, 1, + 0, child); + else + res = rman_reserve_resource(&isa_drq_rman, start, start, 1, + 0, child); + if (res && !passthrough) { rl = device_get_ivars(child); - rle = resource_list_find(rl, SYS_RES_IRQ, *rid); + rle = resource_list_find(rl, type, *rid); rle->start = rman_get_start(res); rle->end = rman_get_end(res); rle->count = 1; diff --git a/sys/alpha/isa/isa_dma.c b/sys/alpha/isa/isa_dma.c new file mode 100644 index 0000000..2cb3e2c --- /dev/null +++ b/sys/alpha/isa/isa_dma.c @@ -0,0 +1,487 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 + * from: isa_dma.c,v 1.3 1999/05/09 23:56:00 peter Exp $ + * $Id$ + */ + +/* + * code to manage AT bus + * + * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): + * Fixed uninitialized variable problem and added code to deal + * with DMA page boundaries in isa_dmarangecheck(). Fixed word + * mode DMA count compution and reorganized DMA setup code in + * isa_dmastart() + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> /* B_READ and B_RAW */ +#include <sys/malloc.h> +#include <sys/bus.h> +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> +#include <isa/isareg.h> +#include <isa/isavar.h> +#include <i386/isa/ic/i8237.h> +#include <machine/bus.h> + +/* +** Register definitions for DMA controller 1 (channels 0..3): +*/ +#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ +#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ +#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ +#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ +#define DMA1_RESET (IO_DMA1 + 1*13) /* reset */ + +/* +** Register definitions for DMA controller 2 (channels 4..7): +*/ +#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */ +#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ +#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ +#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ +#define DMA2_RESET (IO_DMA2 + 2*13) /* reset */ + +static bus_dma_tag_t dma_tag[8]; +static bus_dmamap_t dma_map[8]; +static u_int8_t dma_busy = 0; /* Used in isa_dmastart() */ +static u_int8_t dma_inuse = 0; /* User for acquire/release */ +static u_int8_t dma_auto_mode = 0; + +#define VALID_DMA_MASK (7) + +/* high byte of address is stored in this port for i-th dma channel */ +static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; + +/* + * Setup a DMA channel's bounce buffer. + */ +void +isa_dmainit(chan, bouncebufsize) + int chan; + u_int bouncebufsize; +{ + static int initted = 0; + bus_addr_t boundary = chan >= 4 ? 0x20000 : 0x10000; + + if (!initted) { + /* + * Reset the DMA hardware. + */ + outb(DMA1_RESET, 0); + outb(DMA2_RESET, 0); + isa_dmacascade(4); + + initted = 1; + } + +#ifdef DIAGNOSTIC + if (chan & ~VALID_DMA_MASK) + panic("isa_dmainit: channel out of range"); + + if (dma_tag[chan] || dma_map[chan]) + panic("isa_dmainit: impossible request"); +#endif + + if (bus_dma_tag_create(/*parent*/NULL, + /*alignment*/2, + /*boundary*/boundary, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/bouncebufsize, + /*nsegments*/1, /*maxsegz*/0x3ffff, + /*flags*/BUS_DMA_ISA, + &dma_tag[chan]) != 0) { + panic("isa_dmainit: unable to create dma tag\n"); + } + + if (bus_dmamap_create(dma_tag[chan], 0, &dma_map[chan])) { + panic("isa_dmainit: unable to create dma map\n"); + } + +} + +/* + * Register a DMA channel's usage. Usually called from a device driver + * in open() or during its initialization. + */ +int +isa_dma_acquire(chan) + int chan; +{ +#ifdef DIAGNOSTIC + if (chan & ~VALID_DMA_MASK) + panic("isa_dma_acquire: channel out of range"); +#endif + + if (dma_inuse & (1 << chan)) { + printf("isa_dma_acquire: channel %d already in use\n", chan); + return (EBUSY); + } + dma_inuse |= (1 << chan); + dma_auto_mode &= ~(1 << chan); + + return (0); +} + +/* + * Unregister a DMA channel's usage. Usually called from a device driver + * during close() or during its shutdown. + */ +void +isa_dma_release(chan) + int chan; +{ +#ifdef DIAGNOSTIC + if (chan & ~VALID_DMA_MASK) + panic("isa_dma_release: channel out of range"); + + if ((dma_inuse & (1 << chan)) == 0) + printf("isa_dma_release: channel %d not in use\n", chan); +#endif + + if (dma_busy & (1 << chan)) { + dma_busy &= ~(1 << chan); + /* + * XXX We should also do "dma_bounced &= (1 << chan);" + * because we are acting on behalf of isa_dmadone() which + * was not called to end the last DMA operation. This does + * not matter now, but it may in the future. + */ + } + + dma_inuse &= ~(1 << chan); + dma_auto_mode &= ~(1 << chan); +} + +/* + * isa_dmacascade(): program 8237 DMA controller channel to accept + * external dma control by a board. + */ +void +isa_dmacascade(chan) + int chan; +{ +#ifdef DIAGNOSTIC + if (chan & ~VALID_DMA_MASK) + panic("isa_dmacascade: channel out of range"); +#endif + + /* set dma channel mode, and set dma channel mode */ + if ((chan & 4) == 0) { + outb(DMA1_MODE, DMA37MD_CASCADE | chan); + outb(DMA1_SMSK, chan); + } else { + outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); + outb(DMA2_SMSK, chan & 3); + } +} + +/* + * isa_dmastart(): program 8237 DMA controller channel. + */ + +struct isa_dmastart_arg { + int chan; + int flags; +}; + +static void isa_dmastart_cb(void *arg, bus_dma_segment_t *segs, int nseg, + int error) +{ + int chan = ((struct isa_dmastart_arg *) arg)->chan; + int flags = ((struct isa_dmastart_arg *) arg)->flags; + bus_addr_t phys = segs->ds_addr; + int nbytes = segs->ds_len; + int waport; + + if (nseg != 1) + panic("isa_dmastart: transfer mapping not contiguous"); + + if ((chan & 4) == 0) { + /* + * Program one of DMA channels 0..3. These are + * byte mode channels. + */ + /* set dma channel mode, and reset address ff */ + + /* If B_RAW flag is set, then use autoinitialise mode */ + if (flags & B_RAW) { + if (flags & B_READ) + outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); + else + outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); + } + else + if (flags & B_READ) + outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); + else + outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); + outb(DMA1_FFC, 0); + + /* send start address */ + waport = DMA1_CHN(chan); + outb(waport, phys); + outb(waport, phys>>8); + outb(dmapageport[chan], phys>>16); + + /* send count */ + outb(waport + 1, --nbytes); + outb(waport + 1, nbytes>>8); + + /* unmask channel */ + outb(DMA1_SMSK, chan); + } else { + /* + * Program one of DMA channels 4..7. These are + * word mode channels. + */ + /* set dma channel mode, and reset address ff */ + + /* If B_RAW flag is set, then use autoinitialise mode */ + if (flags & B_RAW) { + if (flags & B_READ) + outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3)); + else + outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3)); + } + else + if (flags & B_READ) + outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); + else + outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); + outb(DMA2_FFC, 0); + + /* send start address */ + waport = DMA2_CHN(chan - 4); + outb(waport, phys>>1); + outb(waport, phys>>9); + outb(dmapageport[chan], phys>>16); + + /* send count */ + nbytes >>= 1; + outb(waport + 2, --nbytes); + outb(waport + 2, nbytes>>8); + + /* unmask channel */ + outb(DMA2_SMSK, chan & 3); + } +} + +void +isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan) +{ + struct isa_dmastart_arg args; + +#ifdef DIAGNOSTIC + if (chan & ~VALID_DMA_MASK) + panic("isa_dmastart: channel out of range"); + + if ((chan < 4 && nbytes > (1<<16)) + || (chan >= 4 && (nbytes > (1<<17) || (uintptr_t)addr & 1))) + panic("isa_dmastart: impossible request"); + + if ((dma_inuse & (1 << chan)) == 0) + printf("isa_dmastart: channel %d not acquired\n", chan); +#endif + +#if 0 + /* + * XXX This should be checked, but drivers like ad1848 only call + * isa_dmastart() once because they use Auto DMA mode. If we + * leave this in, drivers that do this will print this continuously. + */ + if (dma_busy & (1 << chan)) + printf("isa_dmastart: channel %d busy\n", chan); +#endif + + if (!dma_tag || !dma_map[chan]) + panic("isa_dmastart: called without isa_dmainit"); + + dma_busy |= (1 << chan); + + if (flags & B_RAW) { + dma_auto_mode |= (1 << chan); + } else { + dma_auto_mode &= ~(1 << chan); + } + + /* + * Freeze dma while updating registers. + */ + outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4); + + args.chan = chan; + args.flags = flags; + bus_dmamap_load(dma_tag[chan], dma_map[chan], addr, nbytes, + isa_dmastart_cb, &args, 0); +} + +void +isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) +{ +#ifdef DIAGNOSTIC + if (chan & ~VALID_DMA_MASK) + panic("isa_dmadone: channel out of range"); + + if ((dma_inuse & (1 << chan)) == 0) + printf("isa_dmadone: channel %d not acquired\n", chan); +#endif + + if (((dma_busy & (1 << chan)) == 0) && + (dma_auto_mode & (1 << chan)) == 0 ) + printf("isa_dmadone: channel %d not busy\n", chan); + + if ((dma_auto_mode & (1 << chan)) == 0) { + outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4); + bus_dmamap_unload(dma_tag[chan], dma_map[chan]); + } + + dma_busy &= ~(1 << chan); +} + +/* + * Query the progress of a transfer on a DMA channel. + * + * To avoid having to interrupt a transfer in progress, we sample + * each of the high and low databytes twice, and apply the following + * logic to determine the correct count. + * + * Reads are performed with interrupts disabled, thus it is to be + * expected that the time between reads is very small. At most + * one rollover in the low count byte can be expected within the + * four reads that are performed. + * + * There are three gaps in which a rollover can occur : + * + * - read low1 + * gap1 + * - read high1 + * gap2 + * - read low2 + * gap3 + * - read high2 + * + * If a rollover occurs in gap1 or gap2, the low2 value will be + * greater than the low1 value. In this case, low2 and high2 are a + * corresponding pair. + * + * In any other case, low1 and high1 can be considered to be correct. + * + * The function returns the number of bytes remaining in the transfer, + * or -1 if the channel requested is not active. + * + */ +int +isa_dmastatus(int chan) +{ + u_long cnt = 0; + int ffport, waport; + u_long low1, high1, low2, high2; + int s; + + /* channel active? */ + if ((dma_inuse & (1 << chan)) == 0) { + printf("isa_dmastatus: channel %d not active\n", chan); + return(-1); + } + /* channel busy? */ + + if (((dma_busy & (1 << chan)) == 0) && + (dma_auto_mode & (1 << chan)) == 0 ) { + printf("chan %d not busy\n", chan); + return -2 ; + } + if (chan < 4) { /* low DMA controller */ + ffport = DMA1_FFC; + waport = DMA1_CHN(chan) + 1; + } else { /* high DMA controller */ + ffport = DMA2_FFC; + waport = DMA2_CHN(chan - 4) + 2; + } + + s = splhigh(); /* no interrupts Mr Jones! */ + outb(ffport, 0); /* clear register LSB flipflop */ + low1 = inb(waport); + high1 = inb(waport); + outb(ffport, 0); /* clear again */ + low2 = inb(waport); + high2 = inb(waport); + splx(s); /* enable interrupts again */ + + /* + * Now decide if a wrap has tried to skew our results. + * Note that after TC, the count will read 0xffff, while we want + * to return zero, so we add and then mask to compensate. + */ + if (low1 >= low2) { + cnt = (low1 + (high1 << 8) + 1) & 0xffff; + } else { + cnt = (low2 + (high2 << 8) + 1) & 0xffff; + } + + if (chan >= 4) /* high channels move words */ + cnt *= 2; + return(cnt); +} + +/* + * Stop a DMA transfer currently in progress. + */ +int +isa_dmastop(int chan) +{ + if ((dma_inuse & (1 << chan)) == 0) + printf("isa_dmastop: channel %d not acquired\n", chan); + + if (((dma_busy & (1 << chan)) == 0) && + ((dma_auto_mode & (1 << chan)) == 0)) { + printf("chan %d not busy\n", chan); + return -2 ; + } + + if ((chan & 4) == 0) { + outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */); + } else { + outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */); + } + return(isa_dmastatus(chan)); +} diff --git a/sys/alpha/pci/cia.c b/sys/alpha/pci/cia.c index aaa78b9..ce5fae0 100644 --- a/sys/alpha/pci/cia.c +++ b/sys/alpha/pci/cia.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cia.c,v 1.17 1999/05/08 21:58:41 dfr Exp $ + * $Id: cia.c,v 1.18 1999/05/20 15:33:21 gallatin Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -95,6 +95,7 @@ #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> +#include <sys/malloc.h> #include <sys/bus.h> #include <machine/bus.h> #include <sys/rman.h> @@ -109,6 +110,11 @@ #include <machine/cpuconf.h> #include <machine/rpb.h> #include <machine/resource.h> +#include <machine/sgmap.h> + +#include <vm/vm.h> +#include <vm/vm_prot.h> +#include <vm/vm_page.h> #define KV(pa) ALPHA_PHYS_TO_K0SEG(pa) @@ -673,6 +679,142 @@ static driver_t cia_driver = { sizeof(struct cia_softc), }; +#define CIA_SGMAP_BASE (8*1024*1024) +#define CIA_SGMAP_SIZE (8*1024*1024) +#define CIA_PYXIS_BUG_BASE (128*1024*1024) +#define CIA_PYXIS_BUG_SIZE (2*1024*1024) + +static void +cia_sgmap_invalidate(void) +{ + REGVAL(CIA_PCI_TBIA) = CIA_PCI_TBIA_ALL; + alpha_mb(); +} + +static void +cia_sgmap_invalidate_pyxis(void) +{ + volatile u_int64_t dummy; + u_int32_t ctrl; + int i, s; + + s = splhigh(); + + /* + * Put the Pyxis into PCI loopback mode. + */ + alpha_mb(); + ctrl = REGVAL(CIA_CSR_CTRL); + REGVAL(CIA_CSR_CTRL) = ctrl | CTRL_PCI_LOOP_EN; + alpha_mb(); + + /* + * Now, read from PCI dense memory space at offset 128M (our + * target window base), skipping 64k on each read. This forces + * S/G TLB misses. + * + * XXX Looks like the TLB entries are `not quite LRU'. We need + * XXX to read more times than there are actual tags! + */ + for (i = 0; i < CIA_TLB_NTAGS + 4; i++) { + dummy = *((volatile u_int64_t *) + ALPHA_PHYS_TO_K0SEG(CIA_PCI_DENSE + CIA_PYXIS_BUG_BASE + + (i * 65536))); + } + + /* + * Restore normal PCI operation. + */ + alpha_mb(); + REGVAL(CIA_CSR_CTRL) = ctrl; + alpha_mb(); + + splx(s); +} + +static void +cia_sgmap_map(void *arg, vm_offset_t ba, vm_offset_t pa) +{ + u_int64_t *sgtable = arg; + int index = alpha_btop(ba - CIA_SGMAP_BASE); + + if (pa) { + if (pa > (1L<<32)) + panic("cia_sgmap_map: can't map address 0x%lx", pa); + sgtable[index] = ((pa >> 13) << 1) | 1; + } else { + sgtable[index] = 0; + } + alpha_mb(); + + if (cia_ispyxis) + cia_sgmap_invalidate_pyxis(); + else + cia_sgmap_invalidate(); +} + +static void +cia_init_sgmap(void) +{ + void *sgtable; + + /* + * First setup Window 0 to map 8Mb to 16Mb with an + * sgmap. Allocate the map aligned to a 32 boundary. + */ + REGVAL(CIA_PCI_W0BASE) = (CIA_SGMAP_BASE + | CIA_PCI_WnBASE_SG_EN + | CIA_PCI_WnBASE_W_EN); + alpha_mb(); + + REGVAL(CIA_PCI_W0MASK) = CIA_PCI_WnMASK_8M; + alpha_mb(); + + sgtable = contigmalloc(8192, M_DEVBUF, M_NOWAIT, + 0, (1L<<34), + 32*1024, (1L<<34)); + if (!sgtable) + panic("cia_init_sgmap: can't allocate page table"); + REGVAL(CIA_PCI_T0BASE) = + (pmap_kextract((vm_offset_t) sgtable) >> CIA_PCI_TnBASE_SHIFT); + + chipset.sgmap = sgmap_map_create(CIA_SGMAP_BASE, + CIA_SGMAP_BASE + CIA_SGMAP_SIZE, + cia_sgmap_map, sgtable); + + if (cia_ispyxis) { + /* + * Pyxis has broken TLB invalidate. We use the NetBSD + * workaround of using another region to spill entries + * out of the TLB. The 'bug' region is 2Mb mapped at + * 128Mb. + */ + int i; + vm_offset_t pa; + u_int64_t *bugtable; + + REGVAL(CIA_PCI_W2BASE) = CIA_PYXIS_BUG_BASE | + CIA_PCI_WnBASE_SG_EN | CIA_PCI_WnBASE_W_EN; + alpha_mb(); + + REGVAL(CIA_PCI_W2MASK) = CIA_PCI_WnMASK_2M; + alpha_mb(); + + bugtable = contigmalloc(8192, M_DEVBUF, M_NOWAIT, + 0, (1L<<34), + 2*1024, (1L<<34)); + if (!bugtable) + panic("cia_init_sgmap: can't allocate page table"); + REGVAL(CIA_PCI_T2BASE) = + (pmap_kextract((vm_offset_t) bugtable) + >> CIA_PCI_TnBASE_SHIFT); + + pa = sgmap_overflow_page(); + for (i = 0; i < alpha_btop(CIA_PYXIS_BUG_SIZE); i++) + bugtable[i] = ((pa >> 13) << 1) | 1; + } +} + void cia_init() { @@ -730,6 +872,7 @@ cia_probe(device_t dev) pci_init_resources(); isa_init_intr(); + cia_init_sgmap(); device_add_child(dev, "pcib", 0, 0); diff --git a/sys/conf/files.alpha b/sys/conf/files.alpha index b589354..6b3f3e8 100644 --- a/sys/conf/files.alpha +++ b/sys/conf/files.alpha @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.alpha,v 1.18 1999/04/16 21:21:34 peter Exp $ +# $Id: files.alpha,v 1.19 1999/05/26 23:22:13 gallatin Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -35,6 +35,7 @@ alpha/alpha/mountroot.c optional slice alpha/alpha/ipl_funcs.c standard alpha/alpha/pal.s standard alpha/alpha/busdma_machdep.c standard +alpha/alpha/sgmap.c standard alpha/alpha/cons.c standard alpha/alpha/prom.c standard alpha/alpha/promcons.c standard @@ -124,6 +125,7 @@ alpha/pci/tsunami.c optional tsunami alpha/pci/tsunami_pci.c optional tsunami alpha/pci/pcibus.c optional pci alpha/isa/isa.c optional isa +alpha/isa/isa_dma.c optional isa alpha/isa/mcclock_isa.c optional isa alpha/alpha/elf_machdep.c standard libkern/bcd.c standard @@ -163,6 +165,7 @@ dev/syscons/syscons.c optional sc device-driver dev/syscons/scvidctl.c optional sc device-driver isa/syscons_isa.c optional sc device-driver isa/psm.c optional psm device-driver +isa/fd.c optional fd device-driver dev/ata/ata-all.c optional ata device-driver dev/ata/ata-dma.c optional ata device-driver dev/ata/atapi-all.c optional ata device-driver |