code:
/*	$OpenBSD: irongate_bus_mem.c,v 1.6 2008/06/26 05:42:08 ray Exp $	*/
/* $NetBSD: irongate_bus_mem.c,v 1.7 2001/04/17 21:52:00 thorpej Exp $ */

/*-
 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by 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.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <alpha/pci/irongatereg.h>
#include <alpha/pci/irongatevar.h>

#define	CHIP		irongate

#define	CHIP_EX_MALLOC_SAFE(v)	(((struct irongate_config *)(v))->ic_mallocsafe)
#define	CHIP_MEM_EXTENT(v)	(((struct irongate_config *)(v))->ic_mem_ex)

#define	CHIP_MEM_SYS_START(v)	IRONGATE_MEM_BASE

/*
 * AMD 751 core logic appears on EV6.  We require at least EV56
 * support for the assembler to emit BWX opcodes.
 */
__asm(".arch ev6");

#include <alpha/pci/pci_bwx_bus_mem_chipdep.c>

#include <sys/kcore.h>

#include <dev/isa/isareg.h>

extern phys_ram_seg_t mem_clusters[];
extern int mem_cluster_cnt;

void
irongate_bus_mem_init2(bus_space_tag_t t, void *v)
{
	u_long size, start, end;
	int i, error;

	/*
	 * Since the AMD 751 doesn't have DMA windows, we need to
	 * allocate RAM out of the extent map.
	 */
	for (i = 0; i < mem_cluster_cnt; i++) {
		start = mem_clusters[i].start;
		size = mem_clusters[i].size & ~PAGE_MASK;
		end = mem_clusters[i].start + size;

		if (start <= IOM_BEGIN && end >= IOM_END) {
			/*
			 * The ISA hole lies somewhere in this
			 * memory cluster.  The UP1000 firmware
			 * doesn't report this to us properly,
			 * so we have to cope, since devices are
			 * mapped into the ISA hole, but RAM is
			 * not.
			 *
			 * Sigh, the UP1000 is a really cool machine,
			 * but it is sometimes too PC-like for my
			 * taste.
			 */
			if (start < IOM_BEGIN) {
				error = extent_alloc_region(CHIP_MEM_EXTENT(v),
				    start, (IOM_BEGIN - start),
				    EX_NOWAIT |
				    (CHIP_EX_MALLOC_SAFE(v) ? EX_MALLOCOK : 0));
				if (error) {
					printf("WARNING: unable to reserve "
					    "chunk from mem cluster %d "
					    "(0x%lx - 0x%lx)\n", i,
					    start, (u_long) IOM_BEGIN - 1);
				}
			}
			if (end > IOM_END) {
				error = extent_alloc_region(CHIP_MEM_EXTENT(v),
				    IOM_END, (end - IOM_END),
				    EX_NOWAIT |
				    (CHIP_EX_MALLOC_SAFE(v) ? EX_MALLOCOK : 0));
				if (error) {
					printf("WARNING: unable to reserve "
					    "chunk from mem cluster %d "
					    "(0x%lx - 0x%lx)\n", i,
					    (u_long) IOM_END, end - 1);
				}
			}
		} else {
			error = extent_alloc_region(CHIP_MEM_EXTENT(v),
			    start, size,
			    EX_NOWAIT |
			    (CHIP_EX_MALLOC_SAFE(v) ? EX_MALLOCOK : 0));
			if (error) {
				printf("WARNING: unable reserve mem cluster %d "
				    "(0x%lx - 0x%lx)\n", i, start,
				    start + (size - 1));
			}
		}
	}
}


code:
/*	$OpenBSD: irongate_dma.c,v 1.5 2008/06/26 05:42:08 ray Exp $	*/
/* $NetBSD: irongate_dma.c,v 1.3 2000/06/29 08:58:47 mrg Exp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by 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.
 */

/*
 * DMA support for the AMD 751 (``Irongate'') core logic chipset.
 *
 * The AMD 751 is really unlike all of the other Alpha PCI core logic
 * chipsets.  Instead, it looks like a normal PC chipset (not surprising,
 * since it is used for Athlon processors).
 *
 * Because of this, it lacks all of the SGMAP hardware normally present
 * on an Alpha system, and there are no DMA windows.  Instead, a memory
 * bus address is a PCI DMA address, and ISA DMA above 16M has to be
 * bounced (this is not unlike the Jensen, actually).
 */

/*
 * XXX - We should define this before including bus.h, but since other stuff
 *       pulls in bus.h we must do this here.
 */
#define _ALPHA_BUS_DMA_PRIVATE

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/irongatereg.h>
#include <alpha/pci/irongatevar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>

#include "isadma.h"

bus_dma_tag_t irongate_dma_get_tag(bus_dma_tag_t, alpha_bus_t);

void
irongate_dma_init(struct irongate_config *icp)
{
	bus_dma_tag_t t;

	/*
	 * Initialize the DMA tag used for PCI DMA.
	 */
	t = &icp->ic_dmat_pci;
	t->_cookie = icp;
	t->_wbase = 0;
	t->_wsize = 0x100000000UL;
	t->_next_window = NULL;
	t->_boundary = 0;
	t->_sgmap = NULL;
	t->_get_tag = irongate_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;

	t->_dmamem_alloc = _bus_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;

#if NISADMA > 0
	/*
	 * Initialize the DMA tag used for ISA DMA.
	 */
	t = &icp->ic_dmat_isa;
	t->_cookie = icp;
	t->_wbase = 0;
	t->_wsize = 0x1000000;
	t->_next_window = NULL;
	t->_boundary = 0;
	t->_sgmap = NULL;
	t->_get_tag = irongate_dma_get_tag;
	t->_dmamap_create = isadma_bounce_dmamap_create;
	t->_dmamap_destroy = isadma_bounce_dmamap_destroy;
	t->_dmamap_load = isadma_bounce_dmamap_load;
	t->_dmamap_load_mbuf = isadma_bounce_dmamap_load_mbuf;
	t->_dmamap_load_uio = isadma_bounce_dmamap_load_uio;
	t->_dmamap_load_raw = isadma_bounce_dmamap_load_raw;
	t->_dmamap_unload = isadma_bounce_dmamap_unload;
	t->_dmamap_sync = isadma_bounce_dmamap_sync;

	t->_dmamem_alloc = isadma_bounce_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;
#endif

	/* XXX XXX BEGIN XXX XXX */
	{							/* XXX */
		extern paddr_t alpha_XXX_dmamap_or;		/* XXX */
		alpha_XXX_dmamap_or = 0;			/* XXX */
	}							/* XXX */
	/* XXX XXX END XXX XXX */
}

/*
 * Return the bus dma tag to be used for the specified bus type.
 * INTERNAL USE ONLY!
 */
bus_dma_tag_t
irongate_dma_get_tag(bus_dma_tag_t t, alpha_bus_t bustype)
{
	struct irongate_config *icp = t->_cookie;

	switch (bustype) {
	case ALPHA_BUS_PCI:
	case ALPHA_BUS_EISA:
		/*
		 * Busses capable of 32-bit DMA get the PCI DMA tag.
		 */
		return (&icp->ic_dmat_pci);

	case ALPHA_BUS_ISA:
		/*
		 * Lame 24-bit busses have to bounce.
		 */
		return (&icp->ic_dmat_isa);

	default:
		panic("irongate_dma_get_tag: shouldn't be here, really...");
	}
}

license: unknown


code:
/*	$OpenBSD: irongate_pci.c,v 1.7 2014/03/29 18:09:28 guenther Exp $	*/
/* $NetBSD: irongate_pci.c,v 1.2 2000/06/29 08:58:47 mrg Exp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by 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.
 */

/*
 * PCI Configuration Space support for the AMD 751 (``Irongate'') core logic
 * chipset.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/irongatereg.h>
#include <alpha/pci/irongatevar.h>

void		irongate_attach_hook(struct device *, struct device *,
		    struct pcibus_attach_args *);
int		irongate_bus_maxdevs(void *, int);
pcitag_t	irongate_make_tag(void *, int, int, int);
void		irongate_decompose_tag(void *, pcitag_t, int *, int *,
		    int *);
int		irongate_conf_size(void *, pcitag_t);
pcireg_t	irongate_conf_read(void *, pcitag_t, int);
void		irongate_conf_write(void *, pcitag_t, int, pcireg_t);

/* AMD 751 systems are always single-processor, so this is easy. */
#define	PCI_CONF_LOCK(s)	(s) = splhigh()
#define	PCI_CONF_UNLOCK(s)	splx((s))

#define	PCI_CONF_ADDR	(IRONGATE_IO_BASE|IRONGATE_CONFADDR)
#define	PCI_CONF_DATA	(IRONGATE_IO_BASE|IRONGATE_CONFDATA)

#define	REGVAL(r)	(*(volatile u_int32_t *)ALPHA_PHYS_TO_K0SEG(r))

void
irongate_pci_init(pci_chipset_tag_t pc, void *v)
{

	pc->pc_conf_v = v;
	pc->pc_attach_hook = irongate_attach_hook;
	pc->pc_bus_maxdevs = irongate_bus_maxdevs;
	pc->pc_make_tag = irongate_make_tag;
	pc->pc_decompose_tag = irongate_decompose_tag;
	pc->pc_conf_size = irongate_conf_size;
	pc->pc_conf_read = irongate_conf_read;
	pc->pc_conf_write = irongate_conf_write;
}

void
irongate_attach_hook(struct device *parent, struct device *self,
    struct pcibus_attach_args *pba)
{
}

int
irongate_bus_maxdevs(void *ipv, int busno)
{

	return 32;
}

pcitag_t
irongate_make_tag(void *ipv, int b, int d, int f)
{

	return (b << 16) | (d << 11) | (f << 8);
}

void
irongate_decompose_tag(void *ipv, pcitag_t tag, int *bp, int *dp, int *fp)
{

	if (bp != NULL)
		*bp = (tag >> 16) & 0xff;
	if (dp != NULL)
		*dp = (tag >> 11) & 0x1f;
	if (fp != NULL)
		*fp = (tag >> 8) & 0x7;
}

int
irongate_conf_size(void *ipv, pcitag_t tag)
{
	return PCI_CONFIG_SPACE_SIZE;
}

