4098ccafa4
every operation to retrieve the bs_cookie value almost nothing actually uses. The bus_space struct contains a private data pointer (poorly named bs_cookie, now renamed to bs_privdata) which is used only by a few old armv4 xscale implementations. The bus_space functions were all defined to take this value as the first parameter instead of the bus_space_tag_t, requiring all the inline macro and function expansions to dereference the tag to pass it to another function, which never uses it. Now all the functions take the tag as the first parameter and retrieve the privdata if they need it. Also fix a couple bus_space_unmap() implementations that were calling kva_free() instead of pmap_unmapdev(). Discussed with: cognet
486 lines
13 KiB
C
486 lines
13 KiB
C
/* $NetBSD: ixp425_pci_space.c,v 1.6 2006/04/10 03:36:03 simonb Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2003
|
|
* Ichiro FUKUHARA <ichiro@ichiro.org>.
|
|
* 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 Ichiro FUKUHARA.
|
|
* 4. The name of the company nor the name of the author may be used to
|
|
* endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
/*
|
|
* bus_space PCI functions for ixp425
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/bus.h>
|
|
#include <sys/endian.h>
|
|
|
|
#include <machine/pcb.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_kern.h>
|
|
#include <vm/pmap.h>
|
|
#include <vm/vm_page.h>
|
|
#include <vm/vm_extern.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <arm/xscale/ixp425/ixp425reg.h>
|
|
#include <arm/xscale/ixp425/ixp425var.h>
|
|
|
|
/*
|
|
* Macros to read/write registers
|
|
*/
|
|
#define CSR_READ_4(x) *(volatile uint32_t *) \
|
|
(IXP425_PCI_CSR_BASE + (x))
|
|
#define CSR_WRITE_4(x, v) *(volatile uint32_t *) \
|
|
(IXP425_PCI_CSR_BASE + (x)) = (v)
|
|
|
|
/* Proto types for all the bus_space structure functions */
|
|
bs_protos(ixp425_pci);
|
|
bs_protos(ixp425_pci_io);
|
|
bs_protos(ixp425_pci_mem);
|
|
|
|
/* special I/O functions */
|
|
static u_int8_t _pci_io_bs_r_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
static u_int16_t _pci_io_bs_r_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
static u_int32_t _pci_io_bs_r_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
|
|
static void _pci_io_bs_w_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t);
|
|
static void _pci_io_bs_w_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t);
|
|
static void _pci_io_bs_w_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int32_t);
|
|
|
|
#ifdef __ARMEB__
|
|
static u_int8_t _pci_io_bs_r_1_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
static u_int16_t _pci_io_bs_r_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
static u_int32_t _pci_io_bs_r_4_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
|
|
static void _pci_io_bs_w_1_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t);
|
|
static void _pci_io_bs_w_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t);
|
|
static void _pci_io_bs_w_4_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int32_t);
|
|
|
|
static u_int8_t _pci_mem_bs_r_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
static u_int16_t _pci_mem_bs_r_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
static u_int32_t _pci_mem_bs_r_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
|
|
|
|
static void _pci_mem_bs_w_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t);
|
|
static void _pci_mem_bs_w_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t);
|
|
static void _pci_mem_bs_w_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int32_t);
|
|
#endif
|
|
|
|
struct bus_space ixp425_pci_io_bs_tag_template = {
|
|
/* mapping/unmapping */
|
|
.bs_map = ixp425_pci_io_bs_map,
|
|
.bs_unmap = ixp425_pci_io_bs_unmap,
|
|
.bs_subregion = ixp425_pci_bs_subregion,
|
|
|
|
.bs_alloc = ixp425_pci_io_bs_alloc,
|
|
.bs_free = ixp425_pci_io_bs_free,
|
|
|
|
/* barrier */
|
|
.bs_barrier = ixp425_pci_bs_barrier,
|
|
|
|
/*
|
|
* IXP425 processor does not have PCI I/O windows
|
|
*/
|
|
/* read (single) */
|
|
.bs_r_1 = _pci_io_bs_r_1,
|
|
.bs_r_2 = _pci_io_bs_r_2,
|
|
.bs_r_4 = _pci_io_bs_r_4,
|
|
|
|
/* write (single) */
|
|
.bs_w_1 = _pci_io_bs_w_1,
|
|
.bs_w_2 = _pci_io_bs_w_2,
|
|
.bs_w_4 = _pci_io_bs_w_4,
|
|
|
|
#ifdef __ARMEB__
|
|
.bs_r_1_s = _pci_io_bs_r_1_s,
|
|
.bs_r_2_s = _pci_io_bs_r_2_s,
|
|
.bs_r_4_s = _pci_io_bs_r_4_s,
|
|
|
|
.bs_w_1_s = _pci_io_bs_w_1_s,
|
|
.bs_w_2_s = _pci_io_bs_w_2_s,
|
|
.bs_w_4_s = _pci_io_bs_w_4_s,
|
|
#else
|
|
.bs_r_1_s = _pci_io_bs_r_1,
|
|
.bs_r_2_s = _pci_io_bs_r_2,
|
|
.bs_r_4_s = _pci_io_bs_r_4,
|
|
|
|
.bs_w_1_s = _pci_io_bs_w_1,
|
|
.bs_w_2_s = _pci_io_bs_w_2,
|
|
.bs_w_4_s = _pci_io_bs_w_4,
|
|
#endif
|
|
};
|
|
|
|
void
|
|
ixp425_io_bs_init(bus_space_tag_t bs, void *cookie)
|
|
{
|
|
*bs = ixp425_pci_io_bs_tag_template;
|
|
bs->bs_privdata = cookie;
|
|
}
|
|
|
|
struct bus_space ixp425_pci_mem_bs_tag_template = {
|
|
/* mapping/unmapping */
|
|
.bs_map = ixp425_pci_mem_bs_map,
|
|
.bs_unmap = ixp425_pci_mem_bs_unmap,
|
|
.bs_subregion = ixp425_pci_bs_subregion,
|
|
|
|
.bs_alloc = ixp425_pci_mem_bs_alloc,
|
|
.bs_free = ixp425_pci_mem_bs_free,
|
|
|
|
/* barrier */
|
|
.bs_barrier = ixp425_pci_bs_barrier,
|
|
|
|
#ifdef __ARMEB__
|
|
/* read (single) */
|
|
.bs_r_1_s = _pci_mem_bs_r_1,
|
|
.bs_r_2_s = _pci_mem_bs_r_2,
|
|
.bs_r_4_s = _pci_mem_bs_r_4,
|
|
|
|
.bs_r_1 = ixp425_pci_mem_bs_r_1,
|
|
.bs_r_2 = ixp425_pci_mem_bs_r_2,
|
|
.bs_r_4 = ixp425_pci_mem_bs_r_4,
|
|
|
|
/* write (single) */
|
|
.bs_w_1_s = _pci_mem_bs_w_1,
|
|
.bs_w_2_s = _pci_mem_bs_w_2,
|
|
.bs_w_4_s = _pci_mem_bs_w_4,
|
|
|
|
.bs_w_1 = ixp425_pci_mem_bs_w_1,
|
|
.bs_w_2 = ixp425_pci_mem_bs_w_2,
|
|
.bs_w_4 = ixp425_pci_mem_bs_w_4,
|
|
#else
|
|
/* read (single) */
|
|
.bs_r_1 = ixp425_pci_mem_bs_r_1,
|
|
.bs_r_2 = ixp425_pci_mem_bs_r_2,
|
|
.bs_r_4 = ixp425_pci_mem_bs_r_4,
|
|
.bs_r_1_s = ixp425_pci_mem_bs_r_1,
|
|
.bs_r_2_s = ixp425_pci_mem_bs_r_2,
|
|
.bs_r_4_s = ixp425_pci_mem_bs_r_4,
|
|
|
|
/* write (single) */
|
|
.bs_w_1 = ixp425_pci_mem_bs_w_1,
|
|
.bs_w_2 = ixp425_pci_mem_bs_w_2,
|
|
.bs_w_4 = ixp425_pci_mem_bs_w_4,
|
|
.bs_w_1_s = ixp425_pci_mem_bs_w_1,
|
|
.bs_w_2_s = ixp425_pci_mem_bs_w_2,
|
|
.bs_w_4_s = ixp425_pci_mem_bs_w_4,
|
|
#endif
|
|
};
|
|
|
|
void
|
|
ixp425_mem_bs_init(bus_space_tag_t bs, void *cookie)
|
|
{
|
|
*bs = ixp425_pci_mem_bs_tag_template;
|
|
bs->bs_privdata = cookie;
|
|
}
|
|
|
|
/* common routine */
|
|
int
|
|
ixp425_pci_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset,
|
|
bus_size_t size, bus_space_handle_t *nbshp)
|
|
{
|
|
*nbshp = bsh + offset;
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
ixp425_pci_bs_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset,
|
|
bus_size_t len, int flags)
|
|
{
|
|
/* NULL */
|
|
}
|
|
|
|
/* io bs */
|
|
int
|
|
ixp425_pci_io_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size,
|
|
int cacheable, bus_space_handle_t *bshp)
|
|
{
|
|
*bshp = bpa;
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
ixp425_pci_io_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size)
|
|
{
|
|
/* Nothing to do. */
|
|
}
|
|
|
|
int
|
|
ixp425_pci_io_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend,
|
|
bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
|
|
bus_addr_t *bpap, bus_space_handle_t *bshp)
|
|
{
|
|
panic("ixp425_pci_io_bs_alloc(): not implemented\n");
|
|
}
|
|
|
|
void
|
|
ixp425_pci_io_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size)
|
|
{
|
|
panic("ixp425_pci_io_bs_free(): not implemented\n");
|
|
}
|
|
|
|
/* special I/O functions */
|
|
static __inline u_int32_t
|
|
_bs_r(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int32_t be)
|
|
{
|
|
u_int32_t data;
|
|
|
|
CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3);
|
|
CSR_WRITE_4(PCI_NP_CBE, be | COMMAND_NP_IO_READ);
|
|
data = CSR_READ_4(PCI_NP_RDATA);
|
|
if (CSR_READ_4(PCI_ISR) & ISR_PFE)
|
|
CSR_WRITE_4(PCI_ISR, ISR_PFE);
|
|
|
|
return data;
|
|
}
|
|
|
|
static u_int8_t
|
|
_pci_io_bs_r_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
|
|
data = _bs_r(tag, ioh, off, be);
|
|
|
|
return data >> (8 * n);
|
|
}
|
|
|
|
static u_int16_t
|
|
_pci_io_bs_r_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
|
|
data = _bs_r(tag, ioh, off, be);
|
|
|
|
return data >> (8 * n);
|
|
}
|
|
|
|
static u_int32_t
|
|
_pci_io_bs_r_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data;
|
|
|
|
data = _bs_r(tag, ioh, off, 0);
|
|
return data;
|
|
}
|
|
|
|
#ifdef __ARMEB__
|
|
static u_int8_t
|
|
_pci_io_bs_r_1_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
|
|
data = _bs_r(tag, ioh, off, be);
|
|
|
|
return data >> (8 * n);
|
|
}
|
|
|
|
static u_int16_t
|
|
_pci_io_bs_r_2_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
|
|
data = _bs_r(tag, ioh, off, be);
|
|
|
|
return data >> (8 * n);
|
|
}
|
|
|
|
static u_int32_t
|
|
_pci_io_bs_r_4_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data;
|
|
|
|
data = _bs_r(tag, ioh, off, 0);
|
|
return le32toh(data);
|
|
}
|
|
#endif /* __ARMEB__ */
|
|
|
|
static __inline void
|
|
_bs_w(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int32_t be, u_int32_t data)
|
|
{
|
|
CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3);
|
|
CSR_WRITE_4(PCI_NP_CBE, be | COMMAND_NP_IO_WRITE);
|
|
CSR_WRITE_4(PCI_NP_WDATA, data);
|
|
if (CSR_READ_4(PCI_ISR) & ISR_PFE)
|
|
CSR_WRITE_4(PCI_ISR, ISR_PFE);
|
|
}
|
|
|
|
static void
|
|
_pci_io_bs_w_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int8_t val)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
|
|
data = val << (8 * n);
|
|
_bs_w(tag, ioh, off, be, data);
|
|
}
|
|
|
|
static void
|
|
_pci_io_bs_w_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int16_t val)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
|
|
data = val << (8 * n);
|
|
_bs_w(tag, ioh, off, be, data);
|
|
}
|
|
|
|
static void
|
|
_pci_io_bs_w_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int32_t val)
|
|
{
|
|
_bs_w(tag, ioh, off, 0, val);
|
|
}
|
|
|
|
#ifdef __ARMEB__
|
|
static void
|
|
_pci_io_bs_w_1_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int8_t val)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
|
|
data = val << (8 * n);
|
|
_bs_w(tag, ioh, off, be, data);
|
|
}
|
|
|
|
static void
|
|
_pci_io_bs_w_2_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int16_t val)
|
|
{
|
|
u_int32_t data, n, be;
|
|
|
|
n = (ioh + off) % 4;
|
|
be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
|
|
data = val << (8 * n);
|
|
_bs_w(tag, ioh, off, be, data);
|
|
}
|
|
|
|
static void
|
|
_pci_io_bs_w_4_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int32_t val)
|
|
{
|
|
_bs_w(tag, ioh, off, 0, htole32(val));
|
|
}
|
|
#endif /* __ARMEB__ */
|
|
|
|
/* mem bs */
|
|
int
|
|
ixp425_pci_mem_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size,
|
|
int cacheable, bus_space_handle_t *bshp)
|
|
{
|
|
*bshp = (vm_offset_t)pmap_mapdev(bpa, size);
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
ixp425_pci_mem_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size)
|
|
{
|
|
|
|
pmap_unmapdev((vm_offset_t)h, size);
|
|
}
|
|
|
|
int
|
|
ixp425_pci_mem_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend,
|
|
bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
|
|
bus_addr_t *bpap, bus_space_handle_t *bshp)
|
|
{
|
|
panic("ixp425_mem_bs_alloc(): not implemented\n");
|
|
}
|
|
|
|
void
|
|
ixp425_pci_mem_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size)
|
|
{
|
|
panic("ixp425_mem_bs_free(): not implemented\n");
|
|
}
|
|
|
|
#ifdef __ARMEB__
|
|
static u_int8_t
|
|
_pci_mem_bs_r_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
return ixp425_pci_mem_bs_r_1(tag, ioh, off);
|
|
}
|
|
|
|
static u_int16_t
|
|
_pci_mem_bs_r_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
return (ixp425_pci_mem_bs_r_2(tag, ioh, off));
|
|
}
|
|
|
|
static u_int32_t
|
|
_pci_mem_bs_r_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off)
|
|
{
|
|
u_int32_t data;
|
|
|
|
data = ixp425_pci_mem_bs_r_4(tag, ioh, off);
|
|
return (le32toh(data));
|
|
}
|
|
|
|
static void
|
|
_pci_mem_bs_w_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int8_t val)
|
|
{
|
|
ixp425_pci_mem_bs_w_1(tag, ioh, off, val);
|
|
}
|
|
|
|
static void
|
|
_pci_mem_bs_w_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int16_t val)
|
|
{
|
|
ixp425_pci_mem_bs_w_2(tag, ioh, off, val);
|
|
}
|
|
|
|
static void
|
|
_pci_mem_bs_w_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off,
|
|
u_int32_t val)
|
|
{
|
|
ixp425_pci_mem_bs_w_4(tag, ioh, off, htole32(val));
|
|
}
|
|
#endif /* __ARMEB__ */
|
|
|
|
/* End of ixp425_pci_space.c */
|