ISA and PCI support for DEC AlphaStations

This commit is contained in:
cgd 1995-06-28 01:24:50 +00:00
parent 5cc82e159a
commit 549f126f4b
14 changed files with 2670 additions and 0 deletions

View File

@ -0,0 +1,47 @@
/* $NetBSD: isa_dma.h,v 1.1 1995/06/28 01:24:50 cgd Exp $ */
/*
* Copyright (c) 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
struct isadma_fcns {
int (*isadma_map) __P((caddr_t addr, vm_size_t size,
vm_offset_t *mappings, int flags));
void (*isadma_unmap) __P((caddr_t addr, vm_size_t size,
int nmappings, vm_offset_t *mappings));
void (*isadma_copytobuf) __P((caddr_t addr, vm_size_t size,
int nmappings, vm_offset_t *mappings));
void (*isadma_copyfrombuf) __P((caddr_t addr, vm_size_t size,
int nmappings, vm_offset_t *mappings));
};
/*
* Global which tells which set of functions are correct
* for this machine.
*/
struct isadma_fcns *isadma_fcns;
struct isadma_fcns apecs_isadma_fcns; /* APECS DMA mapping */

View File

@ -0,0 +1,54 @@
/* $NetBSD: isa_intr.h,v 1.1 1995/06/28 01:24:57 cgd Exp $ */
/*
* Copyright (c) 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/* Prototypes for ISA-ish I/O interrupt functions. */
/*
* XXX
* XXX THIS WILL LIKELY HAVE TO BE COMPLETELY CHANGED.
* XXX
*/
struct isa_intr_fcns {
void (*isa_intr_setup) __P((void));
void *(*isa_intr_establish) __P((int irq, isa_intrtype type,
isa_intrlevel level, int (*ih_fun)(void *), void *ih_arg));
void (*isa_intr_disestablish) __P((void *handler));
void (*isa_iointr) __P((void *framep, int vec));
};
/*
* Global which tells which set of functions are correct
* for this machine.
*/
struct isa_intr_fcns *isa_intr_fcns;
struct isa_intr_fcns sio_intr_fcns; /* SIO ISA ICU handling */

View File

@ -0,0 +1,169 @@
/* $NetBSD: isa_machdep.c,v 1.1 1995/06/28 01:24:59 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <machine/autoconf.h>
#include <machine/pio.h>
#include <machine/rpb.h>
#include <machine/vmparam.h>
#include <machine/pte.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
#include <alpha/isa/isa_intr.h>
#include <alpha/isa/isa_dma.h>
int isamatch __P((struct device *, void *, void *));
void isaattach __P((struct device *, struct device *, void *));
struct cfdriver isacd = {
NULL, "isa", isamatch, isaattach, DV_DULL, sizeof(struct isa_softc), 1
};
int
isamatch(parent, cfdata, aux)
struct device *parent;
void *cfdata, *aux;
{
struct cfdata *cf = cfdata;
struct confargs *ca = aux;
#if 0 /* XXX -- Assume that it's valid if unit number OK */
/* It can only occur on the mainbus. */
if (ca->ca_bus->ab_type != BUS_MAIN)
return (0);
/* Make sure that we're looking for this type of device. */
if (!BUS_MATCHNAME(ca, "isa"))
return (0);
#endif /* XXX */
/* See if the unit number is valid. */
switch (hwrpb->rpb_type) {
#if defined(DEC_2100_A50)
case ST_DEC_2100_A50:
if (cf->cf_unit > 0)
return (0);
break;
#endif
default:
return (0);
}
return (1);
}
void
isaattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct isa_softc *sc = (struct isa_softc *)self;
printf("\n");
TAILQ_INIT(&sc->sc_subdevs);
/* XXX set up ISA DMA controllers? */
config_scan(isascan, self);
}
void *
isa_intr_establish(irq, type, level, ih_fun, ih_arg)
int irq;
isa_intrtype type;
isa_intrlevel level;
int (*ih_fun)(void *);
void *ih_arg;
{
return (*isa_intr_fcns->isa_intr_establish)(irq, type, level,
ih_fun, ih_arg);
}
void
isa_intr_disestablish(handler)
void *handler;
{
(*isa_intr_fcns->isa_intr_disestablish)(handler);
}
int
isadma_map(addr, size, mappings, flags)
caddr_t addr;
vm_size_t size;
vm_offset_t *mappings;
int flags;
{
(*isadma_fcns->isadma_map)(addr, size, mappings, flags);
}
void
isadma_unmap(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
(*isadma_fcns->isadma_unmap)(addr, size, nmappings, mappings);
}
void
isadma_copytobuf(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
(*isadma_fcns->isadma_copytobuf)(addr, size, nmappings, mappings);
}
void
isadma_copyfrombuf(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
(*isadma_fcns->isadma_copyfrombuf)(addr, size, nmappings, mappings);
}

View File

@ -0,0 +1,135 @@
#include <sys/types.h>
#include <machine/pio.h>
#include <machine/pte.h>
static u_int8_t jensen_inb __P((int port));
/* static void jensen_insb __P((int port, void *addr, int cnt)); */
static u_int16_t jensen_inw __P((int port));
/* static void jensen_insw __P((int port, void *addr, int cnt)); */
u_int32_t jensen_inl __P((int port));
/* static void jensen_insl __P((int port, void *addr, int cnt)); */
static void jensen_outb __P((int port, u_int8_t datum));
/* static void jensen_outsb __P((int port, void *addr, int cnt)); */
static void jensen_outw __P((int port, u_int16_t datum));
/* static void jensen_outsw __P((int port, void *addr, int cnt)); */
static void jensen_outl __P((int port, u_int32_t datum));
/* static void jensen_outsl __P((int port, void *addr, int cnt)); */
struct alpha_isafcndesc jensen_isafcns = {
jensen_inb, 0 /* jensen_insb */,
jensen_inw, 0 /* jensen_insw */,
jensen_inl, 0 /* jensen_insl */,
jensen_outb, 0 /* jensen_outsb */,
jensen_outw, 0 /* jensen_outsw */,
jensen_outl, 0 /* jensen_outsl */,
};
u_int8_t
jensen_inb(ioaddr)
int ioaddr;
{
u_int32_t *port, val;
u_int8_t rval;
int offset;
offset = ioaddr & 3;
port = (int32_t *)phystok0seg(0x300000000L | 0 << 5 | ioaddr << 7);
val = *port;
rval = ((val) >> (8 * offset)) & 0xff;
rval = val & 0xff;
printf("inb(0x%x) => 0x%x @ %p => 0x%x\n", ioaddr, val, port, rval);
return rval;
}
u_int16_t
jensen_inw(ioaddr)
int ioaddr;
{
u_int32_t *port, val;
u_int16_t rval;
int offset;
offset = ioaddr & 3;
port = (int32_t *)phystok0seg(0x300000000L | 1 << 5 | ioaddr << 7);
val = *port;
rval = ((val) >> (8 * offset)) & 0xffff;
rval = val & 0xffff;
panic("inw(0x%x) => 0x%x @ %p => 0x%x\n", ioaddr, val, port, rval);
return rval;
}
u_int32_t
jensen_inl(ioaddr)
int ioaddr;
{
u_int32_t *port, val;
u_int32_t rval;
int offset;
offset = ioaddr & 3;
port = (int32_t *)phystok0seg(0x300000000L | 3 << 5 | ioaddr << 7);
val = *port;
rval = ((val) >> (8 * offset)) & 0xffffffff;
rval = val & 0xffffffff;
printf("inl(0x%x) => 0x%x @ %p => 0x%x\n", ioaddr, val, port, rval);
return rval;
}
void
jensen_outb(ioaddr, val)
int ioaddr;
u_int8_t val;
{
u_int32_t *port, nval;
int offset;
offset = ioaddr & 3;
nval = val /*<< (8 * offset)*/;
port = (int32_t *)phystok0seg(0x300000000L | 0 << 5 | ioaddr << 7);
printf("outb(0x%x, 0x%x) => 0x%x @ %p\n", ioaddr, val, nval, port);
*port = nval;
}
void
jensen_outw(ioaddr, val)
int ioaddr;
u_int16_t val;
{
u_int32_t *port, nval;
int offset;
offset = ioaddr & 3;
nval = val /*<< (8 * offset)*/;
port = (int32_t *)phystok0seg(0x300000000L | 1 << 5 | ioaddr << 7);
printf("outb(0x%x, 0x%x) => 0x%x @ %p\n", ioaddr, val, nval, port);
*port = nval;
}
void
jensen_outl(ioaddr, val)
int ioaddr;
u_int32_t val;
{
u_int32_t *port, nval;
int offset;
offset = ioaddr & 3;
nval = val /*<< (8 * offset)*/;
port = (int32_t *)phystok0seg(0x300000000L | 3 << 5 | ioaddr << 7);
printf("outb(0x%x, 0x%x) => 0x%x @ %p\n", ioaddr, val, nval, port);
*port = nval;
}

258
sys/arch/alpha/pci/apecs.c Normal file
View File