pcireg_t
irongate_conf_read(void *ipv, pcitag_t tag, int offset)
{
	int d;

	/*
	 * The AMD 751 appears in PCI configuration space, but
	 * that is ... counter-intuitive to the way we normally
	 * attach PCI-Host bridges on the Alpha.  So, filter out
	 * the AMD 751 device here.  We provide a private entry
	 * point for getting at it from machdep code.
	 */
	irongate_decompose_tag(ipv, tag, NULL, &d, NULL);
	if (d == IRONGATE_PCIHOST_DEV)
		return ((pcireg_t) -1);

	return (irongate_conf_read0(ipv, tag, offset));
}

pcireg_t
irongate_conf_read0(void *ipv, pcitag_t tag, int offset)
{
	pcireg_t data;
	int s;

	PCI_CONF_LOCK(s);
	REGVAL(PCI_CONF_ADDR) = (CONFADDR_ENABLE | tag | (offset & 0xff));
	alpha_mb();
	data = REGVAL(PCI_CONF_DATA);
	REGVAL(PCI_CONF_ADDR) = 0;
	alpha_mb();
	PCI_CONF_UNLOCK(s);

	return (data);
}

void
irongate_conf_write(void *ipv, pcitag_t tag, int offset, pcireg_t data)
{
	int s;

	PCI_CONF_LOCK(s);
	REGVAL(PCI_CONF_ADDR) = (CONFADDR_ENABLE | tag | (offset & 0xff));
	alpha_mb();
	REGVAL(PCI_CONF_DATA) = data;
	alpha_mb();
	REGVAL(PCI_CONF_ADDR) = 0;
	alpha_mb();
	PCI_CONF_UNLOCK(s);
}


code:
/*	$OpenBSD: irongatereg.h,v 1.3 2008/06/26 05:42:08 ray Exp $	*/
/* $NetBSD: irongatereg.h,v 1.2 2000/06/26 02:42:10 thorpej Exp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by 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.
 */

/*
 * Register definitions for the AMD 751 (``Irongate'') core logic
 * chipset.
 */

/*
 * Address map.
 *
 * This from the Tsunami address map:
 * EV6 has a new superpage which can pass through 44 address bits.  (Umm, a
 * superduperpage?) But, the firmware doesn't turn it on, so we use the old
 * one and let the HW sign extend va/pa<40> to get us the pa<43> that makes
 * the needed I/O space access. This is just as well; it means we don't have
 * to worry about which GENERIC code might get called on other CPU models.
 *
 *	E.g., we want this:		0x0801##fc00##0000
 *	We use this:			0x0101##fc00##0000
 *	...mix in the old SP:     0xffff##fc00##0000##0000
 *	...after PA sign ext:     0xffff##ff01##fc00##0000
 *	(PA<42:41> ignored)
 *
 * PCI memory and RAM:			0000.0000.0000
 * IACK					0001.f800.0000
 * PCI I/O:				0001.fc00.0000
 * AMD 751 (also in PCI config space):	0001.fe00.0000
 */

/*
 * This hack allows us to map the I/O address space without using
 * the KSEG sign extension hack.
 */
#define	IRONGATE_PHYSADDR(x)						\
	(((x) & ~0x0100##0000##0000) | 0x0800##0000##0000)

#define	IRONGATE_KSEG_BIAS	0x0100##0000##0000UL

#define	IRONGATE_MEM_BASE	(IRONGATE_KSEG_BIAS | 0x0000##0000##0000UL)
#define	IRONGATE_IACK_BASE	(IRONGATE_KSEG_BIAS | 0x0001##f800##0000UL)
#define	IRONGATE_IO_BASE	(IRONGATE_KSEG_BIAS | 0x0001##fc00##0000UL)
#define	IRONGATE_SELF_BASE	(IRONGATE_KSEG_BIAS | 0x0001##fe00##0000UL)

/*
 * PCI configuration register access using done by using
 * ``configuration mode 1'' (in PC lingo), using the I/O
 * space addresses described in the PCI Local Bus Specification
 * Revision 2.2.
 */
#define	IRONGATE_CONFADDR	0x0cf8
#define	IRONGATE_CONFDATA	0x0cfc

#define	CONFADDR_ENABLE		0x80000000U

/*
 * The AMD 751 PCI-Host bridge is located at device 0, and the
 * AGP controller (seen as a PCI-PCI bridge) is at device 1.
 */
#define	IRONGATE_PCIHOST_DEV	0
#define	IRONGATE_PCIAGP_DEV	1


code:
/*	$OpenBSD: irongatevar.h,v 1.5 2008/06/26 05:42:08 ray Exp $	*/
/* $NetBSD: irongatevar.h,v 1.3 2000/11/29 06:29:10 thorpej Exp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by 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.
 */

#include <dev/isa/isavar.h>
#include <dev/pci/pcivar.h>

/*
 * AMD 751 chipset's configuration.
 *
 * All of the information that the chipset-specific functions need to
 * do their dirty work (and more!).
 */
struct irongate_config {
	int	ic_initted;

	struct alpha_bus_space ic_iot, ic_memt;
	struct alpha_pci_chipset ic_pc;

	struct alpha_bus_dma_tag ic_dmat_pci;
	struct alpha_bus_dma_tag ic_dmat_isa;

	u_int32_t ic_rev;

	struct extent *ic_io_ex, *ic_mem_ex;
	int	ic_mallocsafe;
};

void	irongate_init(struct irongate_config *, int);
void	irongate_pci_init(pci_chipset_tag_t, void *);
void	irongate_dma_init(struct irongate_config *);

void	irongate_bus_io_init(bus_space_tag_t, void *);
void	irongate_bus_mem_init(bus_space_tag_t, void *);

void	irongate_bus_mem_init2(bus_space_tag_t, void *);

pcireg_t irongate_conf_read0(void *, pcitag_t, int);


code:
/*	$OpenBSD: lca.c,v 1.23 2013/06/04 19:12:34 miod Exp $	*/
/*	$NetBSD: lca.c,v 1.14 1996/12/05 01:39:35 cgd Exp $	*/

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by 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.
 */

/*
 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Authors: Jeffrey Hsu and Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/autoconf.h>
#include <machine/cpuconf.h>
#include <machine/rpb.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>
#ifdef DEC_AXPPCI_33
#include <alpha/pci/pci_axppci_33.h>
#endif
#ifdef DEC_ALPHABOOK1
#include <alpha/pci/pci_alphabook1.h>
#endif
#ifdef DEC_EB66
#include <alpha/pci/pci_eb66.h>
#endif

int	lcamatch(struct device *, void *, void *);
void	lcaattach(struct device *, struct device *, void *);

struct cfattach lca_ca = {
	sizeof(struct device), lcamatch, lcaattach,
};

struct cfdriver lca_cd = {
	NULL, "lca", DV_DULL,
};

int	lcaprint(void *, const char *pnp);

#if 0
int	lca_bus_get_window(int, int,
	    struct alpha_bus_space_translation *);
#endif
void	lca_machine_check(unsigned long, struct trapframe *, unsigned long,
	    unsigned long);

/* There can be only one. */
int lcafound;
struct lca_config lca_configuration;

int
lcamatch(parent, match, aux)
	struct device *parent;
	void *match;
	void *aux;
{
	struct mainbus_attach_args *ma = aux;

	/* Make sure that we're looking for a LCA. */
	if (strcmp(ma->ma_name, lca_cd.cd_name) != 0)
		return (0);

	if (lcafound)
		return (0);

	return (1);
}

/*
 * Set up the chipset's function pointers.
 */
void
lca_init(lcp, mallocsafe)
	struct lca_config *lcp;
	int mallocsafe;
{

	/*
	 * The LCA HAE register is WRITE-ONLY, so we can't tell where
	 * the second sparse window is actually mapped.  Therefore,
	 * we have to guess where it is.  This seems to be the normal
	 * address.
	 */
	lcp->lc_s_mem_w2_masked_base = 0x80000000;

	if (!lcp->lc_initted) {
		/* don't do these twice since they set up extents */
		lca_bus_io_init(&lcp->lc_iot, lcp);
		lca_bus_mem_init(&lcp->lc_memt, lcp);

#if 0
		/*
		 * We have 1 I/O window and 3 MEM windows.
		 */
		alpha_bus_window_count[ALPHA_BUS_TYPE_PCI_IO] = 1;
		alpha_bus_window_count[ALPHA_BUS_TYPE_PCI_MEM] = 3;
		alpha_bus_get_window = lca_bus_get_window;
#endif
	}
	lcp->lc_mallocsafe = mallocsafe;

	lca_pci_init(&lcp->lc_pc, lcp);
	alpha_pci_chipset = &lcp->lc_pc;
	alpha_pci_chipset->pc_name = "lca";
	alpha_pci_chipset->pc_mem = LCA_PCI_SPARSE;
	alpha_pci_chipset->pc_ports = LCA_PCI_SIO;
	alpha_pci_chipset->pc_hae_mask = IOC_HAE_ADDREXT;
	alpha_pci_chipset->pc_dense = LCA_PCI_DENSE;
	alpha_pci_chipset->pc_bwx = 0;

	/*
	 * Refer to ``DECchip 21066 and DECchip 21068 Alpha AXP Microprocessors
	 * Hardware Reference Manual''.
	 * ...
	 */

	/*
	 * According to section 6.4.1, all bits of the IOC_HAE register are
	 * undefined after reset.  Bits <31:27> are write-only.  However, we
	 * cannot blindly set it to zero.  The serial ROM code that initializes
	 * the PCI devices' address spaces, allocates sparse memory blocks in
	 * the range that must use the IOC_HAE register for address translation,
	 * and sets this register accordingly (see section 6.4.14).
	 *
	 *	IOC_HAE left AS IS.
	 */

	/*
	 * According to section 6.4.2, all bits of the IOC_CONF register are
	 * undefined after reset.  Bits <1:0> are write-only.  Set them to
	 * 0x00 for PCI Type 0 configuration access.
	 *
	 *	IOC_CONF set to ZERO.
	 */
	REGVAL64(LCA_IOC_CONF) = 0;

	/*
	 * Disable parity on the bus. According to Linux, on some systems,
	 * siop(4) behaves badly unless parity is disabled.
	 */
	REGVAL64(LCA_IOC_PAR_DIS) = IOC_PAR_DISABLE;

	lcp->lc_initted = 1;
}

void
lcaattach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct lca_config *lcp;
	struct pcibus_attach_args pba;

	/* note that we've attached the chipset; can't have 2 LCAs. */
	/* Um, not sure about this.  XXX JH */
	lcafound = 1;

	/*
	 * set up the chipset's info; done once at console init time
	 * (maybe), but we must do it twice to take care of things
	 * that need to use memory allocation.
	 */
	lcp = &lca_configuration;
	lca_init(lcp, 1);

	/* XXX print chipset information */
	printf("\n");

	lca_dma_init(lcp);

	/* safe to override since LCA machines do not set mcheck_handler */
	platform.mcheck_handler = lca_machine_check;

	switch (cputype) {
#ifdef DEC_AXPPCI_33
	case ST_DEC_AXPPCI_33:
		pci_axppci_33_pickintr(lcp);
		break;
#endif
#ifdef DEC_ALPHABOOK1
	case ST_ALPHABOOK1:
		pci_alphabook1_pickintr(lcp);
		break;
#endif
#ifdef DEC_EB66
	case ST_EB66:
		pci_eb66_pickintr(lcp);
		break;
#endif

	default:
		panic("lcaattach: shouldn't be here, really...");
	}

	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	pba.pba_iot = &lcp->lc_iot;
	pba.pba_memt = &lcp->lc_memt;
	pba.pba_dmat =
	    alphabus_dma_get_tag(&lcp->lc_dmat_direct, ALPHA_BUS_PCI);
	pba.pba_pc = &lcp->lc_pc;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = 0;
#ifdef notyet
	pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED |
	    PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
#endif
	config_found(self, &pba, lcaprint);
}

int
lcaprint(aux, pnp)
	void *aux;
	const char *pnp;
{
	register struct pcibus_attach_args *pba = aux;

	/* only PCIs can attach to LCAes; easy. */
	if (pnp)
		printf("%s at %s", pba->pba_busname, pnp);
	printf(" bus %d", pba->pba_bus);
	return (UNCONF);
}

#if 0
int
lca_bus_get_window(type, window, abst)
	int type, window;
	struct alpha_bus_space_translation *abst;
{
	struct lca_config *lcp = &lca_configuration;
	bus_space_tag_t st;

	switch (type) {
	case ALPHA_BUS_TYPE_PCI_IO:
		st = &lcp->lc_iot;
		break;

	case ALPHA_BUS_TYPE_PCI_MEM:
		st = &lcp->lc_memt;
		break;

	default:
		panic("lca_bus_get_window");
	}

	return (alpha_bus_space_get_window(st, window, abst));
}
#endif

void
lca_machine_check(unsigned long mces, struct trapframe *framep,
    unsigned long vector, unsigned long param)
{
	int64_t stat0;

	machine_check(mces, framep, vector, param);
	/* clear error flags in IOC_STATUS0 register */
	stat0 = REGVAL64(LCA_IOC_STAT0);
	REGVAL64(LCA_IOC_STAT0) = stat0;
}


code:
/*	$OpenBSD: lca_bus_io.c,v 1.5 2001/11/06 19:53:13 miod Exp $	*/
/* $NetBSD: lca_bus_io.c,v 1.8 1997/09/02 13:19:31 thorpej Exp $ */

/*
 * Copyright (c) 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>

#define	CHIP		lca

#define	CHIP_EX_MALLOC_SAFE(v)	(((struct lca_config *)(v))->lc_mallocsafe)
#define	CHIP_IO_EXTENT(v)	(((struct lca_config *)(v))->lc_io_ex)

/* IO region 1 */
#define	CHIP_IO_W1_BUS_START(v)	0x00000000UL
#define	CHIP_IO_W1_BUS_END(v)	0x00ffffffUL
#define	CHIP_IO_W1_SYS_START(v)	LCA_PCI_SIO
#define	CHIP_IO_W1_SYS_END(v)	(LCA_PCI_SIO + ((0x00ffffffUL + 1) << 5) - 1)

#include <alpha/pci/pci_swiz_bus_io_chipdep.c>


code:
/* $OpenBSD: lca_bus_mem.c,v 1.5 2001/11/06 19:53:13 miod Exp $ */
/* $NetBSD: lca_bus_mem.c,v 1.8 1997/09/02 13:19:32 thorpej Exp $ */

/*
 * Copyright (c) 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>

#define	CHIP	lca

#define	CHIP_EX_MALLOC_SAFE(v)	(((struct lca_config *)(v))->lc_mallocsafe)
#define	CHIP_D_MEM_EXTENT(v)	(((struct lca_config *)(v))->lc_d_mem_ex)
#define	CHIP_S_MEM_EXTENT(v)	(((struct lca_config *)(v))->lc_s_mem_ex)

/* Dense region 1 */
#define	CHIP_D_MEM_W1_BUS_START(v)	0x00000000UL
#define	CHIP_D_MEM_W1_BUS_END(v)	0xffffffffUL
#define	CHIP_D_MEM_W1_SYS_START(v)	LCA_PCI_DENSE
#define	CHIP_D_MEM_W1_SYS_END(v)	(LCA_PCI_DENSE + 0xffffffffUL)

/* Sparse region 1 */
#define	CHIP_S_MEM_W1_BUS_START(v)	0x00000000UL
#define	CHIP_S_MEM_W1_BUS_END(v)	0x00ffffffUL
#define	CHIP_S_MEM_W1_SYS_START(v)	LCA_PCI_SPARSE
#define	CHIP_S_MEM_W1_SYS_END(v)					\
    (LCA_PCI_SPARSE + (0x01000000UL << 5) - 1)

/* Sparse region 2 */
#define CHIP_S_MEM_W2_BUS_START(v)					\
    ((((struct lca_config *)(v))->lc_s_mem_w2_masked_base) +		\
      0x01000000UL)
#define CHIP_S_MEM_W2_BUS_END(v)					\
    ((((struct lca_config *)(v))->lc_s_mem_w2_masked_base) +		\
      0x07ffffffUL)
#define CHIP_S_MEM_W2_SYS_START(v)					\
    (LCA_PCI_SPARSE + (0x01000000UL << 5))
#define CHIP_S_MEM_W2_SYS_END(v)					\
    (LCA_PCI_SPARSE + (0x08000000UL << 5) - 1)

#include <alpha/pci/pci_swiz_bus_mem_chipdep.c>


code:
/*	$OpenBSD: lca_dma.c,v 1.10 2013/03/08 18:26:54 miod Exp $	*/
/* $NetBSD: lca_dma.c,v 1.13 2000/06/29 08:58:47 mrg Exp $ */

/*-
 * 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.
 */

/*
 * XXX - We should define this before including bus.h, but since other stuff
 *       pulls in bus.h we must do this here.
 */
#define _ALPHA_BUS_DMA_PRIVATE

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>

bus_dma_tag_t lca_dma_get_tag(bus_dma_tag_t, alpha_bus_t);

int	lca_bus_dmamap_load_sgmap(bus_dma_tag_t, bus_dmamap_t, void *,
	    bus_size_t, struct proc *, int);

int	lca_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t, bus_dmamap_t,
	    struct mbuf *, int);

