code:
/*	$OpenBSD: vm_machdep.c,v 1.13 2015/05/05 02:13:47 guenther Exp $	*/
/*	$NetBSD: vm_machdep.c,v 1.53 2006/08/31 16:49:21 matt Exp $	*/

/*
 * Copyright (c) 2007 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice, this permission notice, and the disclaimer below
 * appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved.
 * Copyright (c) 1982, 1986 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department, and William Jolitz.
 *
 * 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. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
 *
 *	@(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
 */
/*-
 * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
 * Copyright (c) 1989, 1990 William Jolitz
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department, and William Jolitz.
 *
 * 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 the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
 *
 *	@(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
 */

/*
 *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/vnode.h>
#include <sys/buf.h>
#include <sys/user.h>
#include <sys/exec.h>
#include <sys/ptrace.h>
#include <sys/signalvar.h>

#include <uvm/uvm_extern.h>

#include <sh/locore.h>
#include <sh/cpu.h>
#include <sh/reg.h>
#include <sh/mmu.h>
#include <sh/cache.h>

extern void proc_trampoline(void);

/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb and trap frame, making the child ready to run.
 *
 * Rig the child's kernel stack so that it will start out in
 * proc_trampoline() and call child_return() with p2 as an
 * argument. This causes the newly-created child process to go
 * directly to user level with an apparent return value of 0 from
 * fork(), while the parent process returns normally.
 *
 * p1 is the process being forked; if p1 == &proc0, we are creating
 * a kernel thread, and the return path and argument are specified with
 * `func' and `arg'.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 */
void
cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb;
	struct trapframe *tf;
	struct switchframe *sf;
	vaddr_t spbase, fptop;
#define	P1ADDR(x)	(SH3_PHYS_TO_P1SEG(*__pmap_kpte_lookup(x) & PG_PPN))

	KDASSERT(p1 == curproc || p1 == &proc0);

	bzero(&p2->p_md, sizeof(p2->p_md));

	/* Copy flags */
	p2->p_md.md_flags = p1->p_md.md_flags;

	pcb = NULL;		/* XXXGCC: -Wuninitialized */
#ifdef SH3
	/*
	 * Convert frame pointer top to P1. because SH3 can't make
	 * wired TLB entry, context store space accessing must not cause
	 * exception. For SH3, we are 4K page, P3/P1 conversion don't
	 * cause virtual-aliasing.
	 */
	if (CPU_IS_SH3)
		pcb = (struct pcb *)P1ADDR((vaddr_t)&p2->p_addr->u_pcb);
#endif /* SH3 */
#ifdef SH4
	/* SH4 can make wired entry, no need to convert to P1. */
	if (CPU_IS_SH4)
		pcb = &p2->p_addr->u_pcb;
#endif /* SH4 */

	p2->p_md.md_pcb = pcb;
	fptop = (vaddr_t)pcb + PAGE_SIZE;

	/* set up the kernel stack pointer */
	spbase = (vaddr_t)p2->p_addr + PAGE_SIZE;
#ifdef P1_STACK
	/* Convert to P1 from P3 */
	/*
	 * wbinv u-area to avoid cache-aliasing, since kernel stack
	 * is accessed from P1 instead of P3.
	 */
	if (SH_HAS_VIRTUAL_ALIAS)
		sh_dcache_wbinv_range((vaddr_t)p2->p_addr, USPACE);
	spbase = P1ADDR(spbase);
#else /* !P1_STACK */
	/* Prepare u-area PTEs */
#ifdef SH3
	if (CPU_IS_SH3)
		sh3_switch_setup(p2);
#endif
#ifdef SH4
	if (CPU_IS_SH4)
		sh4_switch_setup(p2);
#endif
#endif /* !P1_STACK */

#ifdef KSTACK_DEBUG
	/* Fill magic number for tracking */
	memset((char *)fptop - PAGE_SIZE + sizeof(struct user), 0x5a,
	    PAGE_SIZE - sizeof(struct user));
	memset((char *)spbase, 0xa5, (USPACE - PAGE_SIZE));
	memset(&pcb->pcb_sf, 0xb4, sizeof(struct switchframe));
#endif /* KSTACK_DEBUG */

	/*
	 * Copy the user context.
	 */
	p2->p_md.md_regs = tf = (struct trapframe *)fptop - 1;
	memcpy(tf, p1->p_md.md_regs, sizeof(struct trapframe));

	/*
	 * If specified, give the child a different stack.
	 */
	if (stack != NULL)
		tf->tf_r15 = (u_int)stack + stacksize;

	/* Setup switch frame */
	sf = &pcb->pcb_sf;
	sf->sf_r11 = (int)arg;		/* proc_trampoline hook func's arg */
	sf->sf_r12 = (int)func;		/* proc_trampoline hook func */
	sf->sf_r15 = spbase + USPACE - PAGE_SIZE;/* current stack pointer */
	sf->sf_r7_bank = sf->sf_r15;	/* stack top */
	sf->sf_r6_bank = (vaddr_t)tf;	/* current frame pointer */
	/* when switch to me, jump to proc_trampoline */
	sf->sf_pr = (int)proc_trampoline;
	/*
	 * Enable interrupt when switch frame is restored, since
	 * kernel thread begin to run without restoring trapframe.
	 */
	sf->sf_sr = PSL_MD;		/* kernel mode, interrupt enable */

#ifdef SH4
	if (CPU_IS_SH4) {
		/*
		 * Propagate floating point registers to the new process
		 * (they are not in the trapframe).
		 */
		if (p1 == curproc)
			fpu_save(&p1->p_md.md_pcb->pcb_fp);
		bcopy(&p1->p_md.md_pcb->pcb_fp, &pcb->pcb_fp,
		    sizeof(struct fpreg));
	}
#endif
}

/*
 * Map an IO request into kernel virtual address space.
 * All requests are (re)mapped into kernel VA space via the phys_map
 * (a name with only slightly more meaning than "kernel_map")
 */

void
vmapbuf(struct buf *bp, vsize_t len)
{
	vaddr_t faddr, taddr, off;
	paddr_t fpa;
	pmap_t kpmap, upmap;

	if ((bp->b_flags & B_PHYS) == 0)
		panic("vmapbuf");
	bp->b_saveaddr = bp->b_data;
	faddr = trunc_page((vaddr_t)bp->b_data);
	off = (vaddr_t)bp->b_data - faddr;
	len = round_page(off + len);
	taddr = uvm_km_valloc_prefer_wait(phys_map, len, faddr);
	bp->b_data = (caddr_t)(taddr + off);
	/*
	 * The region is locked, so we expect that pmap_pte() will return
	 * non-NULL.
	 * XXX: unwise to expect this in a multithreaded environment.
	 * anything can happen to a pmap between the time we lock a
	 * region, release the pmap lock, and then relock it for
	 * the pmap_extract().
	 *
	 * no need to flush TLB since we expect nothing to be mapped
	 * where we we just allocated (TLB will be flushed when our
	 * mapping is removed).
	 */
	upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
	kpmap = vm_map_pmap(phys_map);
	while (len) {
		pmap_extract(upmap, faddr, &fpa);
		pmap_enter(kpmap, taddr, fpa,
		    PROT_READ | PROT_WRITE, PMAP_WIRED);
		faddr += PAGE_SIZE;
		taddr += PAGE_SIZE;
		len -= PAGE_SIZE;
	}
	pmap_update(kpmap);
}

/*
 * Free the io map PTEs associated with this IO operation.
 * We also invalidate the TLB entries and restore the original b_addr.
 */
void
vunmapbuf(struct buf *bp, vsize_t len)
{
	vaddr_t addr, off;
	pmap_t kpmap;

	if ((bp->b_flags & B_PHYS) == 0)
		panic("vunmapbuf");
	addr = trunc_page((vaddr_t)bp->b_data);
	off = (vaddr_t)bp->b_data - addr;
	len = round_page(off + len);
	kpmap = vm_map_pmap(phys_map);
	pmap_remove(kpmap, addr, addr + len);
	pmap_update(kpmap);
	uvm_km_free_wakeup(phys_map, addr, len);
	bp->b_data = bp->b_saveaddr;
	bp->b_saveaddr = 0;
}


code:
/Makefile/1.8/Sun Dec  8 14:46:39 2013//TOPENBSD_5_8_BASE
D/compile////
D/conf////
D/dev////
D/include////
D/socppc////
D/stand////

path: sys/arch/socppc/CVS/Entries

license: unknown


code: src/sys/arch/socppc

path: sys/arch/socppc/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.8 2013/12/08 14:46:39 espie Exp $

S=	${.CURDIR}/../..
KFILE=	GENERIC
.if exists(conf/GENERIC.MP)
KFILE=	GENERIC.MP
.endif
TDIRS=	${_arch} include
TAGS=	${.CURDIR}/tags

NOPROG=
NOMAN=
NOOBJ=
SUBDIR=	stand

# config the fattest kernel we can find into a temporary dir
# to create a Makefile.  Then use make to pull some variables
# out and push them into the sub-shell to expand the paths,
# and finally run ctags.
tags::
	TDIR=`mktemp -d /tmp/_tagXXXXXXXXXX` || exit 1; \
	eval "S=${S}" && \
	config -s ${S} -b $${TDIR} ${.CURDIR}/conf/${KFILE} && \
	eval "_arch=\"`make -V _arch -f $${TDIR}/Makefile`\"" && \
	eval "_mach=\"`make -V _mach -f $${TDIR}/Makefile`\"" && \
	eval "_machdir=\$S/arch/$${_mach}" && \
	eval "_archdir=\$S/arch/$${_arch}" && \
	eval "HFILES=\"`find $S \( -path $S/'arch' -o -path $S/stand -o -path $S/lib/libsa -o -path $S'/lib/libkern/arch' \) -prune -o -name '*.h'; find $${_machdir} $${_archdir} $S/lib/libkern/arch/$${_mach} \( -name boot -o -name stand \) -prune -o -name '*.h'`\"" && \
	eval "SFILES=\"`make -V SFILES -f $${TDIR}/Makefile`\"" && \
	eval "CFILES=\"`make -V CFILES -f $${TDIR}/Makefile`\"" && \
	eval "AFILES=\"`make -V AFILES -f $${TDIR}/Makefile`\"" && \
	ctags -wd -f ${TAGS} $${CFILES} $${HFILES} && \
	egrep "^[_A-Z]*ENTRY[_A-Z]*\(.*\)" $${SFILES} $${AFILES} | \
	    sed "s;\\([^:]*\\):\\([^(]*\\)(\\([^, )]*\\)\\(.*\\);\\3	\\1	/^\\2(\\3\\4$$/;" \
	    >> ${TAGS} && \
	sort -o ${TAGS} ${TAGS} && \
	rm -rf $${TDIR}

links:
	-for i in conf ${TDIRS}; do \
	    (cd $$i && rm -f tags; ln -s tags tags); done

obj:	_SUBDIRUSE

.include <bsd.prog.mk>

path: sys/arch/socppc/Makefile


code:
/.cvsignore/1.1/Sat May 10 12:11:34 2008//TOPENBSD_5_8_BASE
D

path: sys/arch/socppc/compile/CVS/Entries


code: src/sys/arch/socppc/compile

path: sys/arch/socppc/compile/CVS/Repository


code: src/sys/arch/socppc/conf

path: sys/arch/socppc/conf/CVS/Repository


code:
#	$OpenBSD: GENERIC,v 1.30 2014/12/11 19:44:17 tedu Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

machine		socppc powerpc
include		"../../../conf/GENERIC"
maxusers	32			# estimated number of users

option		PCIVERBOSE
option		USBVERBOSE

option		USER_PCICONF	# user-space PCI configuration
option		APERTURE

config		bsd	swap generic

mainbus0	at root
cpu0		at mainbus0
obio0		at mainbus0

# On-board CF
wdc0		at mainbus0
wdc1		at mainbus0
wd*		at wdc? flags 0x0000

# On-board IPIC
ipic0		at obio?

# On-board I2C
sociic0		at obio?
sociic1		at obio?
iic*		at sociic?
ricohrtc0	at iic? addr 0x32	# Ricoh RTC
fintek0		at iic?	flags 0x0001	# temp/fan controller

# On-board DUART
com0		at obio?
com1		at obio?

# On-board PCI
socpcic*	at mainbus?
socpcic*	at obio?
pci*		at socpcic?

pciide*		at pci?
wd*		at pciide? flags 0x0000

vge*		at pci?

# On-board USB
ehci0		at obio?
usb*		at ehci?

# USB devices
uhub*	at usb?			# USB Hubs
uhub*	at uhub?		# USB Hubs
ulpt*	at uhub?		# USB Printers
umass*	at uhub?		# USB Mass Storage devices
uhidev*	at uhub?		# Human Interface Devices
ums*	at uhidev?		# USB mouse
wsmouse* at ums? mux 0
ukbd*	at uhidev?		# USB keyboard
wskbd*	at ukbd? mux 1
uhid*	at uhidev?		# USB generic HID support
upd*	at uhidev?		# USB Power Devices sensors
axe*	at uhub?		# ASIX Electronics AX88172 USB Ethernet
axen*	at uhub?		# ASIX Electronics AX88179 USB Ethernet
mos*	at uhub?		# MOSCHIP CS730/7830 10/100 Ethernet
smsc*	at uhub?		# SMSC LAN95xx Ethernet
uath*	at uhub?		# Atheros AR5005UR/AR5005UX
athn*	at uhub?		# Atheros AR9002U
ural*	at uhub?		# Ralink RT2500USB
rum*	at uhub?		# Ralink RT2501USB/RT2601USB
run*	at uhub?		# Ralink RT2700U/RT2800U/RT3000U
rsu*	at uhub?		# Realtek RTL8188SU/RTL8191SU/RTL8192SU
urtwn*	at uhub?		# Realtek RTL8188CU/RTL8192CU
zyd*	at uhub?		# Zydas ZD1211
ugen*	at uhub?		# USB Generic driver
uthum*	at uhidev?		# TEMPerHUM sensor
ugold*	at uhidev?		# gold TEMPer sensor
utwitch* at uhidev?		# YUREX BBU sensor

udl*		at uhub?
wsdisplay*	at udl?

scsibus*	at scsi?
sd*		at scsibus?

# On-board TSEC
tsec0		at obio?
tsec1		at obio?

rgephy*		at mii?		# Realtek 8169S/8110S PHY
eephy*		at mii?		# Marvell 88E1000 series PHY
rlphy*		at mii?		# Realtek 8139 internal PHYs
ciphy*		at mii?		# Cicada CS8201 10/100/1000 copper PHY
gentbi*		at mii?		# Generic 1000BASE-X ten-bit PHY
ukphy*		at mii?		# Generic unknown PHY