@ -0,0 +1,258 @@
/* $NetBSD: apecs.c,v 1.1 1995/06/28 01:25:18 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <vm/vm.h>
#include <machine/autoconf.h>
#include <machine/pio.h>
#include <machine/rpb.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <alpha/isa/isa_dma.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/pci_chipset.h>
#include <alpha/pci/apecsreg.h>
int apecsmatch __P((struct device *, void *, void *));
void apecsattach __P((struct device *, struct device *, void *));
struct cfdriver apecscd = {
NULL, "apecs", apecsmatch, apecsattach, DV_DULL, sizeof(struct device)
};
static int apecsprint __P((void *, char *pnp));
#ifdef DEC_2100_A50
extern void pci_2100_a50_pickintr __P((void));
#endif
#define REGVAL(r) (*(int32_t *)phystok0seg(r))
static int nsgmapent = 1024;
static vm_offset_t sgmap_pci_base = 0x800000;
/*static */struct sgmapent *sgmap;
static char /* * */ sgbitmap[1024 / NBBY];
int
apecsmatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct cfdata *cf = match;
struct confargs *pa = aux;
/* XXX */
return (1);
}
void
apecsattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct confargs *ca = aux;
struct confargs nca;
int pass2_comanche, widemem, pass2_epic;
pass2_comanche = (REGVAL(COMANCHE_ED) & COMANCHE_ED_PASS2) != 0;
widemem = (REGVAL(COMANCHE_GCR) & COMANCHE_GCR_WIDEMEM) != 0;
pass2_epic = (REGVAL(EPIC_DCSR) & EPIC_DCSR_PASS2) != 0;
sgmap = (struct sgmapent *)malloc(1024 * sizeof(struct sgmapent),
M_DEVBUF, M_WAITOK);
printf(": DECchip %s Core Logic chipset\n",
widemem ? "21072" : "21071");
printf("%s: DC21071-CA pass %d, %d-bit memory bus\n",
self->dv_xname, pass2_comanche ? 2 : 1, widemem ? 128 : 64);
printf("%s: DC21071-DA pass %d\n", self->dv_xname, pass2_epic ? 2 : 1);
/* XXX print bcache size */
if (!pass2_epic)
printf("WARNING: 21071-DA NOT PASS2... NO BETS...\n");
/* set up the chipset's functions */
isadma_fcns = &apecs_isadma_fcns;
isa_pio_fcns = &apecs_pio_fcns;
if (!pass2_epic)
pci_cs_fcns = &apecs_p1e_cs_fcns;
else
pci_cs_fcns = &apecs_p2e_cs_fcns;
switch (hwrpb->rpb_type) {
#if defined(DEC_2100_A50)
case ST_DEC_2100_A50:
pci_2100_a50_pickintr();
break;
#endif
default:
panic("apecsattach: shouldn't be here, really...");
}
/* attach the PCI bus that hangs off of it... */
nca.ca_name = "pci";
nca.ca_slot = 0;
nca.ca_offset = 0;
nca.ca_bus = NULL;
if (!config_found(self, &nca, apecsprint))
panic("apecsattach: couldn't attach PCI bus");
}
static int
apecsprint(aux, pnp)
void *aux;
char *pnp;
{
register struct confargs *ca = aux;
if (pnp)
printf("%s at %s", ca->ca_name, pnp);
return (UNCONF);
}
vm_offset_t /* XXX? */
apecs_sgmap_alloc(va, npg, nocross, waitok)
caddr_t va;
int npg;
vm_size_t nocross;
int waitok;
{
int s;
int base, i, stride;
#ifdef DIAGNOSTIC
/* Quick sanity checks. */
if ((vm_offset_t)va & PGOFSET)
panic("apecs_sgmap_alloc: va not page aligned");
if ((nocross & (nocross - 1)) != 0 || nocross == 0)
panic("apecs_sgmap_alloc: bogus alignment 0x%lx", nocross);
if (npg <= 0)
panic("apecs_sgmap_alloc: not allocating anything");
if (npg > nsgmapent)
panic("apecs_sgmap_alloc: insane allocation");
if (ptoa(npg) > nocross)
panic("apecs_sgmap_alloc: must cross boundary");
#endif
stride = atop(nocross);
#ifdef DIAGNOSTIC
if (stride > nsgmapent)
panic("apecs_sgmap_alloc: cheesy implementation loses");
#endif
top:
s = splhigh();
for (base = 0; base < nsgmapent; base += stride) {
for (i = base; i < base + npg; i++)
if (isset(sgbitmap, i))
goto nextstride;
break;
nextstride:
}
if (base < nsgmapent) /* found a free chunk, claim it */
for (i = base; i < base + npg; i++)
setbit(sgbitmap, i);
splx(s);
if (base >= nsgmapent) { /* didn't find a free chunk */
if (!waitok)
return 0;
tsleep(&sgmap, PRIBIO+1, "sgmap", 0);
goto top;
}
for (i = base; i < base + npg; i++) {
#ifdef DIAGNOSTIC
if ((sgmap[i].val & SGMAPENT_EVAL) != 0)
panic("apecs_sgmap_alloc: unallocated entry valid");
#endif
sgmap[i].val = SGMAP_MAKEENTRY(atop(vtophys(va)));
va += PAGE_SIZE;
}
/* Invalidate old cached entries. */
REGVAL(EPIC_TBIA) = 1;
/* Return the PCI address. */
return (ptoa(base) + sgmap_pci_base);
}
void
apecs_sgmap_dealloc(pa, npg)
vm_offset_t pa;
int npg;
{
int i, pfn;
#ifdef DIAGNOSTIC
/* Quick sanity checks. */
if (pa & PGOFSET)
panic("apecs_sgmap_dealloc: pa not page aligned");
if (npg <= 0)
panic("apecs_sgmap_dealloc: not deallocating anything");
if (npg > nsgmapent)
panic("apecs_sgmap_dealloc: insane deallocation");
#endif
pfn = atop(pa - sgmap_pci_base);
#ifdef DIAGNOSTIC
/* Bounds check the deallocation range. Paranoid about wraparound. */
if (pfn < 0 || pfn >= nsgmapent || (pfn + npg) >= nsgmapent)
panic("apecs_sgmap_dealloc: pa out of range (%s)",
pfn < 0 ? "too low" : "too high");
#endif
for (i = 0; i < npg; i++) {
#ifdef DIAGNOSTIC
/* Make sure it's actually allocated. */
if (isclr(sgbitmap, i + pfn))
panic("apecs_sgmap_dealloc: multiple frees: entry %d",
i + pfn);
#endif
/* Clear the entries and the allocation map bits. */
clrbit(sgbitmap, i + pfn);
sgmap[i + pfn].val &= ~SGMAPENT_EVAL;
}
/* Invalidate old cached entries. */
REGVAL(EPIC_TBIA) = 1;
/* Wake up anybody waiting for map entries. */
wakeup(&sgmap);
}

View File