int	lca_bus_dmamap_load_uio_sgmap(bus_dma_tag_t, bus_dmamap_t,
	    struct uio *, int);

int	lca_bus_dmamap_load_raw_sgmap(bus_dma_tag_t, bus_dmamap_t,
	    bus_dma_segment_t *, int, bus_size_t, int);

void	lca_bus_dmamap_unload_sgmap(bus_dma_tag_t, bus_dmamap_t);

/*
 * Direct-mapped window: 1G at 1G
 */
#define	LCA_DIRECT_MAPPED_BASE	(1*1024*1024*1024)
#define	LCA_DIRECT_MAPPED_SIZE	(1*1024*1024*1024)

/*
 * SGMAP window: 8M at 8M
 */
#define	LCA_SGMAP_MAPPED_BASE	(8*1024*1024)
#define	LCA_SGMAP_MAPPED_SIZE	(8*1024*1024)

/*
 * Macro to flush LCA scatter/gather TLB.
 */
#define	LCA_TLB_INVALIDATE() \
do { \
	alpha_mb(); \
	REGVAL64(LCA_IOC_TBIA) = 0; \
	alpha_mb(); \
} while (0)

void
lca_dma_init(lcp)
	struct lca_config *lcp;
{
	bus_dma_tag_t t;

	/*
	 * Initialize the DMA tag used for direct-mapped DMA.
	 */
	t = &lcp->lc_dmat_direct;
	t->_cookie = lcp;
	t->_wbase = LCA_DIRECT_MAPPED_BASE;
	t->_wsize = LCA_DIRECT_MAPPED_SIZE;
	t->_next_window = NULL;
	t->_boundary = 0;
	t->_sgmap = NULL;
	t->_get_tag = lca_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;

	t->_dmamem_alloc = _bus_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;

	/*
	 * Initialize the DMA tag used for sgmap-mapped DMA.
	 */
	t = &lcp->lc_dmat_sgmap;
	t->_cookie = lcp;
	t->_wbase = LCA_SGMAP_MAPPED_BASE;
	t->_wsize = LCA_SGMAP_MAPPED_SIZE;
	t->_next_window = NULL;
	t->_boundary = 0;
	t->_sgmap = &lcp->lc_sgmap;
	t->_get_tag = lca_dma_get_tag;
	t->_dmamap_create = alpha_sgmap_dmamap_create;

	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
	t->_dmamap_load = lca_bus_dmamap_load_sgmap;
	t->_dmamap_load_mbuf = lca_bus_dmamap_load_mbuf_sgmap;
	t->_dmamap_load_uio = lca_bus_dmamap_load_uio_sgmap;
	t->_dmamap_load_raw = lca_bus_dmamap_load_raw_sgmap;
	t->_dmamap_unload = lca_bus_dmamap_unload_sgmap;
	t->_dmamap_sync = _bus_dmamap_sync;

	t->_dmamem_alloc = _bus_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;

	/* Initialize window 1 as a direct-mapped window. */
	REGVAL64(LCA_IOC_W_BASE1) = LCA_DIRECT_MAPPED_BASE | IOC_W_BASE_WEN;
	REGVAL64(LCA_IOC_W_MASK1) = IOC_W_MASK_1G;
	alpha_mb();

	/* Disable window 0 while we set it up. */
	REGVAL64(LCA_IOC_W_BASE0) = 0;
	alpha_mb();

