NetBSD-5.0.2/sys/arch/mvme68k/mvme68k/bus_space.c
/* $NetBSD: bus_space.c,v 1.10 2008/04/28 20:23:29 martin Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Steve C. Woodford and Jason R. Thorpe.
*
* 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.
*/
/*
* Implementation of bus_space mapping for the mvme68k.
* Derived from the hp300 bus_space implementation by Jason Thorpe.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.10 2008/04/28 20:23:29 martin Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <machine/cpu.h>
#include <machine/pte.h>
#define _MVME68K_BUS_DMA_PRIVATE /* For _bus_dmamem_map/_bus_dmamem_unmap */
#define _MVME68K_BUS_SPACE_PRIVATE
#include <machine/bus.h>
#undef _MVME68K_BUS_DMA_PRIVATE
#undef _MVME68K_BUS_SPACE_PRIVATE
static void peek1(void *, void *);
static void peek2(void *, void *);
static void peek4(void *, void *);
static void poke1(void *, u_int);
static void poke2(void *, u_int);
static void poke4(void *, u_int);
static int do_peek(void (*)(void *, void *), void *, void *);
static int do_poke(void (*)(void *, u_int), void *, u_int);
/*
* Used in locore.s/trap.c to determine if faults are being trapped.
*/
label_t *nofault;
/* ARGSUSED */
int
_bus_space_map(void *cookie, bus_addr_t addr, bus_size_t size, int flags,
bus_space_handle_t *bushp)
{
bus_dma_segment_t seg;
void *va;
if (addr >= intiobase_phys && addr < intiotop_phys) {
#ifdef DEBUG
if ((addr + size) >= intiotop_phys)
panic("%s: Invalid INTIO range!", __func__);
#endif
/*
* Intio space is direct-mapped in pmap_bootstrap(); just
* do the translation.
*/
addr -= intiobase_phys;
*bushp = (bus_space_handle_t)&(intiobase[addr]);
return 0;
}
/*
* Otherwise, set up a VM mapping for the requested address range
*/
seg.ds_addr = seg._ds_cpuaddr = m68k_trunc_page(addr);
seg.ds_len = m68k_round_page(size);
if (_bus_dmamem_map(NULL, &seg, 1, seg.ds_len, &va,
flags | BUS_DMA_COHERENT))
return EIO;
/*
* The handle is really the virtual address we just mapped
*/
*bushp = (bus_space_handle_t)((char *)va + m68k_page_offset(addr));
return 0;
}
/* ARGSUSED */
void
_bus_space_unmap(void *cookie, bus_space_handle_t bush, bus_size_t size)
{
/* Nothing to do for INTIO space */
if ((char *)bush >= intiobase && (char *)bush < intiolimit)
return;
bush = m68k_trunc_page(bush);
size = m68k_round_page(size);
_bus_dmamem_unmap(NULL, (void *) bush, size);
}
/* ARGSUSED */
int
_bus_space_peek_1(void *cookie, bus_space_handle_t bush, bus_size_t offset,
uint8_t *valuep)
{
uint8_t v;
if (valuep == NULL)
valuep = &v;
return do_peek(&peek1, (void *)(bush + offset), (void *)valuep);
}
/* ARGSUSED */
int
_bus_space_peek_2(void *cookie, bus_space_handle_t bush, bus_size_t offset,
uint16_t *valuep)
{
uint16_t v;
if (valuep == NULL)
valuep = &v;
return do_peek(&peek2, (void *)(bush + offset), (void *)valuep);
}
/* ARGSUSED */
int
_bus_space_peek_4(void *cookie, bus_space_handle_t bush, bus_size_t offset,
uint32_t *valuep)
{
uint32_t v;
if (valuep == NULL)
valuep = &v;
return do_peek(&peek4, (void *)(bush + offset), (void *)valuep);
}
/* ARGSUSED */
int
_bus_space_poke_1(void *cookie, bus_space_handle_t bush, bus_size_t offset,
uint8_t value)
{
return do_poke(&poke1, (void *)(bush + offset), (u_int)value);
}
/* ARGSUSED */
int
_bus_space_poke_2(void *cookie, bus_space_handle_t bush, bus_size_t offset,
uint16_t value)
{
return do_poke(&poke2, (void *)(bush + offset), (u_int)value);
}
/* ARGSUSED */
int
_bus_space_poke_4(void *cookie, bus_space_handle_t bush, bus_size_t offset,
uint32_t value)
{
return do_poke(&poke4, (void *)(bush + offset), (u_int)value);
}
static void
peek1(void *addr, void *vp)
{
*((uint8_t *)vp) = *((uint8_t *)addr);
}
static void
peek2(void *addr, void *vp)
{
*((uint16_t *)vp) = *((uint16_t *)addr);
}
static void
peek4(void *addr, void *vp)
{
*((uint32_t *)vp) = *((uint32_t *)addr);
}
static void
poke1(void *addr, u_int value)
{
*((uint8_t *)addr) = value;
}
static void
poke2(void *addr, u_int value)
{
*((uint16_t *)addr) = value;
}
static void
poke4(void *addr, u_int value)
{
*((uint32_t *)addr) = value;
}
static int
do_peek(void (*peekfn)(void *, void *), void *addr, void *valuep)
{
label_t faultbuf;
nofault = &faultbuf;
if (setjmp(&faultbuf)) {
nofault = NULL;
return 1;
}
(*peekfn)(addr, valuep);
nofault = NULL;
return 0;
}
static int
do_poke(void (*pokefn)(void *, u_int), void *addr, u_int value)
{
label_t faultbuf;
nofault = &faultbuf;
if (setjmp(&faultbuf)) {
nofault = NULL;
return 1;
}
(*pokefn)(addr, value);
nofault = NULL;
return 0;
}