@ -0,0 +1,343 @@
/* $NetBSD: apecs_isa.c,v 1.1 1995/06/28 01:25:24 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <vm/vm.h>
#include <machine/pio.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isadmavar.h>
#include <alpha/isa/isa_dma.h>
#include <alpha/pci/apecsreg.h>
static u_int8_t apecs_inb __P((int port));
/* static void apecs_insb __P((int port, void *addr, int cnt)); */
#define apecs_insb 0 /* XXX */
static u_int16_t apecs_inw __P((int port));
/* static void apecs_insw __P((int port, void *addr, int cnt)); */
#define apecs_insw 0 /* XXX */
u_int32_t apecs_inl __P((int port));
/* static void apecs_insl __P((int port, void *addr, int cnt)); */
#define apecs_insl 0 /* XXX */
static void apecs_outb __P((int port, u_int8_t datum));
/* static void apecs_outsb __P((int port, void *addr, int cnt)); */
#define apecs_outsb 0 /* XXX */
static void apecs_outw __P((int port, u_int16_t datum));
/* static void apecs_outsw __P((int port, void *addr, int cnt)); */
#define apecs_outsw 0 /* XXX */
static void apecs_outl __P((int port, u_int32_t datum));
/* static void apecs_outsl __P((int port, void *addr, int cnt)); */
#define apecs_outsl 0 /* XXX */
struct isa_pio_fcns apecs_pio_fcns = {
apecs_inb, apecs_insb,
apecs_inw, apecs_insw,
apecs_inl, apecs_insl,
apecs_outb, apecs_outsb,
apecs_outw, apecs_outsw,
apecs_outl, apecs_outsl,
};
static int apecs_isadma_map __P((caddr_t addr, vm_size_t size,
vm_offset_t *mappings, int flags));
static void apecs_isadma_unmap __P((caddr_t addr, vm_size_t size,
int nmappings, vm_offset_t *mappings));
static void apecs_isadma_copytobuf __P((caddr_t addr, vm_size_t size,
int nmappings, vm_offset_t *mappings));
static void apecs_isadma_copyfrombuf __P((caddr_t addr, vm_size_t size,
int nmappings, vm_offset_t *mappings));
struct isadma_fcns apecs_isadma_fcns = {
apecs_isadma_map, apecs_isadma_unmap,
apecs_isadma_copytobuf, apecs_isadma_copyfrombuf,
};
u_int8_t
apecs_inb(ioaddr)
int ioaddr;
{
u_int32_t *port, val;
u_int8_t rval;
int offset;
MB();
offset = ioaddr & 3;
port = (int32_t *)phystok0seg(APECS_PCI_SIO | 0 << 3 | ioaddr << 5);
val = *port;
rval = ((val) >> (8 * offset)) & 0xff;
/* rval = val & 0xff; */
return rval;
}
u_int16_t
apecs_inw(ioaddr)
int ioaddr;
{
u_int32_t *port, val;
u_int16_t rval;
int offset;
MB();
offset = ioaddr & 3;
port = (int32_t *)phystok0seg(APECS_PCI_SIO | 1 << 3 | ioaddr << 5);
val = *port;
rval = ((val) >> (8 * offset)) & 0xffff;
rval = val & 0xffff;
panic("inw(0x%x) => 0x%x @ %p => 0x%x\n", ioaddr, val, port, rval);
return rval;
}
u_int32_t
apecs_inl(ioaddr)
int ioaddr;
{
u_int32_t *port, val;
u_int32_t rval;
int offset;
MB();
offset = ioaddr & 3;
port = (int32_t *)phystok0seg(APECS_PCI_SIO | 3 << 3 | ioaddr << 5);
val = *port;
rval = ((val) >> (8 * offset)) & 0xffffffff;
rval = val & 0xffffffff;
return rval;
}
void
apecs_outb(ioaddr, val)
int ioaddr;
u_int8_t val;
{
u_int32_t *port, nval;
int offset;
offset = ioaddr & 3;
nval = val /*<< (8 * offset)*/;
nval = val << (8 * offset);
port = (int32_t *)phystok0seg(APECS_PCI_SIO | 0 << 3 | ioaddr << 5);
*port = nval;
MB();
}
void
apecs_outw(ioaddr, val)
int ioaddr;
u_int16_t val;
{
u_int32_t *port, nval;
int offset;
offset = ioaddr & 3;
nval = val /*<< (8 * offset)*/;
port = (int32_t *)phystok0seg(APECS_PCI_SIO | 1 << 3 | ioaddr << 5);
*port = nval;
MB();
}
void
apecs_outl(ioaddr, val)
int ioaddr;
u_int32_t val;
{
u_int32_t *port, nval;
int offset;
offset = ioaddr & 3;
nval = val /*<< (8 * offset)*/;
port = (int32_t *)phystok0seg(APECS_PCI_SIO | 3 << 3 | ioaddr << 5);
*port = nval;
MB();
}
static caddr_t bounced_addr;
static caddr_t bounce_buffer;
static vm_size_t bounce_size;
int
apecs_isadma_map(addr, size, mappings, flags)
caddr_t addr;
vm_size_t size;
vm_offset_t *mappings;
int flags;
{
vm_offset_t off, truncaddr;
vm_offset_t isa_truncpa; /* XXX? */
vm_size_t alignment;
int i, npages, waitok;
/*
* ISADMA_MAP_{,NO}BOUNCE and ISADMA_MAP_{CONTIG,SCATTER} are
* completely ignored, because all allocations will be in the
* low 16M and will be contiguous. I LOVE VIRTUAL DMA!
*/
truncaddr = trunc_page(addr);
off = (vm_offset_t)addr - truncaddr;
npages = num_pages(size + off);
if (npages == 0)
panic("apecs_isadma_map: map nothing");
alignment = 64 * 1024;
if ((flags & ISADMA_MAP_16BIT) != 0)
alignment <<= 1;
waitok = (flags & ISADMA_MAP_WAITOK) != 0;
if (npages > atop(alignment)) {
int s;
void *tmpbb;
/*
* Allocate a bounce buffer.
*/
s = splhigh();
retry:
while (bounce_buffer != NULL) {
/*
* If a bounce buffer is in use and we can't
* wait, bug out now, otherwise sleep.
*/
if (!waitok) {
splx(s);
return 0;
}
tsleep(&bounce_buffer, PRIBIO+1, "apecsbb", 0);
}
/*
* Try to allocate a bounce buffer.
*/
tmpbb = malloc(alignment, M_DEVBUF,
waitok ? M_WAITOK : M_NOWAIT);
if (tmpbb == NULL) { /* couldn't wait, and failed */
splx(s);
return 0;
}
/*
* If we slept in malloc() and somebody else got it,
* give it up and try it again!
*/
if (bounce_buffer != NULL) {
free(tmpbb, M_DEVBUF);
goto retry;
}
/*
* It's ours, all ours!
*/
bounce_buffer = tmpbb;
splx(s);
bounced_addr = addr;
bounce_size = size;
truncaddr = (vm_offset_t)bounce_buffer;
npages = atop(alignment);
}
isa_truncpa = apecs_sgmap_alloc(truncaddr, npages, alignment, waitok);
mappings[0] = isa_truncpa + off;
for (i = 1; i < npages; i++)
mappings[i] = isa_truncpa + ptoa(i);
return (npages);
}
void
apecs_isadma_unmap(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
int npages;
npages = nmappings;
if (npages == 0)
panic("apecs_isadma_unmap: unmap nothing");
apecs_sgmap_dealloc(trunc_page(mappings[0]), npages);
if (addr == bounced_addr) {
/*
* Free the bounce buffer and wake up anybody who
* wants to bounce.
*/
bounced_addr = NULL;
bounce_size = 0;
free(bounce_buffer, M_DEVBUF);
bounce_buffer = NULL;
wakeup(&bounce_buffer);
}
}
void
apecs_isadma_copytobuf(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
if (addr != bounced_addr)
return;
log(LOG_NOTICE, "apecs_isa_copytobuf: copied %d byte buffer\n",
bounce_size);
bcopy(addr, bounce_buffer, bounce_size);
}
void
apecs_isadma_copyfrombuf(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
if (addr != bounced_addr)
return;
log(LOG_NOTICE, "apecs_isa_copyfrombuf: copied %d byte buffer\n",
bounce_size);
bcopy(bounce_buffer, addr, bounce_size);
}

View File