	/*
	 * Initialize the SGMAP.
	 */
	alpha_sgmap_init(t, &lcp->lc_sgmap, "lca_sgmap",
	    LCA_SGMAP_MAPPED_BASE, 0, LCA_SGMAP_MAPPED_SIZE,
	    sizeof(u_int64_t), NULL, 0);

	/*
	 * Set up window 0 as an 8MB SGMAP-mapped window
	 * starting at 8MB.
	 */
	REGVAL64(LCA_IOC_W_BASE0) = LCA_SGMAP_MAPPED_BASE |
	    IOC_W_BASE_SG | IOC_W_BASE_WEN;
	REGVAL64(LCA_IOC_W_MASK0) = IOC_W_MASK_8M;
	alpha_mb();

	if ((lcp->lc_sgmap.aps_ptpa & IOC_W_T_BASE) !=
	    lcp->lc_sgmap.aps_ptpa)
		panic("lca_dma_init: bad page table address");
	REGVAL64(LCA_IOC_W_T_BASE0) = lcp->lc_sgmap.aps_ptpa;
	alpha_mb();

	/* Enable the scatter/gather TLB. */
	REGVAL64(LCA_IOC_TB_ENA) = IOC_TB_ENA_TEN;
	alpha_mb();

	LCA_TLB_INVALIDATE();

	/* XXX XXX BEGIN XXX XXX */
	{							/* XXX */
		extern paddr_t alpha_XXX_dmamap_or;		/* XXX */
		alpha_XXX_dmamap_or = LCA_DIRECT_MAPPED_BASE;	/* XXX */
	}							/* XXX */
	/* XXX XXX END XXX XXX */
}

/*
 * Return the bus dma tag to be used for the specified bus type.
 * INTERNAL USE ONLY!
 */
bus_dma_tag_t
lca_dma_get_tag(t, bustype)
	bus_dma_tag_t t;
	alpha_bus_t bustype;
{
	struct lca_config *lcp = t->_cookie;

	switch (bustype) {
	case ALPHA_BUS_PCI:
	case ALPHA_BUS_EISA:
		/*
		 * Systems with an LCA can only support 1G
		 * of memory, so we use the direct-mapped window
		 * on busses that have 32-bit DMA.
		 */
		return (&lcp->lc_dmat_direct);

	case ALPHA_BUS_ISA:
		/*
		 * ISA doesn't have enough address bits to use
		 * the direct-mapped DMA window, so we must use
		 * SGMAPs.
		 */
		return (&lcp->lc_dmat_sgmap);

	default:
		panic("lca_dma_get_tag: shouldn't be here, really...");
	}
}

/*
 * Load an LCA SGMAP-mapped DMA map with a linear buffer.
 */
int
lca_bus_dmamap_load_sgmap(t, map, buf, buflen, p, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	void *buf;
	bus_size_t buflen;
	struct proc *p;
	int flags;
{
	int error;

	error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
	    t->_sgmap);
	if (error == 0)
		LCA_TLB_INVALIDATE();

	return (error);
}

/*
 * Load an LCA SGMAP-mapped DMA map with an mbuf chain.
 */
int
lca_bus_dmamap_load_mbuf_sgmap(t, map, m, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct mbuf *m;
	int flags;
{
	int error;

	error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, t->_sgmap);
	if (error == 0)
		LCA_TLB_INVALIDATE();

	return (error);
}

/*
 * Load an LCA SGMAP-mapped DMA map with a uio.
 */