# PCI
athn*		at pci?		# Atheros AR9k (802.11a/g/n)
hifn*		at pci?		# Hi/fn 7751 crypto card

pseudo-device	hotplug		1	# devices hot plugging
pseudo-device	wsmux		2	# mouse & keyboard multiplexor

path: sys/arch/socppc/conf/GENERIC


code:
#	$OpenBSD: Makefile.socppc,v 1.42 2015/01/13 01:12:50 deraadt Exp $

# For instructions on building kernels consult the config(8) and options(4)
# manual pages.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
#	IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
# DEBUG is set to -g by config if debugging is requested (config -g).
# PROF is set to -pg by config if profiling is requested (config -p).

.include <bsd.own.mk>

SIZE?=	size
STRIP?=	strip

# source tree is located via $S relative to the compilation directory
.ifndef S
S!=	cd ../../../..; pwd
.endif

_machdir?=	$S/arch/${_mach}
_archdir?=	$S/arch/${_arch}

INCLUDES=	-nostdinc -I$S -I. -I$S/arch
CPPFLAGS=	${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -D__${_mach}__ -MD -MP
CWARNFLAGS=	-Werror -Wall -Wimplicit-function-declaration \
		-Wno-main -Wno-uninitialized \
		-Wframe-larger-than=2047

CMACHFLAGS=	-msoft-float -Wa,-many
CMACHFLAGS+=	-fno-builtin-printf -fno-builtin-snprintf \
		-fno-builtin-vsnprintf -fno-builtin-log \
		-fno-builtin-log2 -fno-builtin-malloc ${NOPIE_FLAGS}
.if ${IDENT:M-DNO_PROPOLICE}
CMACHFLAGS+=	-fno-stack-protector
.endif

COPTS?=		-O2
CFLAGS=		${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE}
AFLAGS=		-D_LOCORE ${CMACHFLAGS}
LINKFLAGS=	-N -Ttext 200000 -e start --warn-common -nopie

.if ${IDENT:M-DDDB_STRUCT}
DB_STRUCTINFO=	db_structinfo.h
.else
DB_STRUCTINFO=
.endif

HOSTCC?=	${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS=	${CFLAGS}
HOSTED_C=	${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $<

NORMAL_C_NOP=	${CC} ${CFLAGS} ${CPPFLAGS} -c $<
NORMAL_C=	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_S=	${CC} ${AFLAGS} ${CPPFLAGS} -c $<

%OBJS

%CFILES

%SFILES

# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP} swapxxx.o
#	${SYSTEM_LD_HEAD}
#	${SYSTEM_LD} swapxxx.o
#	${SYSTEM_LD_TAIL}
SYSTEM_HEAD=	locore.o param.o ioconf.o
SYSTEM_OBJ=	${SYSTEM_HEAD} ${OBJS}
SYSTEM_DEP=	Makefile ${SYSTEM_OBJ}
SYSTEM_LD_HEAD=	@rm -f $@
SYSTEM_LD=	@echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_HEAD} vers.o $${OBJS}'; \
		${LD} ${LINKFLAGS} -o $@ ${SYSTEM_HEAD} vers.o ${OBJS}
SYSTEM_LD_TAIL=	@${SIZE} $@; chmod 755 $@

DEBUG?=
.if ${DEBUG} == "-g"
LINKFLAGS+=	-X
STRIPFLAGS=	-g -x
SYSTEM_LD_TAIL+=; \
		echo mv $@ $@.gdb; rm -f $@.gdb; mv $@ $@.gdb; \
		echo ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb; \
		${STRIP} ${STRIPFLAGS} -o $@ $@.gdb
.else
LINKFLAGS+=	-S -x
.endif

%LOAD

# cc's -MD puts the source and output paths in the dependency file;
# since those are temp files here we need to fix it up.  It also
# puts the file in /tmp, so we use -MF to put it in the current
# directory as assym.P and then generate assym.d from it with a
# good target name
assym.h: $S/kern/genassym.sh Makefile \
	 ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf
	cat ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf | \
	    sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} -MF assym.P > assym.h.tmp
	sed '1s/.*/assym.h: \\/' assym.P > assym.d
	sort -u assym.h.tmp > assym.h

param.c: $S/conf/param.c
	rm -f param.c
	cp $S/conf/param.c .

param.o: param.c Makefile
	${NORMAL_C}

mcount.o: $S/lib/libkern/mcount.c Makefile
	${NORMAL_C_NOP}

ioconf.o: ioconf.c
	${NORMAL_C}

vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
	sh $S/conf/newvers.sh
	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c

clean::
	rm -f eddep *bsd *bsd.gdb tags *.[dio] [a-z]*.s \
	    [Ee]rrs linterrs assym.h ${DB_STRUCTINFO}

lint:
	@lint -hbxncez -Dvolatile= ${CPPFLAGS} -UKGDB \
	    ${CFILES} ioconf.c param.c | \
	    grep -v 'static function .* unused'

depend:
	@touch $@

tags:
	@echo "see $S/kern/Makefile for tags"

db_structinfo.h: $S/ddb/db_structinfo.c $S/ddb/parse_structinfo.pl
	${CC} ${CFLAGS} ${CPPFLAGS} -MT $@ -gstabs -c $S/ddb/db_structinfo.c
	objdump -g db_structinfo.o | perl $S/ddb/parse_structinfo.pl > $@
	rm -f db_structinfo.o

locore.o: ${_machdir}/${_mach}/locore.S assym.h
mutex.o: assym.h

# The install target can be redefined by putting a
# install-kernel-${MACHINE_NAME} target into /etc/mk.conf
MACHINE_NAME!=  uname -n
install: install-kernel-${MACHINE_NAME}
.if !target(install-kernel-${MACHINE_NAME}})
install-kernel-${MACHINE_NAME}:
	cmp -s bsd /bsd || ln -f /bsd /obsd
	cp bsd /nbsd
	mv /nbsd /bsd
.endif

# pull in the dependency information
.if !empty(DB_STRUCTINFO) && !exists(${DB_STRUCTINFO})
 ${SYSTEM_OBJ}: ${DB_STRUCTINFO}
.endif
.ifnmake clean
. for o in ${SYSTEM_OBJ} assym.h ${DB_STRUCTINFO}
.  if exists(${o:R}.d)
.   include "${o:R}.d"
.  elif exists($o)
    .PHONY: $o
.  endif
. endfor
.endif

%RULES


code:
#	$OpenBSD: RAMDISK,v 1.11 2015/07/17 22:52:29 tedu Exp $

machine		socppc powerpc
maxusers	4

option		TIMEZONE=0
option		DST=0
option		SMALL_KERNEL
option		NO_PROPOLICE
option		BOOT_CONFIG

option		MINIROOTSIZE=8192
option		RAMDISK_HOOKS

option		PCIVERBOSE
option		USBVERBOSE

option		FFS
option		FFS2
option		NFSCLIENT
option		CD9660
option		UDF
option		MSDOSFS
option		INET6

config		bsd root on rd0a swap on rd0b

mainbus0	at root
cpu0		at mainbus0
obio0		at mainbus0
ipic0		at obio?

wdc0		at mainbus0		# On-board CF
wdc1		at mainbus0
wd*		at wdc? flags 0x0000

sociic0		at obio?
sociic1		at obio?
iic*		at sociic?
ricohrtc0	at iic? addr 0x32	# Ricoh RTC
fintek0		at iic?	flags 0x0001	# temp/fan controller

com0		at obio?
com1		at obio?

socpcic*	at mainbus?
socpcic*	at obio?
tsec0		at obio?
tsec1		at obio?

pci*		at socpcic?
pciide*		at pci?
wd*		at pciide? flags 0x0000

ehci0		at obio?
usb*		at ehci?

uhub*		at usb?
uhub*		at uhub?
umass*		at uhub?
ural*		at uhub?		# Ralink RT2500USB
rum*		at uhub?		# Ralink RT2501USB/RT2601USB
zyd*		at uhub?		# Zydas ZD1211

scsibus*	at scsi?
sd*		at scsibus?

vge*		at pci?
athn*		at pci?			# Atheros AR9k (802.11a/g/n)

rgephy*		at mii?			# Realtek 8169S/8110S PHY
eephy*		at mii?			# Marvell 88E1000 series PHY
ciphy*		at mii?			# Cicada CS8201 10/100/1000 copper PHY
gentbi*		at mii?			# Generic 1000BASE-X ten-bit PHY
ukphy*		at mii?			# Generic unknown PHY

pseudo-device	loop 1
pseudo-device	bpfilter 1
pseudo-device	rd 1

path: sys/arch/socppc/conf/RAMDISK


code:
#	$OpenBSD: files.socppc,v 1.13 2015/01/20 17:08:35 mpi Exp $

#
# macppc-specific configuration info
#
maxpartitions 16

maxusers 2 8 64

file	arch/socppc/socppc/autoconf.c
file	arch/socppc/socppc/clock.c
file	arch/socppc/socppc/conf.c
file	arch/socppc/socppc/disksubr.c			disk
file	arch/socppc/socppc/machdep.c
file	arch/socppc/socppc/mem.c
file	dev/cninit.c
file	arch/socppc/socppc/db_interface.c		ddb
file	arch/socppc/socppc/fdt.c
file	arch/socppc/socppc/n1200_dts.S

define	mainbus {}
device	mainbus
attach	mainbus at root
file	arch/socppc/socppc/mainbus.c			mainbus

device	cpu
attach	cpu at mainbus
file	arch/socppc/socppc/cpu.c

# MPC8349E on-board devices
device	obio {[addr = 0], [ivec = -1], [phy = -1]}
attach	obio at mainbus
file	arch/socppc/dev/obio.c

# On-board IPIC
device	ipic
attach	ipic at obio
file	arch/socppc/dev/ipic.c

# On-board I2C
device	sociic: i2cbus
attach	sociic at obio
file	arch/socppc/dev/sociic.c

# On-board DUART
attach	com at obio with com_obio
file	arch/socppc/dev/com_obio.c

# On-board CF
attach	wdc at mainbus with wdc_mainbus
file	arch/socppc/dev/wdc_mainbus.c

#
# Media Independent Interface (mii)
#
include "../../../dev/mii/files.mii"

# On-board TSEC
device	tsec: ether, ifnet, mii, ifmedia
attach	tsec at obio
file	arch/socppc/dev/if_tsec.c

major	{rd = 17}
major	{wd = 0}
major	{sd = 2}
major	{cd = 3}

include "../../../scsi/files.scsi"

include "dev/pci/files.pci"
file	arch/socppc/dev/pciide_machdep.c		pciide

# On-board PCI
device	socpcic: pcibus
attach	socpcic at mainbus with socpcic_mainbus
attach	socpcic at obio with socpcic_obio
file	arch/socppc/dev/socpcic.c

#
# Machine-independent ATAPI drivers
#

include "../../../dev/atapiscsi/files.atapiscsi"
include "../../../dev/ata/files.ata"

# WSCONS bits for wskbd.h
#
include "dev/wscons/files.wscons"
include "dev/wsfont/files.wsfont"
include "dev/rasops/files.rasops"

#
# Machine-independent USB drivers
#
include "dev/usb/files.usb"

# On-board USB
attach	ehci at obio with ehci_obio
file	arch/socppc/dev/ehci_obio.c			ehci

#
# Machine-independent I2C drivers
#
include "dev/i2c/files.i2c"


code: src/sys/arch/socppc/dev

path: sys/arch/socppc/dev/CVS/Repository


code:
/*	$OpenBSD: com_obio.c,v 1.3 2009/09/06 20:09:34 kettenis Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <machine/autoconf.h>

#include <dev/ofw/openfirm.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

int	com_obio_match(struct device *, void *, void *);
void	com_obio_attach(struct device *, struct device *, void *);

struct cfattach com_obio_ca = {
	sizeof(struct com_softc), com_obio_match, com_obio_attach
};

struct cfdriver com_obio_cd = {
	NULL, "com", DV_DULL
};

int
com_obio_match(struct device *parent, void *cfdata, void *aux)
{
	struct obio_attach_args *oa = aux;
	char buf[32];

	if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "serial") != 0)
		return (0);

	if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "ns16550") != 0)
		return (0);

	return (1);
}

void
com_obio_attach(struct device *parent, struct device *self, void *aux)
{
	struct com_softc *sc = (void *)self;
	struct obio_attach_args *oa = aux;
	int freq;

	if (OF_getprop(oa->oa_node, "clock-frequency", &freq,
	    sizeof(freq))!= sizeof(freq)) {
		printf(": unknown clock frequency\n");
		return;
	}

	sc->sc_iot = oa->oa_iot;
	sc->sc_iobase = oa->oa_offset;
	sc->sc_frequency = freq;

	if (sc->sc_iobase != comconsaddr) {
		if (bus_space_map(sc->sc_iot, sc->sc_iobase,
		    COM_NPORTS, 0, &sc->sc_ioh)) {
			printf(": can't map registers\n");
			return;
		}
	} else
		sc->sc_ioh = comconsioh;

	com_attach_subr(sc);

	intr_establish(oa->oa_ivec, IST_LEVEL, IPL_TTY, comintr,
	    sc, sc->sc_dev.dv_xname);
}


code:
/*	$OpenBSD: ehci_obio.c,v 1.5 2015/01/24 20:59:42 kettenis Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/rwlock.h>
#include <sys/timeout.h>

#include <machine/autoconf.h>

#include <dev/ofw/openfirm.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>

#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>

#include <dev/pci/pcidevs.h>

#define USB_EHCI_OFFSET		0x00100
#define USB_SNOOP1		0x00400 - USB_EHCI_OFFSET
#define  USB_SNOOP_2GB		0x1e000000
#define USB_CONTROL		0x00500 - USB_EHCI_OFFSET
#define  USB_CONTROL_USB_EN	0x04000000

int	ehci_obio_match(struct device *, void *, void *);
void	ehci_obio_attach(struct device *, struct device *, void *);

struct cfattach ehci_obio_ca = {
	sizeof(struct ehci_softc), ehci_obio_match, ehci_obio_attach
};

struct cfdriver ehci_obio_cd = {
	NULL, "ehci", DV_DULL
};

struct powerpc_bus_dma_tag ehci_bus_dma_tag = {
	NULL,
	_dmamap_create,
	_dmamap_destroy,
	_dmamap_load,
	_dmamap_load_mbuf,
	_dmamap_load_uio,
	_dmamap_load_raw,
	_dmamap_unload,
	_dmamap_sync,
	_dmamem_alloc,
	_dmamem_alloc_range,
	_dmamem_free,
	_dmamem_map,
	_dmamem_unmap,
	_dmamem_mmap
};

int
ehci_obio_match(struct device *parent, void *cfdata, void *aux)
{
	struct obio_attach_args *oa = aux;
	char buf[32];

	if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "fsl-usb2-mph") != 0)
		return (0);

	return (1);
}

void
ehci_obio_attach(struct device *parent, struct device *self, void *aux)
{
	struct ehci_softc *sc = (void *)self;
	struct obio_attach_args *oa = aux;
	usbd_status r;
	int s;

	sc->iot = oa->oa_iot;
	sc->sc_size = 1028;
	if (bus_space_map(sc->iot, oa->oa_offset + USB_EHCI_OFFSET,
	    sc->sc_size, 0, &sc->ioh)) {
		printf(": can't map registers\n");
		return;
	}

	sc->sc_id_vendor = PCI_VENDOR_FREESCALE;
	strlcpy(sc->sc_vendor, "Freescale", sizeof sc->sc_vendor);

	sc->sc_bus.dmatag = &ehci_bus_dma_tag;

	bus_space_write_4(sc->iot, sc->ioh, USB_CONTROL, USB_CONTROL_USB_EN);
	bus_space_write_4(sc->iot, sc->ioh, USB_SNOOP1, USB_SNOOP_2GB);

	s = splhardusb();
	sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
	EOWRITE2(sc, EHCI_USBINTR, 0);

	intr_establish(oa->oa_ivec, IST_LEVEL, IPL_USB, ehci_intr, sc,
	    sc->sc_bus.bdev.dv_xname);

	r = ehci_init(sc);
	if (r != USBD_NORMAL_COMPLETION) {
		printf(": init failed, error=%d\n", r);
		goto unmap_ret;
	}
	splx(s);

	printf("\n");

	/* Attach usb device. */
	config_found(self, &sc->sc_bus, usbctlprint);

	return;