@ -0,0 +1,339 @@
/* $NetBSD: apecs_pci.c,v 1.1 1995/06/28 01:25:30 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <vm/vm.h>
#include <machine/autoconf.h>
#include <machine/pio.h>
#include <dev/isa/isavar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/pci_chipset.h>
#include <alpha/pci/apecsreg.h>
void apecs_setup __P((void));
pcitag_t apecs_make_tag __P((int, int, int));
pcireg_t apecs_conf_read __P((pcitag_t, int));
void apecs_conf_write __P((pcitag_t, int, pcireg_t));
int apecs_map_mem __P((pcitag_t, int, vm_offset_t *, vm_offset_t *));
int apecs_pcidma_map __P((caddr_t, vm_size_t, vm_offset_t *));
void apecs_pcidma_unmap __P((caddr_t, vm_size_t, int, vm_offset_t *));
struct pci_cs_fcns apecs_p1e_cs_fcns = { /* XXX WHAT'S DIFFERENT? */
apecs_setup,
apecs_make_tag,
apecs_conf_read,
apecs_conf_write,
apecs_map_mem,
apecs_pcidma_map,
apecs_pcidma_unmap,
};
struct pci_cs_fcns apecs_p2e_cs_fcns = { /* XXX WHAT'S DIFFERENT? */
apecs_setup,
apecs_make_tag,
apecs_conf_read,
apecs_conf_write,
apecs_map_mem,
apecs_pcidma_map,
apecs_pcidma_unmap,
};
#define REGVAL(r) (*(u_int32_t *)phystok0seg(r))
void
apecs_setup()
{
/*
* Set up PCI bus mastering DMA windows on the APECS chip.
*
* What the PROM wants:
* a 1G direct-mapped window that maps the PCI address
* space from 4G -> 5G to memory addresses 0 -> 1G,
* set up in window two.
*
* What we want:
* a 1G direct-mapped window that maps the PCI address
* space from 0 -> 1G to memory addresses 0 -> 1G.
*
* Unless we satisfy the PROM, we can't live through a reboot.
* If we don't do what we want, I have to write more code.
* So:
* Leave window two alone, map window 1 the way I want it.
*
* XXX verify that windows don't overlap
* XXX be trickier
* XXX magic numbers
*/
#if 0 /* should be routine to dump regs */
printf("old base1 was 0x%x\n", REGVAL(EPIC_PCI_BASE_1));
printf("old mask1 was 0x%x\n", REGVAL(EPIC_PCI_MASK_1));
printf("old tbase1 was 0x%x\n", REGVAL(EPIC_TBASE_1));
printf("old base2 was 0x%x\n", REGVAL(EPIC_PCI_BASE_2));
printf("old mask2 was 0x%x\n", REGVAL(EPIC_PCI_MASK_2));
printf("old tbase2 was 0x%x\n", REGVAL(EPIC_TBASE_2));
#endif
#if 0 /* XXX STUPID PROM; MUST LEAVE WINDOW 2 ALONE. See above */
/* Turn off DMA window enables in PCI Base Reg 2. */
REGVAL(EPIC_PCI_BASE_2) = 0;
/* Set up Translated Base Register 2; translate to sybBus addr 0. */
REGVAL(EPIC_TBASE_2) = 0;
/* Set up PCI mask register 2; map 1G space. */
REGVAL(EPIC_PCI_MASK_2) = 0x3ff00000;
/* Enable window 2; from PCI address 4G, direct mapped. */
REGVAL(EPIC_PCI_BASE_2) = 0x40080000;
#endif /* STUPID PROM */
/* Turn off DMA window enables in PCI Base Reg 1. */
REGVAL(EPIC_PCI_BASE_1) = 0;
/* Set up Translated Base Register 1; translate to sybBus addr 0. */
{ /* XXX */
extern struct sgmapent *sgmap;
REGVAL(EPIC_TBASE_1) = vtophys(sgmap) >> 1;
} /* XXX */
/* Set up PCI mask register 1; map 8MB space. */
REGVAL(EPIC_PCI_MASK_1) = 0x00700000;
/* Enable window 1; from PCI address 8MB, direct mapped. */
REGVAL(EPIC_PCI_BASE_1) = 0x008c0000;
/*
* Should set up HAXR1 and HAXR2... However, the PROM again
* wants them where they're set to be...
*/
#if 0
printf("old haxr0 was 0x%x\n", REGVAL(EPIC_HAXR0));
printf("old haxr1 was 0x%x\n", REGVAL(EPIC_HAXR1));
printf("old haxr2 was 0x%x\n", REGVAL(EPIC_HAXR2));
#endif
#if 0 /* XXX STUPID PROM */
/* HAXR0 is wired zero; no op. */
REGVAL(EPIC_HAXR0) = 0;
/* HAXR1: maps PCI memory space above 16M. 16M -> 2G+16M. */
REGVAL(EPIC_HAXR1) = 0x80000000;
/* HAXR2: maps PCI I/O space above 256K. 256K -> 256k. */
REGVAL(EPIC_HAXR2) = 0;
#endif
}
pcitag_t
apecs_make_tag(bus, device, function)
int bus, device, function;
{
pcitag_t tag;
if (bus >= 256 || device >= 32 || function >= 8)
panic("apecs_make_tag: bad request");
tag = (bus << 21) | (device << 16) | (function << 13);
#if 0
printf("apecs_make_tag: bus %d, device %d, function %d -> 0x%lx\n", bus,
device, function, tag);
#endif
return tag;
}
pcireg_t
apecs_conf_read(tag, offset)
pcitag_t tag;
int offset; /* XXX */
{
pcireg_t *datap, data;
int reg = offset >> 2; /* XXX */
if ((tag & 0x1fe00000) != 0) {
panic("apecs_conf_read: bus != 0?");
}
/* XXX FILL IN HAXR2 bits. */
datap = (pcireg_t *)
phystok0seg(APECS_PCI_CONF | tag | reg << 7 | 0 << 5 | 0x3 << 3);
if (badaddr(datap, sizeof *datap))
return ((pcireg_t)-1);
data = *datap;
#if 0
printf("apecs_conf_read: tag 0x%lx, reg 0x%lx -> %x @ %p\n", tag, reg,
data, datap);
#endif
return data;
}
void
apecs_conf_write(tag, offset, data)
pcitag_t tag;
int offset; /* XXX */
pcireg_t data;
{
pcireg_t *datap;
int reg = offset >> 2; /* XXX */
if ((tag & 0x1fe00000) != 0) {
panic("apecs_conf_read: bus != 0?");
}
/* XXX FILL IN HAXR2 bits. */
datap = (pcireg_t *)
phystok0seg(APECS_PCI_CONF | tag | reg << 7 | 0 << 5 | 0x3 << 3);
#if 0
printf("apecs_conf_write: tag 0x%lx, reg 0x%lx -> 0x%x @ %p\n", tag,
reg, data, datap);
#endif
*datap = data;
}
#ifndef APECS_PCI_PMEM_START
#define APECS_PCI_PMEM_START 0x00100000 /* WAY XXX */
#endif
vm_offset_t apecs_pci_paddr = APECS_PCI_PMEM_START;
int
apecs_map_mem(tag, reg, vap, pap)
pcitag_t tag;
int reg;
vm_offset_t *vap, *pap;
{
pcireg_t data;
vm_offset_t pci_pa, sb_pa;
if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3))
panic("apecs_map_mem: bad request");
/*
* "HERE WE GO AGAIN!!!"
*
* The PROM has already mapped the device for us. The PROM is
* our friend. We wouldn't want to make the PROM unhappy.
*
* So, we take the address that's been assigned (already) to
* the register, and figure out what physical and virtual addresses
* go with it...
*/
/*
* Section 6.2.5.1, `Address Maps', says that a device which wants 2^n
* bytes of memory will hardwire the bottom n bits of the address to 0.
* As recommended, we write all 1s and see what we get back.
*/
data = pci_conf_read(tag, reg);
if (data & PCI_MAP_IO)
panic("apecs_map_mem: attempt to memory map an I/O region");
switch (data & PCI_MAP_MEMORY_TYPE_MASK) {
case PCI_MAP_MEMORY_TYPE_32BIT:
break;
case PCI_MAP_MEMORY_TYPE_32BIT_1M:
printf("apecs_map_mem: attempt to map restricted 32-bit region\n");
return EOPNOTSUPP;
case PCI_MAP_MEMORY_TYPE_64BIT:
printf("apecs_map_mem: attempt to map 64-bit region\n");
return EOPNOTSUPP;
default:
printf("apecs_map_mem: reserved mapping type\n");
return EINVAL;
}
if (data & PCI_MAP_MEMORY_CACHABLE) {
/* XXX probably should impact mapping location? */
printf("apecs_map_mem: memory wants to be cacheable.\n");
}
/* figure out where it was mapped... */
pci_pa = data & PCI_MAP_MEMORY_ADDRESS_MASK; /* PCI bus address */
sb_pa = ((data & 0x7fffffc) << 5) | (2L << 32); /* sysBus address */
/* and tell the driver. */
*vap = phystok0seg(sb_pa);
*pap = pci_pa;
#if 0
printf("pci_map_mem: memory mapped at 0x%lx\n", *pap);
printf("pci_map_mem: virtual 0x%lx\n", *vap);
#endif
return 0;
}
int
apecs_pcidma_map(addr, size, mappings)
caddr_t addr;
vm_size_t size;
vm_offset_t *mappings;
{
vm_offset_t va;
long todo;
int i;
i = 0;
va = (vm_offset_t)addr;
todo = size;
while (todo > 0) {
mappings[i] = vtophys(va) | 0x40000000;
#if 0
printf("a_pd_m mapping %d: %lx -> %lx -> %lx\n", i, va,
vtophys(va), mappings[i]);
#endif
i++;
todo -= PAGE_SIZE - (va - trunc_page(va));
va += PAGE_SIZE - (va - trunc_page(va));
}
return (i);
}
void
apecs_pcidma_unmap(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
/* maybe XXX if diagnostic, check that mapping happened. */
printf("apecs_pcidma_unmap: nada\n");
}

View File