int
lca_bus_dmamap_load_uio_sgmap(t, map, uio, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct uio *uio;
	int flags;
{
	int error;

	error = pci_sgmap_pte64_load_uio(t, map, uio, flags, t->_sgmap);
	if (error == 0)
		LCA_TLB_INVALIDATE();

	return (error);
}

/*
 * Load an LCA SGMAP-mapped DMA map with raw memory.
 */
int
lca_bus_dmamap_load_raw_sgmap(t, map, segs, nsegs, size, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	bus_dma_segment_t *segs;
	int nsegs;
	bus_size_t size;
	int flags;
{
	int error;

	error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
	    t->_sgmap);
	if (error == 0)
		LCA_TLB_INVALIDATE();

	return (error);
}

/*
 * Unload an LCA DMA map.
 */
void
lca_bus_dmamap_unload_sgmap(t, map)
	bus_dma_tag_t t;
	bus_dmamap_t map;
{

	/*
	 * Invalidate any SGMAP page table entries used by this
	 * mapping.
	 */
	pci_sgmap_pte64_unload(t, map, t->_sgmap);
	LCA_TLB_INVALIDATE();

	/*
	 * Do the generic bits of the unload.
	 */
	_bus_dmamap_unload(t, map);
}


code:
/*	$OpenBSD: lca_pci.c,v 1.11 2015/07/18 00:21:14 miod Exp $	*/
/* $NetBSD: lca_pci.c,v 1.13 1997/09/02 13:19:35 thorpej Exp $ */

/*
 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/autoconf.h>	/* badaddr proto */

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>

void		lca_attach_hook(struct device *, struct device *,
		    struct pcibus_attach_args *);
int		lca_bus_maxdevs(void *, int);
pcitag_t	lca_make_tag(void *, int, int, int);
void		lca_decompose_tag(void *, pcitag_t, int *, int *,
		    int *);
int		lca_conf_size(void *, pcitag_t);
pcireg_t	lca_conf_read(void *, pcitag_t, int);
void		lca_conf_write(void *, pcitag_t, int, pcireg_t);

void
lca_pci_init(pc, v)
	pci_chipset_tag_t pc;
	void *v;
{

	pc->pc_conf_v = v;
	pc->pc_attach_hook = lca_attach_hook;
	pc->pc_bus_maxdevs = lca_bus_maxdevs;
	pc->pc_make_tag = lca_make_tag;
	pc->pc_decompose_tag = lca_decompose_tag;
	pc->pc_conf_size = lca_conf_size;
	pc->pc_conf_read = lca_conf_read;
	pc->pc_conf_write = lca_conf_write;
}

void
lca_attach_hook(parent, self, pba)
	struct device *parent, *self;
	struct pcibus_attach_args *pba;
{
}

int
lca_bus_maxdevs(cpv, busno)
	void *cpv;
	int busno;
{

	if (busno == 0)
		return 16;
	else
		return 32;
}

pcitag_t
lca_make_tag(cpv, b, d, f)
	void *cpv;
	int b, d, f;
{

	return (b << 16) | (d << 11) | (f << 8);
}

void
lca_decompose_tag(cpv, tag, bp, dp, fp)
	void *cpv;
	pcitag_t tag;
	int *bp, *dp, *fp;
{

	if (bp != NULL)
		*bp = (tag >> 16) & 0xff;
	if (dp != NULL)
		*dp = (tag >> 11) & 0x1f;
	if (fp != NULL)
		*fp = (tag >> 8) & 0x7;
}

int
lca_conf_size(void *cpv, pcitag_t tag)
{
	return PCI_CONFIG_SPACE_SIZE;
}

pcireg_t
lca_conf_read(cpv, tag, offset)
	void *cpv;
	pcitag_t tag;
	int offset;
{
	struct lca_config *lcp = cpv;
	pcireg_t *datap, data;
	int s, secondary, device, ba;

	s = 0;					/* XXX gcc -Wuninitialized */

	alpha_mb();
	REGVAL64(LCA_IOC_STAT0) = REGVAL64(LCA_IOC_STAT0);
	alpha_mb();

	/* secondary if bus # != 0 */
	pci_decompose_tag(&lcp->lc_pc, tag, &secondary, &device, 0);
	if (secondary) {
		s = splhigh();
		alpha_mb();
		REGVAL(LCA_IOC_CONF) = 0x01;
		alpha_mb();
	} else {
		/*
		 * on the LCA, must frob the tag used for
		 * devices on the primary bus, in the same ways
		 * as is used by type 1 configuration cycles
		 * on PCs.
		 */
		tag = (1 << (device + 11)) | (tag & 0x7ff);
	}

	datap = (pcireg_t *)ALPHA_PHYS_TO_K0SEG(LCA_PCI_CONF |
	    tag << 5UL |					/* XXX */
	    (offset & ~0x03) << 5 |				/* XXX */
	    0 << 5 |						/* XXX */
	    0x3 << 3);						/* XXX */
	data = (pcireg_t)-1;
	if (!(ba = badaddr(datap, sizeof *datap))) {
		if (REGVAL64(LCA_IOC_STAT0) & IOC_STAT0_ERR) {
			alpha_mb();
			REGVAL64(LCA_IOC_STAT0) = REGVAL64(LCA_IOC_STAT0);
			alpha_mb();
		} else
			data = *datap;
	}

	if (secondary) {
		alpha_mb();
		REGVAL(LCA_IOC_CONF) = 0x00;
		alpha_mb();
		splx(s);
	}

#if 0
	printf("lca_conf_read: tag 0x%lx, reg 0x%lx -> %x @ %p%s\n", tag, reg,
	    data, datap, ba ? " (badaddr)" : "");
#endif

	return data;
}

void
lca_conf_write(cpv, tag, offset, data)
	void *cpv;
	pcitag_t tag;
	int offset;
	pcireg_t data;
{
	struct lca_config *lcp = cpv;
	pcireg_t *datap;
	int s, secondary, device;

	s = 0;					/* XXX gcc -Wuninitialized */

	/* secondary if bus # != 0 */
	pci_decompose_tag(&lcp->lc_pc, tag, &secondary, &device, 0);
	if (secondary) {
		s = splhigh();
		alpha_mb();
		REGVAL(LCA_IOC_CONF) = 0x01;
		alpha_mb();
	} else {
		/*
		 * on the LCA, must frob the tag used for
		 * devices on the primary bus, in the same ways
		 * as is used by type 1 configuration cycles
		 * on PCs.
		 */
		tag = (1 << (device + 11)) | (tag & 0x7ff);
	}

	datap = (pcireg_t *)ALPHA_PHYS_TO_K0SEG(LCA_PCI_CONF |
	    tag << 5UL |					/* XXX */
	    (offset & ~0x03) << 5 |				/* XXX */
	    0 << 5 |						/* XXX */
	    0x3 << 3);						/* XXX */
	*datap = data;

	if (secondary) {
		alpha_mb();
		REGVAL(LCA_IOC_CONF) = 0x00;
		alpha_mb();
		splx(s);
	}

#if 0
	printf("lca_conf_write: tag 0x%lx, reg 0x%lx -> 0x%x @ %p\n", tag,
	    reg, data, datap);
#endif
}


code:
/*	$OpenBSD: lcareg.h,v 1.8 2013/06/04 19:12:34 miod Exp $	*/
/* $NetBSD: lcareg.h,v 1.7 1997/06/06 23:54:31 thorpej Exp $ */

/*
 * Copyright (c) 1995 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Authors: Jeffrey Hsu, Jason R. Thorpe
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

/*
 * 21066 chip registers
 */

#define REGVAL(r)	(*(volatile int32_t *)ALPHA_PHYS_TO_K0SEG(r))
#define REGVAL64(r)	(*(volatile int64_t *)ALPHA_PHYS_TO_K0SEG(r))

/*
 * Base addresses
 */
#define LCA_IOC_BASE	0x180000000L		/* LCA IOC Regs */
#define LCA_PCI_SIO	0x1c0000000L		/* PCI Sp. I/O Space */
#define LCA_PCI_CONF	0x1e0000000L		/* PCI Conf. Space */
#define LCA_PCI_SPARSE	0x200000000L		/* PCI Sparse Space */
#define LCA_PCI_DENSE	0x300000000L		/* PCI Dense Space */

#define LCA_IOC_HAE	LCA_IOC_BASE		/* Host Address Ext. (64) */
#define	IOC_HAE_ADDREXT	0x00000000f8000000UL
#define	IOC_HAE_RSVSD	0xffffffff07ffffffUL

#define LCA_IOC_CONF	(LCA_IOC_BASE + 0x020)	/* Configuration Cycle Type */

#define LCA_IOC_STAT0	(LCA_IOC_BASE + 0x040)	/* Status 0 */
#define	IOC_STAT0_CMD	0x000000000000000fUL	/* PCI command mask */
#define	IOC_STAT0_ERR	0x0000000000000010UL	/* IOC error indicator R/W1C */
#define	IOC_STAT0_LOST	0x0000000000000020UL	/* IOC lose error info R/W1C */
#define	IOC_STAT0_THIT	0x0000000000000040UL	/* test hit */
#define	IOC_STAT0_TREF	0x0000000000000080UL	/* test reference */
#define	IOC_STAT0_CODE	0x0000000000000700UL	/* code mask */
#define	IOC_STAT0_CODESHIFT 8
#define	IOC_STAT0_P_NBR	0x00000000ffffe000UL	/* page number mask */

#define LCA_IOC_STAT1	(LCA_IOC_BASE + 0x060)	/* Status 1 */
#define	IOC_STAT1_ADDR	0x00000000ffffffffUL	/* PCI address mask */

#define	LCA_IOC_TBIA	(LCA_IOC_BASE + 0x080)	/* TLB Invalidate All */
#define	LCA_IOC_TB_ENA	(LCA_IOC_BASE + 0x0a0)	/* TLB Enable */
#define	IOC_TB_ENA_TEN	0x0000000000000080UL

#define	LCA_IOC_PAR_DIS	(LCA_IOC_BASE + 0x0e0)	/* Parity Disable */
#define	IOC_PAR_DISABLE	0x0000000000000020UL

#define LCA_IOC_W_BASE0	(LCA_IOC_BASE + 0x100)	/* Window Base */
#define LCA_IOC_W_MASK0	(LCA_IOC_BASE + 0x140)	/* Window Mask */
#define LCA_IOC_W_T_BASE0 (LCA_IOC_BASE + 0x180) /* Translated Base */

#define LCA_IOC_W_BASE1	(LCA_IOC_BASE + 0x120)	/* Window Base */
#define LCA_IOC_W_MASK1	(LCA_IOC_BASE + 0x160)	/* Window Mask */
#define LCA_IOC_W_T_BASE1 (LCA_IOC_BASE + 0x1a0) /* Translated Base */

#define	IOC_W_BASE_W_BASE 0x00000000fff00000UL	/* Window base value */
#define	IOC_W_BASE_SG	  0x0000000100000000UL	/* Window uses SGMAPs */
#define	IOC_W_BASE_WEN	  0x0000000200000000UL	/* Window enable */

#define	IOC_W_MASK_1M	0x0000000000000000UL	/* 1MB window */
#define	IOC_W_MASK_2M	0x0000000000100000UL	/* 2MB window */
#define	IOC_W_MASK_4M	0x0000000000300000UL	/* 4MB window */
#define	IOC_W_MASK_8M	0x0000000000700000UL	/* 8MB window */
#define	IOC_W_MASK_16M	0x0000000000f00000UL	/* 16MB window */
#define	IOC_W_MASK_32M	0x0000000001f00000UL	/* 32MB window */
#define	IOC_W_MASK_64M	0x0000000003f00000UL	/* 64MB window */
#define	IOC_W_MASK_128M	0x0000000007f00000UL	/* 128M window */
#define	IOC_W_MASK_256M	0x000000000ff00000UL	/* 256M window */
#define	IOC_W_MASK_512M	0x000000001ff00000UL	/* 512M window */
#define	IOC_W_MASK_1G	0x000000003ff00000UL	/* 1GB window */
#define	IOC_W_MASK_2G	0x000000007ff00000UL	/* 2GB window */
#define	IOC_W_MASK_4G	0x00000000fff00000UL	/* 4GB window */

#define	IOC_W_T_BASE	0x00000000fffffc00UL	/* page table base */


code:
/*	$OpenBSD: lcavar.h,v 1.11 2006/03/16 22:32:44 miod Exp $	*/
/* $NetBSD: lcavar.h,v 1.7 1997/06/06 23:54:32 thorpej Exp $ */

/*
 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Jeffrey Hsu
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <dev/isa/isavar.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/pci_sgmap_pte64.h>

/*
 * LCA chipset's configuration.
 *
 * All of the information that the chipset-specific functions need to
 * do their dirty work (and more!).
 */
struct lca_config {
	int	lc_initted;

	struct alpha_bus_space lc_iot, lc_memt;
	struct alpha_pci_chipset lc_pc;

	struct alpha_bus_dma_tag lc_dmat_direct;
	struct alpha_bus_dma_tag lc_dmat_sgmap;

	struct alpha_sgmap lc_sgmap;

	bus_addr_t lc_s_mem_w2_masked_base;

	struct extent *lc_io_ex, *lc_d_mem_ex, *lc_s_mem_ex;
	int	lc_mallocsafe;
};

void	lca_init(struct lca_config *, int);
void	lca_pci_init(pci_chipset_tag_t, void *);
void	lca_dma_init(struct lca_config *);

void	lca_bus_io_init(bus_space_tag_t, void *);
void	lca_bus_mem_init(bus_space_tag_t, void *);


code:
/* $OpenBSD: mcpcia.c,v 1.6 2012/12/05 23:20:10 deraadt Exp $ */
/* $NetBSD: mcpcia.c,v 1.20 2007/03/04 05:59:11 christos Exp $ */

/*-
 * Copyright (c) 1999 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.
 */

/*
 * Copyright (c) 1998 by Matthew Jacob
 * NASA AMES Research Center.
 * 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 immediately at the beginning of the file, without modification,
 *    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 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 AUTHOR 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.
 */

/*
 * MCPCIA mcbus to PCI bus adapter
 * found on AlphaServer 4100 systems.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>

#include <machine/autoconf.h>
#include <machine/rpb.h>
#include <machine/sysarch.h>

#include <alpha/mcbus/mcbusreg.h>
#include <alpha/mcbus/mcbusvar.h>
#include <alpha/pci/mcpciareg.h>
#include <alpha/pci/mcpciavar.h>
#include <alpha/pci/pci_kn300.h>

#define KV(_addr)	((caddr_t)ALPHA_PHYS_TO_K0SEG((_addr)))
#define	MCPCIA_SYSBASE(mc)	\
	((((unsigned long) (mc)->cc_gid) << MCBUS_GID_SHIFT) | \
	 (((unsigned long) (mc)->cc_mid) << MCBUS_MID_SHIFT) | \
	 (MCBUS_IOSPACE))

#define	MCPCIA_PROBE(mid, gid)	\
	badaddr((void *)KV(((((unsigned long) gid) << MCBUS_GID_SHIFT) | \
	 (((unsigned long) mid) << MCBUS_MID_SHIFT) | \
	 (MCBUS_IOSPACE) | MCPCIA_PCI_BRIDGE | _MCPCIA_PCI_REV)), \
	sizeof(u_int32_t))

int	mcpciamatch (struct device *, void *, void *);
void	mcpciaattach (struct device *, struct device *, void *);
void	mcpcia_config_cleanup (void);

int	mcpciaprint (void *, const char *);

struct cfattach mcpcia_ca = {
	sizeof(struct mcpcia_softc), mcpciamatch, mcpciaattach
};

struct cfdriver mcpcia_cd = {
        NULL, "mcpcia", DV_DULL,
};

/*
 * We have one statically-allocated mcpcia_config structure; this is
 * the one used for the console (which, coincidentally, is the only
 * MCPCIA with an EISA adapter attached to it).
 */
struct mcpcia_config mcpcia_console_configuration;

int
mcpciaprint(aux, pnp)
       void *aux;
       const char *pnp;
{
       register struct pcibus_attach_args *pba = aux;
       /* only PCIs can attach to MCPCIA for now */
       if (pnp)
               printf("%s at %s", pba->pba_busname, pnp);
       printf(" bus %d", pba->pba_bus);
       return (UNCONF);
}

int
mcpciamatch(parent, cf, aux)
	struct device *parent;
	void *cf;
	void *aux;
{
	struct mcbus_dev_attach_args *ma = aux;

	if (ma->ma_type == MCBUS_TYPE_PCI)
		return (1);

	return (0);
}

void
mcpciaattach(parent, self, aux)
	struct device *parent;
	struct device *self;
	void *aux;
{
	static int first = 1;
	struct mcbus_dev_attach_args *ma = aux;
	struct mcpcia_softc *mcp = (struct mcpcia_softc *)self;
	struct mcpcia_config *ccp;
	struct pcibus_attach_args pba;
	u_int32_t ctl;

	/*
	 * Make sure this MCPCIA exists...
	 */
	if (MCPCIA_PROBE(ma->ma_mid, ma->ma_gid)) {
		mcp->mcpcia_cc = NULL;
		printf(" (not present)\n");
		return;
	}
	printf("\n");

	/*
	 * Determine if we're the console's MCPCIA.
	 */
	if (ma->ma_mid == mcpcia_console_configuration.cc_mid &&
	    ma->ma_gid == mcpcia_console_configuration.cc_gid)
		ccp = &mcpcia_console_configuration;
	else {
		ccp = malloc(sizeof(*ccp), M_DEVBUF, M_WAITOK | M_ZERO);

		ccp->cc_mid = ma->ma_mid;
		ccp->cc_gid = ma->ma_gid;
	}
	mcp->mcpcia_cc = ccp;
	ccp->cc_sc = mcp;

	/* This initializes cc_sysbase so we can do register access. */
	mcpcia_init0(ccp, 1);

	ctl = REGVAL(MCPCIA_PCI_REV(ccp));
	printf("%s: Horse rev %d, %s handed Saddle rev %d, CAP rev %d\n",
	    mcp->mcpcia_dev.dv_xname, HORSE_REV(ctl),
	    (SADDLE_TYPE(ctl) & 1) ? "right" : "left", SADDLE_REV(ctl),
	    CAP_REV(ctl));

	mcpcia_dma_init(ccp);

	/*
	 * Set up interrupts
	 */
	pci_kn300_pickintr(ccp, first);
	first = 0;

	/*
	 * Attach PCI bus
	 */
	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	pba.pba_iot = &ccp->cc_iot;
	pba.pba_memt = &ccp->cc_memt;
	pba.pba_dmat =
	    alphabus_dma_get_tag(&ccp->cc_dmat_direct, ALPHA_BUS_PCI);
	pba.pba_pc = &ccp->cc_pc;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = 0;

	config_found(self, &pba, mcpciaprint);

	/*
	 * Clear any errors that may have occurred during the probe
	 * sequence.
	 */
	REGVAL(MCPCIA_CAP_ERR(ccp)) = 0xFFFFFFFF;
	alpha_mb();
}

void
mcpcia_init()
{
	struct mcpcia_config *ccp = &mcpcia_console_configuration;
	int i;

	/*
	 * Look for all of the MCPCIAs on the system.  One of them
	 * will have an EISA attached to it.  This MCPCIA is the
	 * only one that can be used for the console.  Once we find
	 * that one, initialize it.
	 */
	for (i = 0; i < MCPCIA_PER_MCBUS; i++) {
		ccp->cc_mid = mcbus_mcpcia_probe_order[i];
		/*
		 * XXX If we ever support more than one MCBUS, we'll
		 * XXX have to probe for them, and map them to unit
		 * XXX numbers.
		 */
		ccp->cc_gid = MCBUS_GID_FROM_INSTANCE(0);
		ccp->cc_sysbase = MCPCIA_SYSBASE(ccp);

		if (badaddr((void *)ALPHA_PHYS_TO_K0SEG(MCPCIA_PCI_REV(ccp)),
		    sizeof(u_int32_t)))
			continue;

		if (EISA_PRESENT(REGVAL(MCPCIA_PCI_REV(ccp)))) {
			mcpcia_init0(ccp, 0);
			return;
		}
	}

	panic("mcpcia_init: unable to find EISA bus");
}

void
mcpcia_init0(ccp, mallocsafe)
	struct mcpcia_config *ccp;
	int mallocsafe;
{
	u_int32_t ctl;

	snprintf(ccp->pc_io_ex_name, sizeof ccp->pc_io_ex_name,
	    "mcpcia%d_bus_io", ccp->cc_mid);
	snprintf(ccp->pc_mem_dex_name, sizeof ccp->pc_mem_dex_name,
	    "mcpciad%d_bus_mem", ccp->cc_mid);
	snprintf(ccp->pc_mem_dex_name, sizeof ccp->pc_mem_sex_name,
	    "mcpcias%d_bus_mem", ccp->cc_mid);

	if (!ccp->cc_initted) {
		/* don't do these twice since they set up extents */
		mcpcia_bus_io_init(&ccp->cc_iot, ccp);
		mcpcia_bus_mem_init(&ccp->cc_memt, ccp);
	}
	ccp->cc_mallocsafe = mallocsafe;

	mcpcia_pci_init(&ccp->cc_pc, ccp);

        /*
         * Establish a precalculated base for convenience's sake.
         */
        ccp->cc_sysbase = MCPCIA_SYSBASE(ccp);

        /*
         * Disable interrupts and clear errors prior to probing
         */
        REGVAL(MCPCIA_INT_MASK0(ccp)) = 0;
        REGVAL(MCPCIA_INT_MASK1(ccp)) = 0;
        REGVAL(MCPCIA_CAP_ERR(ccp)) = 0xFFFFFFFF;
        alpha_mb();

        if (ccp == &mcpcia_console_configuration) {
                /*
                 * Use this opportunity to also find out the MID and CPU
                 * type of the currently running CPU (that's us, billybob....)
                 */
                ctl = REGVAL(MCPCIA_WHOAMI(ccp));
                mcbus_primary.mcbus_cpu_mid = MCBUS_CPU_MID(ctl);
                if ((MCBUS_CPU_INFO(ctl) & CPU_Fill_Err) == 0 &&
                    mcbus_primary.mcbus_valid == 0) {
                        mcbus_primary.mcbus_bcache =
                            MCBUS_CPU_INFO(ctl) & CPU_BCacheMask;
                        mcbus_primary.mcbus_valid = 1;
                }
                alpha_mb();
        }

	alpha_pci_chipset = &ccp->cc_pc;
	alpha_pci_chipset->pc_name = "mcpcia";
	alpha_pci_chipset->pc_hae_mask = 0;
	alpha_pci_chipset->pc_dense = MCPCIA_PCI_DENSE;

        ccp->cc_initted = 1;
}

void
mcpcia_config_cleanup()
{
	volatile u_int32_t ctl;
	struct mcpcia_softc *mcp;
	struct mcpcia_config *ccp;
	int i;
	extern struct cfdriver mcpcia_cd;

	/*
	 * Turn on Hard, Soft error interrupts. Maybe i2c too.
	 */
	for (i = 0; i < mcpcia_cd.cd_ndevs; i++) {
		if ((mcp = mcpcia_cd.cd_devs[i]) == NULL)
			continue;

		ccp = mcp->mcpcia_cc;
		if (ccp == NULL)
			continue;

		ctl = REGVAL(MCPCIA_INT_MASK0(ccp));
		ctl |= MCPCIA_GEN_IENABL;
		REGVAL(MCPCIA_INT_MASK0(ccp)) = ctl;
		alpha_mb();

		/* force stall while write completes */
		ctl = REGVAL(MCPCIA_INT_MASK0(ccp));
	}
}


code:
/* $OpenBSD: mcpcia_bus_io.c,v 1.2 2012/12/05 23:20:10 deraadt Exp $ */
/* $NetBSD: mcpcia_bus_io.c,v 1.3 2000/06/29 08:58:47 mrg Exp $ */

/*
 * Copyright (c) 1998 by Matthew Jacob
 * NASA AMES Research Center.
 * 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 immediately at the beginning of the file, without modification,
 *    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 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 AUTHOR 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/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <alpha/pci/mcpciareg.h>
#include <alpha/pci/mcpciavar.h>

#define	CHIP		mcpcia

#define	CHIP_EX_MALLOC_SAFE(v)	(((struct mcpcia_config *)(v))->cc_mallocsafe)
#define	CHIP_IO_EXTENT(v)	(((struct mcpcia_config *)(v))->cc_io_ex)
#define	CHIP_IO_EX_STORE(v)	(((struct mcpcia_config *)(v))->cc_io_exstorage)
#define	CHIP_IO_EX_STORE_SIZE(v)					\
	(sizeof (((struct mcpcia_config *)(v))->cc_io_exstorage))

/* IO Region 1 */
#define	CHIP_IO_W1_BUS_START(v)	0x00000000UL
#define	CHIP_IO_W1_BUS_END(v)	0x0000ffffUL
#define	CHIP_IO_W1_SYS_START(v)						\
	(((struct mcpcia_config *)(v))->cc_sysbase | MCPCIA_PCI_IOSPACE)
#define	CHIP_IO_W1_SYS_END(v)						\
	(CHIP_IO_W1_SYS_START(v) + ((CHIP_IO_W1_BUS_END(v) + 1) << 5) - 1)

/* IO Region 2 */
#define	CHIP_IO_W2_BUS_START(v)	0x00010000UL
#define	CHIP_IO_W2_BUS_END(v)	0x01ffffffUL
#define	CHIP_IO_W2_SYS_START(v)						\
	(((struct mcpcia_config *)(v))->cc_sysbase + MCPCIA_PCI_IOSPACE + \
	    (0x00010000 << 5))
#define	CHIP_IO_W2_SYS_END(v)						\
	((CHIP_IO_W1_SYS_START(v) + ((CHIP_IO_W2_BUS_END(v) + 1) << 5) - 1))

#define CHIP_EXTENT_NAME(v)		((struct mcpcia_config *)(v))->pc_io_ex_name
#define CHIP_EXTENT_STORAGE(v)		((struct mcpcia_config *)(v))->pc_io_ex_storage

#include "alpha/pci/pci_swiz_bus_io_chipdep.c"


code:
/* $OpenBSD: mcpcia_bus_mem.c,v 1.2 2012/12/05 23:20:10 deraadt Exp $ */
/* $NetBSD: mcpcia_bus_mem.c,v 1.3 2000/06/29 08:58:47 mrg Exp $ */

/*
 * Copyright (c) 1998 by Matthew Jacob
 * NASA AMES Research Center.
 * 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 immediately at the beginning of the file, without modification,
 *    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 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 AUTHOR 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/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <alpha/pci/mcpciareg.h>
#include <alpha/pci/mcpciavar.h>

#define	CHIP		mcpcia

#define	CHIP_EX_MALLOC_SAFE(v)	(((struct mcpcia_config *)(v))->cc_mallocsafe)
#define	CHIP_D_MEM_EXTENT(v)	(((struct mcpcia_config *)(v))->cc_d_mem_ex)
#define	CHIP_D_MEM_EX_STORE(v)						\
	(((struct mcpcia_config *)(v))->cc_dmem_exstorage)
#define	CHIP_D_MEM_EX_STORE_SIZE(v)					\
	(sizeof (((struct mcpcia_config *)(v))->cc_dmem_exstorage))
#define	CHIP_S_MEM_EXTENT(v)	(((struct mcpcia_config *)(v))->cc_s_mem_ex)
#define	CHIP_S_MEM_EX_STORE(v)						\
	(((struct mcpcia_config *)(v))->cc_smem_exstorage)
#define	CHIP_S_MEM_EX_STORE_SIZE(v)					\
	(sizeof (((struct mcpcia_config *)(v))->cc_smem_exstorage))

/* Dense region 1 */
#define	CHIP_D_MEM_W1_BUS_START(v)	0x00000000UL
#define	CHIP_D_MEM_W1_BUS_END(v)	0x7fffffffUL
#define	CHIP_D_MEM_W1_SYS_START(v)					\
	(((struct mcpcia_config *)(v))->cc_sysbase | MCPCIA_PCI_DENSE)
#define	CHIP_D_MEM_W1_SYS_END(v)					\
	(CHIP_D_MEM_W1_SYS_START(v) + 0x7fffffffUL)

/* Sparse region 1 */
#define	CHIP_S_MEM_W1_BUS_START(v)	0x00000000UL
#define	CHIP_S_MEM_W1_BUS_END(v)	0x00ffffffUL
#define	CHIP_S_MEM_W1_SYS_START(v)					\
	(((struct mcpcia_config *)(v))->cc_sysbase | MCPCIA_PCI_SPARSE)
#define	CHIP_S_MEM_W1_SYS_END(v)					\
	(CHIP_S_MEM_W1_SYS_START(v) + ((CHIP_S_MEM_W1_BUS_END(v) + 1) << 5) - 1)

/* Sparse region 2 */
#define	CHIP_S_MEM_W2_BUS_START(v)	0x01000000UL
#define	CHIP_S_MEM_W2_BUS_END(v)	0x07FFFFFFUL
#define	CHIP_S_MEM_W2_SYS_START(v)					\
	((((struct mcpcia_config *)(v))->cc_sysbase|MCPCIA_PCI_SPARSE) + \
	(0x01000000UL<<5))
#define	CHIP_S_MEM_W2_SYS_END(v)					\
	(CHIP_S_MEM_W1_SYS_START(v) + ((CHIP_S_MEM_W2_BUS_END(v) + 1) << 5) - 1)

#define CHIP_EXTENT_DNAME(v)		((struct mcpcia_config *)(v))->pc_mem_dex_name
#define CHIP_EXTENT_SNAME(v)		((struct mcpcia_config *)(v))->pc_mem_sex_name
#define CHIP_EXTENT_DSTORAGE(v)		((struct mcpcia_config *)(v))->pc_mem_dex_storage
#define CHIP_EXTENT_SSTORAGE(v)		((struct mcpcia_config *)(v))->pc_mem_sex_storage

#include "alpha/pci/pci_swiz_bus_mem_chipdep.c"


code:
/* $OpenBSD: mcpcia_dma.c,v 1.5 2014/06/14 23:11:20 jmatthew Exp $ */
/* $NetBSD: mcpcia_dma.c,v 1.15 2001/07/19 18:55:40 thorpej Exp $ */

/*-
 * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe and Matthew Jacob 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.
 */

#define _ALPHA_BUS_DMA_PRIVATE

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>
#include <machine/rpb.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/mcpciareg.h>
#include <alpha/pci/mcpciavar.h>
#include <alpha/pci/pci_kn300.h>

bus_dma_tag_t mcpcia_dma_get_tag (bus_dma_tag_t, alpha_bus_t);

int	mcpcia_bus_dmamap_load_sgmap (bus_dma_tag_t, bus_dmamap_t, void *,
	    bus_size_t, struct proc *, int);

int	mcpcia_bus_dmamap_load_mbuf_sgmap (bus_dma_tag_t, bus_dmamap_t,
	    struct mbuf *, int);

int	mcpcia_bus_dmamap_load_uio_sgmap (bus_dma_tag_t, bus_dmamap_t,
	    struct uio *, int);

int	mcpcia_bus_dmamap_load_raw_sgmap (bus_dma_tag_t, bus_dmamap_t,
	    bus_dma_segment_t *, int, bus_size_t, int);

void	mcpcia_bus_dmamap_unload_sgmap (bus_dma_tag_t, bus_dmamap_t);

/*
 * Direct-mapped window: 2G at 2G
 */
#define	MCPCIA_DIRECT_MAPPED_BASE	(2UL*1024UL*1024UL*1024UL)
#define	MCPCIA_DIRECT_MAPPED_SIZE	(2UL*1024UL*1024UL*1024UL)

/*
 * SGMAP window for PCI: 1G at 1G
 */
#define	MCPCIA_PCI_SG_MAPPED_BASE	(1UL*1024UL*1024UL*1024UL)
#define	MCPCIA_PCI_SG_MAPPED_SIZE	(1UL*1024UL*1024UL*1024UL)

/*
 * SGMAP window for ISA: 8M at 8M
 */
#define	MCPCIA_ISA_SG_MAPPED_BASE	(8*1024*1024)
#define	MCPCIA_ISA_SG_MAPPED_SIZE	(8*1024*1024)

#define	MCPCIA_SGTLB_INVALIDATE(ccp)					\
do {									\
	alpha_mb();							\
	REGVAL(MCPCIA_SG_TBIA(ccp)) = 0xdeadbeef;			\
	alpha_mb();							\
} while (0)

void
mcpcia_dma_init(ccp)
	struct mcpcia_config *ccp;
{
	bus_dma_tag_t t;

	/*
	 * Initialize the DMA tag used for direct-mapped DMA.
	 */
	t = &ccp->cc_dmat_direct;
	t->_cookie = ccp;
	t->_wbase = MCPCIA_DIRECT_MAPPED_BASE;
	t->_wsize = MCPCIA_DIRECT_MAPPED_SIZE;
	t->_next_window = &ccp->cc_dmat_pci_sgmap;
	t->_boundary = 0;
	t->_sgmap = NULL;
	t->_get_tag = mcpcia_dma_get_tag;
	/*
	 * Since we fall back to sgmap if the direct mapping fails,
	 * we need to set up for sgmap in any case.
	 */
	t->_dmamap_create = alpha_sgmap_dmamap_create;
	t->_dmamap_destroy = alpha_sgmap_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;

	t->_dmamem_alloc = _bus_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;

	/*
	 * Initialize the DMA tag used for sgmap-mapped PCI DMA.
	 */
	t = &ccp->cc_dmat_pci_sgmap;
	t->_cookie = ccp;
	t->_wbase = MCPCIA_PCI_SG_MAPPED_BASE;
	t->_wsize = MCPCIA_PCI_SG_MAPPED_SIZE;
	t->_next_window = NULL;
	t->_boundary = 0;
	t->_sgmap = &ccp->cc_pci_sgmap;
	t->_get_tag = mcpcia_dma_get_tag;
	t->_dmamap_create = alpha_sgmap_dmamap_create;
	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
	t->_dmamap_load = mcpcia_bus_dmamap_load_sgmap;
	t->_dmamap_load_mbuf = mcpcia_bus_dmamap_load_mbuf_sgmap;
	t->_dmamap_load_uio = mcpcia_bus_dmamap_load_uio_sgmap;
	t->_dmamap_load_raw = mcpcia_bus_dmamap_load_raw_sgmap;
	t->_dmamap_unload = mcpcia_bus_dmamap_unload_sgmap;
	t->_dmamap_sync = _bus_dmamap_sync;

	t->_dmamem_alloc = _bus_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;

	/*
	 * Initialize the DMA tag used for sgmap-mapped ISA DMA.
	 */
	t = &ccp->cc_dmat_isa_sgmap;
	t->_cookie = ccp;
	t->_wbase = MCPCIA_ISA_SG_MAPPED_BASE;
	t->_wsize = MCPCIA_ISA_SG_MAPPED_SIZE;
	t->_next_window = NULL;
	t->_boundary = 0;
	t->_sgmap = &ccp->cc_isa_sgmap;
	t->_get_tag = mcpcia_dma_get_tag;
	t->_dmamap_create = alpha_sgmap_dmamap_create;
	t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
	t->_dmamap_load = mcpcia_bus_dmamap_load_sgmap;
	t->_dmamap_load_mbuf = mcpcia_bus_dmamap_load_mbuf_sgmap;
	t->_dmamap_load_uio = mcpcia_bus_dmamap_load_uio_sgmap;
	t->_dmamap_load_raw = mcpcia_bus_dmamap_load_raw_sgmap;
	t->_dmamap_unload = mcpcia_bus_dmamap_unload_sgmap;
	t->_dmamap_sync = _bus_dmamap_sync;

	t->_dmamem_alloc = _bus_dmamem_alloc;
	t->_dmamem_free = _bus_dmamem_free;
	t->_dmamem_map = _bus_dmamem_map;
	t->_dmamem_unmap = _bus_dmamem_unmap;
	t->_dmamem_mmap = _bus_dmamem_mmap;

	/*
	 * Initialize the SGMAPs.
	 */
	alpha_sgmap_init(&ccp->cc_dmat_pci_sgmap, &ccp->cc_pci_sgmap,
	    "mcpcia pci sgmap",
	    MCPCIA_PCI_SG_MAPPED_BASE, 0, MCPCIA_PCI_SG_MAPPED_SIZE,
	    sizeof(u_int64_t), NULL, 0);

	alpha_sgmap_init(&ccp->cc_dmat_isa_sgmap, &ccp->cc_isa_sgmap,
	    "mcpcia isa sgmap",
	    MCPCIA_ISA_SG_MAPPED_BASE, 0, MCPCIA_ISA_SG_MAPPED_SIZE,
	    sizeof(u_int64_t), NULL, 0);

	/*
	 * Disable windows first.
	 */
	REGVAL(MCPCIA_W0_BASE(ccp)) = 0;
	REGVAL(MCPCIA_W1_BASE(ccp)) = 0;
	REGVAL(MCPCIA_W2_BASE(ccp)) = 0;
	REGVAL(MCPCIA_W3_BASE(ccp)) = 0;
	REGVAL(MCPCIA_T0_BASE(ccp)) = 0;
	REGVAL(MCPCIA_T1_BASE(ccp)) = 0;
	REGVAL(MCPCIA_T2_BASE(ccp)) = 0;
	REGVAL(MCPCIA_T3_BASE(ccp)) = 0;
	alpha_mb();

	/*
	 * Set up window 0 as an 8MB SGMAP-mapped window starting at 8MB.
	 */
	REGVAL(MCPCIA_W0_MASK(ccp)) = MCPCIA_WMASK_8M;
	REGVAL(MCPCIA_T0_BASE(ccp)) =
		ccp->cc_isa_sgmap.aps_ptpa >> MCPCIA_TBASEX_SHIFT;
	alpha_mb();
	REGVAL(MCPCIA_W0_BASE(ccp)) =
		MCPCIA_WBASE_EN | MCPCIA_WBASE_SG | MCPCIA_ISA_SG_MAPPED_BASE;
	alpha_mb();

	MCPCIA_SGTLB_INVALIDATE(ccp);

	/*
	 * Set up window 1 as a 2 GB Direct-mapped window starting at 2GB.
	 */
	REGVAL(MCPCIA_W1_MASK(ccp)) = MCPCIA_WMASK_2G;
	REGVAL(MCPCIA_T1_BASE(ccp)) = 0;
	alpha_mb();
	REGVAL(MCPCIA_W1_BASE(ccp)) =
		MCPCIA_DIRECT_MAPPED_BASE | MCPCIA_WBASE_EN;
	alpha_mb();

	/*
	 * Set up window 2 as a 1G SGMAP-mapped window starting at 1G.
	 */
	REGVAL(MCPCIA_W2_MASK(ccp)) = MCPCIA_WMASK_1G;
	REGVAL(MCPCIA_T2_BASE(ccp)) =
		ccp->cc_pci_sgmap.aps_ptpa >> MCPCIA_TBASEX_SHIFT;
	alpha_mb();
	REGVAL(MCPCIA_W2_BASE(ccp)) =
		MCPCIA_WBASE_EN | MCPCIA_WBASE_SG | MCPCIA_PCI_SG_MAPPED_BASE;
	alpha_mb();

	/* XXX XXX BEGIN XXX XXX */
	{							/* XXX */
		extern paddr_t alpha_XXX_dmamap_or;		/* XXX */
		alpha_XXX_dmamap_or = MCPCIA_DIRECT_MAPPED_BASE;/* XXX */
	}							/* XXX */
	/* XXX XXX END XXX XXX */
}

/*
 * Return the bus dma tag to be used for the specified bus type.
 * INTERNAL USE ONLY!
 */
bus_dma_tag_t
mcpcia_dma_get_tag(t, bustype)
	bus_dma_tag_t t;
	alpha_bus_t bustype;
{
	struct mcpcia_config *ccp = t->_cookie;

	switch (bustype) {
	case ALPHA_BUS_PCI:
	case ALPHA_BUS_EISA:
		/*
		 * Start off using the direct-mapped window.  We will
		 * automatically fall backed onto the chained PCI SGMAP
		 * window if necessary.
		 */
		return (&ccp->cc_dmat_direct);

	case ALPHA_BUS_ISA:
		/*
		 * ISA doesn't have enough address bits to use
		 * the direct-mapped DMA window, so we must use
		 * SGMAPs.
		 */
		return (&ccp->cc_dmat_isa_sgmap);

	default:
		panic("mcpcia_dma_get_tag: shouldn't be here, really...");
	}
}

/*
 * Load a MCPCIA SGMAP-mapped DMA map with a linear buffer.
 */
int
mcpcia_bus_dmamap_load_sgmap(t, map, buf, buflen, p, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	void *buf;
	bus_size_t buflen;
	struct proc *p;
	int flags;
{
	int error;
	struct mcpcia_config *ccp = t->_cookie;

	error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
	    t->_sgmap);
	if (error == 0)
		MCPCIA_SGTLB_INVALIDATE(ccp);
	return (error);
}

/*
 * Load a MCPCIA SGMAP-mapped DMA map with an mbuf chain.
 */
int
mcpcia_bus_dmamap_load_mbuf_sgmap(t, map, m, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct mbuf *m;
	int flags;
{
	int error;
	struct mcpcia_config *ccp = t->_cookie;

	error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, t->_sgmap);
	if (error == 0)
		MCPCIA_SGTLB_INVALIDATE(ccp);
	return (error);
}

/*
 * Load a MCPCIA SGMAP-mapped DMA map with a uio.
 */
int
mcpcia_bus_dmamap_load_uio_sgmap(t, map, uio, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct uio *uio;
	int flags;
{
	int error;
	struct mcpcia_config *ccp = t->_cookie;

	error = pci_sgmap_pte64_load_uio(t, map, uio, flags, t->_sgmap);
	if (error == 0)
		MCPCIA_SGTLB_INVALIDATE(ccp);
	return (error);
}

/*
 * Load a MCPCIA SGMAP-mapped DMA map with raw memory.
 */
int
mcpcia_bus_dmamap_load_raw_sgmap(t, map, segs, nsegs, size, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	bus_dma_segment_t *segs;
	int nsegs;
	bus_size_t size;
	int flags;
{
	int error;
	struct mcpcia_config *ccp = t->_cookie;

	error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
	    t->_sgmap);
	if (error == 0)
		MCPCIA_SGTLB_INVALIDATE(ccp);
	return (error);
}

/*
 * Unload a MCPCIA DMA map.
 */
void
mcpcia_bus_dmamap_unload_sgmap(t, map)
	bus_dma_tag_t t;
	bus_dmamap_t map;
{
	struct mcpcia_config *ccp = t->_cookie;

	/*
	 * Invalidate any SGMAP page table entries used by this mapping.
	 */
	pci_sgmap_pte64_unload(t, map, t->_sgmap);
	MCPCIA_SGTLB_INVALIDATE(ccp);

	/*
	 * Do the generic bits of the unload.
	 */
	_bus_dmamap_unload(t, map);
}


code:
/* $OpenBSD: mcpcia_pci.c,v 1.3 2012/12/05 23:20:10 deraadt Exp $ */
/* $NetBSD: mcpcia_pci.c,v 1.5 2007/03/04 05:59:11 christos Exp $ */

/*
 * Copyright (c) 1998 by Matthew Jacob
 * NASA AMES Research Center.
 * 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 immediately at the beginning of the file, without modification,
 *    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 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 AUTHOR 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/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <alpha/pci/mcpciareg.h>
#include <alpha/pci/mcpciavar.h>

#define	KV(_addr)	((void *)ALPHA_PHYS_TO_K0SEG((_addr)))

void	mcpcia_attach_hook(struct device *, struct device *,
	    struct pcibus_attach_args *);
int	mcpcia_bus_maxdevs(void *, int);
pcitag_t mcpcia_make_tag(void *, int, int, int);
void	mcpcia_decompose_tag(void *, pcitag_t, int *, int *, int *);
int	mcpcia_conf_size(void *, pcitag_t);
pcireg_t mcpcia_conf_read(void *, pcitag_t, int);
void	mcpcia_conf_write(void *, pcitag_t, int, pcireg_t);

void
mcpcia_pci_init(pc, v)
	pci_chipset_tag_t pc;
	void *v;
{
	pc->pc_conf_v = v;
	pc->pc_attach_hook = mcpcia_attach_hook;
	pc->pc_bus_maxdevs = mcpcia_bus_maxdevs;
	pc->pc_make_tag = mcpcia_make_tag;
	pc->pc_decompose_tag = mcpcia_decompose_tag;
	pc->pc_conf_size = mcpcia_conf_size;
	pc->pc_conf_read = mcpcia_conf_read;
	pc->pc_conf_write = mcpcia_conf_write;
}

void
mcpcia_attach_hook(parent, self, pba)
	struct device *parent, *self;
	struct pcibus_attach_args *pba;
{
}

int
mcpcia_bus_maxdevs(cpv, busno)
	void *cpv;
	int busno;
{
	return (MCPCIA_MAXDEV);
}

pcitag_t
mcpcia_make_tag(cpv, b, d, f)
	void *cpv;
	int b, d, f;
{
	pcitag_t tag;
	tag = (b << 21) | (d << 16) | (f << 13);
	return (tag);
}

void
mcpcia_decompose_tag(cpv, tag, bp, dp, fp)
	void *cpv;
	pcitag_t tag;
	int *bp, *dp, *fp;
{
	if (bp != NULL)
		*bp = (tag >> 21) & 0xff;
	if (dp != NULL)
		*dp = (tag >> 16) & 0x1f;
	if (fp != NULL)
		*fp = (tag >> 13) & 0x7;
}

int
mcpcia_conf_size(void *cpv, pcitag_t tag)
{
	return PCI_CONFIG_SPACE_SIZE;
}

pcireg_t
mcpcia_conf_read(cpv, tag, offset)
	void *cpv;
	pcitag_t tag;
	int offset;
{
	struct mcpcia_config *ccp = cpv;
	pcireg_t *dp, data = (pcireg_t) -1;
	unsigned long paddr;

	/*
	 * There's nothing in slot 0 on a primary bus- don't even try.
	 */
	if ((tag >> 21) == 0 && ((u_int32_t) tag & 0x1f0000) == 0)
		return (data);

	if (ccp == NULL) {
		panic("NULL ccp in mcpcia_conf_read");
	}
	paddr =	(unsigned long) tag;
	paddr |= (3LL << 3);	/* 32 Bit PCI byte enables */
	paddr |= ((unsigned long) ((offset >> 2) << 7));
	paddr |= MCPCIA_PCI_CONF;
	paddr |= ccp->cc_sysbase;
	dp = (pcireg_t *)KV(paddr);
	if (badaddr(dp, sizeof (*dp)) == 0) {
		data = *dp;
	}
	return (data);
}

void
mcpcia_conf_write(cpv, tag, offset, data)
	void *cpv;
	pcitag_t tag;
	int offset;
	pcireg_t data;
{
	struct mcpcia_config *ccp = cpv;
	pcireg_t *dp;
	unsigned long paddr;

	/*
	 * There's nothing in slot 0 on a primary bus- don't even try.
	 */
	if ((tag >> 21) == 0 && ((u_int32_t) tag & 0x1f0000) == 0)
		return;

	if (ccp == NULL) {
		panic("NULL ccp in mcpcia_conf_write");
	}
	paddr =	(unsigned long) tag;
	paddr |= (3LL << 3);	/* 32 Bit PCI byte enables */
	paddr |= ((unsigned long) ((offset >> 2) << 7));
	paddr |= MCPCIA_PCI_CONF;
	paddr |= ccp->cc_sysbase;

	dp = (pcireg_t *)KV(paddr);
	*dp = data;
}