unmap_ret:
	bus_space_unmap(sc->iot, sc->ioh, sc->sc_size);
	splx(s);
}


code:
/*	$OpenBSD: if_tsec.c,v 1.37 2015/06/24 09:40:53 mpi Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Driver for the TSEC interface on the MPC8349E processors.
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/timeout.h>

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

#include <net/if.h>
#include <net/if_media.h>
#include <net/if_types.h>

#include <dev/ofw/openfirm.h>

#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>

#if NBPFILTER > 0
#include <net/bpf.h>
#endif

#include <netinet/in.h>
#include <netinet/if_ether.h>

extern void myetheraddr(u_char *);

/*
 * TSEC registers.
 */

#define TSEC_IEVENT		0x010
#define  TSEC_IEVENT_BABR	0x80000000
#define  TSEC_IEVENT_RXC	0x40000000
#define  TSEC_IEVENT_BSY	0x20000000
#define  TSEC_IEVENT_EBERR	0x10000000
#define  TSEC_IEVENT_MSRO	0x04000000
#define  TSEC_IEVENT_GTSC	0x02000000
#define  TSEC_IEVENT_BABT	0x01000000
#define  TSEC_IEVENT_TXC	0x00800000
#define  TSEC_IEVENT_TXE	0x00400000
#define  TSEC_IEVENT_TXB	0x00200000
#define  TSEC_IEVENT_TXF	0x00100000
#define  TSEC_IEVENT_LC		0x00040000
#define  TSEC_IEVENT_CRL	0x00020000
#define  TSEC_IEVENT_DXA	TSEC_IEVENT_CRL
#define  TSEC_IEVENT_XFUN	0x00010000
#define  TSEC_IEVENT_RXB	0x00008000
#define  TSEC_IEVENT_MMRD	0x00000400
#define  TSEC_IEVENT_MMWR	0x00000200
#define  TSEC_IEVENT_GRSC	0x00000100
#define  TSEC_IEVENT_RXF	0x00000080
#define  TSEC_IEVENT_FMT	"\020" "\040BABR" "\037RXC" "\036BSY" \
	"\035EBERR" "\033MSRO" "\032GTSC" "\031BABT" "\030TXC" "\027TXE" \
	"\026TXB" "\025TXF" "\023LC" "\022CRL/XDA" "\021XFUN" "\020RXB" \
	"\013MMRD" "\012MMRW" "\011GRSC" "\010RXF"
#define TSEC_IMASK		0x014
#define  TSEC_IMASK_BREN	0x80000000
#define  TSEC_IMASK_RXCEN	0x40000000
#define  TSEC_IMASK_BSYEN	0x20000000
#define  TSEC_IMASK_EBERREN	0x10000000
#define  TSEC_IMASK_MSROEN	0x04000000
#define  TSEC_IMASK_GTSCEN	0x02000000
#define  TSEC_IMASK_BTEN	0x01000000
#define  TSEC_IMASK_TXCEN	0x00800000
#define  TSEC_IMASK_TXEEN	0x00400000
#define  TSEC_IMASK_TXBEN	0x00200000
#define  TSEC_IMASK_TXFEN	0x00100000
#define  TSEC_IMASK_LCEN	0x00040000
#define  TSEC_IMASK_CRLEN	0x00020000
#define  TSEC_IMASK_DXAEN	TSEC_IMASK_CRLEN
#define  TSEC_IMASK_XFUNEN	0x00010000
#define  TSEC_IMASK_RXBEN	0x00008000
#define  TSEC_IMASK_MMRD	0x00000400
#define  TSEC_IMASK_MMWR	0x00000200
#define  TSEC_IMASK_GRSCEN	0x00000100
#define  TSEC_IMASK_RXFEN	0x00000080
#define TSEC_EDIS		0x018
#define TSEC_ECNTRL		0x020
#define  TSEC_ECNTRL_R100M	0x00000008 /* RGMII 100 mode */
#define TSEC_MINFLR		0x024
#define TSEC_PTV		0x028
#define TSEC_DMACTRL		0x02c
#define  TSEC_DMACTRL_TDSEN	0x00000080
#define  TSEC_DMACTRL_TBDSEN	0x00000040
#define  TSEC_DMACTRL_GRS	0x00000010 /* Graceful receive stop */
#define  TSEC_DMACTRL_GTS	0x00000008 /* Graceful transmit stop */
#define  TSEC_DMACTRL_WWR	0x00000002
#define  TSEC_DMACTRL_WOP	0x00000001
#define TSEC_TBIPA		0x030

#define TSEC_TCTRL		0x100
#define TSEC_TSTAT		0x104
#define  TSEC_TSTAT_THLT	0x80000000
#define TSEC_TBPTR		0x184
#define TSEC_TBASE		0x204

#define TSEC_RCTRL		0x300
#define  TSEC_RCTRL_PROM	0x00000008
#define TSEC_RSTAT		0x304
#define  TSEC_RSTAT_QHLT	0x00800000
#define TSEC_MRBLR		0x340
#define TSEC_RBPTR		0x384
#define TSEC_RBASE		0x404

#define TSEC_MACCFG1		0x500
#define  TSEC_MACCFG1_TXEN	0x00000001
#define  TSEC_MACCFG1_RXEN	0x00000004
#define  TSEC_MACCFG1_RESET	0x80000000
#define TSEC_MACCFG2		0x504
#define  TSEC_MACCFG2_IF_MODE	0x00000300 /* I/F mode */
#define  TSEC_MACCFG2_IF_MII	0x00000100 /* I/F mode */
#define  TSEC_MACCFG2_IF_GMII	0x00000200 /* I/F mode */
#define  TSEC_MACCFG2_PAD	0x00000004
#define  TSEC_MACCFG2_CRC	0x00000002
#define  TSEC_MACCFG2_FDX	0x00000001 /* Full duplex */
#define TSEC_MIIMCFG		0x520
#define  TSEC_MIIMCFG_RESET	0x80000000 /* Reset */
#define TSEC_MIIMCOM		0x524
#define  TSEC_MIIMCOM_READ	0x00000001 /* Read cycle */
#define  TSEC_MIIMCOM_SCAN	0x00000002 /* Scan cycle */
#define TSEC_MIIMADD		0x528
#define TSEC_MIIMCON		0x52c
#define TSEC_MIIMSTAT		0x530
#define TSEC_MIIMIND		0x534
#define  TSEC_MIIMIND_BUSY	0x00000001 /* Busy */
#define  TSEC_MIIMIND_SCAN	0x00000002 /* Scan in progress */
#define  TSEC_MIIMIND_NOTVALID	0x00000004 /* Not valid */
#define TSEC_MACSTNADDR1 	0x540
#define TSEC_MACSTNADDR2 	0x544
#define TSEC_IADDR0		0x800
#define TSEC_IADDR1		0x804
#define TSEC_IADDR2		0x818
#define TSEC_IADDR3		0x81c
#define TSEC_IADDR4		0x810
#define TSEC_IADDR5		0x814
#define TSEC_IADDR6		0x818
#define TSEC_IADDR7		0x81c
#define TSEC_GADDR0		0x880
#define TSEC_GADDR1		0x884
#define TSEC_GADDR2		0x888
#define TSEC_GADDR3		0x88c
#define TSEC_GADDR4		0x890
#define TSEC_GADDR5		0x894
#define TSEC_GADDR6		0x898
#define TSEC_GADDR7		0x89c

#define TSEC_ATTR		0xbf8
#define  TSEC_ATTR_RDSEN	0x00000080
#define  TSEC_ATTR_RBDSEN	0x00000040

/*
 * TSEC descriptors.
 */

struct tsec_desc {
	uint16_t td_status;
	uint16_t td_len;
	uint32_t td_addr;
};

/* Tx status bits. */
#define TSEC_TX_TXTRUNC		0x0001 /* TX truncation */
#define TSEC_TX_UN		0x0002 /* Underrun */
#define TSEC_TX_RC		0x003c /* Retry count */
#define TSEC_TX_RL		0x0040 /* Retransmission limit */
#define TSEC_TX_HFE		0x0080 /* Huge frame enable/late collision */
#define TSEC_TX_LC		TSEC_TX_HFE
#define TSEC_TX_TO1		0x0100 /* Transmit software ownership bit */
#define TSEC_TX_DEF		0x0200 /* Defer indication */
#define TSEC_TX_TC		0x0400 /* Tx CRC */
#define TSEC_TX_L		0x0800 /* Last in frame */
#define TSEC_TX_I		0x1000 /* Interrupt */
#define TSEC_TX_W		0x2000 /* Wrap */
#define TSEC_TX_PAD		0x4000 /* PAD/CRC */
#define TSEC_TX_R		0x8000 /* Ready */

/* Rx status bits */
#define TSEC_RX_TR		0x0001 /* Truncation */
#define TSEC_RX_OV		0x0002 /* Overrun */
#define TSEC_RX_CR		0x0004 /* Rx CRC error */
#define TSEC_RX_SH		0x0008 /* Short frame */
#define TSEC_RX_NO		0x0010 /* Rx non-octet aligned frame */
#define TSEC_RX_LG		0x0020 /* Rx framelength violation */
#define TSEC_RX_MC		0x0040 /* Multicast */
#define TSEC_RX_BC		0x0080 /* Broadcast */
#define TSEC_RX_M		0x0100 /* Miss */
#define TSEC_RX_F		0x0400 /* First in frame */
#define TSEC_RX_L		0x0800 /* Last in frame */
#define TSEC_RX_I		TSEC_TX_I
#define TSEC_RX_W		TSEC_TX_W
#define TSEC_RX_RO1		0x4000 /* Receive software ownership bit */
#define TSEC_RX_E		0x8000 /* Empty */

struct tsec_buf {
	bus_dmamap_t	tb_map;
	struct mbuf	*tb_m;
};

#define TSEC_NTXDESC	256
#define TSEC_NTXSEGS	16

#define TSEC_NRXDESC	256

struct tsec_dmamem {
	bus_dmamap_t		tdm_map;
	bus_dma_segment_t	tdm_seg;
	size_t			tdm_size;
	caddr_t			tdm_kva;
};
#define TSEC_DMA_MAP(_tdm)	((_tdm)->tdm_map)
#define TSEC_DMA_LEN(_tdm)	((_tdm)->tdm_size)
#define TSEC_DMA_DVA(_tdm)	((_tdm)->tdm_map->dm_segs[0].ds_addr)
#define TSEC_DMA_KVA(_tdm)	((void *)(_tdm)->tdm_kva)

struct tsec_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	bus_space_handle_t	sc_mii_ioh;
	bus_dma_tag_t		sc_dmat;

	struct arpcom		sc_ac;
#define sc_lladdr	sc_ac.ac_enaddr
	struct mii_data		sc_mii;
#define sc_media	sc_mii.mii_media
	int			sc_link;

	struct tsec_dmamem	*sc_txring;
	struct tsec_buf		*sc_txbuf;
	struct tsec_desc	*sc_txdesc;
	int			sc_tx_prod;
	int			sc_tx_cnt;
	int			sc_tx_cons;

	struct tsec_dmamem	*sc_rxring;
	struct tsec_buf		*sc_rxbuf;
	struct tsec_desc	*sc_rxdesc;
	int			sc_rx_prod;
	struct if_rxring	sc_rx_ring;
	int			sc_rx_cons;

	struct timeout		sc_tick;
};

#define DEVNAME(_s)	((_s)->sc_dev.dv_xname)

int	tsec_match(struct device *, void *, void *);
void	tsec_attach(struct device *, struct device *, void *);

struct cfattach tsec_ca = {
	sizeof(struct tsec_softc), tsec_match, tsec_attach
};

struct cfdriver tsec_cd = {
	NULL, "tsec", DV_IFNET
};

int	tsec_find_phy(int, int);

uint32_t tsec_read(struct tsec_softc *, bus_addr_t);
void	tsec_write(struct tsec_softc *, bus_addr_t, uint32_t);
uint32_t tsec_mii_read(struct tsec_softc *, bus_addr_t);
void	tsec_mii_write(struct tsec_softc *, bus_addr_t, uint32_t);

int	tsec_ioctl(struct ifnet *, u_long, caddr_t);
void	tsec_start(struct ifnet *);
void	tsec_watchdog(struct ifnet *);

int	tsec_media_change(struct ifnet *);
void	tsec_media_status(struct ifnet *, struct ifmediareq *);

int	tsec_mii_readreg(struct device *, int, int);
void	tsec_mii_writereg(struct device *, int, int, int);
void	tsec_mii_statchg(struct device *);

void	tsec_lladdr_write(struct tsec_softc *);

void	tsec_tick(void *);

int	tsec_txintr(void *);
int	tsec_rxintr(void *);
int	tsec_errintr(void *);

void	tsec_tx_proc(struct tsec_softc *);
void	tsec_rx_proc(struct tsec_softc *);