@ -0,0 +1,325 @@
/* $NetBSD: apecsreg.h,v 1.1 1995/06/28 01:25:36 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/*
* APECS Chipset registers and constants.
*
* Taken from ``DECchip 21071 and DECchip 21072 Core Logic Chipsets Data
* Sheet'' (DEC order number EC-QAEMA-TE), pages 4-1 - 4-27, 10-21 - 10-38.
*/
/*
* Base addresses
*/
#define COMANCHE_BASE 0x180000000L /* 21071-CA Regs */
#define EPIC_BASE 0x1a0000000L /* 21071-DA Regs */
#define APECS_PCI_IACK 0x1b0000000L /* PCI Int. Ack. */
#define APECS_PCI_SIO 0x1c0000000L /* PCI Sp. I/O Space */
#define APECS_PCI_CONF 0x1e0000000L /* PCI Conf. Space */
#define APECS_PCI_SPARSE 0x200000000L /* PCI Sparse Space */
#define APECS_PCI_DENSE 0x300000000L /* PCI Dense Space */
/*
* 21071-CA Registers
*/
/*
* 21071-CA General Registers
*/
#define COMANCHE_GCR (COMANCHE_BASE + 0x0000) /* General Control */
#define COMANCHE_GCR_RSVD 0xc009
#define COMANCHE_GCR_SYSARB 0x0006
#define COMANCHE_GCR_WIDEMEM 0x0010
#define COMANCHE_GCR_BC_EN 0x0020
#define COMANCHE_GCR_BC_NOALLOC 0x0040
#define COMANCHE_GCR_BC_LONGWR 0x0080
#define COMANCHE_GCR_BC_IGNTAG 0x0100
#define COMANCHE_GCR_BC_FRCTAG 0x0200
#define COMANCHE_GCR_BC_FRCD 0x0400
#define COMANCHE_GCR_BC_FRCV 0x0800
#define COMANCHE_GCR_BC_FRCP 0x1000
#define COMANCHE_GCR_BC_BADAP 0x2000
#define COMANCHE_RSVD (COMANCHE_BASE + 0x0020) /* Reserved */
#define COMANCHE_ED (COMANCHE_BASE + 0x0040) /* Err & Diag Status */
#define COMANCHE_ED_LOSTERR 0x0001
#define COMANCHE_ED_BC_TAPERR 0x0002
#define COMANCHE_ED_BC_TCPERR 0x0004
#define COMANCHE_ED_NXMERR 0x0008
#define COMANCHE_ED_DMACAUSE 0x0010
#define COMANCHE_ED_VICCAUSE 0x0020
#define COMANCHE_ED_CREQCAUSE 0x01c0
#define COMANCHE_ED_RSVD 0x1e00
#define COMANCHE_ED_PASS2 0x2000
#define COMANCHE_ED_IDXLLOCK 0x4000
#define COMANCHE_ED_WRPEND 0x8000
#define COMANCHE_TAGENB (COMANCHE_BASE + 0x0060) /* Tag Enable */
#define COMANCHE_TAGENB_RSVD 0x0001
#define COMANCHE_TAGENB_C_4G 0x0000
#define COMANCHE_TAGENB_C_2G 0x8000
#define COMANCHE_TAGENB_C_1G 0xc000
#define COMANCHE_TAGENB_C_512M 0xe000
#define COMANCHE_TAGENB_C_256M 0xf000
#define COMANCHE_TAGENB_C_128M 0xf800
#define COMANCHE_TAGENB_C_64M 0xfc00
#define COMANCHE_TAGENB_C_32M 0xfe00
#define COMANCHE_TAGENB_C_16M 0xff00
#define COMANCHE_TAGENB_C_8M 0xff80
#define COMANCHE_TAGENB_C_4M 0xffc0
#define COMANCHE_TAGENB_C_2M 0xffe0
#define COMANCHE_TAGENB_C_1M 0xfff0
#define COMANCHE_TAGENB_C_512K 0xfff8
#define COMANCHE_TAGENB_C_256K 0xfffc
#define COMANCHE_TAGENB_C_128K 0xfffe
#define COMANCHE_TAGENB_M_4G 0xffff
#define COMANCHE_TAGENB_M_2G 0x7fff
#define COMANCHE_TAGENB_M_1G 0x3fff
#define COMANCHE_TAGENB_M_512M 0x1fff
#define COMANCHE_TAGENB_M_256M 0x0fff
#define COMANCHE_TAGENB_M_128M 0x07ff
#define COMANCHE_TAGENB_M_64M 0x03ff
#define COMANCHE_TAGENB_M_32M 0x01ff
#define COMANCHE_TAGENB_M_16M 0x00ff
#define COMANCHE_TAGENB_M_8M 0x007f
#define COMANCHE_TAGENB_M_4M 0x003f
#define COMANCHE_TAGENB_M_2M 0x001f
#define COMANCHE_TAGENB_M_1M 0x000e
#define COMANCHE_TAGENB_M_512K 0x0006
#define COMANCHE_TAGENB_M_256K 0x0002
#define COMANCHE_TAGENB_M_128K 0x0000
#define COMANCHE_ERR_LO (COMANCHE_BASE + 0x0080) /* Error Low Address */
#define COMANCHE_ERR_HI (COMANCHE_BASE + 0x00a0) /* Error High Address */
#define COMANCHE_ERR_HI_RSVD 0xe000
#define COMANCHE_LCK_LO (COMANCHE_BASE + 0x00c0) /* LDx_L Low Address */
#define COMANCHE_LCK_HI (COMANCHE_BASE + 0x00e0) /* LDx_L High Address */
#define COMANCHE_LOCK_HI_RSVD 0xe000
/*
* 21071-CA Memory Registers
*/
#define COMANCHE_GTIM (COMANCHE_BASE + 0x0200) /* Global Timing */
#define COMANCHE_LOCK_HI_RSVD 0xe000
#define COMANCHE_RTIM (COMANCHE_BASE + 0x0220) /* Refresh Timing */
#define COMANCHE_VFP (COMANCHE_BASE + 0x0240) /* Video Frame Ptr. */
#define COMANCHE_VFP_COL 0x001f
#define COMANCHE_VFP_ROW 0x3fe0
#define COMANCHE_VFP_SUBBANK 0x4000
#define COMANCHE_VFP_RSVD 0x8000
#define COMANCHE_PD_LO (COMANCHE_BASE + 0x0260) /* Pres Detect Low */
#define COMANCHE_PD_HI (COMANCHE_BASE + 0x0280) /* Pres Detect High */
/*
* 21071-CA Memory banks' Base Address Register format
*/
#define COMANCHE_B0_BAR (COMANCHE_BASE + 0x0800) /* Bank 0 BA */
#define COMANCHE_B1_BAR (COMANCHE_BASE + 0x0820) /* Bank 1 BA */
#define COMANCHE_B2_BAR (COMANCHE_BASE + 0x0840) /* Bank 2 BA */
#define COMANCHE_B3_BAR (COMANCHE_BASE + 0x0860) /* Bank 3 BA */
#define COMANCHE_B4_BAR (COMANCHE_BASE + 0x0880) /* Bank 4 BA */
#define COMANCHE_B5_BAR (COMANCHE_BASE + 0x08a0) /* Bank 5 BA */
#define COMANCHE_B6_BAR (COMANCHE_BASE + 0x08c0) /* Bank 6 BA */
#define COMANCHE_B7_BAR (COMANCHE_BASE + 0x08e0) /* Bank 7 BA */
#define COMANCHE_B8_BAR (COMANCHE_BASE + 0x0900) /* Bank 8 BA */
#define COMANCHE_BAR_RSVD 0x001f
/*
* 21071-CA Memory banks' Configuration Register format
*/
#define COMANCHE_B0_CR (COMANCHE_BASE + 0x0a00) /* Bank 0 Config */
#define COMANCHE_B1_CR (COMANCHE_BASE + 0x0a20) /* Bank 1 Config */
#define COMANCHE_B2_CR (COMANCHE_BASE + 0x0a40) /* Bank 2 Config */
#define COMANCHE_B3_CR (COMANCHE_BASE + 0x0a60) /* Bank 3 Config */
#define COMANCHE_B4_CR (COMANCHE_BASE + 0x0a80) /* Bank 4 Config */
#define COMANCHE_B5_CR (COMANCHE_BASE + 0x0aa0) /* Bank 5 Config */
#define COMANCHE_B6_CR (COMANCHE_BASE + 0x0ac0) /* Bank 6 Config */
#define COMANCHE_B7_CR (COMANCHE_BASE + 0x0ae0) /* Bank 7 Config */
#define COMANCHE_B8_CR (COMANCHE_BASE + 0x0b00) /* Bank 8 Config */
#define COMANCHE_CR_VALID 0x0001
#define COMANCHE_CR_SIZE 0x001e
#define COMANCHE_CR_SUBENA 0x0020
#define COMANCHE_CR_COLSEL 0x01c0
#define COMANCHE_CR_S0_RSVD 0xfe00
#define COMANCHE_CR_S8_CHECK 0x0200
#define COMANCHE_CR_S8_RSVD 0xfc00
/*
* 21071-CA Memory banks' Timing Register A format
*/
#define COMANCHE_B0_TRA (COMANCHE_BASE + 0x0c00) /* Bank 0 Timing A */
#define COMANCHE_B1_TRA (COMANCHE_BASE + 0x0c20) /* Bank 1 Timing A */
#define COMANCHE_B2_TRA (COMANCHE_BASE + 0x0c40) /* Bank 2 Timing A */
#define COMANCHE_B3_TRA (COMANCHE_BASE + 0x0c60) /* Bank 3 Timing A */
#define COMANCHE_B4_TRA (COMANCHE_BASE + 0x0c80) /* Bank 4 Timing A */
#define COMANCHE_B5_TRA (COMANCHE_BASE + 0x0ca0) /* Bank 5 Timing A */
#define COMANCHE_B6_TRA (COMANCHE_BASE + 0x0cc0) /* Bank 6 Timing A */
#define COMANCHE_B7_TRA (COMANCHE_BASE + 0x0ce0) /* Bank 7 Timing A */
#define COMANCHE_B8_TRA (COMANCHE_BASE + 0x0d00) /* Bank 8 Timing A */
#define COMANCHE_TRA_ROWSETUP 0x0003
#define COMANCHE_TRA_ROWHOLD 0x000c
#define COMANCHE_TRA_COLSETUP 0x0070
#define COMANCHE_TRA_COLHOLD 0x0180
#define COMANCHE_TRA_RDLYROW 0x0e00
#define COMANCHE_TRA_RDLYCOL 0x7000
#define COMANCHE_TRA_RSVD 0x8000
/*
* 21071-CA Memory banks' Timing Register B format
*/
#define COMANCHE_B0_TRB (COMANCHE_BASE + 0x0e00) /* Bank 0 Timing B */
#define COMANCHE_B1_TRB (COMANCHE_BASE + 0x0e20) /* Bank 1 Timing B */
#define COMANCHE_B2_TRB (COMANCHE_BASE + 0x0e40) /* Bank 2 Timing B */
#define COMANCHE_B3_TRB (COMANCHE_BASE + 0x0e60) /* Bank 3 Timing B */
#define COMANCHE_B4_TRB (COMANCHE_BASE + 0x0e80) /* Bank 4 Timing B */
#define COMANCHE_B5_TRB (COMANCHE_BASE + 0x0ea0) /* Bank 5 Timing B */
#define COMANCHE_B6_TRB (COMANCHE_BASE + 0x0ec0) /* Bank 6 Timing B */
#define COMANCHE_B7_TRB (COMANCHE_BASE + 0x0ee0) /* Bank 7 Timing B */
#define COMANCHE_B8_TRB (COMANCHE_BASE + 0x0f00) /* Bank 8 Timing B */
#define COMANCHE_TRB_RTCAS 0x0007
#define COMANCHE_TRB_WTCAS 0x0038
#define COMANCHE_TRB_TCP 0x00c0
#define COMANCHE_TRB_WHOLD0ROW 0x0700
#define COMANCHE_TRB_WHOLD0COL 0x3800
#define COMANCHE_TRB_RSVD 0xc000
/*
* 21071-DA Registers
*/
#define EPIC_DCSR (EPIC_BASE + 0x0000) /* Diagnostic CSR */
#define EPIC_DCSR_TENB 0x00000001
#define EPIC_DCSR_RSVD 0x7fc00082
#define EPIC_DCSR_PENB 0x00000004
#define EPIC_DCSR_DCEI 0x00000008
#define EPIC_DCSR_DPEC 0x00000010
#define EPIC_DCSR_IORT 0x00000020
#define EPIC_DCSR_LOST 0x00000040
#define EPIC_DCSR_DDPE 0x00000100
#define EPIC_DCSR_IOPE 0x00000200
#define EPIC_DCSR_TABT 0x00000400
#define EPIC_DCSR_NDEV 0x00000800
#define EPIC_DCSR_CMRD 0x00001000
#define EPIC_DCSR_UMRD 0x00002000
#define EPIC_DCSR_IPTL 0x00004000
#define EPIC_DCSR_MERR 0x00008000
#define EPIC_DCSR_DBYP 0x00030000
#define EPIC_DCSR_PCMD 0x003c0000
#define EPIC_DCSR_PASS2 0x80000000
#define EPIC_PEAR (EPIC_BASE + 0x0020) /* PCI Err Addr. */
#define EPIC_SEAR (EPIC_BASE + 0x0040) /* sysBus Err Addr. */
#define EPIC_SEAR_RSVD 0x0000000f
#define EPIC_SEAR_SYS_ERR 0xfffffff0
#define EPIC_DUMMY_1 (EPIC_BASE + 0x0060) /* Dummy 1 */
#define EPIC_DUMMY_2 (EPIC_BASE + 0x0080) /* Dummy 2 */
#define EPIC_DUMMY_3 (EPIC_BASE + 0x00a0) /* Dummy 3 */
#define EPIC_TBASE_1 (EPIC_BASE + 0x00c0) /* Trans. Base 1 */
#define EPIC_TBASE_2 (EPIC_BASE + 0x00e0) /* Trans. Base 2 */
#define EPIC_TBASE_RSVD 0x000001ff
#define EPIC_TBASE_T_BASE 0xfffffe00
#define EPIC_PCI_BASE_1 (EPIC_BASE + 0x0100) /* PCI Base 1 */
#define EPIC_PCI_BASE_2 (EPIC_BASE + 0x0120) /* PCI Base 2 */
#define EPIC_PCI_BASE_RSVD 0x0003ffff
#define EPIC_PCI_BASE_SGEN 0x00040000
#define EPIC_PCI_BASE_WENB 0x00080000
#define EPIC_PCI_BASE_PCI_BASE 0xfff00000
#define EPIC_PCI_MASK_1 (EPIC_BASE + 0x0140) /* PCI Mask 1 */
#define EPIC_PCI_MASK_2 (EPIC_BASE + 0x0160) /* PCI Maxk 2 */
#define EPIC_PCI_MASK_RSVD 0x000fffff
#define EPIC_PCI_MASK_PCI_MASK 0xfff00000
#define EPIC_HAXR0 (EPIC_BASE + 0x0180) /* Host Addr Extn 0 */
#define EPIC_HAXR1 (EPIC_BASE + 0x01a0) /* Host Addr Extn 1 */
#define EPIC_HAXR1_RSVD 0x07ffffff
#define EPIC_HAXR1_EADDR 0xf8000000
#define EPIC_HAXR2 (EPIC_BASE + 0x01c0) /* Host Addr Extn 2 */
#define EPIC_HAXR2_CONF_ADDR 0x00000003
#define EPIC_HAXR2_RSVD 0x00fffffc
#define EPIC_HAXR2_EADDR 0xff000000
#define EPIC_PMLT (EPIC_BASE + 0x01e0) /* PCI Mstr Lat Tmr */
#define EPIC_PMLT_PMLC 0x000000ff
#define EPIC_PMLT_RSVD 0xffffff00
#define EPIC_TLB_TAG_0 (EPIC_BASE + 0x0200) /* TLB Tag 0 */
#define EPIC_TLB_TAG_1 (EPIC_BASE + 0x0220) /* TLB Tag 1 */
#define EPIC_TLB_TAG_2 (EPIC_BASE + 0x0240) /* TLB Tag 2 */
#define EPIC_TLB_TAG_3 (EPIC_BASE + 0x0260) /* TLB Tag 3 */
#define EPIC_TLB_TAG_4 (EPIC_BASE + 0x0280) /* TLB Tag 4 */
#define EPIC_TLB_TAG_5 (EPIC_BASE + 0x02a0) /* TLB Tag 5 */
#define EPIC_TLB_TAG_6 (EPIC_BASE + 0x02c0) /* TLB Tag 6 */
#define EPIC_TLB_TAG_7 (EPIC_BASE + 0x02e0) /* TLB Tag 7 */
#define EPIC_TLB_TAG_RSVD 0x00000fff
#define EPIC_TLB_TAG_EVAL 0x00001000
#define EPIC_TLB_TAG_PCI_PAGE 0xffffe000
#define EPIC_TLB_DATA_0 (EPIC_BASE + 0x0300) /* TLB Data 0 */
#define EPIC_TLB_DATA_1 (EPIC_BASE + 0x0320) /* TLB Data 1 */
#define EPIC_TLB_DATA_2 (EPIC_BASE + 0x0340) /* TLB Data 2 */
#define EPIC_TLB_DATA_3 (EPIC_BASE + 0x0360) /* TLB Data 3 */
#define EPIC_TLB_DATA_4 (EPIC_BASE + 0x0380) /* TLB Data 4 */
#define EPIC_TLB_DATA_5 (EPIC_BASE + 0x03a0) /* TLB Data 5 */
#define EPIC_TLB_DATA_6 (EPIC_BASE + 0x03c0) /* TLB Data 6 */
#define EPIC_TLB_DATA_7 (EPIC_BASE + 0x03e0) /* TLB Data 7 */
#define EPIC_TLB_DATA_RSVD 0xffe00001
#define EPIC_TLB_DATA_CPU_PAGE 0x001ffffe
#define EPIC_TBIA (EPIC_BASE + 0x0400) /* TLB Invl All */
/*
* EPIC Scatter-Gather Map Entries
*/
struct sgmapent {
u_int64_t val;
};
#define SGMAPENT_EVAL 0x0000000000000001L
#define SGMAPENT_PFN 0x00000000001ffffeL
#define SGMAPENT_RSVD 0xffffffffffe00000L
#define SGMAP_MAKEENTRY(pfn) (SGMAPENT_EVAL | ((pfn) << 1))

