Merge r1.39 from NetBSD (manage both streaming caches for psycho pairs).
Use explicit bus space accesses instead of mapping the device memory into kva. Fix support for psycho pairs, and catch up with iommu code changes.
This commit is contained in:
parent
833609e922
commit
aac61c2231
@ -26,7 +26,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp
|
||||
* from: NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -48,7 +48,6 @@
|
||||
#include <ofw/ofw_pci.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/cache.h>
|
||||
#include <machine/iommureg.h>
|
||||
#include <machine/bus_common.h>
|
||||
#include <machine/frame.h>
|
||||
@ -72,10 +71,10 @@
|
||||
#include "sparcbus_if.h"
|
||||
|
||||
static void psycho_get_ranges(phandle_t, struct upa_ranges **, int *);
|
||||
static void psycho_set_intr(struct psycho_softc *, int, device_t, u_long *,
|
||||
static void psycho_set_intr(struct psycho_softc *, int, device_t, bus_addr_t,
|
||||
int, driver_intr_t);
|
||||
static int psycho_find_intrmap(struct psycho_softc *, int, u_long **,
|
||||
u_long **, u_long *);
|
||||
static int psycho_find_intrmap(struct psycho_softc *, int, bus_addr_t *,
|
||||
bus_addr_t *, u_long *);
|
||||
static void psycho_intr_stub(void *);
|
||||
#ifdef PSYCHO_STRAY
|
||||
static void psycho_intr_stray(void *);
|
||||
@ -100,12 +99,14 @@ static void psycho_iommu_init(struct psycho_softc *, int);
|
||||
* bus space and bus dma support for UltraSPARC `psycho'. note that most
|
||||
* of the bus dma support is provided by the iommu dvma controller.
|
||||
*/
|
||||
static int psycho_dmamem_alloc(bus_dma_tag_t, void **, int, bus_dmamap_t *);
|
||||
static void psycho_dmamem_free(bus_dma_tag_t, void *, bus_dmamap_t);
|
||||
static int psycho_dmamap_create(bus_dma_tag_t, int, bus_dmamap_t *);
|
||||
static int psycho_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
|
||||
static int psycho_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
|
||||
bus_dmamap_callback_t *, void *, int);
|
||||
static void psycho_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
|
||||
static void psycho_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t);
|
||||
static int psycho_dmamem_alloc(bus_dma_tag_t, void **, int, bus_dmamap_t *);
|
||||
static void psycho_dmamem_free(bus_dma_tag_t, void *, bus_dmamap_t);
|
||||
|
||||
/*
|
||||
* autoconfiguration
|
||||
@ -175,12 +176,27 @@ static int psycho_ndevs;
|
||||
static struct psycho_softc *psycho_softcs[4];
|
||||
|
||||
struct psycho_clr {
|
||||
u_long *pci_clr; /* clear register */
|
||||
struct psycho_softc *pci_sc;
|
||||
bus_addr_t pci_clr; /* clear register */
|
||||
driver_intr_t *pci_handler; /* handler to call */
|
||||
void *pci_arg; /* argument for the handler */
|
||||
void *pci_cookie; /* interrupt cookie of parent bus */
|
||||
void *pci_arg; /* argument for the handler */
|
||||
void *pci_cookie; /* interrupt cookie of parent bus */
|
||||
};
|
||||
|
||||
struct psycho_strayclr {
|
||||
struct psycho_softc *psc_sc;
|
||||
bus_addr_t psc_clr; /* clear register */
|
||||
};
|
||||
|
||||
#define PSYCHO_READ8(sc, off) \
|
||||
bus_space_read_8((sc)->sc_bustag, (sc)->sc_bushandle, (off))
|
||||
#define PSYCHO_WRITE8(sc, off, v) \
|
||||
bus_space_write_8((sc)->sc_bustag, (sc)->sc_bushandle, (off), (v))
|
||||
#define PCICTL_READ8(sc, off) \
|
||||
PSYCHO_READ8((sc), (sc)->sc_pcictl + (off))
|
||||
#define PCICTL_WRITE8(sc, off, v) \
|
||||
PSYCHO_WRITE8((sc), (sc)->sc_pcictl + (off), (v))
|
||||
|
||||
/*
|
||||
* "sabre" is the UltraSPARC IIi onboard UPA to PCI bridge. It manages a
|
||||
* single PCI bus and does not have a streaming buffer. It often has an APB
|
||||
@ -272,14 +288,17 @@ psycho_attach(device_t dev)
|
||||
char *model;
|
||||
phandle_t node;
|
||||
u_int64_t csr;
|
||||
u_long pci_ctl, mlen;
|
||||
u_long pcictl_offs, mlen;
|
||||
int psycho_br[2];
|
||||
int n, i, nreg, rid;
|
||||
#if defined(PSYCHO_DEBUG) || defined(PSYCHO_STRAY)
|
||||
u_long *map, *clr;
|
||||
bus_addr_t map, clr;
|
||||
u_int64_t mr;
|
||||
#endif
|
||||
#ifdef PSYCHO_STRAY
|
||||
struct psycho_strayclr *sclr;
|
||||
#endif
|
||||
|
||||
bootverbose = 1;
|
||||
node = nexus_get_node(dev);
|
||||
sc = device_get_softc(dev);
|
||||
if (OF_getprop(node, "compatible", compat, sizeof(compat)) == -1)
|
||||
@ -322,39 +341,15 @@ psycho_attach(device_t dev)
|
||||
panic("psycho_attach: %d not enough registers", nreg);
|
||||
sc->sc_basepaddr = (vm_offset_t)UPA_REG_PHYS(®[2]);
|
||||
mlen = UPA_REG_SIZE(®[2]);
|
||||
pci_ctl = UPA_REG_PHYS(®[0]);
|
||||
pcictl_offs = UPA_REG_PHYS(®[0]);
|
||||
} else {
|
||||
if (nreg <= 0)
|
||||
panic("psycho_attach: %d not enough registers", nreg);
|
||||
sc->sc_basepaddr = (vm_offset_t)UPA_REG_PHYS(®[0]);
|
||||
mlen = UPA_REG_SIZE(reg);
|
||||
pci_ctl = sc->sc_basepaddr +
|
||||
offsetof(struct psychoreg, psy_pcictl[0]);
|
||||
pcictl_offs = sc->sc_basepaddr + PSR_PCICTL0;
|
||||
}
|
||||
|
||||
if (pci_ctl < sc->sc_basepaddr)
|
||||
panic("psycho_attach: bogus pci control register location");
|
||||
pci_ctl -= sc->sc_basepaddr;
|
||||
rid = 0;
|
||||
sc->sc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
sc->sc_basepaddr, sc->sc_basepaddr + mlen - 1, mlen, RF_ACTIVE);
|
||||
if (sc->sc_mem_res == NULL ||
|
||||
rman_get_start(sc->sc_mem_res) != sc->sc_basepaddr)
|
||||
panic("psycho_attach: could not allocate device memory");
|
||||
sc->sc_bustag = rman_get_bustag(sc->sc_mem_res);
|
||||
sc->sc_bushandle = rman_get_bushandle(sc->sc_mem_res);
|
||||
if (sparc64_bus_mem_map(UPA_BUS_SPACE, sc->sc_basepaddr, mlen, 0, NULL,
|
||||
(void **)&sc->sc_regs))
|
||||
panic("psycho_attach: cannot map regs");
|
||||
csr = sc->sc_regs->psy_csr;
|
||||
sc->sc_ign = 0x7c0; /* APB IGN is always 0x7c */
|
||||
if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
|
||||
sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6;
|
||||
|
||||
device_printf(dev, "%s: impl %d, version %d: ign %x ",
|
||||
model, PSYCHO_GCSR_IMPL(csr), PSYCHO_GCSR_VERS(csr),
|
||||
sc->sc_ign);
|
||||
|
||||
/*
|
||||
* Match other psycho's that are already configured against
|
||||
* the base physical address. This will be the same for a
|
||||
@ -377,21 +372,45 @@ psycho_attach(device_t dev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (osc == NULL) {
|
||||
rid = 0;
|
||||
sc->sc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
sc->sc_basepaddr, sc->sc_basepaddr + mlen - 1, mlen,
|
||||
RF_ACTIVE);
|
||||
if (sc->sc_mem_res == NULL ||
|
||||
rman_get_start(sc->sc_mem_res) != sc->sc_basepaddr)
|
||||
panic("psycho_attach: can't allocate device memory");
|
||||
sc->sc_bustag = rman_get_bustag(sc->sc_mem_res);
|
||||
sc->sc_bushandle = rman_get_bushandle(sc->sc_mem_res);
|
||||
} else {
|
||||
/*
|
||||
* There's another psycho using the same register space. Copy the
|
||||
* relevant stuff.
|
||||
*/
|
||||
sc->sc_mem_res = NULL;
|
||||
sc->sc_bustag = osc->sc_bustag;
|
||||
sc->sc_bushandle = osc->sc_bushandle;
|
||||
}
|
||||
if (pcictl_offs < sc->sc_basepaddr)
|
||||
panic("psycho_attach: bogus pci control register location");
|
||||
sc->sc_pcictl = pcictl_offs - sc->sc_basepaddr;
|
||||
csr = PSYCHO_READ8(sc, PSR_CS);
|
||||
sc->sc_ign = 0x7c0; /* APB IGN is always 0x7c */
|
||||
if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
|
||||
sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6;
|
||||
|
||||
device_printf(dev, "%s: impl %d, version %d: ign %x ",
|
||||
model, (int)PSYCHO_GCSR_IMPL(csr), (int)PSYCHO_GCSR_VERS(csr),
|
||||
sc->sc_ign);
|
||||
|
||||
/*
|
||||
* Setup the PCI control register
|
||||
*/
|
||||
csr = bus_space_read_8(sc->sc_bustag, sc->sc_bushandle,
|
||||
pci_ctl + offsetof(struct pci_ctl, pci_csr));
|
||||
csr |= PCICTL_MRLM |
|
||||
PCICTL_ARB_PARK |
|
||||
PCICTL_ERRINTEN |
|
||||
PCICTL_4ENABLE;
|
||||
csr &= ~(PCICTL_SERR |
|
||||
PCICTL_CPU_PRIO |
|
||||
PCICTL_ARB_PRIO |
|
||||
csr = PCICTL_READ8(sc, PCR_CS);
|
||||
csr |= PCICTL_MRLM | PCICTL_ARB_PARK | PCICTL_ERRINTEN | PCICTL_4ENABLE;
|
||||
csr &= ~(PCICTL_SERR | PCICTL_CPU_PRIO | PCICTL_ARB_PRIO |
|
||||
PCICTL_RTRYWAIT);
|
||||
bus_space_write_8(sc->sc_bustag, sc->sc_bushandle,
|
||||
pci_ctl + offsetof(struct pci_ctl, pci_csr), csr);
|
||||
PCICTL_WRITE8(sc, PCR_CS, csr);
|
||||
|
||||
/* grab the psycho ranges */
|
||||
psycho_get_ranges(sc->sc_node, &sc->sc_range, &sc->sc_nrange);
|
||||
@ -446,14 +465,16 @@ psycho_attach(device_t dev)
|
||||
sc->sc_cfgt = psycho_alloc_bus_tag(sc, PCI_CONFIG_BUS_SPACE);
|
||||
if (bus_dma_tag_create(sc->sc_dmatag, 8, 1, 0, 0x3ffffffff, NULL, NULL,
|
||||
0x3ffffffff, 0xff, 0xffffffff, 0, &sc->sc_dmat) != 0)
|
||||
panic("bus_dma_tag_create failed");
|
||||
panic("psycho_attach: bus_dma_tag_create failed");
|
||||
/* Customize the tag */
|
||||
sc->sc_dmat->cookie = sc;
|
||||
sc->sc_dmat->dmamem_alloc = psycho_dmamem_alloc;
|
||||
sc->sc_dmat->dmamem_free = psycho_dmamem_free;
|
||||
sc->sc_dmat->dmamap_create = psycho_dmamap_create;
|
||||
sc->sc_dmat->dmamap_destroy = psycho_dmamap_destroy;
|
||||
sc->sc_dmat->dmamap_load = psycho_dmamap_load;
|
||||
sc->sc_dmat->dmamap_unload = psycho_dmamap_unload;
|
||||
sc->sc_dmat->dmamap_sync = psycho_dmamap_sync;
|
||||
sc->sc_dmat->dmamem_alloc = psycho_dmamem_alloc;
|
||||
sc->sc_dmat->dmamem_free = psycho_dmamem_free;
|
||||
/* XXX: register as root dma tag (kluge). */
|
||||
sparc64_root_dma_tag = sc->sc_dmat;
|
||||
|
||||
@ -487,28 +508,32 @@ psycho_attach(device_t dev)
|
||||
* XXX Not all controllers have these, but installing them
|
||||
* is better than trying to sort through this mess.
|
||||
*/
|
||||
psycho_set_intr(sc, 0, dev, &sc->sc_regs->ue_int_map,
|
||||
INTR_TYPE_MISC | INTR_FAST, psycho_ue);
|
||||
psycho_set_intr(sc, 1, dev, &sc->sc_regs->ce_int_map,
|
||||
INTR_TYPE_MISC, psycho_ce);
|
||||
psycho_set_intr(sc, 2, dev,
|
||||
&sc->sc_regs->pciaerr_int_map, INTR_TYPE_MISC | INTR_FAST,
|
||||
psycho_set_intr(sc, 0, dev, PSR_UE_INT_MAP, INTR_FAST,
|
||||
psycho_ue);
|
||||
psycho_set_intr(sc, 1, dev, PSR_CE_INT_MAP, 0, psycho_ce);
|
||||
psycho_set_intr(sc, 2, dev, PSR_PCIAERR_INT_MAP, INTR_FAST,
|
||||
psycho_bus_a);
|
||||
psycho_set_intr(sc, 3, dev,
|
||||
&sc->sc_regs->pciberr_int_map, INTR_TYPE_MISC | INTR_FAST,
|
||||
psycho_set_intr(sc, 3, dev, PSR_PCIBERR_INT_MAP, INTR_FAST,
|
||||
psycho_bus_b);
|
||||
psycho_set_intr(sc, 4, dev, &sc->sc_regs->power_int_map,
|
||||
INTR_TYPE_MISC | INTR_FAST, psycho_powerfail);
|
||||
psycho_set_intr(sc, 4, dev, PSR_POWER_INT_MAP, INTR_FAST,
|
||||
psycho_powerfail);
|
||||
#ifdef PSYCHO_MAP_WAKEUP
|
||||
/*
|
||||
* On some models, this is mapped to the same interrupt as
|
||||
* pciberr by default, so leave it alone for now since
|
||||
* psycho_wakeup() doesn't do anything useful anyway.
|
||||
*/
|
||||
psycho_set_intr(sc, 5, dev, &sc->sc_regs->pwrmgt_int_map,
|
||||
INTR_TYPE_MISC, psycho_wakeup);
|
||||
psycho_set_intr(sc, 5, dev, PSR_PWRMGT_INT_MAP, 0,
|
||||
psycho_wakeup);
|
||||
#endif /* PSYCHO_MAP_WAKEUP */
|
||||
|
||||
|
||||
/* Initialize the counter-timer if we handle a psycho. */
|
||||
if (sc->sc_mode == PSYCHO_MODE_PSYCHO) {
|
||||
sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle,
|
||||
PSR_TC0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup IOMMU and PCI configuration if we're the first
|
||||
* of a pair of psycho's to arrive here.
|
||||
@ -519,10 +544,21 @@ psycho_attach(device_t dev)
|
||||
*
|
||||
* For the moment, 32KB should be more than enough.
|
||||
*/
|
||||
sc->sc_is = malloc(sizeof(struct iommu_state), M_DEVBUF,
|
||||
M_NOWAIT);
|
||||
if (sc->sc_is == NULL)
|
||||
panic("psycho_attach: malloc iommu_state failed");
|
||||
sc->sc_is->is_sb[0] = 0;
|
||||
sc->sc_is->is_sb[1] = 0;
|
||||
if (OF_getproplen(sc->sc_node, "no-streaming-cache") < 0)
|
||||
sc->sc_is->is_sb[0] = sc->sc_pcictl + PCR_STRBUF;
|
||||
psycho_iommu_init(sc, 2);
|
||||
} else {
|
||||
/* Just copy IOMMU state, config tag and address */
|
||||
sc->sc_is = osc->sc_is;
|
||||
if (OF_getproplen(sc->sc_node, "no-streaming-cache") < 0)
|
||||
sc->sc_is->is_sb[1] = sc->sc_pcictl + PCR_STRBUF;
|
||||
iommu_reset(sc->sc_is);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -534,42 +570,42 @@ psycho_attach(device_t dev)
|
||||
* will never be cleared).
|
||||
*/
|
||||
#if defined(PSYCHO_DEBUG) || defined(PSYCHO_STRAY)
|
||||
for (map = &sc->sc_regs->pcia0_int_map,
|
||||
clr = &sc->sc_regs->pcia0_int_clr[0], n = 0;
|
||||
map <= &sc->sc_regs->pcib3_int_map; map++, clr += 4, n++) {
|
||||
for (map = PSR_PCIA0_INT_MAP, clr = PSR_PCIA0_INT_CLR, n = 0;
|
||||
map <= PSR_PCIB3_INT_MAP; map += 8, clr += 32, n++) {
|
||||
mr = PSYCHO_READ8(sc, map);
|
||||
#ifdef PSYCHO_DEBUG
|
||||
device_printf(dev, "intr map (pci) %d: %lx\n", n, *map);
|
||||
device_printf(dev, "intr map (pci) %d: %#lx\n", n, (u_long)mr);
|
||||
#endif
|
||||
*map &= ~INTMAP_V;
|
||||
membar(StoreStore);
|
||||
PSYCHO_WRITE8(sc, map, mr & ~INTMAP_V);
|
||||
for (i = 0; i < 4; i++)
|
||||
clr[i] = 0;
|
||||
membar(StoreStore);
|
||||
*map |= INTMAP_V;
|
||||
PCICTL_WRITE8(sc, clr + i * 8, 0);
|
||||
PSYCHO_WRITE8(sc, map, mr | INTMAP_V);
|
||||
}
|
||||
for (map = &sc->sc_regs->scsi_int_map, n = 0,
|
||||
clr = &sc->sc_regs->scsi_int_clr, n = 0;
|
||||
map <= &sc->sc_regs->ffb1_int_map; map++, clr++, n++) {
|
||||
for (map = PSR_SCSI_INT_MAP, clr = PSR_SCSI_INT_CLR, n = 0;
|
||||
map <= PSR_FFB1_INT_MAP; map += 8, clr += 8, n++) {
|
||||
mr = PSYCHO_READ8(sc, map);
|
||||
#ifdef PSYCHO_DEBUG
|
||||
device_printf(dev, "intr map (obio) %d: %lx, clr: %p\n", n,
|
||||
*map, clr);
|
||||
device_printf(dev, "intr map (obio) %d: %#lx, clr: %#lx\n", n,
|
||||
(u_long)mr, (u_long)clr);
|
||||
#endif
|
||||
*map &= ~INTMAP_V;
|
||||
membar(StoreStore);
|
||||
*clr = 0;
|
||||
PSYCHO_WRITE8(sc, map, mr & ~INTMAP_V);
|
||||
PSYCHO_WRITE8(sc, clr, 0);
|
||||
#ifdef PSYCHO_STRAY
|
||||
/*
|
||||
* This can cause interrupt storms, and is therefore disabled
|
||||
* by default.
|
||||
* XXX: use intr_setup() to not confuse higher level code
|
||||
*/
|
||||
if (INTVEC(*map) != 0x7e6 && INTVEC(*map) != 0x7e7 &&
|
||||
INTVEC(*map) != 0)
|
||||
intr_setup(PIL_LOW, intr_dequeue, INTVEC(*map), psycho_intr_stray,
|
||||
(void *)clr);
|
||||
if (INTVEC(mr) != 0x7e6 && INTVEC(mr) != 0x7e7 &&
|
||||
INTVEC(mr) != 0) {
|
||||
sclr = malloc(sizeof(*sclr), M_DEVBUF, M_WAITOK);
|
||||
sclr->psc_sc = sc;
|
||||
sclr->psc_clr = clr;
|
||||
intr_setup(PIL_LOW, intr_dequeue, INTVEC(mr),
|
||||
psycho_intr_stray, sclr);
|
||||
}
|
||||
#endif
|
||||
membar(StoreStore);
|
||||
*map |= INTMAP_V;
|
||||
PSYCHO_WRITE8(sc, map, mr | INTMAP_V);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -590,34 +626,39 @@ psycho_attach(device_t dev)
|
||||
|
||||
static void
|
||||
psycho_set_intr(struct psycho_softc *sc, int index,
|
||||
device_t dev, u_long *map, int iflags, driver_intr_t handler)
|
||||
device_t dev, bus_addr_t map, int iflags, driver_intr_t handler)
|
||||
{
|
||||
int rid;
|
||||
int rid, vec;
|
||||
u_int64_t mr;
|
||||
|
||||
mr = PSYCHO_READ8(sc, map);
|
||||
vec = INTVEC(mr);
|
||||
sc->sc_irq_res[index] = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
|
||||
INTVEC(*map), INTVEC(*map), 1, RF_ACTIVE);
|
||||
vec, vec, 1, RF_ACTIVE);
|
||||
if (sc->sc_irq_res[index] == NULL)
|
||||
panic("psycho_set_intr: failed to get interupt");
|
||||
panic("psycho_set_intr: failed to get interrupt");
|
||||
bus_setup_intr(dev, sc->sc_irq_res[index], INTR_TYPE_MISC | iflags,
|
||||
handler, sc, &sc->sc_ihand[index]);
|
||||
*map |= INTMAP_V;
|
||||
PSYCHO_WRITE8(sc, map, mr | INTMAP_V);
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_find_intrmap(struct psycho_softc *sc, int ino, u_long **intrmapptr,
|
||||
u_long **intrclrptr, u_long *intrdiagptr)
|
||||
psycho_find_intrmap(struct psycho_softc *sc, int ino, bus_addr_t *intrmapptr,
|
||||
bus_addr_t *intrclrptr, bus_addr_t *intrdiagptr)
|
||||
{
|
||||
u_long *intrmap, *intrclr, diag;
|
||||
bus_addr_t intrmap, intrclr;
|
||||
u_int64_t im;
|
||||
u_long diag;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
/* Hunt thru obio first */
|
||||
diag = sc->sc_regs->obio_int_diag;
|
||||
for (intrmap = &sc->sc_regs->scsi_int_map,
|
||||
intrclr = &sc->sc_regs->scsi_int_clr;
|
||||
intrmap <= &sc->sc_regs->ffb1_int_map;
|
||||
intrmap++, intrclr++, diag >>= 2) {
|
||||
if (INTINO(*intrmap) == ino) {
|
||||
diag = PSYCHO_READ8(sc, PSR_OBIO_INT_DIAG);
|
||||
for (intrmap = PSR_SCSI_INT_MAP, intrclr = PSR_SCSI_INT_CLR;
|
||||
intrmap <= PSR_FFB1_INT_MAP; intrmap += 8, intrclr += 8,
|
||||
diag >>= 2) {
|
||||
im = PSYCHO_READ8(sc, intrmap);
|
||||
if (INTINO(im) == ino) {
|
||||
diag &= 2;
|
||||
found = 1;
|
||||
break;
|
||||
@ -625,14 +666,14 @@ psycho_find_intrmap(struct psycho_softc *sc, int ino, u_long **intrmapptr,
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
diag = sc->sc_regs->pci_int_diag;
|
||||
diag = PSYCHO_READ8(sc, PSR_PCI_INT_DIAG);
|
||||
/* Now do PCI interrupts */
|
||||
for (intrmap = &sc->sc_regs->pcia0_int_map,
|
||||
intrclr = &sc->sc_regs->pcia0_int_clr[0];
|
||||
intrmap <= &sc->sc_regs->pcib3_int_map;
|
||||
intrmap++, intrclr += 4, diag >>= 8) {
|
||||
if (((*intrmap ^ ino) & 0x3c) == 0) {
|
||||
intrclr += ino & 3;
|
||||
for (intrmap = PSR_PCIA0_INT_MAP, intrclr = PSR_PCIA0_INT_CLR;
|
||||
intrmap <= PSR_PCIB3_INT_MAP; intrmap += 8, intrclr += 32,
|
||||
diag >>= 8) {
|
||||
im = PSYCHO_READ8(sc, intrmap);
|
||||
if (((im ^ ino) & 0x3c) == 0) {
|
||||
intrclr += 8 * (ino & 3);
|
||||
diag = (diag >> ((ino & 3) * 2)) & 2;
|
||||
found = 1;
|
||||
break;
|
||||
@ -665,60 +706,59 @@ static void
|
||||
psycho_ue(void *arg)
|
||||
{
|
||||
struct psycho_softc *sc = (struct psycho_softc *)arg;
|
||||
struct psychoreg *regs = sc->sc_regs;
|
||||
u_int64_t afar, afsr;
|
||||
|
||||
sc->sc_regs->ue_int_clr = 0;
|
||||
afar = PSYCHO_READ8(sc, PSR_UE_AFA);
|
||||
afsr = PSYCHO_READ8(sc, PSR_UE_AFS);
|
||||
/* It's uncorrectable. Dump the regs and panic. */
|
||||
panic("%s: uncorrectable DMA error AFAR %llx AFSR %llx\n",
|
||||
device_get_name(sc->sc_dev),
|
||||
(long long)regs->psy_ue_afar, (long long)regs->psy_ue_afsr);
|
||||
panic("%s: uncorrectable DMA error AFAR %#lx AFSR %#lx\n",
|
||||
device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr);
|
||||
}
|
||||
|
||||
static void
|
||||
psycho_ce(void *arg)
|
||||
{
|
||||
struct psycho_softc *sc = (struct psycho_softc *)arg;
|
||||
struct psychoreg *regs = sc->sc_regs;
|
||||
u_int64_t afar, afsr;
|
||||
|
||||
sc->sc_regs->ce_int_clr = 0;
|
||||
PSYCHO_WRITE8(sc, PSR_CE_INT_CLR, 0);
|
||||
afar = PSYCHO_READ8(sc, PSR_CE_AFA);
|
||||
afsr = PSYCHO_READ8(sc, PSR_CE_AFS);
|
||||
/* It's correctable. Dump the regs and continue. */
|
||||
printf("%s: correctable DMA error AFAR %llx AFSR %llx\n",
|
||||
device_get_name(sc->sc_dev),
|
||||
(long long)regs->psy_ce_afar, (long long)regs->psy_ce_afsr);
|
||||
printf("%s: correctable DMA error AFAR %#lx AFSR %#lx\n",
|
||||
device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr);
|
||||
}
|
||||
|
||||
static void
|
||||
psycho_bus_a(void *arg)
|
||||
{
|
||||
struct psycho_softc *sc = (struct psycho_softc *)arg;
|
||||
struct psychoreg *regs = sc->sc_regs;
|
||||
u_int64_t afar, afsr;
|
||||
|
||||
sc->sc_regs->pciaerr_int_clr = 0;
|
||||
afar = PSYCHO_READ8(sc, PSR_PCICTL0 + PCR_AFA);
|
||||
afsr = PSYCHO_READ8(sc, PSR_PCICTL0 + PCR_AFS);
|
||||
/* It's uncorrectable. Dump the regs and panic. */
|
||||
panic("%s: PCI bus A error AFAR %lx AFSR %lx\n",
|
||||
device_get_name(sc->sc_dev),
|
||||
regs->psy_pcictl[0].pci_afar, regs->psy_pcictl[0].pci_afsr);
|
||||
panic("%s: PCI bus A error AFAR %#lx AFSR %#lx\n",
|
||||
device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr);
|
||||
}
|
||||
|
||||
static void
|
||||
psycho_bus_b(void *arg)
|
||||
{
|
||||
struct psycho_softc *sc = (struct psycho_softc *)arg;
|
||||
struct psychoreg *regs = sc->sc_regs;
|
||||
u_int64_t afar, afsr;
|
||||
|
||||
sc->sc_regs->pciberr_int_clr = 0;
|
||||
afar = PSYCHO_READ8(sc, PSR_PCICTL1 + PCR_AFA);
|
||||
afsr = PSYCHO_READ8(sc, PSR_PCICTL1 + PCR_AFS);
|
||||
/* It's uncorrectable. Dump the regs and panic. */
|
||||
panic("%s: PCI bus B error AFAR %lx AFSR %lx\n",
|
||||
device_get_name(sc->sc_dev),
|
||||
regs->psy_pcictl[1].pci_afar, regs->psy_pcictl[1].pci_afsr);
|
||||
panic("%s: PCI bus B error AFAR %#lx AFSR %#lx\n",
|
||||
device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr);
|
||||
}
|
||||
|
||||
static void
|
||||
psycho_powerfail(void *arg)
|
||||
{
|
||||
struct psycho_softc *sc = (struct psycho_softc *)arg;
|
||||
|
||||
sc->sc_regs->power_int_clr = 0;
|
||||
/* We lost power. Try to shut down NOW. */
|
||||
printf("Power Failure Detected: Shutting down NOW.\n");
|
||||
shutdown_nice(0);
|
||||
@ -730,7 +770,7 @@ psycho_wakeup(void *arg)
|
||||
{
|
||||
struct psycho_softc *sc = (struct psycho_softc *)arg;
|
||||
|
||||
sc->sc_regs->pwrmgt_int_clr = 0;
|
||||
PSYCHO_WRITE8(sc, PSR_PWRMGT_INT_CLR, 0);
|
||||
/* Gee, we don't really have a framework to deal with this properly. */
|
||||
printf("%s: power management wakeup\n", device_get_name(sc->sc_dev));
|
||||
}
|
||||
@ -741,30 +781,20 @@ void
|
||||
psycho_iommu_init(struct psycho_softc *sc, int tsbsize)
|
||||
{
|
||||
char *name;
|
||||
struct iommu_state *is;
|
||||
struct iommu_state *is = sc->sc_is;
|
||||
u_int32_t iobase = -1;
|
||||
int *vdma = NULL;
|
||||
int nitem;
|
||||
|
||||
is = malloc(sizeof(struct iommu_state), M_DEVBUF, M_NOWAIT);
|
||||
if (is == NULL)
|
||||
panic("psycho_iommu_init: malloc failed");
|
||||
|
||||
sc->sc_is = is;
|
||||
|
||||
/* punch in our copies */
|
||||
is->is_bustag = sc->sc_bustag;
|
||||
is->is_iommu = &sc->sc_regs->psy_iommu;
|
||||
is->is_dtag = &sc->sc_regs->tlb_tag_diag[0];
|
||||
is->is_ddram = &sc->sc_regs->tlb_data_diag[0];
|
||||
is->is_dqueue = &sc->sc_regs->iommu_queue_diag[0];
|
||||
is->is_dva = &sc->sc_regs->iommu_svadiag;
|
||||
is->is_dtcmp = &sc->sc_regs->iommu_tlb_comp_diag;
|
||||
|
||||
if (OF_getproplen(sc->sc_node, "no-streaming-cache") < 0)
|
||||
is->is_sb = 0;
|
||||
else
|
||||
is->is_sb = &sc->sc_regs->psy_iommu_strbuf;
|
||||
is->is_bushandle = sc->sc_bushandle;
|
||||
is->is_iommu = PSR_IOMMU;
|
||||
is->is_dtag = PSR_IOMMU_TLB_TAG_DIAG;
|
||||
is->is_ddram = PSR_IOMMU_TLB_DATA_DIAG;
|
||||
is->is_dqueue = PSR_IOMMU_QUEUE_DIAG;
|
||||
is->is_dva = PSR_IOMMU_SVADIAG;
|
||||
is->is_dtcmp = PSR_IOMMU_TLB_CMP_DIAG;
|
||||
|
||||
/*
|
||||
* Separate the men from the boys. Get the `virtual-dma'
|
||||
@ -930,7 +960,7 @@ psycho_route_interrupt(device_t bus, device_t dev, int pin)
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_read_ivar(device_t dev, device_t child, int which, u_long *result)
|
||||
psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
|
||||
@ -950,8 +980,8 @@ psycho_intr_stub(void *arg)
|
||||
struct psycho_clr *pc;
|
||||
|
||||
pc = (struct psycho_clr *)arg;
|
||||
*pc->pci_clr = 0;
|
||||
pc->pci_handler(pc->pci_arg);
|
||||
PSYCHO_WRITE8(pc->pci_sc, pc->pci_clr, 0);
|
||||
}
|
||||
|
||||
#ifdef PSYCHO_STRAY
|
||||
@ -963,8 +993,9 @@ psycho_intr_stub(void *arg)
|
||||
static void
|
||||
psycho_intr_stray(void *arg)
|
||||
{
|
||||
struct psycho_strayclr *sclr = arg;
|
||||
|
||||
*((u_long *)arg) = 0;
|
||||
PSYCHO_WRITE8(sclr->psc_sc, sclr->psc_clr, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -975,14 +1006,13 @@ psycho_setup_intr(device_t dev, device_t child,
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
struct psycho_clr *pc;
|
||||
u_long *intrmapptr, *intrclrptr;
|
||||
int ino;
|
||||
int error;
|
||||
bus_addr_t intrmapptr, intrclrptr;
|
||||
long vec = rman_get_start(ires);
|
||||
u_int64_t mr;
|
||||
int ino, error;
|
||||
|
||||
sc = (struct psycho_softc *)device_get_softc(dev);
|
||||
pc = (struct psycho_clr *)
|
||||
malloc(sizeof(*pc), M_DEVBUF, M_NOWAIT);
|
||||
pc = (struct psycho_clr *)malloc(sizeof(*pc), M_DEVBUF, M_NOWAIT);
|
||||
if (pc == NULL)
|
||||
return (NULL);
|
||||
|
||||
@ -1004,15 +1034,16 @@ psycho_setup_intr(device_t dev, device_t child,
|
||||
}
|
||||
|
||||
#ifdef PSYCHO_DEBUG
|
||||
device_printf(dev, "psycho_setup_intr: INO %d, map %p, clr %p\n", ino,
|
||||
intrmapptr, intrclrptr);
|
||||
device_printf(dev, "psycho_setup_intr: INO %d, map %#lx, clr %#lx\n",
|
||||
ino, (u_long)intrmapptr, (u_long)intrclrptr);
|
||||
#endif
|
||||
pc->pci_sc = sc;
|
||||
pc->pci_arg = arg;
|
||||
pc->pci_handler = intr;
|
||||
pc->pci_clr = intrclrptr;
|
||||
/* Disable the interrupt while we fiddle with it */
|
||||
*intrmapptr &= ~INTMAP_V;
|
||||
membar(Sync);
|
||||
mr = PSYCHO_READ8(sc, intrmapptr);
|
||||
PSYCHO_WRITE8(sc, intrmapptr, mr & ~INTMAP_V);
|
||||
error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
|
||||
psycho_intr_stub, pc, cookiep);
|
||||
if (error != 0) {
|
||||
@ -1026,14 +1057,13 @@ psycho_setup_intr(device_t dev, device_t child,
|
||||
* Clear the interrupt, it might have been triggered before it was
|
||||
* set up.
|
||||
*/
|
||||
*intrclrptr = 0;
|
||||
membar(StoreStore);
|
||||
PSYCHO_WRITE8(sc, intrclrptr, 0);
|
||||
/*
|
||||
* Enable the interrupt now we have the handler installed.
|
||||
* Read the current value as we can't change it besides the
|
||||
* valid bit so so make sure only this bit is changed.
|
||||
*/
|
||||
*intrmapptr |= INTMAP_V;
|
||||
PSYCHO_WRITE8(sc, intrmapptr, mr | INTMAP_V);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1140,7 +1170,7 @@ psycho_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
|
||||
static int
|
||||
psycho_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *r)
|
||||
struct resource *r)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -1195,10 +1225,10 @@ psycho_alloc_bus_tag(struct psycho_softc *sc, int type)
|
||||
{
|
||||
bus_space_tag_t bt;
|
||||
|
||||
bt = (bus_space_tag_t)
|
||||
malloc(sizeof(struct bus_space_tag), M_DEVBUF, M_NOWAIT);
|
||||
bt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (bt == NULL)
|
||||
panic("could not allocate psycho bus tag");
|
||||
panic("psycho_alloc_bus_tag: out of memory");
|
||||
|
||||
bzero(bt, sizeof *bt);
|
||||
bt->cookie = sc;
|
||||
@ -1225,7 +1255,26 @@ psycho_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
|
||||
struct psycho_softc *sc;
|
||||
|
||||
sc = (struct psycho_softc *)dmat->cookie;
|
||||
return (iommu_dvmamem_free(dmat, sc->sc_is, vaddr, map));
|
||||
iommu_dvmamem_free(dmat, sc->sc_is, vaddr, map);
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
|
||||
sc = (struct psycho_softc *)dmat->cookie;
|
||||
return (iommu_dvmamap_create(dmat, sc->sc_is, flags, mapp));
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
|
||||
sc = (struct psycho_softc *)dmat->cookie;
|
||||
return (iommu_dvmamap_destroy(dmat, sc->sc_is, map));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -45,23 +45,146 @@
|
||||
* PSYCHO implements two PCI buses, A and B.
|
||||
*/
|
||||
|
||||
struct psychoreg {
|
||||
struct upareg {
|
||||
/* UPA port ID register */ /* 1fe.0000.0000 */
|
||||
u_int64_t upa_portid;
|
||||
/* UPA config register */ /* 1fe.0000.0008 */
|
||||
u_int64_t upa_config;
|
||||
} sys_upa;
|
||||
/*
|
||||
* psycho register offset.s
|
||||
*
|
||||
* NB: FFB0 and FFB1 intr map regs also appear at 0x6000 and 0x8000
|
||||
* respectively.
|
||||
*/
|
||||
#define PSR_UPA_PORTID 0x0000 /* UPA port ID register */
|
||||
#define PSR_UPA_CONFIG 0x0008 /* UPA config register */
|
||||
#define PSR_CS 0x0010 /* PSYCHO control/status register */
|
||||
#define PSR_ECCC 0x0020 /* ECC control register */
|
||||
#define PSR_UE_AFS 0x0030 /* Uncorrectable Error AFSR */
|
||||
#define PSR_UE_AFA 0x0038 /* Uncorrectable Error AFAR */
|
||||
#define PSR_CE_AFS 0x0040 /* Correctable Error AFSR */
|
||||
#define PSR_CE_AFA 0x0048 /* Correctable Error AFAR */
|
||||
#define PSR_PM_CTL 0x0100 /* Performance monitor control reg */
|
||||
#define PSR_PM_COUNT 0x0108 /* Performance monitor counter reg */
|
||||
#define PSR_IOMMU 0x0200 /* IOMMU registers. */
|
||||
#define PSR_PCIA0_INT_MAP 0x0c00 /* PCI bus a slot 0 irq map reg */
|
||||
#define PSR_PCIA1_INT_MAP 0x0c08 /* PCI bus a slot 1 irq map reg */
|
||||
#define PSR_PCIA2_INT_MAP 0x0c10 /* PCI bus a slot 2 irq map reg (IIi) */
|
||||
#define PSR_PCIA3_INT_MAP 0x0c18 /* PCI bus a slot 3 irq map reg (IIi) */
|
||||
#define PSR_PCIB0_INT_MAP 0x0c20 /* PCI bus b slot 0 irq map reg */
|
||||
#define PSR_PCIB1_INT_MAP 0x0c28 /* PCI bus b slot 1 irq map reg */
|
||||
#define PSR_PCIB2_INT_MAP 0x0c30 /* PCI bus b slot 2 irq map reg */
|
||||
#define PSR_PCIB3_INT_MAP 0x0c38 /* PCI bus b slot 3 irq map reg */
|
||||
#define PSR_SCSI_INT_MAP 0x1000 /* SCSI interrupt map reg */
|
||||
#define PSR_ETHER_INT_MAP 0x1008 /* ethernet interrupt map reg */
|
||||
#define PSR_BPP_INT_MAP 0x1010 /* parallel interrupt map reg */
|
||||
#define PSR_AUDIOR_INT_MAP 0x1018 /* audio record interrupt map reg */
|
||||
#define PSR_AUDIOP_INT_MAP 0x1020 /* audio playback interrupt map reg */
|
||||
#define PSR_POWER_INT_MAP 0x1028 /* power fail interrupt map reg */
|
||||
#define PSR_SKBDMS_INT_MAP 0x1030 /* serial/kbd/mouse interrupt map reg */
|
||||
#define PSR_FD_INT_MAP 0x1038 /* floppy interrupt map reg */
|
||||
#define PSR_SPARE_INT_MAP 0x1040 /* spare interrupt map reg */
|
||||
#define PSR_KBD_INT_MAP 0x1048 /* kbd [unused] interrupt map reg */
|
||||
#define PSR_MOUSE_INT_MAP 0x1050 /* mouse [unused] interrupt map reg */
|
||||
#define PSR_SERIAL_INT_MAP 0x1058 /* second serial interrupt map reg */
|
||||
#define PSR_TIMER0_INT_MAP 0x1060 /* timer 0 interrupt map reg */
|
||||
#define PSR_TIMER1_INT_MAP 0x1068 /* timer 1 interrupt map reg */
|
||||
#define PSR_UE_INT_MAP 0x1070 /* UE interrupt map reg */
|
||||
#define PSR_CE_INT_MAP 0x1078 /* CE interrupt map reg */
|
||||
#define PSR_PCIAERR_INT_MAP 0x1080 /* PCI bus a error interrupt map reg */
|
||||
#define PSR_PCIBERR_INT_MAP 0x1088 /* PCI bus b error interrupt map reg */
|
||||
#define PSR_PWRMGT_INT_MAP 0x1090 /* power mgmt wake interrupt map reg */
|
||||
#define PSR_FFB0_INT_MAP 0x1098 /* FFB0 graphics interrupt map reg */
|
||||
#define PSR_FFB1_INT_MAP 0x10a0 /* FFB1 graphics interrupt map reg */
|
||||
/* Note: clear interrupt 0 registers are not really used */
|
||||
#define PSR_PCIA0_INT_CLR 0x1400 /* PCI a slot 0 clear int regs 0..3 */
|
||||
#define PSR_PCIA1_INT_CLR 0x1420 /* PCI a slot 1 clear int regs 0..3 */
|
||||
#define PSR_PCIA2_INT_CLR 0x1440 /* PCI a slot 1 clear int regs 0..3 */
|
||||
#define PSR_PCIA3_INT_CLR 0x1460 /* PCI a slot 1 clear int regs 0..3 */
|
||||
#define PSR_PCIB0_INT_CLR 0x1480 /* PCI b slot 0 clear int regs 0..3 */
|
||||
#define PSR_PCIB1_INT_CLR 0x14a0 /* PCI b slot 1 clear int regs 0..3 */
|
||||
#define PSR_PCIB2_INT_CLR 0x14c0 /* PCI b slot 2 clear int regs 0..3 */
|
||||
#define PSR_PCIB3_INT_CLR 0x14d0 /* PCI b slot 3 clear int regs 0..3 */
|
||||
#define PSR_SCSI_INT_CLR 0x1800 /* SCSI clear int reg */
|
||||
#define PSR_ETHER_INT_CLR 0x1808 /* ethernet clear int reg */
|
||||
#define PSR_BPP_INT_CLR 0x1810 /* parallel clear int reg */
|
||||
#define PSR_AUDIOR_INT_CLR 0x1818 /* audio record clear int reg */
|
||||
#define PSR_AUDIOP_INT_CLR 0x1820 /* audio playback clear int reg */
|
||||
#define PSR_POWER_INT_CLR 0x1828 /* power fail clear int reg */
|
||||
#define PSR_SKBDMS_INT_CLR 0x1830 /* serial/kbd/mouse clear int reg */
|
||||
#define PSR_FD_INT_CLR 0x1838 /* floppy clear int reg */
|
||||
#define PSR_SPARE_INT_CLR 0x1840 /* spare clear int reg */
|
||||
#define PSR_KBD_INT_CLR 0x1848 /* kbd [unused] clear int reg */
|
||||
#define PSR_MOUSE_INT_CLR 0x1850 /* mouse [unused] clear int reg */
|
||||
#define PSR_SERIAL_INT_CLR 0x1858 /* second serial clear int reg */
|
||||
#define PSR_TIMER0_INT_CLR 0x1860 /* timer 0 clear int reg */
|
||||
#define PSR_TIMER1_INT_CLR 0x1868 /* timer 1 clear int reg */
|
||||
#define PSR_UE_INT_CLR 0x1870 /* UE clear int reg */
|
||||
#define PSR_CE_INT_CLR 0x1878 /* CE clear int reg */
|
||||
#define PSR_PCIAERR_INT_CLR 0x1880 /* PCI bus a error clear int reg */
|
||||
#define PSR_PCIBERR_INT_CLR 0x1888 /* PCI bus b error clear int reg */
|
||||
#define PSR_PWRMGT_INT_CLR 0x1890 /* power mgmt wake clr interrupt reg */
|
||||
#define PSR_INTR_RETRY_TIM 0x1a00 /* interrupt retry timer */
|
||||
#define PSR_TC0 0x1c00 /* timer/counter 0 */
|
||||
#define PSR_TC1 0x1c10 /* timer/counter 1 */
|
||||
#define PSR_DMA_WRITE_SYNC 0x1c20 /* PCI DMA write sync register (IIi) */
|
||||
#define PSR_PCICTL0 0x2000 /* PCICTL registers for 1st psycho. */
|
||||
#define PSR_PCICTL1 0x4000 /* PCICTL registers for 2nd psycho. */
|
||||
#define PSR_DMA_SCB_DIAG0 0xa000 /* DMA scoreboard diag reg 0 */
|
||||
#define PSR_DMA_SCB_DIAG1 0xa008 /* DMA scoreboard diag reg 1 */
|
||||
#define PSR_IOMMU_SVADIAG 0xa400 /* IOMMU virtual addr diag reg */
|
||||
#define PSR_IOMMU_TLB_CMP_DIAG 0xa408 /* IOMMU TLB tag compare diag reg */
|
||||
#define PSR_IOMMU_QUEUE_DIAG 0xa500 /* IOMMU LRU queue diag regs 0..15 */
|
||||
#define PSR_IOMMU_TLB_TAG_DIAG 0xa580 /* TLB tag diag regs 0..15 */
|
||||
#define PSR_IOMMU_TLB_DATA_DIAG 0xa600 /* TLB data RAM diag regs 0..15 */
|
||||
#define PSR_PCI_INT_DIAG 0xa800 /* PCI int state diag reg */
|
||||
#define PSR_OBIO_INT_DIAG 0xa808 /* OBIO and misc int state diag reg */
|
||||
#define PSR_STRBUF_DIAG 0xb000 /* Streaming buffer diag regs */
|
||||
/*
|
||||
* Here is the rest of the map, which we're not specifying:
|
||||
*
|
||||
* 1fe.0100.0000 - 1fe.01ff.ffff PCI configuration space
|
||||
* 1fe.0100.0000 - 1fe.0100.00ff PCI B configuration header
|
||||
* 1fe.0101.0000 - 1fe.0101.00ff PCI A configuration header
|
||||
* 1fe.0200.0000 - 1fe.0200.ffff PCI A I/O space
|
||||
* 1fe.0201.0000 - 1fe.0201.ffff PCI B I/O space
|
||||
* 1ff.0000.0000 - 1ff.7fff.ffff PCI A memory space
|
||||
* 1ff.8000.0000 - 1ff.ffff.ffff PCI B memory space
|
||||
*
|
||||
* NB: config and I/O space can use 1-4 byte accesses, not 8 byte
|
||||
* accesses. Memory space can use any sized accesses.
|
||||
*
|
||||
* Note that the SUNW,sabre/SUNW,simba combinations found on the
|
||||
* Ultra5 and Ultra10 machines uses slightly differrent addresses
|
||||
* than the above. This is mostly due to the fact that the APB is
|
||||
* a multi-function PCI device with two PCI bridges, and the U2P is
|
||||
* two separate PCI bridges. It uses the same PCI configuration
|
||||
* space, though the configuration header for each PCI bus is
|
||||
* located differently due to the SUNW,simba PCI busses being
|
||||
* function 0 and function 1 of the APB, whereas the psycho's are
|
||||
* each their own PCI device. The I/O and memory spaces are each
|
||||
* split into 8 equally sized areas (8x2MB blocks for I/O space,
|
||||
* and 8x512MB blocks for memory space). These are allocated in to
|
||||
* either PCI A or PCI B, or neither in the APB's `I/O Address Map
|
||||
* Register A/B' (0xde) and `Memory Address Map Register A/B' (0xdf)
|
||||
* registers of each simba. We must ensure that both of the
|
||||
* following are correct (the prom should do this for us):
|
||||
*
|
||||
* (PCI A Memory Address Map) & (PCI B Memory Address Map) == 0
|
||||
*
|
||||
* (PCI A I/O Address Map) & (PCI B I/O Address Map) == 0
|
||||
*
|
||||
* 1fe.0100.0000 - 1fe.01ff.ffff PCI configuration space
|
||||
* 1fe.0100.0800 - 1fe.0100.08ff PCI B configuration header
|
||||
* 1fe.0100.0900 - 1fe.0100.09ff PCI A configuration header
|
||||
* 1fe.0200.0000 - 1fe.02ff.ffff PCI I/O space (divided)
|
||||
* 1ff.0000.0000 - 1ff.ffff.ffff PCI memory space (divided)
|
||||
*/
|
||||
|
||||
/* PSYCHO control/status register */ /* 1fe.0000.0010 */
|
||||
u_int64_t psy_csr;
|
||||
/*
|
||||
* 63 59 55 50 45 4 3 2 1 0
|
||||
* +------+------+------+------+--//---+--------+-------+-----+------+
|
||||
* | IMPL | VERS | MID | IGN | xxx | APCKEN | APERR | IAP | MODE |
|
||||
* +------+------+------+------+--//---+--------+-------+-----+------+
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* PSR_CS defines:
|
||||
*
|
||||
* 63 59 55 50 45 4 3 2 1 0
|
||||
* +------+------+------+------+--//---+--------+-------+-----+------+
|
||||
* | IMPL | VERS | MID | IGN | xxx | APCKEN | APERR | IAP | MODE |
|
||||
* +------+------+------+------+--//---+--------+-------+-----+------+
|
||||
*
|
||||
*/
|
||||
#define PSYCHO_GCSR_IMPL(csr) ((u_int)(((csr) >> 60) & 0xf))
|
||||
#define PSYCHO_GCSR_VERS(csr) ((u_int)(((csr) >> 56) & 0xf))
|
||||
#define PSYCHO_GCSR_MID(csr) ((u_int)(((csr) >> 51) & 0x1f))
|
||||
@ -71,293 +194,15 @@ struct psychoreg {
|
||||
#define PSYCHO_CSR_IAP 2 /* invert UPA address parity */
|
||||
#define PSYCHO_CSR_MODE 1 /* UPA/PCI handshake */
|
||||
|
||||
u_int64_t pad0;
|
||||
/* ECC control register */ /* 1fe.0000.0020 */
|
||||
u_int64_t psy_ecccr;
|
||||
/* 1fe.0000.0028 */
|
||||
u_int64_t reserved;
|
||||
/* Uncorrectable Error AFSR */ /* 1fe.0000.0030 */
|
||||
u_int64_t psy_ue_afsr;
|
||||
/* Uncorrectable Error AFAR */ /* 1fe.0000.0038 */
|
||||
u_int64_t psy_ue_afar;
|
||||
/* Correctable Error AFSR */ /* 1fe.0000.0040 */
|
||||
u_int64_t psy_ce_afsr;
|
||||
/* Correctable Error AFAR */ /* 1fe.0000.0048 */
|
||||
u_int64_t psy_ce_afar;
|
||||
|
||||
u_int64_t pad1[22];
|
||||
|
||||
struct perfmon {
|
||||
/* Performance monitor control reg */ /* 1fe.0000.0100 */
|
||||
u_int64_t pm_cr;
|
||||
/* Performance monitor counter reg */ /* 1fe.0000.0108 */
|
||||
u_int64_t pm_count;
|
||||
} psy_pm;
|
||||
|
||||
u_int64_t pad2[30];
|
||||
|
||||
/* 1fe.0000.0200,0210 */
|
||||
struct iommureg psy_iommu;
|
||||
|
||||
u_int64_t pad3[317];
|
||||
|
||||
/* PCI bus a slot 0 irq map reg */ /* 1fe.0000.0c00 */
|
||||
u_int64_t pcia0_int_map;
|
||||
/* PCI bus a slot 1 irq map reg */ /* 1fe.0000.0c08 */
|
||||
u_int64_t pcia1_int_map;
|
||||
/* PCI bus a slot 2 irq map reg (IIi) */ /* 1fe.0000.0c10 */
|
||||
u_int64_t pcia2_int_map;
|
||||
/* PCI bus a slot 3 irq map reg (IIi) */ /* 1fe.0000.0c18 */
|
||||
u_int64_t pcia3_int_map;
|
||||
/* PCI bus b slot 0 irq map reg */ /* 1fe.0000.0c20 */
|
||||
u_int64_t pcib0_int_map;
|
||||
/* PCI bus b slot 1 irq map reg */ /* 1fe.0000.0c28 */
|
||||
u_int64_t pcib1_int_map;
|
||||
/* PCI bus b slot 2 irq map reg */ /* 1fe.0000.0c30 */
|
||||
u_int64_t pcib2_int_map;
|
||||
/* PCI bus b slot 3 irq map reg */ /* 1fe.0000.0c38 */
|
||||
u_int64_t pcib3_int_map;
|
||||
|
||||
u_int64_t pad4[120];
|
||||
|
||||
/* SCSI interrupt map reg */ /* 1fe.0000.1000 */
|
||||
u_int64_t scsi_int_map;
|
||||
/* ethernet interrupt map reg */ /* 1fe.0000.1008 */
|
||||
u_int64_t ether_int_map;
|
||||
/* parallel interrupt map reg */ /* 1fe.0000.1010 */
|
||||
u_int64_t bpp_int_map;
|
||||
/* audio record interrupt map reg */ /* 1fe.0000.1018 */
|
||||
u_int64_t audior_int_map;
|
||||
/* audio playback interrupt map reg */ /* 1fe.0000.1020 */
|
||||
u_int64_t audiop_int_map;
|
||||
/* power fail interrupt map reg */ /* 1fe.0000.1028 */
|
||||
u_int64_t power_int_map;
|
||||
/* serial/kbd/mouse interrupt map reg */ /* 1fe.0000.1030 */
|
||||
u_int64_t ser_kbd_ms_int_map;
|
||||
/* floppy interrupt map reg */ /* 1fe.0000.1038 */
|
||||
u_int64_t fd_int_map;
|
||||
/* spare interrupt map reg */ /* 1fe.0000.1040 */
|
||||
u_int64_t spare_int_map;
|
||||
/* kbd [unused] interrupt map reg */ /* 1fe.0000.1048 */
|
||||
u_int64_t kbd_int_map;
|
||||
/* mouse [unused] interrupt map reg */ /* 1fe.0000.1050 */
|
||||
u_int64_t mouse_int_map;
|
||||
/* second serial interrupt map reg */ /* 1fe.0000.1058 */
|
||||
u_int64_t serial_int_map;
|
||||
/* timer 0 interrupt map reg */ /* 1fe.0000.1060 */
|
||||
u_int64_t timer0_int_map;
|
||||
/* timer 1 interrupt map reg */ /* 1fe.0000.1068 */
|
||||
u_int64_t timer1_int_map;
|
||||
/* UE interrupt map reg */ /* 1fe.0000.1070 */
|
||||
u_int64_t ue_int_map;
|
||||
/* CE interrupt map reg */ /* 1fe.0000.1078 */
|
||||
u_int64_t ce_int_map;
|
||||
/* PCI bus a error interrupt map reg */ /* 1fe.0000.1080 */
|
||||
u_int64_t pciaerr_int_map;
|
||||
/* PCI bus b error interrupt map reg */ /* 1fe.0000.1088 */
|
||||
u_int64_t pciberr_int_map;
|
||||
/* power mgmt wake interrupt map reg */ /* 1fe.0000.1090 */
|
||||
u_int64_t pwrmgt_int_map;
|
||||
/* FFB0 graphics interrupt map reg */ /* 1fe.0000.1098 */
|
||||
u_int64_t ffb0_int_map;
|
||||
/* FFB1 graphics interrupt map reg */ /* 1fe.0000.10a0 */
|
||||
u_int64_t ffb1_int_map;
|
||||
|
||||
u_int64_t pad5[107];
|
||||
|
||||
/* Note: clear interrupt 0 registers are not really used */
|
||||
|
||||
/* PCI a slot 0 clear int regs 0..7 */ /* 1fe.0000.1400-1418 */
|
||||
u_int64_t pcia0_int_clr[4];
|
||||
/* PCI a slot 1 clear int regs 0..7 */ /* 1fe.0000.1420-1438 */
|
||||
u_int64_t pcia1_int_clr[4];
|
||||
/* PCI a slot 2 clear int regs 0..7 */ /* 1fe.0000.1440-1458 */
|
||||
u_int64_t pcia2_int_clr[4];
|
||||
/* PCI a slot 3 clear int regs 0..7 */ /* 1fe.0000.1480-1478 */
|
||||
u_int64_t pcia3_int_clr[4];
|
||||
/* PCI b slot 0 clear int regs 0..7 */ /* 1fe.0000.1480-1498 */
|
||||
u_int64_t pcib0_int_clr[4];
|
||||
/* PCI b slot 1 clear int regs 0..7 */ /* 1fe.0000.14a0-14b8 */
|
||||
u_int64_t pcib1_int_clr[4];
|
||||
/* PCI b slot 2 clear int regs 0..7 */ /* 1fe.0000.14c0-14d8 */
|
||||
u_int64_t pcib2_int_clr[4];
|
||||
/* PCI b slot 3 clear int regs 0..7 */ /* 1fe.0000.14d0-14f8 */
|
||||
u_int64_t pcib3_int_clr[4];
|
||||
|
||||
u_int64_t pad6[96];
|
||||
|
||||
/* SCSI clear int reg */ /* 1fe.0000.1800 */
|
||||
u_int64_t scsi_int_clr;
|
||||
/* ethernet clear int reg */ /* 1fe.0000.1808 */
|
||||
u_int64_t ether_int_clr;
|
||||
/* parallel clear int reg */ /* 1fe.0000.1810 */
|
||||
u_int64_t bpp_int_clr;
|
||||
/* audio record clear int reg */ /* 1fe.0000.1818 */
|
||||
u_int64_t audior_int_clr;
|
||||
/* audio playback clear int reg */ /* 1fe.0000.1820 */
|
||||
u_int64_t audiop_int_clr;
|
||||
/* power fail clear int reg */ /* 1fe.0000.1828 */
|
||||
u_int64_t power_int_clr;
|
||||
/* serial/kbd/mouse clear int reg */ /* 1fe.0000.1830 */
|
||||
u_int64_t ser_kb_ms_int_clr;
|
||||
/* floppy clear int reg */ /* 1fe.0000.1838 */
|
||||
u_int64_t fd_int_clr;
|
||||
/* spare clear int reg */ /* 1fe.0000.1840 */
|
||||
u_int64_t spare_int_clr;
|
||||
/* kbd [unused] clear int reg */ /* 1fe.0000.1848 */
|
||||
u_int64_t kbd_int_clr;
|
||||
/* mouse [unused] clear int reg */ /* 1fe.0000.1850 */
|
||||
u_int64_t mouse_int_clr;
|
||||
/* second serial clear int reg */ /* 1fe.0000.1858 */
|
||||
u_int64_t serial_clr;
|
||||
/* timer 0 clear int reg */ /* 1fe.0000.1860 */
|
||||
u_int64_t timer0_int_clr;
|
||||
/* timer 1 clear int reg */ /* 1fe.0000.1868 */
|
||||
u_int64_t timer1_int_clr;
|
||||
/* UE clear int reg */ /* 1fe.0000.1870 */
|
||||
u_int64_t ue_int_clr;
|
||||
/* CE clear int reg */ /* 1fe.0000.1878 */
|
||||
u_int64_t ce_int_clr;
|
||||
/* PCI bus a error clear int reg */ /* 1fe.0000.1880 */
|
||||
u_int64_t pciaerr_int_clr;
|
||||
/* PCI bus b error clear int reg */ /* 1fe.0000.1888 */
|
||||
u_int64_t pciberr_int_clr;
|
||||
/* power mgmt wake clr interrupt reg */ /* 1fe.0000.1890 */
|
||||
u_int64_t pwrmgt_int_clr;
|
||||
|
||||
u_int64_t pad7[45];
|
||||
|
||||
/* interrupt retry timer */ /* 1fe.0000.1a00 */
|
||||
u_int64_t intr_retry_timer;
|
||||
|
||||
u_int64_t pad8[63];
|
||||
|
||||
struct timer_counter {
|
||||
/* timer/counter 0/1 count register */ /* 1fe.0000.1c00,1c10 */
|
||||
u_int64_t tc_count;
|
||||
/* timer/counter 0/1 limit register */ /* 1fe.0000.1c08,1c18 */
|
||||
u_int64_t tc_limit;
|
||||
} tc[2];
|
||||
|
||||
/* PCI DMA write sync register (IIi) */ /* 1fe.0000.1c20 */
|
||||
u_int64_t pci_dma_write_sync;
|
||||
|
||||
u_int64_t pad9[123];
|
||||
|
||||
struct pci_ctl {
|
||||
/* PCI a/b control/status register */ /* 1fe.0000.2000,4000 */
|
||||
u_int64_t pci_csr;
|
||||
u_int64_t pad10;
|
||||
/* PCI a/b AFSR register */ /* 1fe.0000.2010,4010 */
|
||||
u_int64_t pci_afsr;
|
||||
/* PCI a/b AFAR register */ /* 1fe.0000.2018,4018 */
|
||||
u_int64_t pci_afar;
|
||||
/* PCI a/b diagnostic register */ /* 1fe.0000.2020,4020 */
|
||||
u_int64_t pci_diag;
|
||||
/* PCI target address space reg (IIi)*/ /* 1fe.0000.2028,4028 */
|
||||
u_int64_t pci_tasr;
|
||||
|
||||
u_int64_t pad11[250];
|
||||
|
||||
/* This is really the IOMMU's, not the PCI bus's */
|
||||
/* 1fe.0000.2800-210 */
|
||||
struct iommu_strbuf pci_strbuf;
|
||||
#define psy_iommu_strbuf psy_pcictl[0].pci_strbuf
|
||||
|
||||
u_int64_t pad12[765];
|
||||
} psy_pcictl[2]; /* For PCI a and b */
|
||||
|
||||
/*
|
||||
* NB: FFB0 and FFB1 intr map regs also appear at 1fe.0000.6000 and
|
||||
* 1fe.0000.8000 respectively
|
||||
*/
|
||||
u_int64_t pad13[2048];
|
||||
|
||||
/* DMA scoreboard diag reg 0 */ /* 1fe.0000.a000 */
|
||||
u_int64_t dma_scb_diag0;
|
||||
/* DMA scoreboard diag reg 1 */ /* 1fe.0000.a008 */
|
||||
u_int64_t dma_scb_diag1;
|
||||
|
||||
u_int64_t pad14[126];
|
||||
|
||||
/* IOMMU virtual addr diag reg */ /* 1fe.0000.a400 */
|
||||
u_int64_t iommu_svadiag;
|
||||
/* IOMMU TLB tag compare diag reg */ /* 1fe.0000.a408 */
|
||||
u_int64_t iommu_tlb_comp_diag;
|
||||
|
||||
u_int64_t pad15[30];
|
||||
|
||||
/* IOMMU LRU queue diag */ /* 1fe.0000.a500-a578 */
|
||||
u_int64_t iommu_queue_diag[16];
|
||||
/* TLB tag diag */ /* 1fe.0000.a580-a5f8 */
|
||||
u_int64_t tlb_tag_diag[16];
|
||||
/* TLB data RAM diag */ /* 1fe.0000.a600-a678 */
|
||||
u_int64_t tlb_data_diag[16];
|
||||
|
||||
u_int64_t pad16[48];
|
||||
|
||||
/* PCI int state diag reg */ /* 1fe.0000.a800 */
|
||||
u_int64_t pci_int_diag;
|
||||
/* OBIO and misc int state diag reg */ /* 1fe.0000.a808 */
|
||||
u_int64_t obio_int_diag;
|
||||
|
||||
u_int64_t pad17[254];
|
||||
|
||||
struct strbuf_diag {
|
||||
/* streaming buffer data RAM diag */ /* 1fe.0000.b000-b3f8 */
|
||||
u_int64_t strbuf_data_diag[128];
|
||||
/* streaming buffer error status diag *//* 1fe.0000.b400-b7f8 */
|
||||
u_int64_t strbuf_error_diag[128];
|
||||
/* streaming buffer page tag diag */ /* 1fe.0000.b800-b878 */
|
||||
u_int64_t strbuf_pg_tag_diag[16];
|
||||
u_int64_t pad18[16];
|
||||
/* streaming buffer line tag diag */ /* 1fe.0000.b900-b978 */
|
||||
u_int64_t strbuf_ln_tag_diag[16];
|
||||
u_int64_t pad19[208];
|
||||
} psy_strbufdiag[2]; /* For PCI a and b */
|
||||
|
||||
/*
|
||||
* Here is the rest of the map, which we're not specifying:
|
||||
*
|
||||
* 1fe.0100.0000 - 1fe.01ff.ffff PCI configuration space
|
||||
* 1fe.0100.0000 - 1fe.0100.00ff PCI B configuration header
|
||||
* 1fe.0101.0000 - 1fe.0101.00ff PCI A configuration header
|
||||
* 1fe.0200.0000 - 1fe.0200.ffff PCI A I/O space
|
||||
* 1fe.0201.0000 - 1fe.0201.ffff PCI B I/O space
|
||||
* 1ff.0000.0000 - 1ff.7fff.ffff PCI A memory space
|
||||
* 1ff.8000.0000 - 1ff.ffff.ffff PCI B memory space
|
||||
*
|
||||
* NB: config and I/O space can use 1-4 byte accesses, not 8 byte
|
||||
* accesses. Memory space can use any sized accesses.
|
||||
*
|
||||
* Note that the SUNW,sabre/SUNW,simba combinations found on the
|
||||
* Ultra5 and Ultra10 machines uses slightly differrent addresses
|
||||
* than the above. This is mostly due to the fact that the APB is
|
||||
* a multi-function PCI device with two PCI bridges, and the U2P is
|
||||
* two separate PCI bridges. It uses the same PCI configuration
|
||||
* space, though the configuration header for each PCI bus is
|
||||
* located differently due to the SUNW,simba PCI busses being
|
||||
* function 0 and function 1 of the APB, whereas the psycho's are
|
||||
* each their own PCI device. The I/O and memory spaces are each
|
||||
* split into 8 equally sized areas (8x2MB blocks for I/O space,
|
||||
* and 8x512MB blocks for memory space). These are allocated in to
|
||||
* either PCI A or PCI B, or neither in the APB's `I/O Address Map
|
||||
* Register A/B' (0xde) and `Memory Address Map Register A/B' (0xdf)
|
||||
* registers of each simba. We must ensure that both of the
|
||||
* following are correct (the prom should do this for us):
|
||||
*
|
||||
* (PCI A Memory Address Map) & (PCI B Memory Address Map) == 0
|
||||
*
|
||||
* (PCI A I/O Address Map) & (PCI B I/O Address Map) == 0
|
||||
*
|
||||
* 1fe.0100.0000 - 1fe.01ff.ffff PCI configuration space
|
||||
* 1fe.0100.0800 - 1fe.0100.08ff PCI B configuration header
|
||||
* 1fe.0100.0900 - 1fe.0100.09ff PCI A configuration header
|
||||
* 1fe.0200.0000 - 1fe.02ff.ffff PCI I/O space (divided)
|
||||
* 1ff.0000.0000 - 1ff.ffff.ffff PCI memory space (divided)
|
||||
*/
|
||||
};
|
||||
/* Offsets into the PSR_PCICTL* register block. */
|
||||
#define PCR_CS 0x0000 /* PCI control/status register */
|
||||
#define PCR_AFS 0x0010 /* PCI AFSR register */
|
||||
#define PCR_AFA 0x0018 /* PCI AFAR register */
|
||||
#define PCR_DIAG 0x0020 /* PCI diagnostic register */
|
||||
#define PCR_TAS 0x0028 /* PCI target address space reg (IIi) */
|
||||
#define PCR_STRBUF 0x0800 /* IOMMU streaming buffer registers. */
|
||||
|
||||
/* Device space defines. */
|
||||
#define PSYCHO_CONF_SIZE 0x1000000
|
||||
#define PSYCHO_CONF_BUS_SHIFT 16
|
||||
#define PSYCHO_CONF_DEV_SHIFT 11
|
||||
|
@ -43,7 +43,6 @@ struct psycho_softc {
|
||||
* PSYCHO register. we record the base physical address of these
|
||||
* also as it is the base of the entire PSYCHO
|
||||
*/
|
||||
struct psychoreg *sc_regs;
|
||||
vm_offset_t sc_basepaddr;
|
||||
|
||||
/* Interrupt Group Number for this device */
|
||||
@ -54,6 +53,8 @@ struct psycho_softc {
|
||||
bus_space_handle_t sc_bushandle;
|
||||
bus_dma_tag_t sc_dmatag;
|
||||
|
||||
bus_addr_t sc_pcictl;
|
||||
|
||||
int sc_clockfreq;
|
||||
phandle_t sc_node; /* prom node */
|
||||
int sc_mode;
|
||||
|
Loading…
Reference in New Issue
Block a user