void	tsec_up(struct tsec_softc *);
void	tsec_down(struct tsec_softc *);
void	tsec_iff(struct tsec_softc *);
int	tsec_encap(struct tsec_softc *, struct mbuf *, int *);

void	tsec_reset(struct tsec_softc *);
void	tsec_stop_dma(struct tsec_softc *);

struct tsec_dmamem *
	tsec_dmamem_alloc(struct tsec_softc *, bus_size_t, bus_size_t);
void	tsec_dmamem_free(struct tsec_softc *, struct tsec_dmamem *);
struct mbuf *tsec_alloc_mbuf(struct tsec_softc *, bus_dmamap_t);
void	tsec_fill_rx_ring(struct tsec_softc *);

/*
 * The MPC8349E processor has two TSECs but only one external
 * management interface to control external PHYs.  The registers
 * controlling the management interface are part of TSEC1. So to
 * control a PHY attached to TSEC2, one needs to access TSEC1's
 * registers.  To deal with this, the first TSEC that attaches maps
 * the register space for both TSEC1 and TSEC2 and stores the bus
 * space tag and bus space handle in these global variables.  We use
 * these to create subregions for each individual interface and the
 * management interface.
 */
bus_space_tag_t		tsec_iot;
bus_space_handle_t	tsec_ioh;

int
tsec_match(struct device *parent, void *cfdata, void *aux)
{
	struct obio_attach_args *oa = aux;
	char buf[32];

	if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "network") != 0)
		return (0);

	if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "gianfar") != 0)
		return (0);

	return (1);
}

void
tsec_attach(struct device *parent, struct device *self, void *aux)
{
	struct tsec_softc *sc = (void *)self;
	struct obio_attach_args *oa = aux;
	struct ifnet *ifp;
	int phy, n;

	if (OF_getprop(oa->oa_node, "phy-handle", &phy,
	    sizeof(phy)) == sizeof(phy)) {
		int node, reg;

		node = tsec_find_phy(OF_peer(0), phy);
		if (node == -1 || OF_getprop(node, "reg", &reg,
		    sizeof(reg)) != sizeof(reg)) {
			printf(": can't find PHY\n");
			return;
		}

		oa->oa_phy = reg;
	}

	/* Map registers for TSEC1 & TSEC2 if they're not mapped yet. */
	if (oa->oa_iot != tsec_iot) {
		tsec_iot = oa->oa_iot;
		if (bus_space_map(tsec_iot, oa->oa_offset & 0xffffc000,
		    8192, 0, &tsec_ioh)) {
			printf(": can't map registers\n");
			return;
		}
	}

	sc->sc_iot = tsec_iot;
	sc->sc_dmat = oa->oa_dmat;

	/* Ethernet Controller registers. */
	bus_space_subregion(tsec_iot, tsec_ioh, oa->oa_offset & 0x3fff,
	    3072, &sc->sc_ioh);

	/* MII Management registers. */
	bus_space_subregion(tsec_iot, tsec_ioh, 0, 3072, &sc->sc_mii_ioh);

	myetheraddr(sc->sc_lladdr);
	printf(": address %s\n", ether_sprintf(sc->sc_lladdr));

	timeout_set(&sc->sc_tick, tsec_tick, sc);

	ifp = &sc->sc_ac.ac_if;
	ifp->if_softc = sc;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_ioctl = tsec_ioctl;
	ifp->if_start = tsec_start;
	ifp->if_watchdog = tsec_watchdog;
	IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_NTXDESC - 1);
	IFQ_SET_READY(&ifp->if_snd);
	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);

	ifp->if_capabilities = IFCAP_VLAN_MTU;

	sc->sc_mii.mii_ifp = ifp;
	sc->sc_mii.mii_readreg = tsec_mii_readreg;
	sc->sc_mii.mii_writereg = tsec_mii_writereg;
	sc->sc_mii.mii_statchg = tsec_mii_statchg;

	ifmedia_init(&sc->sc_media, 0, tsec_media_change, tsec_media_status);

	tsec_reset(sc);

	/* Reset management. */
	tsec_write(sc, TSEC_MIIMCFG, TSEC_MIIMCFG_RESET);
	tsec_write(sc, TSEC_MIIMCFG, 0x00000003);
	for (n = 0; n < 100; n++) {
		if ((tsec_read(sc, TSEC_MIIMIND) & TSEC_MIIMIND_BUSY) == 0)
			break;
	}

	mii_attach(self, &sc->sc_mii, 0xffffffff, oa->oa_phy,
	    MII_OFFSET_ANY, 0);
	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
		printf("%s: no PHY found!\n", sc->sc_dev.dv_xname);
		ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
	} else
		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);

	if_attach(ifp);
	ether_ifattach(ifp);

	intr_establish(oa->oa_ivec, IST_LEVEL, IPL_NET, tsec_txintr, sc,
	    sc->sc_dev.dv_xname);
	intr_establish(oa->oa_ivec + 1, IST_LEVEL, IPL_NET, tsec_rxintr, sc,
	    sc->sc_dev.dv_xname);
	intr_establish(oa->oa_ivec + 2, IST_LEVEL, IPL_NET, tsec_errintr, sc,
	    sc->sc_dev.dv_xname);
}

int
tsec_find_phy(int node, int phy)
{
	int child, handle;

	if (OF_getprop(node, "linux,phandle", &handle,
	    sizeof(handle)) == sizeof(handle) && phy == handle)
		return (node);

	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		node = tsec_find_phy(child, phy);
		if (node != -1)
			return node;
	}

	return (-1);
}

uint32_t
tsec_read(struct tsec_softc *sc, bus_addr_t addr)
{
	return (letoh32(bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr)));
}

void
tsec_write(struct tsec_softc *sc, bus_addr_t addr, uint32_t data)
{
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, htole32(data));
}

uint32_t
tsec_mii_read(struct tsec_softc *sc, bus_addr_t addr)
{
	return (letoh32(bus_space_read_4(sc->sc_iot, sc->sc_mii_ioh, addr)));
}

void
tsec_mii_write(struct tsec_softc *sc, bus_addr_t addr, uint32_t data)
{
	bus_space_write_4(sc->sc_iot, sc->sc_mii_ioh, addr, htole32(data));
}

void
tsec_lladdr_write(struct tsec_softc *sc)
{
	uint32_t addr1, addr2;

	addr1 = sc->sc_lladdr[5] << 24 | sc->sc_lladdr[4] << 16 |
	    sc->sc_lladdr[3] << 8 | sc->sc_lladdr[2];
	addr2 = sc->sc_lladdr[1] << 24 | sc->sc_lladdr[0] << 16;
	tsec_write(sc, TSEC_MACSTNADDR1, addr1);
	tsec_write(sc, TSEC_MACSTNADDR2, addr2);
}

void
tsec_start(struct ifnet *ifp)
{
	struct tsec_softc *sc = ifp->if_softc;
	struct mbuf *m;
	int idx;

	if (!(ifp->if_flags & IFF_RUNNING))
		return;
	if (ifp->if_flags & IFF_OACTIVE)
		return;
	if (IFQ_IS_EMPTY(&ifp->if_snd))
		return;
	if (!sc->sc_link)
		return;

	idx = sc->sc_tx_prod;
	while ((sc->sc_txdesc[idx].td_status & TSEC_TX_TO1) == 0) {
		IFQ_POLL(&ifp->if_snd, m);
		if (m == NULL)
			break;

		if (tsec_encap(sc, m, &idx)) {
			ifp->if_flags |= IFF_OACTIVE;
			break;
		}

		/* Now we are committed to transmit the packet. */
		IFQ_DEQUEUE(&ifp->if_snd, m);

#if NBPFILTER > 0
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
	}

	if (sc->sc_tx_prod != idx) {
		sc->sc_tx_prod = idx;

		/* Set a timeout in case the chip goes out to lunch. */
		ifp->if_timer = 5;
	}
}

int
tsec_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
{
	struct tsec_softc *sc = ifp->if_softc;
	struct ifaddr *ifa = (struct ifaddr *)addr;
	struct ifreq *ifr = (struct ifreq *)addr;
	int error = 0, s;

	s = splnet();

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		if (ifa->ifa_addr->sa_family == AF_INET)
			arp_ifinit(&sc->sc_ac, ifa);
		/* FALLTHROUGH */
	case SIOCSIFFLAGS:
		if (ifp->if_flags & IFF_UP) {
			if (ifp->if_flags & IFF_RUNNING)
				error = ENETRESET;
			else
				tsec_up(sc);
		} else {
			if (ifp->if_flags & IFF_RUNNING)
				tsec_down(sc);
		}
		break;

	case SIOCGIFMEDIA:
	case SIOCSIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
		break;

	case SIOCGIFRXR:
		error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data,
		    NULL, MCLBYTES, &sc->sc_rx_ring);
		break;

	default:
		error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr);
		break;
	}

	if (error == ENETRESET) {
		if (ifp->if_flags & IFF_RUNNING)
			tsec_iff(sc);
		error = 0;
	}

	splx(s);
	return (error);
}

void
tsec_watchdog(struct ifnet *ifp)
{
	printf("%s\n", __func__);
}

int
tsec_media_change(struct ifnet *ifp)
{
	struct tsec_softc *sc = ifp->if_softc;

	if (LIST_FIRST(&sc->sc_mii.mii_phys))
		mii_mediachg(&sc->sc_mii);

	return (0);
}

void
tsec_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
{
	struct tsec_softc *sc = ifp->if_softc;

	if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
		mii_pollstat(&sc->sc_mii);
		ifmr->ifm_active = sc->sc_mii.mii_media_active;
		ifmr->ifm_status = sc->sc_mii.mii_media_status;
	}
}

int
tsec_mii_readreg(struct device *self, int phy, int reg)
{
	struct tsec_softc *sc = (void *)self;
	uint32_t v;
	int n;

	tsec_mii_write(sc, TSEC_MIIMADD, (phy << 8) | reg);
	tsec_mii_write(sc, TSEC_MIIMCOM, 0);
	tsec_mii_write(sc, TSEC_MIIMCOM, TSEC_MIIMCOM_READ);
	for (n = 0; n < 100; n++) {
		v = tsec_mii_read(sc, TSEC_MIIMIND);
		if ((v & (TSEC_MIIMIND_NOTVALID | TSEC_MIIMIND_BUSY)) == 0)
			return (tsec_mii_read(sc, TSEC_MIIMSTAT));
		delay(10);
	}

	printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname);
	return (0);
}

void
tsec_mii_writereg(struct device *self, int phy, int reg, int val)
{
	struct tsec_softc *sc = (void *)self;
	uint32_t v;
	int n;

	tsec_mii_write(sc, TSEC_MIIMADD, (phy << 8) | reg);
	tsec_mii_write(sc, TSEC_MIIMCON, val);
	for (n = 0; n < 100; n++) {
		v = tsec_mii_read(sc, TSEC_MIIMIND);
		if ((v & TSEC_MIIMIND_BUSY) == 0)
			return;
		delay(10);
	}

	printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname);
}

void
tsec_mii_statchg(struct device *self)
{
	struct tsec_softc *sc = (void *)self;
	uint32_t maccfg2, ecntrl;

	ecntrl = tsec_read(sc, TSEC_ECNTRL);
	maccfg2 = tsec_read(sc, TSEC_MACCFG2);
	maccfg2 &= ~TSEC_MACCFG2_IF_MODE;

	switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
	case IFM_1000_SX:
	case IFM_1000_LX:
	case IFM_1000_CX:
	case IFM_1000_T:
		maccfg2 |= TSEC_MACCFG2_IF_GMII;
		sc->sc_link = 1;
		break;
	case IFM_100_TX:
		ecntrl |= TSEC_ECNTRL_R100M;
		maccfg2 |= TSEC_MACCFG2_IF_MII;
		sc->sc_link = 1;
		break;
	case IFM_10_T:
		ecntrl &= ~TSEC_ECNTRL_R100M;
		maccfg2 |= TSEC_MACCFG2_IF_MII;
		sc->sc_link = 1;
		break;
	default:
		sc->sc_link = 0;
		return;
	}

	if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
		maccfg2 |= TSEC_MACCFG2_FDX;
	else
		maccfg2 &= ~TSEC_MACCFG2_FDX;

	tsec_write(sc, TSEC_MACCFG2, maccfg2);
	tsec_write(sc, TSEC_ECNTRL, ecntrl);
}

void
tsec_tick(void *arg)
{
	struct tsec_softc *sc = arg;
	int s;

	s = splnet();
	mii_tick(&sc->sc_mii);
	splx(s);

	timeout_add_sec(&sc->sc_tick, 1);
}

int
tsec_txintr(void *arg)
{
	struct tsec_softc *sc = arg;
	uint32_t ievent;

	ievent = tsec_read(sc, TSEC_IEVENT);
	if ((ievent & (TSEC_IEVENT_TXC | TSEC_IEVENT_TXE |
	    TSEC_IEVENT_TXB | TSEC_IEVENT_TXF)) == 0)
		printf("%s: tx %b\n", DEVNAME(sc), ievent, TSEC_IEVENT_FMT);
	ievent &= (TSEC_IEVENT_TXC | TSEC_IEVENT_TXE |
	    TSEC_IEVENT_TXB | TSEC_IEVENT_TXF);
	tsec_write(sc, TSEC_IEVENT, ievent);

	tsec_tx_proc(sc);

	return (1);
}

int
tsec_rxintr(void *arg)
{
	struct tsec_softc *sc = arg;
	uint32_t ievent;

	ievent = tsec_read(sc, TSEC_IEVENT);
	if ((ievent & (TSEC_IEVENT_RXB | TSEC_IEVENT_RXF)) == 0)
		printf("%s: rx %b\n", DEVNAME(sc), ievent, TSEC_IEVENT_FMT);
	ievent &= (TSEC_IEVENT_RXB | TSEC_IEVENT_RXF);
	tsec_write(sc, TSEC_IEVENT, ievent);

	tsec_rx_proc(sc);

	return (1);
}

int
tsec_errintr(void *arg)
{
	struct tsec_softc *sc = arg;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	uint32_t ievent;

	ievent = tsec_read(sc, TSEC_IEVENT);
	if ((ievent & TSEC_IEVENT_BSY) == 0)
		printf("%s: err %b\n", DEVNAME(sc), ievent, TSEC_IEVENT_FMT);
	ievent &= TSEC_IEVENT_BSY;
	tsec_write(sc, TSEC_IEVENT, ievent);

	if (ievent & TSEC_IEVENT_BSY) {
		/*
		 * We ran out of buffers and dropped one (or more)
		 * packets.  We must clear RSTAT[QHLT] after
		 * processing the ring to get things started again.
		 */
		tsec_rx_proc(sc);
		tsec_write(sc, TSEC_RSTAT, TSEC_RSTAT_QHLT);
		ifp->if_ierrors++;
	}

	return (1);
}