View File

@ -0,0 +1,189 @@
/* $NetBSD: pci_2100_a50.c,v 1.1 1995/06/28 01:25:43 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <vm/vm.h>
#include <dev/isa/isavar.h>
#include <alpha/isa/isa_intr.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <alpha/pci/pci_chipset.h>
void pci_2100_a50_attach __P((struct device *, struct device *, void *));
void *pci_2100_a50_map_int __P((pcitag_t, pci_intrlevel, int (*) (void *),
void *, int));
struct pci_cfg_fcns pci_2100_a50_sio1_cfg_fcns = { /* XXX diff? */
pci_2100_a50_attach, pci_2100_a50_map_int,
};
struct pci_cfg_fcns pci_2100_a50_sio2_cfg_fcns = {
pci_2100_a50_attach, pci_2100_a50_map_int,
};
void
pci_2100_a50_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
int bus, device;
#if 0
for (bus = 0; bus <= 255; bus++)
#else
/*
* XXX
* Some current chipsets do wacky things with bus numbers > 0.
* This seems like a violation of protocol, but the PCI BIOS does
* allow one to query the maximum bus number, and eventually we
* should do so.
*/
for (bus = 0; bus <= 0; bus++)
#endif
for (device = 0; device <= 31; device++)
pci_attach_subdev(self, bus, device);
}
void *
pci_2100_a50_map_int(tag, level, func, arg, pin)
pcitag_t tag;
pci_intrlevel level;
int (*func) __P((void *));
void *arg;
int pin;
{
int bus, device, pirq;
pcireg_t pirqreg;
u_int8_t line;
bus = (tag >> 21) & 0xff; /* XXX */
device = (tag >> 16) & 0x1f;
if (bus != 0) /* XXX */
return NULL;
switch (device) {
case 6: /* NCR SCSI */
pirq = 3;
break;
case 11: /* slot 1 */
switch (pin) {
case PCI_INTERRUPT_PIN_A:
case PCI_INTERRUPT_PIN_D:
pirq = 0;
break;
case PCI_INTERRUPT_PIN_B:
pirq = 2;
break;
case PCI_INTERRUPT_PIN_C:
pirq = 1;
break;
};
break;
case 12: /* slot 2 */
switch (pin) {
case PCI_INTERRUPT_PIN_A:
case PCI_INTERRUPT_PIN_D:
pirq = 1;
break;
case PCI_INTERRUPT_PIN_B:
pirq = 0;
break;
case PCI_INTERRUPT_PIN_C:
pirq = 2;
break;
};
break;
case 13: /* slot 3 */
switch (pin) {
case PCI_INTERRUPT_PIN_A:
case PCI_INTERRUPT_PIN_D:
pirq = 2;
break;
case PCI_INTERRUPT_PIN_B:
pirq = 1;
break;
case PCI_INTERRUPT_PIN_C:
pirq = 0;
break;
};
break;
}
pirqreg = pci_conf_read(pci_make_tag(0, 7, 0), 0x60); /* XXX */
#if 0
printf("pci_2100_a50_map_int: device %d pin %c: pirq %d, reg = %x\n",
device, '@' + pin, pirq, pirqreg);
#endif
line = (pirqreg >> (pirq * 8)) & 0xff;
if ((line & 0x80) != 0)
return 0; /* not routed? */
line &= 0xf;
#if 0
printf("pci_2100_a50_map_int: device %d pin %c: mapped to line %d\n",
device, '@' + pin, line);
#endif
return isa_intr_establish(line, ISA_IST_LEVEL, pcilevel_to_isa(level),
func, arg);
}
void
pci_2100_a50_pickintr()
{
pcireg_t sioclass;
int sioII;
/* XXX MAGIC NUMBER */
sioclass = pci_conf_read(pci_make_tag(0, 7, 0), PCI_CLASS_REG);
sioII = (sioclass & 0xff) >= 3;
if (!sioII)
printf("WARNING: SIO NOT SIO II... NO BETS...\n");
if (!sioII)
pci_cfg_fcns = &pci_2100_a50_sio1_cfg_fcns;
else
pci_cfg_fcns = &pci_2100_a50_sio2_cfg_fcns;
isa_intr_fcns = &sio_intr_fcns;
(*isa_intr_fcns->isa_intr_setup)();
set_iointr(isa_intr_fcns->isa_iointr);
}

