/*-
* Copyright (C) 1999 SHIMIZU Ryo. 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. 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.
*/
/*
* called by hardware interrupt routine
*/
int
apbus_intr_dispatch(int level, int stat)
{
struct newsmips_intr *ip;
struct newsmips_intrhand *ih;
int nintr;
static void
apbus_dma_unmapped(bus_dma_tag_t t, bus_dmamap_t map)
{
int seg;
for (seg = 0; seg < map->dm_nsegs; seg++) {
/*
* set MSB to indicate unmapped DMA.
* also need bit 30 for memory over 256MB.
*/
if ((map->dm_segs[seg].ds_addr & 0x30000000) == 0)
map->dm_segs[seg].ds_addr |= 0x80000000;
else
map->dm_segs[seg].ds_addr |= 0xc0000000;
}
}
static int
apbus_dma_mapalloc(bus_dma_tag_t t, bus_dmamap_t map, int flags)
{
int i, j, cnt;
cnt = round_page(map->_dm_size) / PAGE_SIZE;
again:
for (i = 0; i < APBUS_NDMAMAP; i += j + 1) {
for (j = 0; j < cnt; j++) {
if (apbus_dma_maptbl[i + j])
break;
}
if (j == cnt) {
for (j = 0; j < cnt; j++)
apbus_dma_maptbl[i + j] = 1;
map->_dm_maptbl = i;
map->_dm_maptblcnt = cnt;
return 0;
}
}
if ((flags & BUS_DMA_NOWAIT) == 0) {
tsleep(&apbus_dma_maptbl, PRIBIO, "apdmat", 0);
goto again;
}
return ENOMEM;
}
static void
apbus_dma_mapfree(bus_dma_tag_t t, bus_dmamap_t map)
{
int i, n;
if (map->_dm_maptblcnt > 0) {
n = map->_dm_maptbl;
for (i = 0; i < map->_dm_maptblcnt; i++, n++) {
#ifdef DIAGNOSTIC
if (apbus_dma_maptbl[n] == 0)
panic("freeing free DMA map");
APBUS_MAPTBL(n, 0xffffffff); /* causes DMA error */
#endif
apbus_dma_maptbl[n] = 0;
}
wakeup(&apbus_dma_maptbl);
map->_dm_maptblcnt = 0;
}
}
static void
apbus_dma_mapset(bus_dma_tag_t t, bus_dmamap_t map)
{
int i;
bus_addr_t addr, eaddr;
int seg;
bus_dma_segment_t *segs;
i = 0;
for (seg = 0; seg < map->dm_nsegs; seg++) {
segs = &map->dm_segs[seg];
for (addr = segs->ds_addr, eaddr = addr + segs->ds_len;
addr < eaddr; addr += PAGE_SIZE, i++) {
#ifdef DIAGNOSTIC
if (i >= map->_dm_maptblcnt)
panic("DMA map table overflow");
#endif
APBUS_MAPTBL(map->_dm_maptbl + i,
NEWS5000_APBUS_MAP_VALID |
NEWS5000_APBUS_MAP_COHERENT |
(addr >> PGSHIFT));
}
}
map->dm_segs[0].ds_addr = map->_dm_maptbl << PGSHIFT;
map->dm_segs[0].ds_len = map->dm_mapsize;
map->dm_nsegs = 1;
}
static int
apbus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
{
int error;