void
tsec_tx_proc(struct tsec_softc *sc)
{
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct tsec_desc *txd;
	struct tsec_buf *txb;
	int idx;

	bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_txring), 0,
	    TSEC_DMA_LEN(sc->sc_txring),
	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);

	while (sc->sc_tx_cnt > 0) {
		idx = sc->sc_tx_cons;
		KASSERT(idx < TSEC_NTXDESC);

		txd = &sc->sc_txdesc[idx];
		if (txd->td_status & TSEC_TX_R)
			break;

		txb = &sc->sc_txbuf[idx];
		if (txb->tb_m) {
			bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0,
			    txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
			bus_dmamap_unload(sc->sc_dmat, txb->tb_map);

			m_freem(txb->tb_m);
			txb->tb_m = NULL;
			ifp->if_opackets++;
		}

		ifp->if_flags &= ~IFF_OACTIVE;

		sc->sc_tx_cnt--;

		if (txd->td_status & TSEC_TX_W)
			sc->sc_tx_cons = 0;
		else
			sc->sc_tx_cons++;

		__asm volatile("eieio" ::: "memory");
		txd->td_status &= TSEC_TX_W;
	}

	if (sc->sc_tx_cnt == 0)
		ifp->if_timer = 0;
}

void
tsec_rx_proc(struct tsec_softc *sc)
{
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct tsec_desc *rxd;
	struct tsec_buf *rxb;
	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
	struct mbuf *m;
	int idx, len;

	if ((ifp->if_flags & IFF_RUNNING) == 0)
		return;

	bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_rxring), 0,
	    TSEC_DMA_LEN(sc->sc_rxring),
	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);

	while (if_rxr_inuse(&sc->sc_rx_ring) > 0) {
		idx = sc->sc_rx_cons;
		KASSERT(idx < TSEC_NRXDESC);

		rxd = &sc->sc_rxdesc[idx];
		if (rxd->td_status & TSEC_RX_E)
			break;

		len = rxd->td_len;
		rxb = &sc->sc_rxbuf[idx];
		KASSERT(rxb->tb_m);

		bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0,
		    len, BUS_DMASYNC_POSTREAD);
		bus_dmamap_unload(sc->sc_dmat, rxb->tb_map);

		/* Strip off CRC. */
		len -= ETHER_CRC_LEN;
		KASSERT(len > 0);

		m = rxb->tb_m;
		rxb->tb_m = NULL;
		m->m_pkthdr.len = m->m_len = len;

		ml_enqueue(&ml, m);

		if_rxr_put(&sc->sc_rx_ring, 1);
		if (rxd->td_status & TSEC_RX_W)
			sc->sc_rx_cons = 0;
		else
			sc->sc_rx_cons++;
	}

	tsec_fill_rx_ring(sc);

	bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_rxring), 0,
	    TSEC_DMA_LEN(sc->sc_rxring),
	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);

	if_input(ifp, &ml);
}

void
tsec_up(struct tsec_softc *sc)
{
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct tsec_desc *txd, *rxd;
	struct tsec_buf *txb, *rxb;
	uint32_t maccfg1, maccfg2, ecntrl, dmactrl, attr;
	int i;

	/* Allocate Tx descriptor ring. */
	sc->sc_txring = tsec_dmamem_alloc(sc,
	    TSEC_NTXDESC * sizeof(struct tsec_desc), 8);
	sc->sc_txdesc = TSEC_DMA_KVA(sc->sc_txring);

	sc->sc_txbuf = malloc(sizeof(struct tsec_buf) * TSEC_NTXDESC,
	    M_DEVBUF, M_WAITOK);
	for (i = 0; i < TSEC_NTXDESC; i++) {
		txb = &sc->sc_txbuf[i];
		bus_dmamap_create(sc->sc_dmat, MCLBYTES, TSEC_NTXSEGS,
		    MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map);
		txb->tb_m = NULL;
	}

	/* Set wrap bit on last descriptor. */
	txd = &sc->sc_txdesc[TSEC_NTXDESC - 1];
	txd->td_status = TSEC_TX_W;
	bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_txring),
	    (TSEC_NTXDESC - 1) * sizeof(*txd), sizeof(*txd),
	    BUS_DMASYNC_PREWRITE);

	sc->sc_tx_prod = sc->sc_tx_cons = 0;
	sc->sc_tx_cnt = 0;

	tsec_write(sc, TSEC_TBASE, TSEC_DMA_DVA(sc->sc_txring));

	/* Allocate Rx descriptor ring. */
	sc->sc_rxring = tsec_dmamem_alloc(sc,
	    TSEC_NRXDESC * sizeof(struct tsec_desc), 8);
	sc->sc_rxdesc = TSEC_DMA_KVA(sc->sc_rxring);

	sc->sc_rxbuf = malloc(sizeof(struct tsec_buf) * TSEC_NRXDESC,
	    M_DEVBUF, M_WAITOK);

	for (i = 0; i < TSEC_NRXDESC; i++) {
		rxb = &sc->sc_rxbuf[i];
		bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map);
		rxb->tb_m = NULL;
	}

	/* Set wrap bit on last descriptor. */
	rxd = &sc->sc_rxdesc[TSEC_NRXDESC - 1];
	rxd->td_status |= TSEC_RX_W;
	bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_rxring),
	    0, TSEC_DMA_LEN(sc->sc_rxring), BUS_DMASYNC_PREWRITE);

	sc->sc_rx_prod = sc->sc_rx_cons = 0;

	if_rxr_init(&sc->sc_rx_ring, 2, TSEC_NRXDESC);
	tsec_fill_rx_ring(sc);

	tsec_write(sc, TSEC_MRBLR, MCLBYTES);

	tsec_write(sc, TSEC_RBASE, TSEC_DMA_DVA(sc->sc_rxring));

	tsec_lladdr_write(sc);

	tsec_write(sc, TSEC_IADDR0, 0);
	tsec_write(sc, TSEC_IADDR1, 0);
	tsec_write(sc, TSEC_IADDR2, 0);
	tsec_write(sc, TSEC_IADDR3, 0);
	tsec_write(sc, TSEC_IADDR4, 0);
	tsec_write(sc, TSEC_IADDR5, 0);
	tsec_write(sc, TSEC_IADDR6, 0);
	tsec_write(sc, TSEC_IADDR7, 0);
	tsec_write(sc, TSEC_GADDR0, 0);
	tsec_write(sc, TSEC_GADDR1, 0);
	tsec_write(sc, TSEC_GADDR2, 0);
	tsec_write(sc, TSEC_GADDR3, 0);
	tsec_write(sc, TSEC_GADDR4, 0);
	tsec_write(sc, TSEC_GADDR5, 0);
	tsec_write(sc, TSEC_GADDR6, 0);
	tsec_write(sc, TSEC_GADDR7, 0);

	maccfg1 = tsec_read(sc, TSEC_MACCFG1);
	maccfg1 |= TSEC_MACCFG1_TXEN;
	maccfg1 |= TSEC_MACCFG1_RXEN;
	tsec_write(sc, TSEC_MACCFG1, maccfg1);

	/*
	 * Default to full-duplex MII mode, which is the mode most
	 * likely used by a directly connected integrated switch.  For
	 * a real PHY the mode will be set later, based on the
	 * parameters negotiaded by the PHY.
	 */
	maccfg2 = tsec_read(sc, TSEC_MACCFG2);
	maccfg2 &= ~TSEC_MACCFG2_IF_MODE;
	maccfg2 |= TSEC_MACCFG2_IF_MII | TSEC_MACCFG2_FDX;
	tsec_write(sc, TSEC_MACCFG2, maccfg2 | TSEC_MACCFG2_PAD);

	ecntrl = tsec_read(sc, TSEC_ECNTRL);
	tsec_write(sc, TSEC_ECNTRL, ecntrl | TSEC_ECNTRL_R100M);

	dmactrl = tsec_read(sc, TSEC_DMACTRL);
	dmactrl |= TSEC_DMACTRL_TDSEN;
	dmactrl |= TSEC_DMACTRL_TBDSEN;
	dmactrl |= TSEC_DMACTRL_WWR;
	dmactrl |= TSEC_DMACTRL_WOP;
	dmactrl &= ~(TSEC_DMACTRL_GTS | TSEC_DMACTRL_GRS);
	tsec_write(sc, TSEC_DMACTRL, dmactrl);

	attr = tsec_read(sc, TSEC_ATTR);
	attr |= TSEC_ATTR_RDSEN;
	attr |= TSEC_ATTR_RBDSEN;
	tsec_write(sc, TSEC_ATTR, attr);

	tsec_write(sc, TSEC_TSTAT, TSEC_TSTAT_THLT);
	tsec_write(sc, TSEC_RSTAT, TSEC_RSTAT_QHLT);

	/* Configure media. */
	if (LIST_FIRST(&sc->sc_mii.mii_phys))
		mii_mediachg(&sc->sc_mii);

	/* Program promiscuous mode and multicast filters. */
	tsec_iff(sc);

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	tsec_write(sc, TSEC_IMASK, TSEC_IMASK_TXEEN |
	    TSEC_IMASK_TXBEN | TSEC_IMASK_TXFEN |
	    TSEC_IMASK_RXBEN | TSEC_IMASK_RXFEN | TSEC_IMASK_BSYEN);

	timeout_add_sec(&sc->sc_tick, 1);
}

void
tsec_down(struct tsec_softc *sc)
{
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct tsec_buf *txb, *rxb;
	uint32_t maccfg1;
	int i;

	timeout_del(&sc->sc_tick);

	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
	ifp->if_timer = 0;

	tsec_stop_dma(sc);

	maccfg1 = tsec_read(sc, TSEC_MACCFG1);
	maccfg1 &= ~TSEC_MACCFG1_TXEN;
	maccfg1 &= ~TSEC_MACCFG1_RXEN;
	tsec_write(sc, TSEC_MACCFG1, maccfg1);

	for (i = 0; i < TSEC_NTXDESC; i++) {
		txb = &sc->sc_txbuf[i];
		if (txb->tb_m) {
			bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0,
			    txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
			bus_dmamap_unload(sc->sc_dmat, txb->tb_map);
			m_freem(txb->tb_m);
		}
		bus_dmamap_destroy(sc->sc_dmat, txb->tb_map);
	}

	tsec_dmamem_free(sc, sc->sc_txring);
	free(sc->sc_txbuf, M_DEVBUF, 0);

	for (i = 0; i < TSEC_NRXDESC; i++) {
		rxb = &sc->sc_rxbuf[i];
		if (rxb->tb_m) {
			bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0,
			    rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
			bus_dmamap_unload(sc->sc_dmat, rxb->tb_map);
			m_freem(rxb->tb_m);
		}
		bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map);
	}

	tsec_dmamem_free(sc, sc->sc_rxring);
	free(sc->sc_rxbuf, M_DEVBUF, 0);
}

void
tsec_iff(struct tsec_softc *sc)
{
	struct arpcom *ac = &sc->sc_ac;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	uint32_t crc, hash[8];
	uint32_t rctrl;
	int i;

	rctrl = tsec_read(sc, TSEC_RCTRL);
	rctrl &= ~TSEC_RCTRL_PROM;
	ifp->if_flags &= ~IFF_ALLMULTI;

	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
		ifp->if_flags |= IFF_ALLMULTI;
		rctrl |= TSEC_RCTRL_PROM;
		bzero(hash, sizeof(hash));
	} else {
		ETHER_FIRST_MULTI(step, ac, enm);
		while (enm != NULL) {
			crc = ether_crc32_be(enm->enm_addrlo,
			    ETHER_ADDR_LEN);

			crc >>= 24;
			hash[crc / 32] |= 1 << (31 - (crc % 32));

			ETHER_NEXT_MULTI(step, enm);
		}
	}

	for (i = 0; i < nitems(hash); i++)
		tsec_write(sc, TSEC_GADDR0 + i * 4, hash[i]);

	tsec_write(sc, TSEC_RCTRL, rctrl);
}

int
tsec_encap(struct tsec_softc *sc, struct mbuf *m, int *idx)
{
	struct tsec_desc *txd;
	bus_dmamap_t map;
	int cur, frag, i;
	uint16_t status;

	cur = frag = *idx;
	map = sc->sc_txbuf[cur].tb_map;

	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT))
		return (ENOBUFS);

	if (map->dm_nsegs > (TSEC_NTXDESC - sc->sc_tx_cnt - 2)) {
		bus_dmamap_unload(sc->sc_dmat, map);
		return (ENOBUFS);
	}

	/* Sync the DMA map. */
	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
	    BUS_DMASYNC_PREWRITE);

	txd = &sc->sc_txdesc[frag];
	for (i = 0; i < map->dm_nsegs; i++) {
		status = txd->td_status & TSEC_TX_W;
		status |= TSEC_TX_TO1;
		if (i == (map->dm_nsegs - 1))
			status |= TSEC_TX_L;
		txd->td_len = map->dm_segs[i].ds_len;
		txd->td_addr = map->dm_segs[i].ds_addr;
		__asm volatile("eieio" ::: "memory");
		txd->td_status = status | TSEC_TX_R | TSEC_TX_I | TSEC_TX_TC;

		bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_txring),
		    frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE);

		cur = frag;
		if (status & TSEC_TX_W) {
			txd = &sc->sc_txdesc[0];
			frag = 0;
		} else {
			txd++;
			frag++;
		}
		KASSERT(frag != sc->sc_tx_cons);

		tsec_write(sc, TSEC_TSTAT, TSEC_TSTAT_THLT);
	}

	KASSERT(sc->sc_txbuf[cur].tb_m == NULL);
	sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map;
	sc->sc_txbuf[cur].tb_map = map;
	sc->sc_txbuf[cur].tb_m = m;

	sc->sc_tx_cnt += map->dm_nsegs;
	*idx = frag;

	return (0);
}

void
tsec_reset(struct tsec_softc *sc)
{
	tsec_stop_dma(sc);

	/* Set, then clear MACCFG1[Soft_Reset]. */
	tsec_write(sc, TSEC_MACCFG1, TSEC_MACCFG1_RESET);
	tsec_write(sc, TSEC_MACCFG1, 0);

	/* Clear IEVENT. */
	tsec_write(sc, TSEC_IEVENT, 0xffffffff);
}