View File

@ -0,0 +1,73 @@
/* $NetBSD: pci_chipset.h,v 1.1 1995/06/28 01:25:50 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/*
* Function switch to implement the various PCI bus interfaces.
* XXX this probably needs some work...
*/
struct pci_cs_fcns {
void (*cs_setup) __P((void));
pcitag_t (*cs_make_tag) __P((int, int, int));
pcireg_t (*cs_conf_read) __P((pcitag_t, int));
void (*cs_conf_write) __P((pcitag_t, int, pcireg_t));
int (*cs_map_mem) __P((pcitag_t, int, vm_offset_t *,
vm_offset_t *));
int (*cs_pcidma_map) __P((caddr_t, vm_size_t,
vm_offset_t *));
void (*cs_pcidma_unmap) __P((caddr_t, vm_size_t, int,
vm_offset_t *));
};
struct pci_cs_fcns *pci_cs_fcns;
extern struct pci_cs_fcns apecs_p1e_cs_fcns;
extern struct pci_cs_fcns apecs_p2e_cs_fcns;
extern struct pci_cs_fcns lca_cs_fcns;
/*
* Function switch to implement the various PCI configuration schemes.
* XXX this probably needs some work...
*/
struct pci_cfg_fcns {
void (*cfg_attach) __P((struct device *, struct
device *, void *));
void *(*cfg_map_int) __P((pcitag_t, pci_intrlevel,
int (*) (void *), void *, int));
};
struct pci_cfg_fcns *pci_cfg_fcns;
extern struct pci_cfg_fcns pci_2100_a50_sio1_cfg_fcns;
extern struct pci_cfg_fcns pci_2100_a50_sio2_cfg_fcns;
/*
* Miscellaneous functions.
*/
isa_intrlevel pcilevel_to_isa __P((pci_intrlevel));

View File

@ -0,0 +1,200 @@
/* $NetBSD: pci_machdep.c,v 1.1 1995/06/28 01:25:56 cgd Exp $ */
/*
* Copyright (c) 1994 Charles Hannum. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Charles Hannum.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*/
/*
* Machine-specific functions for PCI autoconfiguration.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <vm/vm.h>
#include <dev/isa/isavar.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <alpha/pci/pci_chipset.h>
int pcimatch __P((struct device *, void *, void *));
void pciattach __P((struct device *, struct device *, void *));
struct cfdriver pcicd = {
NULL, "pci", pcimatch, pciattach, DV_DULL, sizeof(struct device)
};
int
pcimatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
return 1;
}
void
pciattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
printf("\n");
(*pci_cs_fcns->cs_setup)();
(*pci_cfg_fcns->cfg_attach)(parent, self, aux);
}
pcitag_t
pci_make_tag(bus, device, function)
int bus, device, function;
{
return (*pci_cs_fcns->cs_make_tag)(bus, device, function);
}
pcireg_t
pci_conf_read(tag, offset)
pcitag_t tag;
int offset; /* XXX */
{
return (*pci_cs_fcns->cs_conf_read)(tag, offset);
}
void
pci_conf_write(tag, offset, data)
pcitag_t tag;
int offset; /* XXX */
pcireg_t data;
{
(*pci_cs_fcns->cs_conf_write)(tag, offset, data);
}
int
pci_map_io(tag, reg, iobasep)
pcitag_t tag;
int reg;
int *iobasep;
{
/*
* XXX should be a chipset-dependent function, but...
* what would it do, and what would use it?
*/
panic("pci_map_io: not implemented");
}
int
pci_map_mem(tag, reg, vap, pap)
pcitag_t tag;
int reg;
vm_offset_t *vap, *pap;
{
return (*pci_cs_fcns->cs_map_mem)(tag, reg, vap, pap);
}
int
pcidma_map(addr, size, mappings)
caddr_t addr;
vm_size_t size;
vm_offset_t *mappings;
{
return (*pci_cs_fcns->cs_pcidma_map)(addr, size, mappings);
}
void
pcidma_unmap(addr, size, nmappings, mappings)
caddr_t addr;
vm_size_t size;
int nmappings;
vm_offset_t *mappings;
{
(*pci_cs_fcns->cs_pcidma_unmap)(addr, size, nmappings, mappings);
}
void *
pci_map_int(tag, level, func, arg)
pcitag_t tag;
pci_intrlevel level;
int (*func) __P((void *));
void *arg;
{
pcireg_t data;
int pin;
data = pci_conf_read(tag, PCI_INTERRUPT_REG);
pin = PCI_INTERRUPT_PIN(data);
if (pin == 0) {
/* No IRQ used. */
return 0;
}
if (pin > 4) {
printf("pci_map_int: bad interrupt pin %d\n", pin);
return NULL;
}
return (*pci_cfg_fcns->cfg_map_int)(tag, level, func, arg, pin);
}
isa_intrlevel
pcilevel_to_isa(level)
pci_intrlevel level;
{
switch (level) {
case PCI_IPL_NONE:
return (ISA_IPL_NONE);
case PCI_IPL_BIO:
return (ISA_IPL_BIO);
case PCI_IPL_NET:
return (ISA_IPL_NET);
case PCI_IPL_TTY:
return (ISA_IPL_TTY);
case PCI_IPL_CLOCK:
return (ISA_IPL_CLOCK);
default:
panic("pcilevel_to_isa: unknown level %d\n", level);
}
}

View File

@ -0,0 +1,53 @@
/* $NetBSD: pci_machdep.h,v 1.1 1995/06/28 01:26:01 cgd Exp $ */
/*
* Copyright (c) 1994 Charles Hannum. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Charles Hannum.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*/
/*
* Machine-specific definitions for PCI autoconfiguration.
*
* See the comments in pci_machdep.c for more explanation.
*/
/*
* Configuration tag; created from a {bus,device,function} triplet by
* pci_make_tag(), and passed to pci_conf_read() and pci_conf_write().
* We could instead always pass the {bus,device,function} triplet to
* the read and write routines, but this would cause extra overhead.
*/
typedef u_long pcitag_t;
/*
* Type of a value read from or written to a configuration register.
* Always 32 bits.
*/
typedef u_int32_t pcireg_t;
extern int pci_mode;
extern int pci_mode_detect __P((void));

107
sys/arch/alpha/pci/sio.c Normal file
View File

@ -0,0 +1,107 @@
/* $NetBSD: sio.c,v 1.1 1995/06/28 01:26:07 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <machine/autoconf.h>
int siomatch __P((struct device *, void *, void *));
void sioattach __P((struct device *, struct device *, void *));
struct cfdriver siocd = {
NULL, "sio", siomatch, sioattach, DV_DULL, sizeof(struct device)
};
static int sioprint __P((void *, char *pnp));
int
siomatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct cfdata *cf = match;
struct pci_attach_args *pa = aux;
if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL ||
PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_INTEL_SIO)
return (0);
return (1);
}
void
sioattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct pci_attach_args *pa = aux;
struct confargs nca;
u_int rev;
char *type;
rev = pa->pa_class & 0xff;
if (rev < 3) {
type = "I";
/* XXX PCI IRQ MAPPING FUNCTION */
} else {
type = "II";
/* XXX PCI IRQ MAPPING FUNCTION */
}
printf(": Saturn %s PCI->ISA bridge (revision 0x%x)\n", type, rev);
if (rev < 3)
printf("%s: WARNING: SIO I SUPPORT UNTESTED\n",
parent->dv_xname);
/* attach the ISA bus that hangs off of it... */
nca.ca_name = "isa";
nca.ca_slot = 0;
nca.ca_offset = 0;
nca.ca_bus = NULL;
if (!config_found(self, &nca, sioprint))
panic("sioattach: couldn't attach ISA bus");
}
static int
sioprint(aux, pnp)
void *aux;
char *pnp;
{
register struct confargs *ca = aux;
if (pnp)
printf("%s at %s", ca->ca_name, pnp);
return (UNCONF);
}

View File

