/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
/*
* SGMAP window A: 256M or 1G at 1G
*/
#define DWLPx_SG_MAPPED_BASE (1*1024*1024*1024)
#define DWLPx_SG_MAPPED_SIZE(x) ((x) * PAGE_SIZE)
/* DWLPx has a 256-byte out-bound DMA prefetch threshold. */
#define DWLPx_SG_MAPPED_PFTHRESH 256
/*
* Set this to always use SGMAPs.
*/
#ifdef DWLPX_ALWAYS_USE_SGMAP
int dwlpx_always_use_sgmap = 1;
#else
int dwlpx_always_use_sgmap = 0;
#endif
void
dwlpx_dma_init(struct dwlpx_config *ccp)
{
char *exname;
bus_dma_tag_t t;
uint32_t *page_table;
int i, lim, wmask;
/*
* Determine size of Window C based on the amount of SGMAP
* page table SRAM available.
*/
if (ccp->cc_sc->dwlpx_sgmapsz == DWLPX_SG128K) {
lim = 128 * 1024;
wmask = PCIA_WMASK_1G;
} else {
lim = 32 * 1024;
wmask = PCIA_WMASK_256M;
}
/*
* Initialize the DMA tag used for direct-mapped DMA. Chain
* this window to the SGMAP window, because we might have
* a lot of memory in the machine.
*/
t = &ccp->cc_dmat_direct;
t->_cookie = ccp;
t->_wbase = DWLPx_DIRECT_MAPPED_BASE;
t->_wsize = DWLPx_DIRECT_MAPPED_SIZE;
t->_next_window = &ccp->cc_dmat_sgmap;
t->_boundary = 0;
t->_sgmap = NULL;
t->_get_tag = dwlpx_dma_get_tag;
t->_dmamap_create = _bus_dmamap_create;
t->_dmamap_destroy = _bus_dmamap_destroy;
t->_dmamap_load = _bus_dmamap_load_direct;
t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
t->_dmamap_unload = _bus_dmamap_unload;
t->_dmamap_sync = _bus_dmamap_sync;
/*
* A few notes about SGMAP-mapped DMA on the DWLPx:
*
* The DWLPx has PCIA-resident SRAM that is used for
* the SGMAP page table; there is no TLB. The DWLPA
* has room for 32K entries, yielding a total of 256M
* of sgva space. The DWLPB has 32K entries or 128K
* entries, depending on TBIT, yielding either 256M or
* 1G of sgva space.
*
* This sgva space must be shared across all windows
* that wish to use SGMAP-mapped DMA; make sure to
* adjust the "sgvabase" argument to alpha_sgmap_init()
* accordingly if you create more than one SGMAP-mapped
* window. Note that sgvabase != window base. The former
* is used to compute indexes into the page table only.
*
* In the current implementation the first window is a
* 2G window direct-mapped mapped at 2G and the second
* window is disabled and the third window is a 256M
* or 1GB scatter/gather map at 1GB.
*
* We just punt on trying to support ISA DMA. If you want
* try that on a TurboLaser, well, you just lose.
*/
/*
* Initialize the page table.
*/
page_table =
(uint32_t *)ALPHA_PHYS_TO_K0SEG(PCIA_SGMAP_PT + ccp->cc_sysbase);
for (i = 0; i < lim; i++)
page_table[i * SGMAP_PTE_SPACING] = 0;
alpha_mb();
/*
* Set up DMA windows for this DWLPx.
*
* Do this even for all HPCs- even for the nonexistent
* one on hose zero of a KFTIA.
*/
for (i = 0; i < NHPC; i++) {
REGVAL(PCIA_WMASK_A(i) + ccp->cc_sysbase) = PCIA_WMASK_2G;
REGVAL(PCIA_TBASE_A(i) + ccp->cc_sysbase) = 0;
REGVAL(PCIA_WBASE_A(i) + ccp->cc_sysbase) =
DWLPx_DIRECT_MAPPED_BASE | PCIA_WBASE_W_EN;
/*
* Return the bus dma tag to be used for the specified bus type.
* INTERNAL USE ONLY!
*/
static bus_dma_tag_t
dwlpx_dma_get_tag(bus_dma_tag_t t, alpha_bus_t bustype)
{
struct dwlpx_config *ccp = t->_cookie;
switch (bustype) {
case ALPHA_BUS_PCI:
case ALPHA_BUS_EISA:
if (dwlpx_always_use_sgmap) {
/*
* Always use SGMAPs (for testing purposes?)
*/
return (&ccp->cc_dmat_sgmap);
}
/*
* Give these busses the direct-mapped window; if the
* address crosses the threshold, it will fall back
* onto the SGMAP window.
*/
return (&ccp->cc_dmat_direct);
case ALPHA_BUS_ISA:
/*
* Don't even bother; it's not easy, given how the
* page table is arranged, and it's not really worth
* the trouble.
*/
panic("dwlpx_dma_get_tag: ISA DMA? Forget it...");
/* NOTREACHED */
default:
panic("dwlpx_dma_get_tag: shouldn't be here, really...");
}
}
/*
* Load a DWLPx SGMAP-mapped DMA map with a linear buffer.
*/
static int
dwlpx_bus_dmamap_load_sgmap(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, struct proc *p, int flags)
{
/*
* Load a DWLPx SGMAP-mapped DMA map with an mbuf chain.
*/
static int
dwlpx_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m, int flags)
{
return (pci_sgmap_pte32_load_mbuf(t, map, m, flags, t->_sgmap));
}
/*
* Load a DWLPx SGMAP-mapped DMA map with a uio.
*/
static int
dwlpx_bus_dmamap_load_uio_sgmap(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags)
{
/*
* Load a DWLPx SGMAP-mapped DMA map with raw memory.
*/
static int
dwlpx_bus_dmamap_load_raw_sgmap(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
{