void
tsec_stop_dma(struct tsec_softc *sc)
{
	uint32_t dmactrl, ievent;
	int n;

	/* Stop DMA. */
	dmactrl = tsec_read(sc, TSEC_DMACTRL);
	dmactrl |= TSEC_DMACTRL_GTS;
	tsec_write(sc, TSEC_DMACTRL, dmactrl);

	for (n = 0; n < 100; n++) {
		ievent = tsec_read(sc, TSEC_IEVENT);
		if (ievent & TSEC_IEVENT_GTSC)
			break;
	}
	KASSERT(n != 100);

	dmactrl = tsec_read(sc, TSEC_DMACTRL);
	dmactrl |= TSEC_DMACTRL_GRS;
	tsec_write(sc, TSEC_DMACTRL, dmactrl);

	for (n = 0; n < 100; n++) {
		ievent = tsec_read(sc, TSEC_IEVENT);
		if (ievent & TSEC_IEVENT_GRSC)
			break;
	}
	KASSERT(n != 100);
}

struct tsec_dmamem *
tsec_dmamem_alloc(struct tsec_softc *sc, bus_size_t size, bus_size_t align)
{
	struct tsec_dmamem *tdm;
	int nsegs;

	tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO);
	tdm->tdm_size = size;

	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0)
		goto tdmfree;

	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1,
	    &nsegs, BUS_DMA_WAITOK) != 0)
		goto destroy;

	if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size,
	    &tdm->tdm_kva, BUS_DMA_WAITOK) != 0)
		goto free;

	if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size,
	    NULL, BUS_DMA_WAITOK) != 0)
		goto unmap;

	bzero(tdm->tdm_kva, size);

	return (tdm);

unmap:
	bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size);
free:
	bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1);
destroy:
	bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map);
tdmfree:
	free(tdm, M_DEVBUF, 0);

	return (NULL);
}

void
tsec_dmamem_free(struct tsec_softc *sc, struct tsec_dmamem *tdm)
{
	bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size);
	bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1);
	bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map);
	free(tdm, M_DEVBUF, 0);
}

struct mbuf *
tsec_alloc_mbuf(struct tsec_softc *sc, bus_dmamap_t map)
{
	struct mbuf *m = NULL;

	m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES);
	if (!m)
		return (NULL);
	m->m_len = m->m_pkthdr.len = MCLBYTES;

	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
		printf("%s: could not load mbuf DMA map", DEVNAME(sc));
		m_freem(m);
		return (NULL);
	}

	bus_dmamap_sync(sc->sc_dmat, map, 0,
	    m->m_pkthdr.len, BUS_DMASYNC_PREREAD);

	return (m);
}

void
tsec_fill_rx_ring(struct tsec_softc *sc)
{
	struct tsec_desc *rxd;
	struct tsec_buf *rxb;
	u_int slots;

	for (slots = if_rxr_get(&sc->sc_rx_ring, TSEC_NRXDESC);
	    slots > 0; slots--) {
		rxb = &sc->sc_rxbuf[sc->sc_rx_prod];
		rxb->tb_m = tsec_alloc_mbuf(sc, rxb->tb_map);
		if (rxb->tb_m == NULL)
			break;

		rxd = &sc->sc_rxdesc[sc->sc_rx_prod];
		rxd->td_len = 0;
		rxd->td_addr = rxb->tb_map->dm_segs[0].ds_addr;
		__asm volatile("eieio" ::: "memory");
		rxd->td_status |= TSEC_RX_E | TSEC_RX_I;

		if (rxd->td_status & TSEC_RX_W)
			sc->sc_rx_prod = 0;
		else
			sc->sc_rx_prod++;
	}
	if_rxr_put(&sc->sc_rx_ring, slots);
}


code:
/*	$OpenBSD: ipic.c,v 1.18 2015/06/24 11:58:06 mpi Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <machine/autoconf.h>
#include <machine/intr.h>

#include <dev/ofw/openfirm.h>

#define IPIC_SICFR	0x00
#define IPIC_SIVCR	0x04
#define IPIC_SIPNR_H	0x08
#define IPIC_SIPNR_L	0x0c
#define IPIC_SIPRR_A	0x10
#define IPIC_SIPRR_D	0x1c
#define IPIC_SIMSR_H	0x20
#define IPIC_SIMSR_L	0x24
#define IPIC_SICNR	0x28
#define IPIC_SEPNR	0x2c
#define IPIC_SMPRR_A	0x30
#define IPIC_SMPRR_B	0x34
#define IPIC_SEMSR	0x38
#define IPIC_SECNR	0x3c
#define IPIC_SERSR	0x40
#define IPIC_SERMR	0x44
#define IPIC_SERCR	0x48
#define IPIC_SIFCR_H	0x50
#define IPIC_SIFCR_L	0x54
#define IPIC_SEFCR	0x58
#define IPIC_SERFR	0x5c
#define IPIC_SCVCR	0x60
#define IPIC_SMVCR	0x64

#define IPIC_NVEC	128

#define IPIC_EXTERNAL(ivec) ((ivec) >= 17 && (ivec) <= 23)

struct ipic_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;

	uint32_t		sc_simsr_h[IPL_NUM];
	uint32_t		sc_simsr_l[IPL_NUM];
	uint32_t		sc_semsr[IPL_NUM];
};

uint32_t ipic_imask;
struct intrq ipic_handler[IPIC_NVEC];
struct ipic_softc *ipic_sc;
int	ipic_preinit_done; /* defaults to 0 - not initialized */

int	ipic_match(struct device *, void *, void *);
void	ipic_attach(struct device *, struct device *, void *);

struct cfattach ipic_ca = {
	sizeof(struct ipic_softc), ipic_match, ipic_attach
};

struct cfdriver ipic_cd = {
	NULL, "ipic", DV_DULL
};

void ipic_preinit(void);
uint32_t ipic_read(struct ipic_softc *, bus_addr_t);
void	ipic_write(struct ipic_softc *, bus_addr_t, uint32_t);
uint32_t ipic_simsr_h(int);
uint32_t ipic_simsr_l(int);
uint32_t ipic_semsr(int);
void	ipic_calc_masks(void);

void	ext_intr(void);

ppc_splraise_t ipic_splraise;
ppc_spllower_t ipic_spllower;
ppc_splx_t ipic_splx;

void	ipic_setipl(int);

void
ipic_preinit(void)
{
	int i;
	struct intrq *iq;

	for (i = 0; i < IPIC_NVEC; i++) {
		iq = &ipic_handler[i];
		TAILQ_INIT(&iq->iq_list);
	}
	ipic_preinit_done = 1;
}

int
ipic_match(struct device *parent, void *cfdata, void *aux)
{
	struct obio_attach_args *oa = aux;
	char buf[32];

	if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "ipic") != 0)
		return (0);

	return (1);
}

void
ipic_attach(struct device *parent, struct device *self, void *aux)
{
	struct ipic_softc *sc = (void *)self;
	struct obio_attach_args *oa = aux;
	int ivec;
	struct intrq *iq;

	sc->sc_iot = oa->oa_iot;
	if (bus_space_map(sc->sc_iot, oa->oa_offset, 128, 0, &sc->sc_ioh)) {
		printf(": can't map registers\n");
		return;
	}

	ipic_sc = sc;

	/* if ipic_preinit has not happened, do it here */
	if (ipic_preinit_done == 0)
		ipic_preinit();

	/*
	 * Deal with pre-established interrupts.
	 */
	for (ivec = 0; ivec < IPIC_NVEC; ivec++) {
		iq = &ipic_handler[ivec];
		if (!TAILQ_EMPTY(&iq->iq_list)) {
			int level = TAILQ_FIRST(&iq->iq_list)->ih_level;

			sc->sc_simsr_h[level] |= ipic_simsr_h(ivec);
			sc->sc_simsr_l[level] |= ipic_simsr_l(ivec);
			sc->sc_semsr[level] |= ipic_semsr(ivec);
			ipic_calc_masks();
		}
	}

	ppc_smask_init();
	ppc_intr_func.raise = ipic_splraise;
	ppc_intr_func.lower = ipic_spllower;
	ppc_intr_func.x = ipic_splx;

	printf("\n");
}

uint32_t
ipic_read(struct ipic_softc *sc, bus_addr_t addr)
{
	return (letoh32(bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr)));
}

void
ipic_write(struct ipic_softc *sc, bus_addr_t addr, uint32_t data)
{
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, htole32(data));
}

uint32_t
ipic_simsr_h(int ivec)
{
	switch (ivec) {
	case 9:
		return 0x00000080;
	case 10:
		return 0x00000040;
	case 32:
		return 0x80000000;
	case 33:
		return 0x40000000;
	case 34:
		return 0x20000000;
	case 35:
		return 0x10000000;
	case 36:
		return 0x08000000;
	case 37:
		return 0x04000000;
	case 39:
		return 0x01000000;
	}

	return 0;
}

uint32_t
ipic_simsr_l(int ivec)
{
	return 0;
}

uint32_t
ipic_semsr(int ivec)
{
	switch (ivec) {
	case 17:
		return 0x40000000;
	case 18:
		return 0x20000000;
	case 19:
		return 0x10000000;
	case 20:
		return 0x08000000;
	case 21:
		return 0x04000000;
	case 22:
		return 0x02000000;
	case 23:
		return 0x01000000;
	case 48:
		return 0x80000000;
	}

	return 0;
}

void
ipic_calc_masks(void)
{
	struct ipic_softc *sc = ipic_sc;

	sc->sc_simsr_h[IPL_NET] |= sc->sc_simsr_h[IPL_BIO];
	sc->sc_simsr_h[IPL_TTY] |= sc->sc_simsr_h[IPL_NET];
	sc->sc_simsr_h[IPL_VM] |= sc->sc_simsr_h[IPL_TTY];
	sc->sc_simsr_h[IPL_CLOCK] |= sc->sc_simsr_h[IPL_VM];
	sc->sc_simsr_h[IPL_HIGH] |= sc->sc_simsr_h[IPL_CLOCK];

	sc->sc_simsr_l[IPL_NET] |= sc->sc_simsr_l[IPL_BIO];
	sc->sc_simsr_l[IPL_TTY] |= sc->sc_simsr_l[IPL_NET];
	sc->sc_simsr_l[IPL_VM] |= sc->sc_simsr_l[IPL_TTY];
	sc->sc_simsr_l[IPL_CLOCK] |= sc->sc_simsr_l[IPL_VM];
	sc->sc_simsr_l[IPL_HIGH] |= sc->sc_simsr_l[IPL_CLOCK];

	sc->sc_semsr[IPL_NET] |= sc->sc_semsr[IPL_BIO];
	sc->sc_semsr[IPL_TTY] |= sc->sc_semsr[IPL_NET];
	sc->sc_semsr[IPL_VM] |= sc->sc_semsr[IPL_TTY];
	sc->sc_semsr[IPL_CLOCK] |= sc->sc_semsr[IPL_VM];
	sc->sc_semsr[IPL_HIGH] |= sc->sc_semsr[IPL_CLOCK];
}

void *
intr_establish(int ivec, int type, int level,
    int (*ih_fun)(void *), void *ih_arg, const char *name)
{
	struct ipic_softc *sc = ipic_sc;
	struct intrhand *ih;
	struct intrq *iq;
	int s, flags;

	if (ipic_preinit_done == 0)
		ipic_preinit();

	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
	if (ih == NULL)
		panic("%s: malloc failed", __func__);
	iq = &ipic_handler[ivec];

	if (ivec < 0 || ivec >= IPIC_NVEC)
		panic("%s: invalid vector %d", __func__, ivec);

	if (sc) {
		sc->sc_simsr_h[level] |= ipic_simsr_h(ivec);
		sc->sc_simsr_l[level] |= ipic_simsr_l(ivec);
		sc->sc_semsr[level] |= ipic_semsr(ivec);
		ipic_calc_masks();
	}

	flags = level & IPL_MPSAFE;
	level &= ~IPL_MPSAFE;

	KASSERT(level <= IPL_TTY || level >= IPL_CLOCK || flags & IPL_MPSAFE);

	ih->ih_fun = ih_fun;
	ih->ih_arg = ih_arg;
	ih->ih_level = level;
	ih->ih_flags = flags;
	ih->ih_irq = ivec;

	evcount_attach(&ih->ih_count, name, &ih->ih_irq);

	/*
	 * Append handler to end of list
	 */
	s = ppc_intr_disable();
	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);

	/* Unmask the interrupt. */
	if (sc)
		ipic_setipl(curcpu()->ci_cpl);
	ppc_intr_enable(s);

	return (ih);
}

void
ext_intr(void)
{
	struct cpu_info *ci = curcpu();
	struct ipic_softc *sc = ipic_sc;
	struct intrhand *ih;
	struct intrq *iq;
	int pcpl;
	int ivec;

	pcpl = ci->ci_cpl;
	ivec = ipic_read(sc, IPIC_SIVCR) & 0x7f;

	iq = &ipic_handler[ivec];
	TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
		if (ih->ih_level <= pcpl) {
			panic("irq handler called at wrong level %d %d",
			    ih->ih_level, pcpl);
			continue;
		}

		ipic_splraise(ih->ih_level);
		ppc_intr_enable(1);

		KERNEL_LOCK();
		if ((*ih->ih_fun)(ih->ih_arg))
			ih->ih_count.ec_count++;
		KERNEL_UNLOCK();

		ppc_intr_disable();
	}

	splx(pcpl);
}

int
ipic_splraise(int newcpl)
{
	struct cpu_info *ci = curcpu();
	int ocpl = ci->ci_cpl;
	int s;

	if (ocpl > newcpl)
		newcpl = ocpl;

	s = ppc_intr_disable();
	ipic_setipl(newcpl);
	ppc_intr_enable(s);

	return (ocpl);
}

int
ipic_spllower(int newcpl)
{
	struct cpu_info *ci = curcpu();
	int ocpl = ci->ci_cpl;

	ipic_splx(newcpl);

	return (ocpl);
}

void
ipic_splx(int newcpl)
{
	struct cpu_info *ci = curcpu();
	int intr, s;

	intr = ppc_intr_disable();
	ipic_setipl(newcpl);
	if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) {
		s = splsofttty();
		dosoftint(newcpl);
		ipic_setipl(s); /* no-overhead splx */
	}
	ppc_intr_enable(intr);
}

/* Must be called with interrupt disable. */
void
ipic_setipl(int ipl)
{
	struct cpu_info *ci = curcpu();
	struct ipic_softc *sc = ipic_sc;
	uint32_t mask;

	ci->ci_cpl = ipl;
	mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[ipl];
	ipic_write(sc, IPIC_SIMSR_H, mask);
	mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[ipl];
	ipic_write(sc, IPIC_SIMSR_L, mask);
	mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[ipl];
	ipic_write(sc, IPIC_SEMSR, mask);
}