@ -0,0 +1,378 @@
/* $NetBSD: sio_pic.c,v 1.1 1995/06/28 01:26:13 cgd Exp $ */
/*
* Copyright (c) 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isareg.h>
#include <alpha/isa/isa_intr.h>
#include <machine/pio.h>
/*
* To add to the long history of wonderful PROM console traits,
* AlphaStation PROMs don't reset themselves completely on boot!
* Therefore, if an interrupt was turned on when the kernel was
* started, we're not going to EVER turn it off... I don't know
* what will happen if new interrupts (that the PROM console doesn't
* want) are turned on. I'll burn that bridge when I come to it.
*/
#define BROKEN_PROM_CONSOLE
static void sio_intr_setup __P((void));
static void *sio_intr_establish __P((int intr, isa_intrtype type,
isa_intrlevel level, int (*ih_fun)(void *), void *ih_arg));
static void sio_intr_disestablish __P((void *handler));
static void sio_iointr __P((void *framep, int vec));
struct isa_intr_fcns sio_intr_fcns = {
sio_intr_setup, sio_intr_establish,
sio_intr_disestablish, sio_iointr,
};
static void sio_strayintr __P((int irq));
/*
* Interrupt handler chains. sio_intr_establish() inserts a handler into
* the list. The handler is called with its (single) argument.
*/
struct intrhand {
int (*ih_fun)();
void *ih_arg;
u_long ih_count;
struct intrhand *ih_next;
int ih_level;
int ih_irq;
};
#define ICU_LEN 16 /* number of ISA IRQs */
static struct intrhand *sio_intrhand[ICU_LEN];
static isa_intrtype sio_intrtype[ICU_LEN];
static u_long sio_strayintrcnt[ICU_LEN];
#ifndef STRAY_MAX
#ifdef BROKEN_PROM_CONSOLE
/*
* If prom console is broken, because initial interrupt settings
* must be kept, there's no way to escape stray interrupts.
*/
#define STRAY_MAX 0
#else
#define STRAY_MAX 5
#endif
#endif
#ifdef BROKEN_PROM_CONSOLE
/*
* If prom console is broken, must remember the initial interrupt
* settings and enforce them. WHEE!
*/
u_int8_t initial_ocw1[2];
u_int8_t initial_elcr[2];
#define INITIALLY_ENABLED(irq) \
((initial_ocw1[(irq) / 8] & (1 << ((irq) % 8))) == 0)
#define INITIALLY_LEVEL_TRIGGERED(irq) \
((initial_elcr[(irq) / 8] & (1 << ((irq) % 8))) != 0)
#else
#define INITIALLY_ENABLED(irq) ((irq) == 2 ? 1 : 0)
#define INITIALLY_LEVEL_TRIGGERED(irq) 0
#endif
void
sio_setirqstat(irq, enabled, type)
int irq, enabled;
isa_intrtype type;
{
u_int8_t ocw1[2], elcr[2];
int icu, bit;
#if 0
printf("sio_setirqstat: irq %d, %s, %s\n", irq,
enabled ? "enabled" : "disabled", isa_intr_typename(type));
#endif
sio_intrtype[irq] = type;
icu = irq / 8;
bit = irq % 8;
ocw1[0] = inb(IO_ICU1 + 1);
ocw1[1] = inb(IO_ICU2 + 1);
elcr[0] = inb(0x4d0); /* XXX */
elcr[1] = inb(0x4d1); /* XXX */
/*
* interrupt enable: set bit to mask (disable) interrupt.
*/
if (enabled)
ocw1[icu] &= ~(1 << bit);
else
ocw1[icu] |= 1 << bit;
/*
* interrupt type select: set bit to get level-triggered.
*/
if (type == ISA_IST_LEVEL)
elcr[icu] |= 1 << bit;
else
elcr[icu] &= ~(1 << bit);
#ifdef not_here
/* see the init function... */
ocw1[0] &= ~0x04; /* always enable IRQ2 on first PIC */
elcr[0] &= ~0x07; /* IRQ[0-2] must be edge-triggered */
elcr[1] &= ~0x21; /* IRQ[13,8] must be edge-triggered */
#endif
#ifdef BROKEN_PROM_CONSOLE
/*
* make sure that the initially clear bits (unmasked interrupts)
* are never set, and that the initially-level-triggered
* intrrupts always remain level-triggered, to keep the prom happy.
*/
if ((ocw1[0] & ~initial_ocw1[0]) != 0 ||
(ocw1[1] & ~initial_ocw1[1]) != 0 ||
(elcr[0] & initial_elcr[0]) != initial_elcr[0] ||
(elcr[1] & initial_elcr[1]) != initial_elcr[1]) {
printf("sio_sis: initial: ocw = (%2x,%2x), elcr = (%2x,%2X)\n",
initial_ocw1[0], initial_ocw1[1],
initial_elcr[0], initial_elcr[1]);
printf(" current: ocw = (%2x,%2x), elcr = (%2x,%2X)\n",
ocw1[0], ocw1[1], elcr[0], elcr[1]);
panic("sio_setirqstat: hosed");
}
#endif
outb(IO_ICU1 + 1, ocw1[0]);
outb(IO_ICU2 + 1, ocw1[1]);
outb(0x4d0, elcr[0]); /* XXX */
outb(0x4d1, elcr[1]); /* XXX */
}
void
sio_intr_setup()
{
int i;
#ifdef BROKEN_PROM_CONSOLE
/*
* Remember the initial values, because the prom is stupid.
*/
initial_ocw1[0] = inb(IO_ICU1 + 1);
initial_ocw1[1] = inb(IO_ICU2 + 1);
initial_elcr[0] = inb(0x4d0); /* XXX */
initial_elcr[1] = inb(0x4d1); /* XXX */
#if 0
printf("initial_ocw1[0] = 0x%x\n", initial_ocw1[0]);
printf("initial_ocw1[1] = 0x%x\n", initial_ocw1[1]);
printf("initial_elcr[0] = 0x%x\n", initial_elcr[0]);
printf("initial_elcr[1] = 0x%x\n", initial_elcr[1]);
#endif
#endif
/*
* set up initial values for interrupt enables.
*/
for (i = 0; i < ICU_LEN; i++) {
switch (i) {
case 0:
case 1:
case 8:
case 13:
/*
* IRQs 0, 1, 8, and 13 must always be
* edge-triggered.
*/
if (INITIALLY_LEVEL_TRIGGERED(i))
printf("sio_intr_setup: %d LT!\n", i);
sio_setirqstat(i, INITIALLY_ENABLED(i), ISA_IST_EDGE);
break;
case 2:
/*
* IRQ 2 must be edge-triggered, and should be
* enabled (otherwise IRQs 8-15 are ignored).
*/
if (INITIALLY_LEVEL_TRIGGERED(i))
printf("sio_intr_setup: %d LT!\n", i);
if (!INITIALLY_ENABLED(i))
printf("sio_intr_setup: %d not enabled!\n", i);
sio_setirqstat(i, 1, ISA_IST_EDGE);
break;
default:
/*
* Otherwise, disable the IRQ and set its
* type to (effectively) "unknown."
*/
sio_setirqstat(i, INITIALLY_ENABLED(i),
INITIALLY_LEVEL_TRIGGERED(i) ? ISA_IST_LEVEL :
ISA_IST_NONE);
break;
}
}
}
void *
sio_intr_establish(irq, type, level, ih_fun, ih_arg)
int irq;
isa_intrtype type;
isa_intrlevel level;
int (*ih_fun)(void *);
void *ih_arg;
{
struct intrhand **p, *c, *ih;
extern int cold;
/* no point in sleeping unless someone can free memory. */
ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
if (ih == NULL)
panic("sio_intr_establish: can't malloc handler info");
if (irq < 0 || irq > ICU_LEN || type == ISA_IST_NONE)
panic("sio_intr_establish: bogus irq or type");
switch (sio_intrtype[irq]) {
case ISA_IST_EDGE:
case ISA_IST_LEVEL:
if (type == sio_intrtype[irq])
break;
case ISA_IST_PULSE:
if (type != ISA_IST_NONE)
panic("intr_establish: can't share %s with %s",
isa_intr_typename(sio_intrtype[irq]),
isa_intr_typename(type));
break;
}
/*
* Figure out where to put the handler.
* This is O(N^2), but we want to preserve the order, and N is
* generally small.
*/
for (p = &sio_intrhand[irq]; (c = *p) != NULL; p = &c->ih_next)
;
/*
* Poke the real handler in now.
*/
ih->ih_fun = ih_fun;
ih->ih_arg = ih_arg;
ih->ih_count = 0;
ih->ih_next = NULL;
ih->ih_level = 0; /* XXX meaningless on alpha */
ih->ih_irq = irq;
*p = ih;
sio_setirqstat(irq, 1, type);
return ih;
}
void
sio_intr_disestablish(handler)
void *handler;
{
printf("sio_intr_disestablish(%lx)\n", handler);
/* XXX */
/* XXX NEVER ALLOW AN INITIALLY-ENABLED INTERRUPT TO BE DISABLED */
/* XXX NEVER ALLOW AN INITIALLY-LT INTERRUPT TO BECOME UNTYPED */
}
/*
* caught a stray interrupt; notify if not too many seen already.
*/
void
sio_strayintr(irq)
int irq;
{
if (++sio_strayintrcnt[irq] <= STRAY_MAX)
log(LOG_ERR, "stray interrupt %d%s\n", irq,
sio_strayintrcnt[irq] >= STRAY_MAX ?
"; stopped logging" : "");
}
void
sio_iointr(framep, vec)
void *framep;
int vec;
{
int irq, handled;
struct intrhand *ih;
irq = (vec - 0x800) >> 4;
#ifdef DIAGNOSTIC
if (irq > ICU_LEN || irq < 0)
panic("sio_iointr: irq out of range (%d)", irq);
#endif
/*
* We cdr down the intrhand chain, calling each handler with
* its appropriate argument;
*
* The handler returns one of three values:
* 0 - This interrupt wasn't for me.
* 1 - This interrupt was for me.
* -1 - This interrupt might have been for me, but I don't know.
* If there are no handlers, or they all return 0, we flags it as a
* `stray' interrupt. On a system with level-triggered interrupts,
* we could terminate immediately when one of them returns 1; but
* this is PC-ish!
*/
for (ih = sio_intrhand[irq], handled = 0; ih != NULL;
ih = ih->ih_next) {
int rv;
rv = (*ih->ih_fun)(ih->ih_arg);
ih->ih_count++;
handled = handled || (rv != 0);
}
if (!handled)
sio_strayintr(irq);
/*
* Some versions of the machines which use the SIO
* (or is it some PALcode revisions on those machines?)
* require the non-specific EOI to be fed to the PIC(s)
* by the interrupt handler.
*/
if (irq > 7)
outb(IO_ICU2 + 0, 0x20 | (irq & 0x07)); /* XXX */
outb(IO_ICU1 + 0, 0x20 | (irq > 7 ? 2 : irq)); /* XXX */
}