FreeBSD/mips booting on Sibyte 1250
Neelkanth Natu
neelnatu at yahoo.com
Wed Jun 17 04:52:29 UTC 2009
Hi Warner,
I have attached the diffs against -current at revision 194280.
There are some changes in the diff that are unrelated to the sibyte
work and probably should be committed separately.
I can provide more information about changes to specific files if necessary.
best
Neel
--- On Fri, 6/12/09, M. Warner Losh <imp at bsdimp.com> wrote:
> From: M. Warner Losh <imp at bsdimp.com>
> Subject: Re: FreeBSD/mips booting on Sibyte 1250
> To: neelnatu at yahoo.com
> Cc: freebsd-mips at freebsd.org
> Date: Friday, June 12, 2009, 8:33 PM
> In message: <856232.92278.qm at web34401.mail.mud.yahoo.com>
> Neelkanth Natu
> <neelnatu at yahoo.com>
> writes:
> : I don't want to keep holding diffs against -current for
> this, so I was
> : hoping to get this checked in. How do I go about doing
> that?
>
> diffs would be a good start :)
>
> Usually, we pass them through /projects/mips/* to make sure
> that we
> have a good integration branch before we collapse/merge the
> changes
> into -current.
>
> Warner
>
-------------- next part --------------
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/conf/files.mips ./sys/conf/files.mips
--- /u/neelnatu/p4/freebsd_current/src/sys/conf/files.mips 2009-06-15 23:27:26.208231000 -0700
+++ ./sys/conf/files.mips 2009-06-16 17:31:21.727409000 -0700
@@ -94,5 +94,6 @@
dev/cfe/cfe_api.c optional cfe
dev/cfe/cfe_console.c optional cfe_console
+dev/cfe/cfe_env.c optional cfe_env
#dev/cfe/cfe_resource.c optional cfe # not yet needed
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/conf/options.mips ./sys/conf/options.mips
--- /u/neelnatu/p4/freebsd_current/src/sys/conf/options.mips 2009-06-15 23:27:26.286232000 -0700
+++ ./sys/conf/options.mips 2009-06-16 17:31:21.732415000 -0700
@@ -33,6 +33,7 @@
CPU_MIPS64 opt_global.h
CPU_NOFPU opt_global.h
CPU_SENTRY5 opt_global.h
+CPU_SB1 opt_global.h
ISA_MIPS1 opt_cputype.h
ISA_MIPS3 opt_cputype.h
@@ -44,6 +45,8 @@
YAMON opt_global.h
CFE opt_global.h
CFE_CONSOLE opt_global.h
+CFE_ENV opt_global.h
+CFE_ENV_SIZE opt_global.h
KERNPHYSADDR opt_global.h
KERNVIRTADDR opt_global.h
@@ -55,3 +58,8 @@
TICK_USE_YAMON_FREQ opt_global.h
TICK_USE_MALTA_RTC opt_global.h
+
+PCI_IOSPACE_SIZE opt_global.h
+PCI_IOSPACE_ADDR opt_global.h
+
+MAXMEM opt_global.h
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/dev/cfe/cfe_api.c ./sys/dev/cfe/cfe_api.c
--- /u/neelnatu/p4/freebsd_current/src/sys/dev/cfe/cfe_api.c 2009-06-15 23:27:31.799448000 -0700
+++ ./sys/dev/cfe/cfe_api.c 2009-06-16 17:31:21.738412000 -0700
@@ -160,7 +160,7 @@
{
cfe_xiocb_t xiocb;
- xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
+ xiocb.xiocb_fcode = CFE_CMD_ENV_ENUM;
xiocb.xiocb_status = 0;
xiocb.xiocb_handle = 0;
xiocb.xiocb_flags = 0;
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/dev/cfe/cfe_console.c ./sys/dev/cfe/cfe_console.c
--- /u/neelnatu/p4/freebsd_current/src/sys/dev/cfe/cfe_console.c 2009-06-15 23:27:31.825449000 -0700
+++ ./sys/dev/cfe/cfe_console.c 2009-06-16 17:31:21.747410000 -0700
@@ -84,14 +84,12 @@
static void
cn_drvinit(void *unused)
{
- char output[32];
struct tty *tp;
if (cfe_consdev.cn_pri != CN_DEAD &&
cfe_consdev.cn_name[0] != '\0') {
tp = tty_alloc(&cfe_ttydevsw, NULL);
- tty_makedev(tp, NULL, "%s", output);
- tty_makealias(tp, "cfecons");
+ tty_makedev(tp, NULL, "cfecons");
}
}
@@ -117,15 +115,21 @@
static void
cfe_tty_outwakeup(struct tty *tp)
{
- int len;
+ int len, written, rc;
u_char buf[CFEBURSTLEN];
for (;;) {
len = ttydisc_getc(tp, buf, sizeof buf);
if (len == 0)
break;
- while (cfe_write(conhandle, buf, len) == 0)
- continue;
+
+ written = 0;
+ while (written < len) {
+ rc = cfe_write(conhandle, &buf[written], len - written);
+ if (rc < 0)
+ break;
+ written += rc;
+ }
}
}
@@ -184,13 +188,9 @@
static int
cfe_cngetc(struct consdev *cp)
{
- int result;
unsigned char ch;
- while ((result = cfe_read(conhandle, &ch, 1)) == 0)
- continue;
-
- if (result > 0) {
+ if (cfe_read(conhandle, &ch, 1) == 1) {
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
int kdb_brk;
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/dev/cfe/cfe_env.c ./sys/dev/cfe/cfe_env.c
--- /u/neelnatu/p4/freebsd_current/src/sys/dev/cfe/cfe_env.c 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/dev/cfe/cfe_env.c 2009-05-12 01:12:44.728865000 -0700
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <dev/cfe/cfe_api.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifndef CFE_ENV_SIZE
+#define CFE_ENV_SIZE PAGE_SIZE /* default is one page */
+#endif
+
+extern void cfe_env_init(void);
+
+static char cfe_env_buf[CFE_ENV_SIZE];
+
+void
+cfe_env_init(void)
+{
+ int idx, len;
+ char name[64], val[128], *cp, *cplim;
+
+ cp = cfe_env_buf;
+ cplim = cp + CFE_ENV_SIZE;
+
+ idx = 0;
+ while (1) {
+ if (cfe_enumenv(idx, name, sizeof(name), val, sizeof(val)) != 0)
+ break;
+
+ if (bootverbose)
+ printf("Importing CFE env: \"%s=%s\"\n", name, val);
+
+ /*
+ * name=val\0\0
+ */
+ len = strlen(name) + 1 + strlen(val) + 1 + 1;
+ if (cplim - cp < len)
+ printf("No space to store CFE env: \"%s=%s\"\n",
+ name, val);
+ else
+ cp += sprintf(cp, "%s=%s", name, val) + 1;
+ ++idx;
+ }
+ *cp++ = '\0';
+
+ kern_envp = cfe_env_buf;
+}
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/conf/SWARM ./sys/mips/conf/SWARM
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/conf/SWARM 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/conf/SWARM 2009-06-13 12:17:44.499588000 -0700
@@ -0,0 +1,82 @@
+#
+# $Id: //depot/user/neelnatu/freebsd_sibyte/src/sys/mips/conf/SWARM#7 $
+#
+
+ident SWARM
+options CPU_NOFPU
+options CPU_SB1
+
+files "../sibyte/files.sibyte"
+hints "SWARM.hints"
+
+options PCI_IOSPACE_ADDR=0xFC000000
+options PCI_IOSPACE_SIZE=0x02000000
+
+#
+# 32-bit kernel cannot deal with physical memory beyond 4GB
+#
+options MAXMEM=4096*1024
+
+options CFE
+options CFE_CONSOLE
+options CFE_ENV
+options ALT_BREAK_TO_DEBUGGER
+
+# cfe loader expects kernel at 0x80001000 for mips32 w/o backwards
+# offsets in the linked elf image (see ldscript hack)
+# XXX can we conditionalize the linker stuff on options CFE?
+options KERNVIRTADDR=0x80001000
+
+makeoptions LDSCRIPT_NAME= ldscript.mips.cfe
+
+#cpu CPU_MIPS64
+#options ISA_MIPS64
+#makeoptions ARCH_FLAGS="-march=mips64 -mgp64 -mabi=o64"
+cpu CPU_MIPS32
+options ISA_MIPS32
+makeoptions ARCH_FLAGS="-march=mips32"
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+makeoptions MODULES_OVERRIDE=""
+
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options NFSCLIENT #Network Filesystem Client
+options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+options PSEUDOFS #Pseudo-filesystem framework
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+
+# Debugging for use in -current
+options INVARIANTS
+options INVARIANT_SUPPORT
+options WITNESS
+
+options MD_ROOT
+options MD_ROOT_SIZE=4096
+options FFS #Fast filesystem
+
+device pci
+device miibus
+device bge
+device loop
+device ether
+device md
+
+options USB_DEBUG
+device usb
+device ohci
+device uhci
+device ehci
+
+device umass
+
+device scbus
+device da
+
+device ata
+device atadisk
+device atapicd
+options ATA_STATIC_ID
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/conf/SWARM.hints ./sys/mips/conf/SWARM.hints
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/conf/SWARM.hints 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/conf/SWARM.hints 2009-05-30 19:35:45.581258000 -0700
@@ -0,0 +1,17 @@
+# $FreeBSD$
+hint.zbbus.0.at="nexus0"
+hint.zbpci.0.at="zbbus0"
+hint.scd.0.at="zbbus0"
+
+#
+# SWARM IDE interface is on the generic bus at chip select 4.
+# The CS4 region is 64KB in size and starts at 0x100B0000.
+# The IDE interrupt is wired to GPIO4 (intsrc 36 to the interrupt mapper)
+#
+hint.ata.0.at="zbbus0"
+hint.ata.0.maddr=0x100B0000
+hint.ata.0.msize=0x10000
+hint.ata.0.irq=36
+#hint.ata.0.disabled=0
+#hint.ata.0.regoffset=0x1F0
+#hint.ata.0.regshift=5
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/cpu.h ./sys/mips/include/cpu.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/cpu.h 2009-06-15 23:27:51.494233000 -0700
+++ ./sys/mips/include/cpu.h 2009-06-16 17:31:21.752415000 -0700
@@ -154,7 +154,11 @@
* The bits in the CONFIG register
*/
#define CFG_K0_UNCACHED 2
+#if defined(CPU_SB1)
+#define CFG_K0_COHERENT 5 /* cacheable coherent */
+#else
#define CFG_K0_CACHED 3
+#endif
/*
* The bits in the context register.
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/cpuregs.h ./sys/mips/include/cpuregs.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/cpuregs.h 2009-06-15 23:27:51.500230000 -0700
+++ ./sys/mips/include/cpuregs.h 2009-06-16 17:31:21.758417000 -0700
@@ -103,6 +103,8 @@
/* CPU dependent mtc0 hazard hook */
#ifdef TARGET_OCTEON
#define COP0_SYNC nop; nop; nop; nop; nop;
+#elif defined(CPU_SB1)
+#define COP0_SYNC ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop
#else
#define COP0_SYNC /* nothing */
#endif
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/intr.h ./sys/mips/include/intr.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/intr.h 2009-06-15 23:27:51.535235000 -0700
+++ ./sys/mips/include/intr.h 2009-06-16 17:31:21.766414000 -0700
@@ -75,8 +75,8 @@
typedef void (*mask_fn)(void *);
-void mips_mask_irq(void);
-void mips_unmask_irq(void);
+void mips_mask_irq(void *);
+void mips_unmask_irq(void *);
struct trapframe;
void mips_set_intr(int pri, uint32_t mask,
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/intr_machdep.h ./sys/mips/include/intr_machdep.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/intr_machdep.h 2009-06-15 23:27:51.537233000 -0700
+++ ./sys/mips/include/intr_machdep.h 2009-06-16 17:31:21.774409000 -0700
@@ -34,6 +34,27 @@
struct trapframe;
+/*
+ * An interrupt source is defined by its interrupt number and handlers to
+ * mask and unmask the sources that trigger it.
+ *
+ * Once an interrupt handler is established for a particular interrupt number
+ * we always keep it enabled from the mips core point of view. However we may
+ * choose to mask the interrupt source feeding into it until the ithread has
+ * had a chance to run.
+ *
+ * XXX how does this work with platforms that have no interrupt mapper feeding
+ * interrupts to the cpu core?
+ */
+struct intsrc {
+ int intrnum;
+ void (*mask_func)(struct intsrc *isrc);
+ void (*unmask_func)(struct intsrc *isrc);
+};
+
+int cpu_register_hard_intsrc(struct intsrc *isrc);
+int cpu_register_soft_intsrc(struct intsrc *isrc);
+
void cpu_establish_hardintr(const char *, int (*)(void*), void (*)(void*),
void *, int, int, void **);
void cpu_establish_softintr(const char *, int (*)(void*), void (*)(void*),
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/md_var.h ./sys/mips/include/md_var.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/md_var.h 2009-06-15 23:27:51.545233000 -0700
+++ ./sys/mips/include/md_var.h 2009-06-16 17:31:21.793420000 -0700
@@ -39,7 +39,7 @@
/*
* Miscellaneous machine-dependent declarations.
*/
-extern int Maxmem;
+extern long Maxmem;
extern char sigcode[];
extern int szsigcode, szosigcode;
@@ -52,6 +52,7 @@
u_long kvtop(void *addr);
int is_physical_memory(vm_offset_t addr);
int is_cacheable_mem(vm_offset_t pa);
+int is_coherent_mem(vm_offset_t pa);
#define MIPS_DEBUG 0
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/pltfm.h ./sys/mips/include/pltfm.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/pltfm.h 2009-06-15 23:27:51.569235000 -0700
+++ ./sys/mips/include/pltfm.h 2009-06-16 17:31:21.801415000 -0700
@@ -6,6 +6,12 @@
#ifndef _MACHINE_PLTFM_H_
#define _MACHINE_PLTFM_H_
+#ifdef CPU_SB1
+/*
+ * XXX Make sure that these macros are not defined for the SB-1 cpu
+ * since they don't make any sense for it.
+ */
+#else
/*
* This files contains platform-specific definitions.
*/
@@ -25,5 +31,6 @@
#endif
#define ADDR_NS16550_UART1 0x1ef14000 /* UART */
#define VADDR_NS16550_UART1 0xbef14000 /* UART */
+#endif
#endif /* !_MACHINE_PLTFM_H_ */
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/include/pte.h ./sys/mips/include/pte.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/include/pte.h 2009-06-15 23:27:51.594236000 -0700
+++ ./sys/mips/include/pte.h 2009-06-16 17:31:21.808412000 -0700
@@ -105,7 +105,11 @@
#define PTE_ODDPG 0x00001000
/*#define PG_ATTR 0x0000003f Not Used */
#define PTE_UNCACHED 0x00000010
+#ifdef CPU_SB1
+#define PTE_CACHE 0x00000028 /* cacheable coherent */
+#else
#define PTE_CACHE 0x00000018
+#endif
/*#define PG_CACHEMODE 0x00000038 Not Used*/
#define PTE_ROPAGE (PTE_V | PTE_RO | PTE_CACHE) /* Write protected */
#define PTE_RWPAGE (PTE_V | PTE_M | PTE_CACHE) /* Not wr-prot not clean */
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/autoconf.c ./sys/mips/mips/autoconf.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/autoconf.c 2009-06-15 23:27:51.705239000 -0700
+++ ./sys/mips/mips/autoconf.c 2009-06-16 17:31:21.813412000 -0700
@@ -93,6 +93,17 @@
configure(dummy)
void *dummy;
{
+ register_t sr;
+
+ /*
+ * Enable interrupts on the processor. The interrupts are still
+ * disabled by the interrupt mask bits until interrupt handlers
+ * are registered.
+ */
+ sr = mips_rd_status();
+ sr &= ~MIPS_INT_MASK;
+ sr |= MIPS_SR_INT_IE;
+ mips_wr_status(sr);
/* initialize new bus architecture */
root_bus_configure();
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/busdma_machdep.c ./sys/mips/mips/busdma_machdep.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/busdma_machdep.c 2009-06-15 23:27:51.707240000 -0700
+++ ./sys/mips/mips/busdma_machdep.c 2009-06-16 17:31:21.818418000 -0700
@@ -88,6 +88,7 @@
#include <machine/bus.h>
#include <machine/cache.h>
#include <machine/cpufunc.h>
+#include <machine/md_var.h>
struct bus_dma_tag {
bus_dma_tag_t parent;
@@ -270,8 +271,7 @@
newtag->map_count = 0;
newtag->_wbase = 0;
newtag->_physbase = 0;
- /* XXXMIPS: Should we limit window size to amount of physical memory */
- newtag->_wsize = MIPS_KSEG1_START - MIPS_KSEG0_START;
+ newtag->_wsize = ptoa(Maxmem);
if (lockfunc != NULL) {
newtag->lockfunc = lockfunc;
newtag->lockfuncarg = lockfuncarg;
@@ -397,6 +397,7 @@
bus_dmamap_t *mapp)
{
bus_dmamap_t newmap = NULL;
+ void *tmpaddr;
int mflags;
@@ -417,7 +418,9 @@
*mapp = newmap;
newmap->dmat = dmat;
- if (dmat->maxsize <= PAGE_SIZE) {
+ if (dmat->maxsize <= PAGE_SIZE &&
+ dmat->alignment < dmat->maxsize &&
+ dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) {
*vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags);
} else {
/*
@@ -450,19 +453,20 @@
}
*mapp = NULL;
return (ENOMEM);
+ } else if ((uintptr_t)*vaddr & (dmat->alignment - 1)) {
+ printf("bus_dmamem_alloc failed to align memory properly.\n");
}
- if (flags & BUS_DMA_COHERENT) {
- void *tmpaddr = (void *)*vaddr;
- if (tmpaddr) {
- tmpaddr = (void *)MIPS_PHYS_TO_KSEG1(vtophys(tmpaddr));
- newmap->origbuffer = *vaddr;
- newmap->allocbuffer = tmpaddr;
- mips_dcache_wbinv_range((vm_offset_t)*vaddr,
- dmat->maxsize);
- *vaddr = tmpaddr;
- } else
- newmap->origbuffer = newmap->allocbuffer = NULL;
+ tmpaddr = (void *)*vaddr;
+ if ((flags & BUS_DMA_COHERENT) && !is_coherent_mem(vtophys(tmpaddr))) {
+ KASSERT(vtophys(tmpaddr) < MIPS_KSEG0_LARGEST_PHYS,
+ ("bus_dmamem_alloc: physaddr 0x%0x cannot "
+ "be mapped in KSEG1", vtophys(tmpaddr)));
+ tmpaddr = (void *)MIPS_PHYS_TO_KSEG1(vtophys(tmpaddr));
+ newmap->origbuffer = *vaddr;
+ newmap->allocbuffer = tmpaddr;
+ mips_dcache_wbinv_range((vm_offset_t)*vaddr, dmat->maxsize);
+ *vaddr = tmpaddr;
} else
newmap->origbuffer = newmap->allocbuffer = NULL;
return (0);
@@ -481,7 +485,9 @@
("Trying to freeing the wrong DMA buffer"));
vaddr = map->origbuffer;
}
- if (dmat->maxsize <= PAGE_SIZE)
+ if (dmat->maxsize <= PAGE_SIZE &&
+ dmat->alignment < dmat->maxsize &&
+ dmat->lowaddr >= ptoa(Maxmem))
free(vaddr, M_DEVBUF);
else {
contigfree(vaddr, dmat->maxsize, M_DEVBUF);
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/cpu.c ./sys/mips/mips/cpu.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/cpu.c 2009-06-15 23:27:51.715239000 -0700
+++ ./sys/mips/mips/cpu.c 2009-06-16 17:31:21.824411000 -0700
@@ -92,9 +92,9 @@
cpuinfo->tlb_nentries = ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
/* L1 instruction cache. */
- tmp = 1 << (((cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT) + 1);
+ tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
if (tmp != 0) {
- cpuinfo->l1.ic_linesize = tmp;
+ cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
cpuinfo->l1.ic_nsets = 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets
@@ -102,9 +102,9 @@
}
/* L1 data cache. */
- tmp = 1 << (((cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT) + 1);
+ tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
if (tmp != 0) {
- cpuinfo->l1.dc_linesize = tmp;
+ cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
cpuinfo->l1.dc_nways = (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
cpuinfo->l1.dc_nsets = 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
#ifdef TARGET_OCTEON
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/intr_machdep.c ./sys/mips/mips/intr_machdep.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/intr_machdep.c 2009-06-15 23:27:51.737242000 -0700
+++ ./sys/mips/mips/intr_machdep.c 2009-06-16 17:31:21.829412000 -0700
@@ -53,16 +53,97 @@
static int last_printed = 0;
#endif
+static struct intsrc *hardintr_srcs[NHARD_IRQS];
+static struct intsrc *softintr_srcs[NSOFT_IRQS];
+
+static int
+cpu_register_intsrc(struct intsrc *intsrcs[], int limit, struct intsrc *isrc)
+{
+ int intrnum;
+
+ intrnum = isrc->intrnum;
+ if (intrnum < 0 || intrnum >= limit)
+ return (EINVAL);
+
+ /*
+ * XXX locking?
+ */
+ if (intsrcs[intrnum] != NULL)
+ return (EEXIST);
+ else
+ intsrcs[intrnum] = isrc;
+ return (0);
+}
+
+int
+cpu_register_hard_intsrc(struct intsrc *isrc)
+{
+
+ return (cpu_register_intsrc(hardintr_srcs, NHARD_IRQS, isrc));
+}
+
+int
+cpu_register_soft_intsrc(struct intsrc *isrc)
+{
+
+ return (cpu_register_intsrc(softintr_srcs, NSOFT_IRQS, isrc));
+}
+
void
-mips_mask_irq(void)
+mips_mask_irq(void *arg)
{
+ struct intsrc *isrc = arg;
+ if (isrc != NULL)
+ (*isrc->mask_func)(isrc);
}
void
-mips_unmask_irq(void)
+mips_unmask_irq(void *arg)
+{
+ struct intsrc *isrc = arg;
+
+ if (isrc != NULL)
+ (*isrc->unmask_func)(isrc);
+}
+
+#define SR_HARD_IRQ_MASK(irq) ((1 << ((irq) + 2)) << 8)
+#define SR_SOFT_IRQ_MASK(irq) ((1 << ((irq) + 0)) << 8)
+
+static void
+cpu_disable_hard_irq(int irq)
+{
+ KASSERT(irq >= 0 && irq < NHARD_IRQS,
+ ("cpu_disable_hard_irq: invalid irq %d", irq));
+
+ mips_wr_status(mips_rd_status() & ~SR_HARD_IRQ_MASK(irq));
+}
+
+static void
+cpu_enable_hard_irq(int irq)
{
+ KASSERT(irq >= 0 && irq < NHARD_IRQS,
+ ("cpu_enable_hard_irq: invalid irq %d", irq));
+ mips_wr_status(mips_rd_status() | SR_HARD_IRQ_MASK(irq));
+}
+
+static void
+cpu_disable_soft_irq(int irq)
+{
+ KASSERT(irq >= 0 && irq < NSOFT_IRQS,
+ ("cpu_disable_soft_irq: invalid irq %d", irq));
+
+ mips_wr_status(mips_rd_status() & ~SR_SOFT_IRQ_MASK(irq));
+}
+
+static void
+cpu_enable_soft_irq(int irq)
+{
+ KASSERT(irq >= 0 && irq < NSOFT_IRQS,
+ ("cpu_enable_soft_irq: invalid irq %d", irq));
+
+ mips_wr_status(mips_rd_status() | SR_SOFT_IRQ_MASK(irq));
}
void
@@ -80,9 +161,20 @@
if (irq < 0 || irq >= NHARD_IRQS)
panic("%s called for unknown hard intr %d", __func__, irq);
+ /*
+ * XXX Disable the hard irq
+ *
+ * It appears that there is a race between intr_event_add_handler()
+ * and intr_event_handle() that can be triggered if we receive an
+ * interrupt while we are adding the handler.
+ *
+ * Work around that by disabling the hard irq temporarily.
+ */
+ cpu_disable_hard_irq(irq);
+
event = hardintr_events[irq];
if (event == NULL) {
- error = intr_event_create(&event, (void *)irq, 0, irq,
+ error = intr_event_create(&event, hardintr_srcs[irq], 0, irq,
(mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
NULL, NULL, "hard intr%d:", irq);
if (error)
@@ -101,7 +193,7 @@
intr_event_add_handler(event, name, filt, handler, arg,
intr_priority(flags), flags, cookiep);
- mips_wr_status(mips_rd_status() | (((1 << irq) << 8) << 2));
+ cpu_enable_hard_irq(irq);
}
void
@@ -117,9 +209,11 @@
if (irq < 0 || irq > NSOFT_IRQS)
panic("%s called for unknown hard intr %d", __func__, irq);
+ cpu_disable_soft_irq(irq);
+
event = softintr_events[irq];
if (event == NULL) {
- error = intr_event_create(&event, (void *)irq, 0, irq,
+ error = intr_event_create(&event, softintr_srcs[irq], 0, irq,
(mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
NULL, NULL, "intr%d:", irq);
if (error)
@@ -130,7 +224,7 @@
intr_event_add_handler(event, name, filt, handler, arg,
intr_priority(flags), flags, cookiep);
- mips_wr_status(mips_rd_status() | (((1<< irq) << 8)));
+ cpu_enable_soft_irq(irq);
}
void
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/locore.S ./sys/mips/mips/locore.S
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/locore.S 2009-06-15 23:27:51.739241000 -0700
+++ ./sys/mips/mips/locore.S 2009-06-16 17:31:21.834416000 -0700
@@ -138,7 +138,11 @@
mtc0 t2, COP_0_STATUS_REG
COP0_SYNC
/* Make sure KSEG0 is cached */
+#ifdef CPU_SB1
+ li t0, CFG_K0_COHERENT
+#else
li t0, CFG_K0_CACHED
+#endif
mtc0 t0, MIPS_COP_0_CONFIG
COP0_SYNC
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/machdep.c ./sys/mips/mips/machdep.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/machdep.c 2009-06-15 23:27:51.748240000 -0700
+++ ./sys/mips/mips/machdep.c 2009-06-16 17:31:21.848415000 -0700
@@ -104,6 +104,7 @@
int cold = 1;
long realmem = 0;
+long Maxmem = 0;
int cpu_clock = MIPS_DEFAULT_HZ;
SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD,
&cpu_clock, 0, "CPU instruction clock rate");
@@ -255,10 +256,7 @@
proc_linkup(&proc0, &thread0);
thread0.td_kstack = kstack0;
thread0.td_kstack_pages = KSTACK_PAGES - 1;
- if (thread0.td_kstack & (1 << PAGE_SHIFT))
- thread0.td_md.md_realstack = thread0.td_kstack + PAGE_SIZE;
- else
- thread0.td_md.md_realstack = thread0.td_kstack;
+ thread0.td_md.md_realstack = roundup2(thread0.td_kstack, PAGE_SIZE * 2);
/* Initialize pcpu info of cpu-zero */
#ifdef SMP
pcpu_init(&__pcpu[0], 0, sizeof(struct pcpu));
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/mem.c ./sys/mips/mips/mem.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/mem.c 2009-06-15 23:27:51.752241000 -0700
+++ ./sys/mips/mips/mem.c 2009-06-16 17:31:21.853419000 -0700
@@ -101,8 +101,15 @@
vm_paddr_t pa;
register int o;
+#ifdef CPU_SB1
+ if (!is_physical_memory(v) ||
+ !is_physical_memory(roundup2(v, PAGE_SIZE) - 1)) {
+ return (EFAULT);
+ }
+#else
if (v + c > (SDRAM_ADDR_START + ctob(physmem)))
return (EFAULT);
+#endif
if (is_cacheable_mem(v) && is_cacheable_mem(v + c)) {
struct fpage *fp;
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/nexus.c ./sys/mips/mips/nexus.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/nexus.c 2009-06-15 23:27:51.762242000 -0700
+++ ./sys/mips/mips/nexus.c 2009-06-16 17:31:21.866418000 -0700
@@ -76,6 +76,7 @@
static struct rman irq_rman;
static struct rman mem_rman;
+static struct rman port_rman;
#ifdef notyet
/*
@@ -173,6 +174,21 @@
panic("%s: mem_rman", __func__);
}
+ /*
+ * MIPS has no concept of the x86 I/O address space but some cpus
+ * provide a memory mapped window to access the PCI I/O BARs.
+ */
+ port_rman.rm_start = 0;
+#ifdef PCI_IOSPACE_SIZE
+ port_rman.rm_end = PCI_IOSPACE_SIZE - 1;
+#endif
+ port_rman.rm_type = RMAN_ARRAY;
+ port_rman.rm_descr = "I/O ports";
+ if (rman_init(&port_rman) != 0 ||
+ rman_manage_region(&port_rman, 0, port_rman.rm_end) != 0)
+ panic("%s: port_rman", __func__);
+
+
return (0);
}
@@ -180,16 +196,21 @@
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
{
- int irq;
+ int irq, error;
- register_t sr = intr_disable();
irq = rman_get_start(res);
if (irq >= NUM_MIPS_IRQS)
return (0);
+ if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
+ flags |= INTR_EXCL;
+
+ error = rman_activate_resource(res);
+ if (error)
+ return (error);
+
cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg,
irq, flags, cookiep);
- intr_restore(sr);
return (0);
}
@@ -238,6 +259,7 @@
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
return (retval);
}
@@ -338,6 +360,9 @@
case SYS_RES_MEMORY:
rm = &mem_rman;
break;
+ case SYS_RES_IOPORT:
+ rm = &port_rman;
+ break;
default:
printf("%s: unknown resource type %d\n", __func__, type);
return (0);
@@ -380,6 +405,11 @@
u_int32_t poffs;
paddr = rman_get_start(r);
+#ifdef PCI_IOSPACE_ADDR
+ if (type == SYS_RES_IOPORT) {
+ paddr += PCI_IOSPACE_ADDR;
+ }
+#endif
psize = rman_get_size(r);
poffs = paddr - trunc_page(paddr);
vaddr = (caddr_t) pmap_mapdev(paddr-poffs, psize+poffs) + poffs;
@@ -473,6 +503,12 @@
nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
+ vm_offset_t va;
+
+ if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
+ va = (vm_offset_t)rman_get_virtual(r);
+ pmap_unmapdev(va, rman_get_size(r));
+ }
return (rman_deactivate_resource(r));
}
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/pmap.c ./sys/mips/mips/pmap.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/pmap.c 2009-06-15 23:27:51.769243000 -0700
+++ ./sys/mips/mips/pmap.c 2009-06-16 17:31:21.873419000 -0700
@@ -313,6 +313,8 @@
}
}
+ Maxmem = atop(phys_avail[i - 1]);
+
if (bootverbose) {
printf("Physical memory chunk(s):\n");
for (i = 0; phys_avail[i + 1] != 0; i += 2) {
@@ -324,6 +326,7 @@
(uintmax_t) phys_avail[i + 1] - 1,
(uintmax_t) size, (uintmax_t) size / PAGE_SIZE);
}
+ printf("Maxmem is 0x%0lx\n", ptoa(Maxmem));
}
/*
* Steal the message buffer from the beginning of memory.
@@ -2226,7 +2229,7 @@
#endif
if (phys < MIPS_KSEG0_LARGEST_PHYS) {
- va = MIPS_PHYS_TO_UNCACHED(phys);
+ va = MIPS_PHYS_TO_CACHED(phys);
bzero((caddr_t)va, PAGE_SIZE);
mips_dcache_wbinv_range(va, PAGE_SIZE);
@@ -2282,7 +2285,7 @@
} else
#endif
if (phys < MIPS_KSEG0_LARGEST_PHYS) {
- va = MIPS_PHYS_TO_UNCACHED(phys);
+ va = MIPS_PHYS_TO_CACHED(phys);
bzero((char *)(caddr_t)va + off, size);
mips_dcache_wbinv_range(va + off, size);
} else {
@@ -2321,7 +2324,7 @@
} else
#endif
if (phys < MIPS_KSEG0_LARGEST_PHYS) {
- va = MIPS_PHYS_TO_UNCACHED(phys);
+ va = MIPS_PHYS_TO_CACHED(phys);
bzero((caddr_t)va, PAGE_SIZE);
mips_dcache_wbinv_range(va, PAGE_SIZE);
} else {
@@ -2803,11 +2806,12 @@
return (void *)MIPS_PHYS_TO_KSEG1(pa);
else {
offset = pa & PAGE_MASK;
- size = roundup(size, PAGE_SIZE);
+ size = roundup(size + offset, PAGE_SIZE);
va = kmem_alloc_nofault(kernel_map, size);
if (!va)
panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
+ pa = trunc_page(pa);
for (tmpva = va; size > 0;) {
pmap_kenter(tmpva, pa);
size -= PAGE_SIZE;
@@ -2822,6 +2826,18 @@
void
pmap_unmapdev(vm_offset_t va, vm_size_t size)
{
+ vm_offset_t base, offset, tmpva;
+
+ /* If the address is within KSEG1 then there is nothing to do */
+ if (va >= MIPS_KSEG1_START && va <= MIPS_KSEG1_END)
+ return;
+
+ base = trunc_page(va);
+ offset = va & PAGE_MASK;
+ size = roundup(size + offset, PAGE_SIZE);
+ for (tmpva = base; tmpva < base + size; tmpva += PAGE_SIZE)
+ pmap_kremove(tmpva);
+ kmem_free(kernel_map, base, size);
}
/*
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/swtch.S ./sys/mips/mips/swtch.S
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/swtch.S 2009-06-15 23:27:51.778242000 -0700
+++ ./sys/mips/mips/swtch.S 2009-06-16 17:31:21.878416000 -0700
@@ -81,14 +81,14 @@
#define _MFC0 dmfc0
#define _MTC0 dmtc0
#define WIRED_SHIFT 34
-#define PAGE_SHIFT 34
+#define PAGE_SHIFT 12
#else
#define _SLL sll
#define _SRL srl
#define _MFC0 mfc0
#define _MTC0 mtc0
#define WIRED_SHIFT 2
-#define PAGE_SHIFT 2
+#define PAGE_SHIFT 12
#endif
.set noreorder # Noreorder is default style!
#if defined(ISA_MIPS32)
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/tick.c ./sys/mips/mips/tick.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/tick.c 2009-06-15 23:27:51.779247000 -0700
+++ ./sys/mips/mips/tick.c 2009-06-16 17:31:21.884415000 -0700
@@ -229,7 +229,7 @@
/* Check to see if the timer has wrapped around. */
if (cur < last)
- delta += (cur + (cycles_per_hz - last));
+ delta += (cur + (0xffffffff - last) + 1);
else
delta += (cur - last);
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/tlb.S ./sys/mips/mips/tlb.S
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/tlb.S 2009-06-15 23:27:51.781242000 -0700
+++ ./sys/mips/mips/tlb.S 2009-06-16 17:31:21.889422000 -0700
@@ -81,14 +81,14 @@
#define _MFC0 dmfc0
#define _MTC0 dmtc0
#define WIRED_SHIFT 34
-#define PAGE_SHIFT 34
+#define PAGE_SHIFT 12
#else
#define _SLL sll
#define _SRL srl
#define _MFC0 mfc0
#define _MTC0 mtc0
#define WIRED_SHIFT 2
-#define PAGE_SHIFT 2
+#define PAGE_SHIFT 12
#endif
.set noreorder # Noreorder is default style!
#if defined(ISA_MIPS32)
@@ -473,7 +473,17 @@
_MFC0 t4, COP_0_TLB_HI # Get current PID
move t2, a0
mfc0 t1, COP_0_TLB_WIRED
+
+ #
+ # Load invalid entry, each TLB entry should have it's own bogus
+ # address calculated by following expression:
+ # MIPS_KSEG0_START + 0x0fff0000 + 2 * i * PAGE_SIZE;
+ # One bogus value for every TLB entry might cause MCHECK exception
+ #
+ sll t3, t1, PAGE_SHIFT + 1
li v0, MIPS_KSEG0_START + 0x0fff0000 # invalid address
+ addu v0, t3
+
mfc0 t3, COP_0_TLB_PG_MASK # save current pgMask
# do {} while (t1 < t2)
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/trap.c ./sys/mips/mips/trap.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/trap.c 2009-06-15 23:27:51.783244000 -0700
+++ ./sys/mips/mips/trap.c 2009-06-16 17:31:21.895420000 -0700
@@ -365,7 +365,7 @@
printf("cpuid = %d\n", PCPU_GET(cpuid));
#endif
MachTLBGetPID(pid);
- printf("badaddr = %p, pc = %p, ra = %p, sp = %p, sr = 0x%x, pid = %d, ASID = 0x%x\n",
+ printf("badaddr = 0x%0x, pc = 0x%0x, ra = 0x%0x, sp = 0x%0x, sr = 0x%x, pid = %d, ASID = 0x%x\n",
trapframe->badvaddr, trapframe->pc, trapframe->ra,
trapframe->sp, trapframe->sr,
(curproc ? curproc->p_pid : -1), pid);
@@ -389,7 +389,7 @@
((type & ~T_USER) != T_SYSCALL)) {
if (++count == 3) {
trap_frame_dump(trapframe);
- panic("too many faults at %p\n", last_badvaddr);
+ panic("too many faults at %x\n", last_badvaddr);
}
} else {
last_badvaddr = this_badvaddr;
@@ -570,7 +570,7 @@
--p->p_lock;
PROC_UNLOCK(p);
#ifdef VMFAULT_TRACE
- printf("vm_fault(%x (pmap %x), %x (%x), %x, %d) -> %x at pc %x\n",
+ printf("vm_fault(%p (pmap %p), %x (%x), %x, %d) -> %x at pc %x\n",
map, &vm->vm_pmap, va, trapframe->badvaddr, ftype, flag,
rv, trapframe->pc);
#endif
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/vm_machdep.c ./sys/mips/mips/vm_machdep.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/mips/vm_machdep.c 2009-06-15 23:27:51.787242000 -0700
+++ ./sys/mips/mips/vm_machdep.c 2009-06-16 17:31:21.901417000 -0700
@@ -395,6 +395,24 @@
* Currently used by the kernel coredump code in order to avoid
* dumping non-memory physical address space.
*/
+#ifdef CPU_SB1
+int
+is_physical_memory(vm_offset_t addr)
+{
+
+ if ((addr >= 0x00000000UL && addr < 0x10000000UL) ||
+ (addr >= 0x80000000UL && addr < 0xa0000000UL) ||
+ (addr >= 0xc0000000UL && addr < 0xd0000000UL)) {
+ return (1);
+ }
+#ifdef ISA_MIPS64
+ if (addr >= 0x0100000000ULL && addr < 0x8000000000ULL) {
+ return (1);
+ }
+#endif
+ return (0);
+}
+#else
int
is_physical_memory(vm_offset_t addr)
{
@@ -403,7 +421,26 @@
else
return 0;
}
+#endif /* CPU_SB1 */
+#ifdef CPU_SB1
+int
+is_cacheable_mem(vm_offset_t pa)
+{
+
+ return (is_physical_memory(pa));
+}
+
+int
+is_coherent_mem(vm_offset_t pa)
+{
+
+ /*
+ * All physical memory is marked cacheable-coherent on the sibyte.
+ */
+ return (is_physical_memory(pa));
+}
+#else
int
is_cacheable_mem(vm_offset_t pa)
{
@@ -418,6 +455,14 @@
return 0;
}
+int
+is_coherent_mem(vm_offset_t pa)
+{
+
+ return (0);
+}
+#endif /* CPU_SB1 */
+
/*
* Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-))
*/
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/ata_zbbus.c ./sys/mips/sibyte/ata_zbbus.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/ata_zbbus.c 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/ata_zbbus.c 2009-05-21 23:42:26.999969000 -0700
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+
+#include <vm/uma.h>
+
+#include <sys/ata.h>
+#include <dev/ata/ata-all.h>
+
+#include <machine/resource.h>
+
+__FBSDID("$FreeBSD$");
+
+static int
+ata_zbbus_probe(device_t dev)
+{
+
+ return (ata_probe(dev));
+}
+
+static int
+ata_zbbus_attach(device_t dev)
+{
+ int i, rid, regshift, regoffset;
+ struct ata_channel *ch;
+ struct resource *io;
+
+ ch = device_get_softc(dev);
+
+ if (ch->attached)
+ return (0);
+ ch->attached = 1;
+
+ rid = 0;
+ io = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE);
+ if (io == NULL)
+ return (ENXIO);
+
+ /*
+ * SWARM needs an address shift of 5 when accessing ATA registers.
+ *
+ * For e.g. an access to register 4 actually needs an address
+ * of (4 << 5) to be output on the generic bus.
+ */
+ regshift = 5;
+ resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "regshift", ®shift);
+ if (regshift && bootverbose)
+ device_printf(dev, "using a register shift of %d\n", regshift);
+
+ regoffset = 0x1F0;
+ resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "regoffset", ®offset);
+ if (regoffset && bootverbose) {
+ device_printf(dev, "using a register offset of 0x%0x\n",
+ regoffset);
+ }
+
+ /* setup the ata register addresses */
+ for (i = ATA_DATA; i <= ATA_COMMAND; ++i) {
+ ch->r_io[i].res = io;
+ ch->r_io[i].offset = (regoffset + i) << regshift;
+ }
+
+ ch->r_io[ATA_CONTROL].res = io;
+ ch->r_io[ATA_CONTROL].offset = (regoffset + ATA_CTLOFFSET) << regshift;
+ ch->r_io[ATA_IDX_ADDR].res = io; /* XXX what is this used for */
+ ata_default_registers(dev);
+
+ /* initialize softc for this channel */
+ ch->unit = 0;
+ ch->flags |= ATA_USE_16BIT;
+ ata_generic_hw(dev);
+
+ return (ata_attach(dev));
+}
+
+static int
+ata_zbbus_detach(device_t dev)
+{
+ int error;
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (!ch->attached)
+ return (0);
+ ch->attached = 0;
+
+ error = ata_detach(dev);
+
+ bus_release_resource(dev, SYS_RES_MEMORY, 0,
+ ch->r_io[ATA_IDX_ADDR].res);
+
+ return (error);
+}
+
+static int
+ata_zbbus_suspend(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (!ch->attached)
+ return (0);
+
+ return (ata_suspend(dev));
+}
+
+static int
+ata_zbbus_resume(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (!ch->attached)
+ return (0);
+
+ return (ata_resume(dev));
+}
+
+static device_method_t ata_zbbus_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ata_zbbus_probe),
+ DEVMETHOD(device_attach, ata_zbbus_attach),
+ DEVMETHOD(device_detach, ata_zbbus_detach),
+ DEVMETHOD(device_suspend, ata_zbbus_suspend),
+ DEVMETHOD(device_resume, ata_zbbus_resume),
+
+ { 0, 0 }
+};
+
+static driver_t ata_zbbus_driver = {
+ "ata",
+ ata_zbbus_methods,
+ sizeof(struct ata_channel)
+};
+
+DRIVER_MODULE(ata, zbbus, ata_zbbus_driver, ata_devclass, 0, 0);
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/files.sibyte ./sys/mips/sibyte/files.sibyte
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/files.sibyte 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/files.sibyte 2009-05-21 23:34:27.313938000 -0700
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+mips/sibyte/sb_machdep.c standard
+mips/sibyte/sb_zbbus.c standard
+mips/sibyte/sb_zbpci.c standard
+mips/sibyte/sb_scd.c standard
+mips/sibyte/ata_zbbus.c standard
+
+mips/sibyte/sb_asm.S standard
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_asm.S ./sys/mips/sibyte/sb_asm.S
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_asm.S 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/sb_asm.S 2009-05-18 20:25:17.798702000 -0700
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+/*
+ * We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit
+ * processor. It has some registers that must be accessed using 64-bit load
+ * and store instructions.
+ *
+ * So we have to resort to assembly because the compiler does not emit the
+ * 'ld' and 'sd' instructions since it thinks that it is compiling for a
+ * 32-bit mips processor.
+ */
+
+.set mips64
+.set noat
+.set noreorder
+
+/*
+ * return (MIPS_PHYS_TO_KSEG1(0x10020008))
+ * Parameters: none
+ */
+LEAF(sb_read_syscfg)
+ lui v0, 0xb002
+ ori v0, v0, 0x8
+ ld v1, 0(v0) /* syscfg = MIPS_PHYS_TO_KSEG1(0x10020008) */
+ move v0, v1
+ dsll32 v0, v0, 0
+ dsrl32 v0, v0, 0 /* v0 = lower_uint32(mask) */
+ jr ra
+ dsrl32 v1, v1, 0 /* v1 = upper_uint32(mask) */
+END(sb_read_syscfg)
+
+/*
+ * MIPS_PHYS_TO_KSEG1(0x10020008) = (uint64_t)val
+ * Parameters:
+ * - lower_uint32(val): a0
+ * - upper_uint32(val): a1
+ */
+LEAF(sb_write_syscfg)
+ lui v0, 0xb002
+ ori v0, v0, 0x8
+ dsll32 a1, a1, 0 /* clear lower 32 bits of a1 */
+ dsll32 a0, a0, 0
+ dsrl32 a0, a0, 0 /* clear upper 32 bits of a0 */
+ or a1, a1, a0
+ sd a1, 0(v0) /* MIPS_PHYS_TO_KSEG1(0x10020008) = val */
+ jr ra
+ nop
+ nop
+END(sb_write_syscfg)
+
+/*
+ * MIPS_PHYS_TO_KSEG1(0x10020028) |= (1 << intsrc)
+ *
+ * Parameters:
+ * - intsrc (a0)
+ */
+LEAF(sb_disable_intsrc)
+ lui v0, 0xb002
+ ori v0, v0, 0x28
+ ld v1, 0(v0) /* mask = MIPS_PHYS_TO_KSEG1(0x10020028) */
+ li a1, 1
+ dsllv a1, a1, a0
+ or a1, a1, v1 /* mask |= (1 << intsrc) */
+ jr ra
+ sd a1, 0(v0) /* MIPS_PHYS_TO_KSEG1(0x10020028) = mask */
+END(sb_disable_intsrc)
+
+/*
+ * MIPS_PHYS_TO_KSEG1(0x10020028) &= ~(1 << intsrc)
+ *
+ * Parameters:
+ * - intsrc (a0)
+ */
+LEAF(sb_enable_intsrc)
+ lui v0, 0xb002
+ ori v0, v0, 0x28
+ ld v1, 0(v0) /* mask = MIPS_PHYS_TO_KSEG1(0x10020028) */
+ li a2, 1
+ dsllv a2, a2, a0
+ nor a2, zero, a2
+ and a2, a2, v1 /* mask &= ~(1 << intsrc) */
+ sd a2, 0(v0) /* MIPS_PHYS_TO_KSEG1(0x10020028) = mask */
+ jr ra
+ nop
+END(sb_enable_intsrc)
+
+/*
+ * return ((uint64_t)MIPS_PHYS_TO_KSEG1(0x10020028))
+ * Parameters: none
+ */
+LEAF(sb_read_intsrc_mask)
+ lui v0, 0xb002
+ ori v0, v0, 0x28
+ ld v1, 0(v0) /* mask = MIPS_PHYS_TO_KSEG1(0x10020028) */
+ move v0, v1
+ dsll32 v0, v0, 0
+ dsrl32 v0, v0, 0 /* v0 = lower_uint32(mask) */
+ jr ra
+ dsrl32 v1, v1, 0 /* v1 = upper_uint32(mask) */
+END(sb_read_intsrc_mask)
+
+/*
+ * return ((uint64_t *)MIPS_PHYS_TO_KSEG1(0x10020200) + intsrc)
+ * Parameters:
+ * - intsrc (a0)
+ */
+LEAF(sb_read_intmap)
+ sll a0, a0, 3 /* compute the offset of the intmap register */
+ lui v0, 0xb002
+ addu a0, a0, v0
+ ld v0, 512(a0) /* v0 = MIPS_PHYS_TO_KSEG1(0x10020200) + off */
+ jr ra
+ nop
+END(sb_read_intmap)
+
+/*
+ * (uint64_t *)MIPS_PHYS_TO_KSEG1(0x10020200) + intsrc = irq
+ * Parameters:
+ * - intsrc (a0)
+ * - irq (a1)
+ */
+LEAF(sb_write_intmap)
+ sll a0, a0, 0x3 /* compute the offset of the intmap register */
+ lui v0, 0xb002
+ addu a0, a0, v0
+ sd a1, 512(a0) /* MIPS_PHYS_TO_KSEG1(0x10020200) + off = irq */
+ jr ra
+ nop
+END(sb_write_intmap)
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_machdep.c ./sys/mips/sibyte/sb_machdep.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_machdep.c 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/sb_machdep.c 2009-06-10 13:53:30.333084000 -0700
@@ -0,0 +1,259 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <machine/cpuregs.h>
+
+#include "opt_ddb.h"
+#include "opt_kdb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pte.h>
+#include <machine/sigframe.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#ifdef CFE
+#include <dev/cfe/cfe_api.h>
+#endif
+
+#include "sb_scd.h"
+
+#ifdef DDB
+#ifndef KDB
+#error KDB must be enabled in order for DDB to work!
+#endif
+#endif
+
+#ifdef CFE
+extern uint32_t cfe_handle;
+extern uint32_t cfe_vector;
+#endif
+
+#ifdef CFE_ENV
+extern void cfe_env_init(void);
+#endif
+
+extern int *edata;
+extern int *end;
+
+static void
+mips_init(void)
+{
+ int i, cfe_mem_idx, tmp;
+ uint64_t maxmem;
+
+#ifdef CFE_ENV
+ cfe_env_init();
+#endif
+
+ TUNABLE_INT_FETCH("boothowto", &boothowto);
+
+ if (boothowto & RB_VERBOSE)
+ bootverbose++;
+
+#ifdef MAXMEM
+ tmp = MAXMEM;
+#else
+ tmp = 0;
+#endif
+ TUNABLE_INT_FETCH("hw.physmem", &tmp);
+ maxmem = (uint64_t)tmp * 1024;
+
+#ifdef CFE
+ /*
+ * Query DRAM memory map from CFE.
+ */
+ physmem = 0;
+ cfe_mem_idx = 0;
+ for (i = 0; i < 10; i += 2) {
+ int result;
+ uint64_t addr, len, type;
+
+ result = cfe_enummem(cfe_mem_idx++, 0, &addr, &len, &type);
+ if (result < 0) {
+ phys_avail[i] = phys_avail[i + 1] = 0;
+ break;
+ }
+
+ KASSERT(type == CFE_MI_AVAILABLE,
+ ("CFE DRAM region is not available?"));
+
+ if (bootverbose)
+ printf("cfe_enummem: 0x%016jx/%llu.\n", addr, len);
+
+ if (maxmem != 0) {
+ if (addr >= maxmem) {
+ printf("Ignoring %llu bytes of memory at 0x%jx "
+ "that is above maxmem %dMB\n",
+ len, addr,
+ (int)(maxmem / (1024 * 1024)));
+ continue;
+ }
+
+ if (addr + len > maxmem) {
+ printf("Ignoring %llu bytes of memory "
+ "that is above maxmem %dMB\n",
+ (addr + len) - maxmem,
+ (int)(maxmem / (1024 * 1024)));
+ len = maxmem - addr;
+ }
+ }
+
+ phys_avail[i] = addr;
+ if (i == 0 && addr == 0) {
+ /*
+ * If this is the first physical memory segment probed
+ * from CFE, omit the region at the start of physical
+ * memory where the kernel has been loaded.
+ */
+ phys_avail[i] += MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ }
+ phys_avail[i + 1] = addr + len;
+ physmem += len;
+ }
+
+ realmem = btoc(physmem);
+#endif
+
+ physmem = realmem;
+
+ init_param1();
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+
+ kdb_init();
+#ifdef KDB
+ if (boothowto & RB_KDB)
+ kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
+#endif
+}
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+
+ /*
+ * XXX SMP
+ * XXX flush data caches
+ */
+ sb_system_reset();
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0 __unused, __register_t a1 __unused,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ vm_offset_t kernend;
+
+ /* clear the BSS and SBSS segments */
+ memset(&edata, 0, (vm_offset_t)&end - (vm_offset_t)&edata);
+ kernend = round_page((vm_offset_t)&end);
+
+#ifdef CFE
+ /*
+ * Initialize CFE firmware trampolines before
+ * we initialize the low-level console.
+ */
+ if (cfe_handle != 0)
+ cfe_init(cfe_handle, cfe_vector);
+#endif
+ cninit();
+
+#ifdef CFE
+ if (cfe_handle == 0)
+ panic("CFE was not detected by locore.\n");
+#endif
+ mips_init();
+
+ mips_timer_init_params(sb_cpu_speed(), 0);
+}
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_scd.c ./sys/mips/sibyte/sb_scd.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_scd.c 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/sb_scd.c 2009-05-15 16:51:56.362688000 -0700
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/resource.h>
+
+#include "sb_scd.h"
+
+__FBSDID("$FreeBSD$");
+
+/*
+ * System Control and Debug (SCD) unit on the Sibyte ZBbus.
+ */
+
+/*
+ * Extract the value starting at bit position 'b' for 'n' bits from 'x'.
+ */
+#define GET_VAL_64(x, b, n) (((x) >> (b)) & ((1ULL << (n)) - 1))
+
+#define SYSCFG_PLLDIV(x) GET_VAL_64((x), 7, 5)
+
+uint64_t
+sb_cpu_speed(void)
+{
+ int plldiv;
+ const uint64_t MHZ = 1000000;
+
+ plldiv = SYSCFG_PLLDIV(sb_read_syscfg());
+ if (plldiv == 0) {
+ printf("PLL_DIV is 0 - assuming 6 (300MHz).\n");
+ plldiv = 6;
+ }
+
+ return (plldiv * 50 * MHZ);
+}
+
+void
+sb_system_reset(void)
+{
+ uint64_t syscfg;
+
+ const uint64_t SYSTEM_RESET = 1ULL << 60;
+ const uint64_t EXT_RESET = 1ULL << 59;
+ const uint64_t SOFT_RESET = 1ULL << 58;
+
+ syscfg = sb_read_syscfg();
+ syscfg &= ~SOFT_RESET;
+ syscfg |= SYSTEM_RESET | EXT_RESET;
+ sb_write_syscfg(syscfg);
+}
+
+int
+sb_route_intsrc(int intsrc)
+{
+ int intrnum;
+
+ KASSERT(intsrc >= 0 && intsrc < NUM_INTSRC,
+ ("Invalid interrupt source number (%d)", intsrc));
+
+ /*
+ * Interrupt 5 is used by sources internal to the CPU (e.g. timer).
+ * Use a deterministic mapping for the remaining sources to map to
+ * interrupt numbers 0 through 4.
+ */
+ intrnum = intsrc % 5;
+
+ /*
+ * Program the interrupt mapper while we are here.
+ */
+ sb_write_intmap(intsrc, intrnum);
+
+ return (intrnum);
+}
+
+#define SCD_PHYSADDR 0x10000000
+#define SCD_SIZE 0x00060000
+
+static int
+scd_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Broadcom/Sibyte System Control and Debug");
+ return (0);
+}
+
+static int
+scd_attach(device_t dev)
+{
+ int rid;
+ struct resource *res;
+
+ if (bootverbose) {
+ device_printf(dev, "attached.\n");
+ }
+
+ rid = 0;
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, SCD_PHYSADDR,
+ SCD_PHYSADDR + SCD_SIZE - 1, SCD_SIZE, 0);
+ if (res == NULL) {
+ panic("Cannot allocate resource for system control and debug.");
+ }
+
+ return (0);
+}
+
+static device_method_t scd_methods[] ={
+ /* Device interface */
+ DEVMETHOD(device_probe, scd_probe),
+ DEVMETHOD(device_attach, scd_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ { 0, 0 }
+};
+
+static driver_t scd_driver = {
+ "scd",
+ scd_methods
+};
+
+static devclass_t scd_devclass;
+
+DRIVER_MODULE(scd, zbbus, scd_driver, scd_devclass, 0, 0);
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_scd.h ./sys/mips/sibyte/sb_scd.h
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_scd.h 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/sb_scd.h 2009-05-15 01:58:12.318422000 -0700
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SB_SCD_H_
+#define _SB_SCD_H_
+
+#define NUM_INTSRC 64 /* total number of interrupt sources */
+
+uint64_t sb_cpu_speed(void);
+void sb_system_reset(void);
+
+int sb_route_intsrc(int src);
+void sb_enable_intsrc(int src);
+void sb_disable_intsrc(int src);
+uint64_t sb_read_intsrc_mask(void);
+
+int sb_read_intmap(int intsrc);
+void sb_write_intmap(int intsrc, int intrnum);
+
+uint64_t sb_read_syscfg(void);
+void sb_write_syscfg(uint64_t val);
+
+#endif /* _SB_SCD_H_ */
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_zbbus.c ./sys/mips/sibyte/sb_zbbus.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_zbbus.c 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/sb_zbbus.c 2009-06-13 12:29:39.515055000 -0700
@@ -0,0 +1,501 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/resource.h>
+#include <machine/intr_machdep.h>
+
+#include "sb_scd.h"
+
+__FBSDID("$FreeBSD$");
+
+static MALLOC_DEFINE(M_INTMAP, "sb1250 intmap", "Sibyte 1250 Interrupt Mapper");
+
+#define NUM_HARD_IRQS 6
+
+struct sb_intmap {
+ int intsrc; /* interrupt mapper register number (0 - 63) */
+ int active; /* Does this source generate interrupts? */
+
+ /*
+ * The device that the interrupt belongs to. Note that multiple
+ * devices may share an interrupt. For e.g. PCI_INT_x lines.
+ *
+ * The device 'dev' in combination with the 'rid' uniquely
+ * identify this interrupt source.
+ */
+ device_t dev;
+ int rid;
+
+ SLIST_ENTRY(sb_intmap) next;
+};
+
+/*
+ * We register 'sb_intsrc.isrc' using cpu_register_hard_intsrc() for each
+ * hard interrupt source [0-5].
+ *
+ * The mask/unmask callbacks use the information in 'sb_intmap' to figure
+ * out the corresponding interrupt sources to mask/unmask.
+ */
+struct sb_intsrc {
+ struct intsrc isrc;
+ SLIST_HEAD(, sb_intmap) sb_intmap_head;
+};
+
+static struct sb_intsrc sb_intsrc[NUM_HARD_IRQS];
+
+static struct sb_intmap *
+sb_intmap_lookup(int intrnum, device_t dev, int rid)
+{
+ struct sb_intsrc *isrc;
+ struct sb_intmap *map;
+
+ isrc = &sb_intsrc[intrnum];
+ SLIST_FOREACH(map, &isrc->sb_intmap_head, next) {
+ if (dev == map->dev && rid == map->rid)
+ break;
+ }
+ return (map);
+}
+
+/*
+ * Keep track of which (dev,rid) tuple is using the interrupt source.
+ *
+ * We don't actually unmask the interrupt source until the device calls
+ * a bus_setup_intr() on the resource.
+ */
+static void
+sb_intmap_add(int intrnum, device_t dev, int rid, int intsrc)
+{
+ struct sb_intsrc *isrc;
+ struct sb_intmap *map;
+ register_t sr;
+
+ KASSERT(intrnum >= 0 && intrnum < NUM_HARD_IRQS,
+ ("intrnum is out of range: %d", intrnum));
+
+ isrc = &sb_intsrc[intrnum];
+ map = sb_intmap_lookup(intrnum, dev, rid);
+ if (map) {
+ KASSERT(intsrc == map->intsrc,
+ ("%s%d allocating SYS_RES_IRQ resource with rid %d "
+ "with a different intsrc (%d versus %d)",
+ device_get_name(dev), device_get_unit(dev), rid,
+ intsrc, map->intsrc));
+ return;
+ }
+
+ map = malloc(sizeof(*map), M_INTMAP, M_WAITOK | M_ZERO);
+ map->intsrc = intsrc;
+ map->dev = dev;
+ map->rid = rid;
+
+ sr = intr_disable();
+ SLIST_INSERT_HEAD(&isrc->sb_intmap_head, map, next);
+ intr_restore(sr);
+}
+
+static void
+sb_intmap_activate(int intrnum, device_t dev, int rid)
+{
+ struct sb_intmap *map;
+ register_t sr;
+
+ KASSERT(intrnum >= 0 && intrnum < NUM_HARD_IRQS,
+ ("intrnum is out of range: %d", intrnum));
+
+ map = sb_intmap_lookup(intrnum, dev, rid);
+ if (map) {
+ /*
+ * See comments in sb_unmask_func() about disabling cpu intr
+ */
+ sr = intr_disable();
+ map->active = 1;
+ sb_enable_intsrc(map->intsrc);
+ intr_restore(sr);
+ } else {
+ /*
+ * In zbbus_setup_intr() we blindly call sb_intmap_activate()
+ * for every interrupt activation that comes our way.
+ *
+ * We might end up here if we did not "hijack" the SYS_RES_IRQ
+ * resource in zbbus_alloc_resource().
+ */
+ printf("sb_intmap_activate: unable to activate interrupt %d "
+ "for device %s%d rid %d.\n", intrnum,
+ device_get_name(dev), device_get_unit(dev), rid);
+ }
+}
+
+static void
+sb_mask_func(struct intsrc *arg)
+{
+ struct sb_intmap *map;
+ struct sb_intsrc *isrc;
+ uint64_t isrc_bitmap;
+
+ isrc_bitmap = 0;
+ isrc = (struct sb_intsrc *)arg;
+ SLIST_FOREACH(map, &isrc->sb_intmap_head, next) {
+ if (map->active == 0)
+ continue;
+ /*
+ * If we have already disabled this interrupt source then don't
+ * do it again. This can happen when multiple devices share
+ * an interrupt source (e.g. PCI_INT_x).
+ */
+ if (isrc_bitmap & (1ULL << map->intsrc))
+ continue;
+ sb_disable_intsrc(map->intsrc);
+ isrc_bitmap |= 1ULL << map->intsrc;
+ }
+}
+
+static void
+sb_unmask_func(struct intsrc *arg)
+{
+ struct sb_intmap *map;
+ struct sb_intsrc *sb_isrc;
+ uint64_t isrc_bitmap;
+ register_t sr;
+
+ isrc_bitmap = 0;
+ sb_isrc = (struct sb_intsrc *)arg;
+
+ /*
+ * Make sure we disable the cpu interrupts when enabling the
+ * interrupt sources.
+ *
+ * This is to prevent a condition where some interrupt sources have
+ * been enabled (but not all) and one of those interrupt sources
+ * triggers an interrupt.
+ *
+ * If any of the interrupt handlers executes in an ithread then
+ * cpu_intr() will return with all interrupt sources feeding into
+ * that cpu irq masked. But when the loop below picks up where it
+ * left off it will enable the remaining interrupt sources!!!
+ *
+ * If the disable the cpu interrupts then this race does not happen.
+ */
+ sr = intr_disable();
+
+ SLIST_FOREACH(map, &sb_isrc->sb_intmap_head, next) {
+ if (map->active == 0)
+ continue;
+ /*
+ * If we have already enabled this interrupt source then don't
+ * do it again. This can happen when multiple devices share
+ * an interrupt source (e.g. PCI_INT_x).
+ */
+ if (isrc_bitmap & (1ULL << map->intsrc))
+ continue;
+ sb_enable_intsrc(map->intsrc);
+ isrc_bitmap |= 1ULL << map->intsrc;
+ }
+
+ intr_restore(sr);
+}
+
+struct zbbus_devinfo {
+ struct resource_list resources;
+};
+
+static MALLOC_DEFINE(M_ZBBUSDEV, "zbbusdev", "zbbusdev");
+
+static int
+zbbus_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Broadcom/Sibyte ZBbus");
+ return (0);
+}
+
+static int
+zbbus_attach(device_t dev)
+{
+ int i, error;
+ struct intsrc *isrc;
+
+ if (bootverbose) {
+ device_printf(dev, "attached.\n");
+ }
+
+ for (i = 0; i < NUM_HARD_IRQS; ++i) {
+ isrc = &sb_intsrc[i].isrc;
+ isrc->intrnum = i;
+ isrc->mask_func = sb_mask_func;
+ isrc->unmask_func = sb_unmask_func;
+ error = cpu_register_hard_intsrc(isrc);
+ if (error)
+ panic("Error %d registering intsrc %d", error, i);
+ }
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static void
+zbbus_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ device_t child;
+ long maddr, msize;
+ int err, irq;
+
+ if (resource_disabled(dname, dunit))
+ return;
+
+ child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+ if (child == NULL) {
+ panic("zbbus: could not add child %s unit %d\n", dname, dunit);
+ }
+
+ if (bootverbose)
+ device_printf(bus, "Adding hinted child %s%d\n", dname, dunit);
+
+ /*
+ * Assign any pre-defined resources to the child.
+ */
+ if (resource_long_value(dname, dunit, "msize", &msize) == 0 &&
+ resource_long_value(dname, dunit, "maddr", &maddr) == 0) {
+ if (bootverbose) {
+ device_printf(bus, "Assigning memory resource "
+ "0x%0lx/%ld to child %s%d\n",
+ maddr, msize, dname, dunit);
+ }
+ err = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
+ if (err) {
+ device_printf(bus, "Unable to set memory resource "
+ "0x%0lx/%ld for child %s%d: %d\n",
+ maddr, msize, dname, dunit, err);
+ }
+ }
+
+ if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
+ if (bootverbose) {
+ device_printf(bus, "Assigning irq resource %d to "
+ "child %s%d\n", irq, dname, dunit);
+ }
+ err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (err) {
+ device_printf(bus, "Unable to set irq resource %d"
+ "for child %s%d: %d\n",
+ irq, dname, dunit, err);
+ }
+ }
+}
+
+static struct resource *
+zbbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *res;
+ int intrnum, intsrc, isdefault;
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+ struct zbbus_devinfo *dinfo;
+
+ isdefault = (start == 0UL && end == ~0UL && count == 1);
+
+ /*
+ * Our direct child is asking for a default resource allocation.
+ */
+ if (device_get_parent(child) == bus) {
+ dinfo = device_get_ivars(child);
+ rl = &dinfo->resources;
+ rle = resource_list_find(rl, type, *rid);
+ if (rle) {
+ if (rle->res)
+ panic("zbbus_alloc_resource: resource is busy");
+ if (isdefault) {
+ start = rle->start;
+ count = ulmax(count, rle->count);
+ end = ulmax(rle->end, start + count - 1);
+ }
+ } else {
+ if (isdefault) {
+ /*
+ * Our child is requesting a default
+ * resource allocation but we don't have the
+ * 'type/rid' tuple in the resource list.
+ *
+ * We have to fail the resource allocation.
+ */
+ return (NULL);
+ } else {
+ /*
+ * The child is requesting a non-default
+ * resource. We just pass the request up
+ * to our parent. If the resource allocation
+ * succeeds we will create a resource list
+ * entry corresponding to that resource.
+ */
+ }
+ }
+ } else {
+ rl = NULL;
+ rle = NULL;
+ }
+
+ /*
+ * nexus doesn't know about the interrupt mapper and only wants to
+ * see the hard irq numbers [0-6]. We translate from the interrupt
+ * source presented to the mapper to the interrupt number presented
+ * to the cpu.
+ */
+ if ((count == 1) && (type == SYS_RES_IRQ)) {
+ intsrc = start;
+ intrnum = sb_route_intsrc(intsrc);
+ start = end = intrnum;
+ } else {
+ intsrc = -1; /* satisfy gcc */
+ intrnum = -1;
+ }
+
+ res = bus_generic_alloc_resource(bus, child, type, rid,
+ start, end, count, flags);
+
+ /*
+ * Keep track of the input into the interrupt mapper that maps
+ * to the resource allocated by 'child' with resource id 'rid'.
+ *
+ * If we don't record the mapping here then we won't be able to
+ * locate the interrupt source when bus_setup_intr(child,rid) is
+ * called.
+ */
+ if (res != NULL && intrnum != -1)
+ sb_intmap_add(intrnum, child, rman_get_rid(res), intsrc);
+
+ /*
+ * If a non-default resource allocation by our child was successful
+ * then keep track of the resource in the resource list associated
+ * with the child.
+ */
+ if (res != NULL && rle == NULL && device_get_parent(child) == bus) {
+ resource_list_add(rl, type, *rid, start, end, count);
+ rle = resource_list_find(rl, type, *rid);
+ if (rle == NULL)
+ panic("zbbus_alloc_resource: cannot find resource");
+ }
+
+ if (rle != NULL) {
+ KASSERT(device_get_parent(child) == bus,
+ ("rle should be NULL for passthru device"));
+ rle->res = res;
+ if (rle->res) {
+ rle->start = rman_get_start(rle->res);
+ rle->end = rman_get_end(rle->res);
+ rle->count = count;
+ }
+ }
+
+ return (res);
+}
+
+static int
+zbbus_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
+ driver_filter_t *filter, driver_intr_t *intr, void *arg,
+ void **cookiep)
+{
+ int error;
+
+ error = bus_generic_setup_intr(dev, child, irq, flags,
+ filter, intr, arg, cookiep);
+ if (error == 0)
+ sb_intmap_activate(rman_get_start(irq), child,
+ rman_get_rid(irq));
+
+ return (error);
+}
+
+static device_t
+zbbus_add_child(device_t bus, int order, const char *name, int unit)
+{
+ device_t child;
+ struct zbbus_devinfo *dinfo;
+
+ child = device_add_child_ordered(bus, order, name, unit);
+ if (child != NULL) {
+ dinfo = malloc(sizeof(struct zbbus_devinfo), M_ZBBUSDEV,
+ M_WAITOK | M_ZERO);
+ resource_list_init(&dinfo->resources);
+ device_set_ivars(child, dinfo);
+ }
+
+ return (child);
+}
+
+static struct resource_list *
+zbbus_get_resource_list(device_t dev, device_t child)
+{
+ struct zbbus_devinfo *dinfo = device_get_ivars(child);
+
+ return (&dinfo->resources);
+}
+
+static device_method_t zbbus_methods[] ={
+ /* Device interface */
+ DEVMETHOD(device_probe, zbbus_probe),
+ DEVMETHOD(device_attach, zbbus_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_alloc_resource, zbbus_alloc_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_get_resource_list,zbbus_get_resource_list),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
+ DEVMETHOD(bus_setup_intr, zbbus_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_add_child, zbbus_add_child),
+ DEVMETHOD(bus_hinted_child, zbbus_hinted_child),
+
+ { 0, 0 }
+};
+
+static driver_t zbbus_driver = {
+ "zbbus",
+ zbbus_methods
+};
+
+static devclass_t zbbus_devclass;
+
+DRIVER_MODULE(zbbus, nexus, zbbus_driver, zbbus_devclass, 0, 0);
diff -Nurd /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_zbpci.c ./sys/mips/sibyte/sb_zbpci.c
--- /u/neelnatu/p4/freebsd_current/src/sys/mips/sibyte/sb_zbpci.c 1969-12-31 16:00:00.000000000 -0800
+++ ./sys/mips/sibyte/sb_zbpci.c 2009-06-13 12:31:52.042328000 -0700
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/pcpu.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
+
+#include <machine/pmap.h>
+#include <machine/resource.h>
+
+#include "pcib_if.h"
+
+#include "sb_scd.h"
+
+__FBSDID("$FreeBSD$");
+
+static struct {
+ vm_offset_t vaddr;
+ vm_paddr_t paddr;
+} zbpci_config_space[MAXCPU];
+
+static const vm_paddr_t CFG_PADDR_BASE = 0xFE000000;
+
+static int
+zbpci_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Broadcom/Sibyte PCI I/O Bridge");
+ return (0);
+}
+
+static int
+zbpci_attach(device_t dev)
+{
+ int n, rid, size;
+ vm_offset_t va;
+ struct resource *res;
+
+ /*
+ * Reserve the the physical memory that is used to read/write to the
+ * pci config space but don't activate it. We are using a page worth
+ * of KVA as a window over this region.
+ */
+ rid = 0;
+ size = (PCI_BUSMAX + 1) * (PCI_SLOTMAX + 1) * (PCI_FUNCMAX + 1) * 256;
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, CFG_PADDR_BASE,
+ CFG_PADDR_BASE + size - 1, size, 0);
+ if (res == NULL) {
+ panic("Cannot allocate resource for config space accesses.");
+ }
+
+ /*
+ * Allocate KVA for accessing PCI config space.
+ */
+ va = kmem_alloc_nofault(kernel_map, PAGE_SIZE * mp_ncpus);
+ if (va == 0) {
+ device_printf(dev, "Cannot allocate virtual addresses for "
+ "config space access.\n");
+ return (ENOMEM);
+ }
+
+ for (n = 0; n < mp_ncpus; ++n) {
+ zbpci_config_space[n].vaddr = va + n * PAGE_SIZE;
+ }
+
+ /*
+ * Sibyte has the PCI bus hierarchy rooted at bus 0 and HT-PCI
+ * hierarchy rooted at bus 1.
+ */
+ if (device_add_child(dev, "pci", 0) == NULL) {
+ panic("zbpci_attach: could not add pci bus 0.\n");
+ }
+
+ if (device_add_child(dev, "pci", 1) == NULL) {
+ panic("zbpci_attach: could not add pci bus 1.\n");
+ }
+
+ if (bootverbose) {
+ device_printf(dev, "attached.\n");
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+zbpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = 0; /* single PCI domain */
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = device_get_unit(child); /* PCI bus 0 or 1 */
+ return (0);
+ default:
+ return (ENOENT);
+ }
+}
+
+/*
+ * We rely on the CFE to have configured the intline correctly to point to
+ * one of PCI-A/PCI-B/PCI-C/PCI-D in the interupt mapper.
+ */
+static int
+zbpci_route_interrupt(device_t pcib, device_t dev, int pin)
+{
+
+ return (PCI_INVALID_IRQ);
+}
+
+/*
+ * This function is expected to be called in a critical section since it
+ * changes the per-cpu pci config space va-to-pa mappings.
+ */
+static vm_offset_t
+zbpci_config_space_va(int bus, int slot, int func, int reg, int bytes)
+{
+ int cpu;
+ vm_offset_t va_page;
+ vm_paddr_t pa, pa_page;
+
+ if (bus <= PCI_BUSMAX && slot <= PCI_SLOTMAX && func <= PCI_FUNCMAX &&
+ reg <= PCI_REGMAX && (bytes == 1 || bytes == 2 || bytes == 4) &&
+ ((reg & (bytes - 1)) == 0)) {
+ cpu = PCPU_GET(cpuid);
+ va_page = zbpci_config_space[cpu].vaddr;
+ pa = CFG_PADDR_BASE |
+ (bus << 16) | (slot << 11) | (func << 8) | reg;
+ pa_page = pa & ~(PAGE_SIZE - 1);
+ if (zbpci_config_space[cpu].paddr != pa_page) {
+ pmap_kremove(va_page);
+ pmap_kenter(va_page, pa_page);
+ zbpci_config_space[cpu].paddr = pa_page;
+ }
+ return (va_page + (pa - pa_page));
+ } else {
+ return (0);
+ }
+}
+
+static uint32_t
+zbpci_read_config(device_t dev, u_int b, u_int s, u_int f, u_int r, int w)
+{
+ uint32_t data;
+ vm_offset_t va;
+
+ critical_enter();
+
+ va = zbpci_config_space_va(b, s, f, r, w);
+ if (va == 0) {
+ panic("zbpci_read_config: invalid %d/%d/%d[%d] %d\n",
+ b, s, f, r, w);
+ }
+
+ switch (w) {
+ case 4:
+ data = *(uint32_t *)va;
+ break;
+ case 2:
+ data = *(uint16_t *)va;
+ break;
+ case 1:
+ data = *(uint8_t *)va;
+ break;
+ default:
+ panic("zbpci_read_config: invalid width %d\n", w);
+ }
+
+ critical_exit();
+
+ return (data);
+}
+
+static void
+zbpci_write_config(device_t d, u_int b, u_int s, u_int f, u_int r,
+ uint32_t data, int w)
+{
+ vm_offset_t va;
+
+ critical_enter();
+
+ va = zbpci_config_space_va(b, s, f, r, w);
+ if (va == 0) {
+ panic("zbpci_write_config: invalid %d/%d/%d[%d] %d/%d\n",
+ b, s, f, r, data, w);
+ }
+
+ switch (w) {
+ case 4:
+ *(uint32_t *)va = data;
+ break;
+ case 2:
+ *(uint16_t *)va = data;
+ break;
+ case 1:
+ *(uint8_t *)va = data;
+ break;
+ default:
+ panic("zbpci_write_config: invalid width %d\n", w);
+ }
+
+ critical_exit();
+}
+
+static device_method_t zbpci_methods[] ={
+ /* Device interface */
+ DEVMETHOD(device_probe, zbpci_probe),
+ DEVMETHOD(device_attach, zbpci_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_read_ivar, zbpci_read_ivar),
+ DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_add_child, bus_generic_add_child),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, pcib_maxslots),
+ DEVMETHOD(pcib_read_config, zbpci_read_config),
+ DEVMETHOD(pcib_write_config, zbpci_write_config),
+ DEVMETHOD(pcib_route_interrupt, zbpci_route_interrupt),
+
+ { 0, 0 }
+};
+
+/*
+ * The "zbpci" class inherits from the "pcib" base class. Therefore in
+ * addition to drivers that belong to the "zbpci" class we will also
+ * consider drivers belonging to the "pcib" when probing children of
+ * "zbpci".
+ */
+DECLARE_CLASS(pcib_driver);
+DEFINE_CLASS_1(zbpci, zbpci_driver, zbpci_methods, 0, pcib_driver);
+
+static devclass_t zbpci_devclass;
+
+DRIVER_MODULE(zbpci, zbbus, zbpci_driver, zbpci_devclass, 0, 0);
More information about the freebsd-mips
mailing list