code:
/*	$OpenBSD: obio.c,v 1.6 2014/05/09 18:16:15 miod Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <machine/autoconf.h>

#include <dev/ofw/openfirm.h>

int	obio_match(struct device *, void *, void *);
void	obio_attach(struct device *, struct device *, void *);

struct cfattach obio_ca = {
	sizeof(struct device), obio_match, obio_attach
};

struct cfdriver obio_cd = {
	NULL, "obio", DV_DULL
};

int	obio_print(void *, const char *);

int
obio_match(struct device *parent, void *cfdata, void *aux)
{
	struct mainbus_attach_args *ma = aux;
	char buf[32];

	if (OF_getprop(ma->ma_node, "device_type", buf, sizeof(buf)) <= 0)
		return (0);

	if (strcmp(buf, "soc") == 0)
		return (1);

	return (0);
}

void
obio_attach(struct device *parent, struct device *self, void *aux)
{
	struct mainbus_attach_args *ma = aux;
	struct obio_attach_args oa;
	char name[32];
	int node;

	printf("\n");

	for (node = OF_child(ma->ma_node); node != 0; node = OF_peer(node)) {
		int reg, ivec;

		if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
			continue;

		if (OF_getprop(node, "reg", &reg, sizeof(reg)) <= 0)
			reg = 0;

		if (OF_getprop(node, "interrupts", &ivec, sizeof(ivec)) <= 0)
			ivec = -1;

		bzero(&oa, sizeof oa);
		oa.oa_iot = ma->ma_iot;
		oa.oa_dmat = ma->ma_dmat;
		oa.oa_name = name;
		oa.oa_node = node;
		oa.oa_offset = reg;
		oa.oa_ivec = ivec;
		config_found(self, &oa, obio_print);
	}
}

int
obio_print(void *aux, const char *name)
{
	struct obio_attach_args *oa = aux;

	if (name)
		printf("\"%s\" at %s", oa->oa_name, name);
	if (oa->oa_offset)
		printf(" offset 0x%05lx", oa->oa_offset);
	if (oa->oa_ivec != -1)
		printf(" ivec %d", oa->oa_ivec);

	return (UNCONF);
}


code:
/*	$OpenBSD: pciide_machdep.c,v 1.1 2008/05/10 12:02:20 kettenis Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

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

#include <machine/autoconf.h>

void *
pciide_machdep_compat_intr_establish(struct device *dev,
    struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
{
	return (NULL);
}

void
pciide_machdep_compat_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
{
}


code:
/*	$OpenBSD: sociic.c,v 1.2 2009/09/06 20:09:34 kettenis Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Driver for the I2C interface on the MPC8349E processors.
 */

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

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

#include <dev/ofw/openfirm.h>

#include <dev/i2c/i2cvar.h>

#define I2C_ADR		0x00	/* Address Register */
#define I2C_FDR		0x04	/* Fequency Divider Register */
#define I2C_CR		0x08	/* Control Register */
#define  I2C_CR_MEN		0x80
#define  I2C_CR_MIEN		0x40
#define  I2C_CR_MSTA		0x20
#define  I2C_CR_MTX		0x10
#define  I2C_CR_TXAK		0x08
#define  I2C_CR_RSTA		0x04
#define  I2C_CR_BCST		0x01
#define I2C_SR		0x0c	/* Status Register */
#define  I2C_SR_MCF		0x80
#define  I2C_SR_MAAS		0x40
#define  I2C_SR_MBB		0x20
#define  I2C_SR_MAL		0x10
#define  I2C_SR_BCSTM		0x08
#define  I2C_SR_SRW		0x04
#define  I2C_SR_MIF		0x02
#define  I2C_SR_RXAK		0x01
#define I2C_DR		0x10	/* Data Register */
#define I2C_DFSRR	0x14	/* Digital Filter Sampling Rate Register */

struct sociic_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;

	struct i2c_controller	sc_i2c;
	struct rwlock		sc_lock;
};

int	sociic_match(struct device *, void *, void *);
void	sociic_attach(struct device *, struct device *, void *);

struct cfattach sociic_ca = {
	sizeof(struct sociic_softc), sociic_match, sociic_attach
};

struct cfdriver sociic_cd = {
	NULL, "sociic", DV_DULL
};

void	sociic_write(struct sociic_softc *, bus_addr_t, uint8_t);
uint8_t	sociic_read(struct sociic_softc *, bus_addr_t);
int	sociic_wait(struct sociic_softc *, int);
int	sociic_wait_bus(struct sociic_softc *);
int	sociic_i2c_acquire_bus(void *, int);
void	sociic_i2c_release_bus(void *, int);
int	sociic_i2c_exec(void *, i2c_op_t, i2c_addr_t,
	    const void *, size_t, void *, size_t, int);

int
sociic_match(struct device *parent, void *cfdata, void *aux)
{
	struct obio_attach_args *oa = aux;
	char buf[32];

	if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "fsl-i2c") != 0)
		return (0);

	return (1);
}

void
sociic_attach(struct device *parent, struct device *self, void *aux)
{
	struct sociic_softc *sc = (void *)self;
	struct obio_attach_args *oa = aux;
	struct i2cbus_attach_args iba;

	sc->sc_iot = oa->oa_iot;
	if (bus_space_map(sc->sc_iot, oa->oa_offset, 24, 0, &sc->sc_ioh)) {
		printf(": can't map registers\n");
		return;
	}

	printf("\n");

	rw_init(&sc->sc_lock, "iiclk");
	sc->sc_i2c.ic_cookie = sc;
	sc->sc_i2c.ic_acquire_bus = sociic_i2c_acquire_bus;
	sc->sc_i2c.ic_release_bus = sociic_i2c_release_bus;
	sc->sc_i2c.ic_exec = sociic_i2c_exec;

	bzero(&iba, sizeof iba);
	iba.iba_name = "iic";
	iba.iba_tag = &sc->sc_i2c;
	config_found(&sc->sc_dev, &iba, iicbus_print);
}

void
sociic_write(struct sociic_softc *sc, bus_addr_t addr, uint8_t data)
{
	bus_space_write_1(sc->sc_iot, sc->sc_ioh, addr, data);
}

uint8_t
sociic_read(struct sociic_softc *sc, bus_addr_t addr)
{
	return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, addr));
}

int
sociic_wait(struct sociic_softc *sc, int flags)
{
	uint8_t sr;
	int i;

	for (i = 0; i < 1000; i++) {
		sr = sociic_read(sc, I2C_SR);
		if (sr & I2C_SR_MIF) {
			sociic_write(sc, I2C_SR, 0);

			if (sr & I2C_SR_MAL)
				return (EIO);

			if ((sr & I2C_SR_MCF) == 0)
				return (EIO);

			if ((flags & I2C_F_READ) == 0 && (sr & I2C_SR_RXAK))
				return (EIO);

			return (0);
		}
		delay(100);
	}

	return (ETIMEDOUT);
}

int
sociic_wait_bus(struct sociic_softc *sc)
{
	uint8_t sr;
	int i;

	for (i = 0; i < 1000; i++) {
		sr = sociic_read(sc, I2C_SR);
		if ((sr & I2C_SR_MBB) == 0)
			return (0);
		delay(1000);
	}

	return (ETIMEDOUT);
}

int
sociic_i2c_acquire_bus(void *arg, int flags)
{
	struct sociic_softc *sc = arg;

	if (cold || (flags & I2C_F_POLL))
		return (0);

	return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR));
}

void
sociic_i2c_release_bus(void *arg, int flags)
{
	struct sociic_softc *sc = arg;

	if (cold || (flags & I2C_F_POLL))
		return;

	rw_exit(&sc->sc_lock);
}

int
sociic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
    const void *vcmdbuf, size_t cmdlen, void *vbuf, size_t buflen, int flags)
{
	struct sociic_softc *sc = arg;
	const uint8_t *cmdbuf = vcmdbuf;
	uint8_t *buf = vbuf;
	int err = 0;
	size_t len;
	uint8_t val;

	/* Clear the bus. */
	sociic_write(sc, I2C_SR, 0);
	sociic_write(sc, I2C_CR, I2C_CR_MEN);
	err = sociic_wait_bus(sc);
	if (err)
		return (err);

	if (cmdlen > 0) {
		sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX);
		sociic_write(sc, I2C_DR, addr << 1);
		err = sociic_wait(sc, I2C_F_WRITE);
		if (err)
			goto out;

		len = cmdlen;
		while (len--) {
			sociic_write(sc, I2C_DR, *cmdbuf++);
			err = sociic_wait(sc, I2C_F_WRITE);
			if (err)
				goto out;
		}
	}

	if (I2C_OP_READ_P(op) && buflen > 0) {
		/* RESTART if we did write a command above. */
		val = I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX;
		if (cmdlen > 0)
			val |= I2C_CR_RSTA;
		sociic_write(sc, I2C_CR, val);
		sociic_write(sc, I2C_DR, (addr << 1) | 1);
		err = sociic_wait(sc, I2C_F_WRITE);
		if (err)
			goto out;

		/* NACK if we're only sending one byte. */
		val = I2C_CR_MEN|I2C_CR_MSTA;
		if (buflen == 1)
			val |= I2C_CR_TXAK;
		sociic_write(sc, I2C_CR, val);

		/* Dummy read. */
		sociic_read(sc, I2C_DR);

		len = buflen;
		while (len--) {
			err = sociic_wait(sc, I2C_F_READ);
			if (err)
				goto out;

			/* NACK on last byte. */
			if (len == 1)
				sociic_write(sc, I2C_CR,
				    I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_TXAK);
			/* STOP after last byte. */
			if (len == 0)
				sociic_write(sc, I2C_CR,
				    I2C_CR_MEN|I2C_CR_TXAK);
			*buf++ = sociic_read(sc, I2C_DR);
		}
	}

	if (I2C_OP_WRITE_P(op) && cmdlen == 0 && buflen > 0) {
		/* START if we didn't write a command. */
		sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX);
		sociic_write(sc, I2C_DR, addr << 1);
		err = sociic_wait(sc, I2C_F_WRITE);
		if (err)
			goto out;
	}

	if (I2C_OP_WRITE_P(op) && buflen > 0) {
		len = buflen;
		while (len--) {
			sociic_write(sc, I2C_DR, *buf++);
			err = sociic_wait(sc, I2C_F_WRITE);
			if (err)
				goto out;
		}
	}

out:
	/* STOP if we're still holding the bus. */
	sociic_write(sc, I2C_CR, I2C_CR_MEN);
	return (err);
}


code:
/*	$OpenBSD: socpcic.c,v 1.9 2010/12/04 17:06:32 miod Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

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

#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>

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

struct socpcic_softc {
	struct device	sc_dev;

	int		sc_node;

	bus_space_tag_t	sc_iot;
	bus_space_handle_t sc_cfg_ioh;
	struct ppc_bus_space sc_mem_bus_space;
	struct ppc_bus_space sc_io_bus_space;
	bus_dma_tag_t	sc_dmat;
	struct ppc_pci_chipset sc_pc;

	/* Interrupt mapping. */
	int		sc_map_mask[4];
	int		*sc_map;
	int		sc_map_len;

	/* Addres space. */
	uint32_t	*sc_ranges;
	int		sc_ranges_len;
};

int	socpcic_mainbus_match(struct device *, void *, void *);
void	socpcic_mainbus_attach(struct device *, struct device *, void *);
int	socpcic_obio_match(struct device *, void *, void *);
void	socpcic_obio_attach(struct device *, struct device *, void *);

struct cfattach socpcic_mainbus_ca = {
	sizeof(struct socpcic_softc),
	socpcic_mainbus_match, socpcic_mainbus_attach
};

struct cfattach socpcic_obio_ca = {
	sizeof(struct socpcic_softc),
	socpcic_obio_match, socpcic_obio_attach
};

struct cfdriver socpcic_cd = {
	NULL, "socpcic", DV_DULL
};

void	socpcic_attach(struct socpcic_softc *sc);
void	socpcic_attach_hook(struct device *, struct device *,
	    struct pcibus_attach_args *);
int	socpcic_bus_maxdevs(void *, int);
pcitag_t socpcic_make_tag(void *, int, int, int);
void	socpcic_decompose_tag(void *, pcitag_t, int *, int *, int *);
int	socpcic_conf_size(void *, pcitag_t);
pcireg_t socpcic_conf_read(void *, pcitag_t, int);
void	socpcic_conf_write(void *, pcitag_t, int, pcireg_t);
int	 socpcic_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *);
const char *socpcic_intr_string(void *, pci_intr_handle_t);
int	 socpcic_intr_line(void *, pci_intr_handle_t);
void	*socpcic_intr_establish(void *, pci_intr_handle_t, int,
	     int (*)(void *), void *, const char *);
void	 socpcic_intr_disestablish(void *, void *);
int	 socpcic_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *);

int	 socpcic_print(void *, const char *);

int
socpcic_mainbus_match(struct device *parent, void *cfdata, void *aux)
{
	struct mainbus_attach_args *ma = aux;
	char buf[32];

	if (OF_getprop(ma->ma_node, "device_type", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "pci") != 0)
		return (0);

	if (OF_getprop(ma->ma_node, "compatible", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "fsl,mpc8349-pci") != 0)
		return (0);

	return (1);
}

void
socpcic_mainbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct socpcic_softc *sc = (void *)self;
	struct mainbus_attach_args *ma = aux;
	int reg[4];

	if (OF_getprop(ma->ma_node, "reg", &reg, sizeof(reg)) < sizeof(reg)) {
		printf(": missing registers\n");
		return;
	}

	sc->sc_iot = ma->ma_iot;
	if (bus_space_map(sc->sc_iot, reg[2], 16, 0, &sc->sc_cfg_ioh)) {
		printf(": can't map configuration registers\n");
		return;
	}

	sc->sc_node = ma->ma_node;
	sc->sc_dmat = ma->ma_dmat;
	socpcic_attach(sc);
}

int
socpcic_obio_match(struct device *parent, void *cfdata, void *aux)
{
	struct obio_attach_args *oa = aux;
	char buf[32];

	if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "pci") != 0)
		return (0);

	if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "83xx") != 0)
		return (0);

	return (1);
}

void
socpcic_obio_attach(struct device *parent, struct device *self, void *aux)
{
	struct socpcic_softc *sc = (void *)self;
	struct obio_attach_args *oa = aux;

	if (oa->oa_offset == 0x8500)
		oa->oa_offset = 0x8300;

	sc->sc_iot = oa->oa_iot;
	if (bus_space_map(sc->sc_iot, oa->oa_offset, 16, 0, &sc->sc_cfg_ioh)) {
		printf(": can't map configuration registers\n");
		return;
	}

	sc->sc_node = oa->oa_node;
	sc->sc_dmat = oa->oa_dmat;
	socpcic_attach(sc);
}

void
socpcic_attach(struct socpcic_softc *sc)
{
	struct pcibus_attach_args pba;
	struct extent *io_ex;
	struct extent *mem_ex;
	bus_addr_t io_base, mem_base;
	bus_size_t io_size, mem_size;
	uint32_t *ranges;
	int len;

	if (OF_getprop(sc->sc_node, "interrupt-map-mask", sc->sc_map_mask,
	    sizeof(sc->sc_map_mask)) != sizeof(sc->sc_map_mask)) {
		printf(": missing interrupt-map-mask\n");
		return;
	}

	sc->sc_map_len = OF_getproplen(sc->sc_node, "interrupt-map");
	if (sc->sc_map_len > 0) {
		sc->sc_map = malloc(sc->sc_map_len, M_DEVBUF, M_NOWAIT);
		if (sc->sc_map == NULL)
			panic("out of memory");

		len = OF_getprop(sc->sc_node, "interrupt-map",
		    sc->sc_map, sc->sc_map_len);
		KASSERT(len == sc->sc_map_len);
	}

	sc->sc_ranges_len = OF_getproplen(sc->sc_node, "ranges");
	if (sc->sc_ranges_len <= 0) {
		printf(": missing ranges\n");
		return;
	}

	sc->sc_ranges = malloc(sc->sc_ranges_len, M_DEVBUF, M_NOWAIT);
	if (ranges == NULL)
		panic("out of memory");

	len = OF_getprop(sc->sc_node, "ranges", sc->sc_ranges,
	    sc->sc_ranges_len);
	KASSERT(len == sc->sc_ranges_len);

	ranges = sc->sc_ranges;
	while (len >= 6 * sizeof(uint32_t)) {
		switch (ranges[0] & OFW_PCI_PHYS_HI_SPACEMASK) {
		case OFW_PCI_PHYS_HI_SPACE_IO:
			KASSERT(ranges[1] == 0);
			KASSERT(ranges[4] == 0);
			sc->sc_io_bus_space.bus_base = ranges[3];
			sc->sc_io_bus_space.bus_size = ranges[5];
			sc->sc_io_bus_space.bus_io = 1;
			io_base = ranges[2];
			io_size = ranges[5];
			break;
		case  OFW_PCI_PHYS_HI_SPACE_MEM32:
			KASSERT(ranges[1] == 0);
			KASSERT(ranges[4] == 0);
			sc->sc_mem_bus_space.bus_base = ranges[3];
			sc->sc_mem_bus_space.bus_size = ranges[5];
			sc->sc_mem_bus_space.bus_io = 0;
			mem_base = ranges[2];
			mem_size = ranges[5];
			break;
		}
		len -= 6 * sizeof(uint32_t);
		ranges += 6;
	}

	sc->sc_pc.pc_conf_v = sc;
	sc->sc_pc.pc_attach_hook = socpcic_attach_hook;
	sc->sc_pc.pc_bus_maxdevs = socpcic_bus_maxdevs;
	sc->sc_pc.pc_make_tag = socpcic_make_tag;
	sc->sc_pc.pc_decompose_tag = socpcic_decompose_tag;
	sc->sc_pc.pc_conf_size = socpcic_conf_size;
	sc->sc_pc.pc_conf_read = socpcic_conf_read;
	sc->sc_pc.pc_conf_write = socpcic_conf_write;

	sc->sc_pc.pc_intr_v = sc;
	sc->sc_pc.pc_intr_map = socpcic_intr_map;
	sc->sc_pc.pc_intr_string = socpcic_intr_string;
	sc->sc_pc.pc_intr_line = socpcic_intr_line;
	sc->sc_pc.pc_intr_establish = socpcic_intr_establish;
	sc->sc_pc.pc_intr_disestablish = socpcic_intr_disestablish;
	sc->sc_pc.pc_ether_hw_addr = socpcic_ether_hw_addr;

	io_ex = extent_create("pciio", 0, 0xffffffff, M_DEVBUF, NULL, 0,
	    EX_NOWAIT | EX_FILLED);
	if (io_ex != NULL && io_size)
		extent_free(io_ex, io_base, io_size, EX_NOWAIT);
	mem_ex = extent_create("pcimem", 0, 0xffffffff, M_DEVBUF, NULL, 0,
	    EX_NOWAIT | EX_FILLED);
	if (mem_ex != NULL)
		extent_free(mem_ex, mem_base, mem_size, EX_NOWAIT);

	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	pba.pba_iot = &sc->sc_io_bus_space;
	pba.pba_memt = &sc->sc_mem_bus_space;
	pba.pba_dmat = sc->sc_dmat;
	pba.pba_ioex = io_ex;
	pba.pba_memex = mem_ex;
	pba.pba_pc = &sc->sc_pc;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = 0;

	printf("\n");

	config_found((struct device *)sc, &pba, socpcic_print);
}

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

int
socpcic_bus_maxdevs(void *cpv, int bus)
{
	return (32);
}

pcitag_t
socpcic_make_tag(void *cpv, int bus, int dev, int fun)
{
	return ((bus << 16) | (dev << 11) | (fun << 8));
}

void
socpcic_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *funp)
{
	if (busp)
		*busp = (tag >> 16) & 0xff;
	if (devp)
		*devp = (tag >> 11) & 0x1f;
	if (funp)
		*funp = (tag >> 8) & 0x7;
}

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

pcireg_t
socpcic_conf_read(void *cpv, pcitag_t tag, int offset)
{
	struct socpcic_softc *sc = cpv;
	int bus, dev, fun;
	pcireg_t addr, data;

	socpcic_decompose_tag(sc, tag, &bus, &dev, &fun);
	if (bus == 0) {
		if (dev > 0 && dev < 11)
			return (0xffffffff);
		if (dev == 31)
			tag = (10 << 11) | (fun << 8);
	}

	addr = 0x80000000 | tag | offset;
	bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, 0, addr);
	bus_space_read_4(sc->sc_iot, sc->sc_cfg_ioh, 0);
	data = bus_space_read_4(sc->sc_iot, sc->sc_cfg_ioh, 4);
	bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, 0, 0);
	bus_space_read_4(sc->sc_iot, sc->sc_cfg_ioh, 0);

	return (data);
}

void
socpcic_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
{
	struct socpcic_softc *sc = cpv;
	int bus, dev, fun;
	pcireg_t addr;

	socpcic_decompose_tag(sc, tag, &bus, &dev, &fun);
	if (bus == 0) {
		if (dev > 0 && dev < 11)
			return;
		if (dev == 31)
			tag = (10 << 11) | (fun << 8);
	}

	addr = 0x80000000 | tag | offset;
	bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, 0, addr);
	bus_space_read_4(sc->sc_iot, sc->sc_cfg_ioh, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, 4, data);
	bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, 0, 0);
	bus_space_read_4(sc->sc_iot, sc->sc_cfg_ioh, 0);
}

int
socpcic_intr_map(void *cpv, pcitag_t tag, int pin, int line,
    pci_intr_handle_t *ihp)
{
	struct socpcic_softc *sc = cpv;
	int bus, dev, func;
	int reg[4];
	int *map;
	int len;

	pci_decompose_tag(&sc->sc_pc, tag, &bus, &dev, &func);

	reg[0] = (dev << 11) | (func << 8);
	reg[1] = reg[2] = 0;
	reg[3] = pin;

	map = sc->sc_map;
	len = sc->sc_map_len;
	while (len >= 7 * sizeof(int)) {
		if ((reg[0] & sc->sc_map_mask[0]) == map[0] &&
		    (reg[1] & sc->sc_map_mask[1]) == map[1] &&
		    (reg[2] & sc->sc_map_mask[2]) == map[2] &&
		    (reg[3] & sc->sc_map_mask[3]) == map[3]) {
			*ihp = map[5];
			return (0);
		}
		len -= 7 * sizeof(int);
		map += 7;
	}

	return (1);
}

const char *
socpcic_intr_string(void *cpv, pci_intr_handle_t ih)
{
	static char str[16];

	snprintf(str, sizeof str, "ivec %ld", ih);
	return (str);
}

int
socpcic_intr_line(void *cpv, pci_intr_handle_t ih)
{
	return (ih);
}

void *
socpcic_intr_establish(void *cpv, pci_intr_handle_t ih, int level,
    int (*func)(void *), void *arg, const char *name)
{
	return (intr_establish(ih, IST_LEVEL, level, func, arg, name));
}

void
socpcic_intr_disestablish(void *lcv, void *cookie)
{
}

int
socpcic_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr)
{
	oaddr[0] = oaddr[1] = oaddr[2] = 0xff;
	oaddr[3] = oaddr[4] = oaddr[5] = 0xff;

	return (0);
}

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

	if (pnp)
		printf("%s at %s", pba->pba_busname, pnp);
	printf(" bus %d", pba->pba_bus);
	return (UNCONF);
}


code:
/*	$OpenBSD: wdc_mainbus.c,v 1.2 2011/05/09 22:33:54 matthew Exp $	*/

/*
 * Copyright (c) 2009 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Driver for Compact Flash interface on the local bus of a PowerQUICC
 * MPC8343E processor as found on the RouterBOARD 600.
 */

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

#include <machine/autoconf.h>

#include <dev/ofw/openfirm.h>

#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>

struct wdc_mainbus_softc {
	struct wdc_softc	sc_wdcdev;
	struct channel_softc	*sc_chanptr;
	struct channel_softc	sc_channel;

	void	*sc_ih;
};

int	wdc_mainbus_match(struct device *, void *, void *);
void	wdc_mainbus_attach(struct device *, struct device *, void *);

struct cfattach wdc_mainbus_ca = {
	sizeof(struct wdc_mainbus_softc), wdc_mainbus_match, wdc_mainbus_attach
};

/*
 * The CF slots on the RouterBOARD 600 are wired up in a completely
 * retarded way.  Instead of using the obvious address lines it uses
 * LAD[11:15], which means we need to waste more than 0.5 MB of
 * address space to map 10 8-bit registers.
 */
#define	WDC_MAINBUS_REG_NPORTS		WDC_NREG
#define	WDC_MAINBUS_REG_SIZE		(WDC_MAINBUS_REG_NPORTS << 16)
#define WDC_MAINBUS_REG_OFFSET		(8 << 17)
#define	WDC_MAINBUS_AUXREG_NPORTS	2
#define	WDC_MAINBUS_AUXREG_SIZE		(WDC_MAINBUS_AUXREG_NPORTS << 16)
#define	WDC_MAINBUS_AUXREG_OFFSET	(6 << 16)

u_int8_t wdc_mainbus_read_reg(struct channel_softc *chp,  enum wdc_regs reg);
void wdc_mainbus_write_reg(struct channel_softc *chp,  enum wdc_regs reg,
    u_int8_t val);

struct channel_softc_vtbl wdc_mainbus_vtbl = {
	wdc_mainbus_read_reg,
	wdc_mainbus_write_reg,
	wdc_default_lba48_write_reg,
	wdc_default_read_raw_multi_2,
	wdc_default_write_raw_multi_2,
	wdc_default_read_raw_multi_4,
	wdc_default_write_raw_multi_4
};

int
wdc_mainbus_match(struct device *parent, void *cfdata, void *aux)
{
	struct mainbus_attach_args *ma = aux;
	char buf[32];

	if (OF_getprop(ma->ma_node, "device_type", buf, sizeof(buf)) <= 0 ||
	    strcmp(buf, "rb,cf") != 0)
		return (0);

	return (1);
}

void
wdc_mainbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct wdc_mainbus_softc *sc = (void *)self;
	struct mainbus_attach_args *ma = aux;
	struct channel_softc *chp = &sc->sc_channel;
	int reg[2];
	int ivec;

	if (OF_getprop(ma->ma_node, "reg", &reg, sizeof(reg)) < sizeof(reg)) {
		printf(": missing registers\n");
		return;
	}

	if (OF_getprop(ma->ma_node, "interrupts", &ivec, sizeof(ivec)) <= 0) {
		printf(": missing interrupts\n");
		return;
	}

	chp->cmd_iot = chp->ctl_iot = ma->ma_iot;
	chp->_vtbl = &wdc_mainbus_vtbl;

	if (bus_space_map(chp->cmd_iot, reg[0] + WDC_MAINBUS_REG_OFFSET,
	    WDC_MAINBUS_REG_SIZE, 0, &chp->cmd_ioh)) {
		printf(": can't map registers\n");
		return;
	}
	if (bus_space_map(chp->ctl_iot, reg[0] + WDC_MAINBUS_AUXREG_OFFSET,
	    WDC_MAINBUS_AUXREG_SIZE, 0, &chp->ctl_ioh)) {
		printf(": can't map registers\n");
		return;
	}

	sc->sc_ih = intr_establish(ivec, IST_LEVEL, IPL_BIO, wdcintr,
	    chp, self->dv_xname);

	sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_PREATA;
	sc->sc_wdcdev.PIO_cap = 0;
	sc->sc_chanptr = chp;
	sc->sc_wdcdev.channels = &sc->sc_chanptr;
	sc->sc_wdcdev.nchannels = 1;
	chp->channel = 0;
	chp->wdc = &sc->sc_wdcdev;

	chp->ch_queue = wdc_alloc_queue();
	if (chp->ch_queue == NULL) {
		printf("%s: cannot allocate channel queue\n",
		    self->dv_xname);
		/* XXX disestablish interrupt */
		return;
	}

	printf("\n");

	wdcattach(chp);
	wdc_print_current_modes(chp);
}

u_int8_t
wdc_mainbus_read_reg(struct channel_softc *chp, enum wdc_regs reg)
{
	uint8_t val;

	if (reg & _WDC_AUX) {
		val = bus_space_read_1(chp->ctl_iot, chp->ctl_ioh,
		    (reg & _WDC_REGMASK) << 16);
		if (val == 0xf9 && reg == wdr_altsts)
			val = 0x7f;
	} else {
		val = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
		    (reg & _WDC_REGMASK) << 16);
		if (val == 0xf9 && reg == wdr_status)
			val = 0x7f;
	}
	return val;
}

void
wdc_mainbus_write_reg(struct channel_softc *chp, enum wdc_regs reg,
    u_int8_t val)
{
	if (reg & _WDC_AUX)
		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh,
		    (reg & _WDC_REGMASK) << 16, val);
	else
		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
		    (reg & _WDC_REGMASK) << 16, val);
}