summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4u
diff options
context:
space:
mode:
authorgd78059 <none@none>2007-04-30 10:50:04 -0700
committergd78059 <none@none>2007-04-30 10:50:04 -0700
commit1c42de6d020629af774dd9e9fc81be3f3ed9398e (patch)
tree15cbf9112a829bff65ac3785ece9f853d9923b34 /usr/src/uts/sun4u
parentd937e6eba72212175f797019b27df74950ec78cd (diff)
downloadillumos-joyent-1c42de6d020629af774dd9e9fc81be3f3ed9398e.tar.gz
6393470 move driver bscbus to usr/src
6393471 move driver bscv to usr/src 6393472 move driver gptwo_cpu to usr/src 6393474 move driver gptwocfg to usr/src 6393478 move driver todstarcat to usr/src 6393479 move driver i2bsc to usr/src 6393481 move driver todm5819p_rmc to usr/src
Diffstat (limited to 'usr/src/uts/sun4u')
-rw-r--r--usr/src/uts/sun4u/Makefile.files7
-rw-r--r--usr/src/uts/sun4u/Makefile.sun4u.shared8
-rw-r--r--usr/src/uts/sun4u/blade/Makefile.blade.shared6
-rw-r--r--usr/src/uts/sun4u/blade/Makefile.files9
-rw-r--r--usr/src/uts/sun4u/blade/bscbus/Makefile100
-rw-r--r--usr/src/uts/sun4u/blade/bscv/Makefile94
-rw-r--r--usr/src/uts/sun4u/blade/io/bscbus.conf31
-rw-r--r--usr/src/uts/sun4u/blade/io/bscv.conf33
-rw-r--r--usr/src/uts/sun4u/gptwo_cpu/Makefile115
-rw-r--r--usr/src/uts/sun4u/gptwocfg/Makefile95
-rw-r--r--usr/src/uts/sun4u/i2bsc/Makefile112
-rw-r--r--usr/src/uts/sun4u/io/gptwo_cpu.c1023
-rw-r--r--usr/src/uts/sun4u/io/gptwocfg.c683
-rw-r--r--usr/src/uts/sun4u/io/i2c/nexus/i2bsc.c1257
-rw-r--r--usr/src/uts/sun4u/io/i2c/nexus/i2bsc.conf31
-rw-r--r--usr/src/uts/sun4u/io/todm5819p_rmc.c409
-rw-r--r--usr/src/uts/sun4u/io/todstarcat.c263
-rw-r--r--usr/src/uts/sun4u/todm5819p_rmc/Makefile89
-rw-r--r--usr/src/uts/sun4u/todstarcat/Makefile88
19 files changed, 4441 insertions, 12 deletions
diff --git a/usr/src/uts/sun4u/Makefile.files b/usr/src/uts/sun4u/Makefile.files
index 96cadbd9c8..04564949c8 100644
--- a/usr/src/uts/sun4u/Makefile.files
+++ b/usr/src/uts/sun4u/Makefile.files
@@ -20,7 +20,7 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -133,6 +133,9 @@ PMUBUS_OBJS += pmubus.o
PMUGPIO_OBJS += pmugpio.o
PMC_OBJS += pmc.o
TRAPSTAT_OBJS += trapstat.o
+I2BSC_OBJS += i2bsc.o
+GPTWOCFG_OBJS += gptwocfg.o
+GPTWO_CPU_OBJS += gptwo_cpu.o
WRSM_OBJS += wci_common.o \
wrsm_barrier.o \
wrsm_cf.o \
@@ -182,8 +185,10 @@ TODMOSTEK_OBJS += todmostek.o
TODDS1287_OBJS += todds1287.o
TODDS1337_OBJS += todds1337.o
TODSTARFIRE_OBJS += todstarfire.o
+TODSTARCAT_OBJS += todstarcat.o
TODBLADE_OBJS += todblade.o
TODM5819_OBJS += todm5819.o
+TODM5819P_RMC_OBJS += todm5819p_rmc.o
TODBQ4802_OBJS += todbq4802.o
TODSG_OBJS += todsg.o
TODOPL_OBJS = todopl.o
diff --git a/usr/src/uts/sun4u/Makefile.sun4u.shared b/usr/src/uts/sun4u/Makefile.sun4u.shared
index c77a378664..618b59d3d2 100644
--- a/usr/src/uts/sun4u/Makefile.sun4u.shared
+++ b/usr/src/uts/sun4u/Makefile.sun4u.shared
@@ -405,9 +405,9 @@ DRV_KMODS += rmclomv
DRV_KMODS += wrsmd
DRV_KMODS += sf
DRV_KMODS += nxge
+DRV_KMODS += i2bsc
$(CLOSED_BUILD)CLOSED_DRV_KMODS += ctsmc
-$(CLOSED_BUILD)CLOSED_DRV_KMODS += i2bsc
$(CLOSED_BUILD)CLOSED_DRV_KMODS += m1535ppm
$(CLOSED_BUILD)CLOSED_DRV_KMODS += memtest
$(CLOSED_BUILD)CLOSED_DRV_KMODS += mi2cv
@@ -448,14 +448,13 @@ MISC_KMODS += sbd
MISC_KMODS += opl_cfg
MISC_KMODS += kmech_krb5
MISC_KMODS += zuluvm
+MISC_KMODS += gptwo_cpu gptwocfg
#
# Brand modules
#
BRAND_KMODS += sn1_brand
-$(CLOSED_BUILD)CLOSED_MISC_KMODS += gptwo_cpu gptwocfg
-
#
# Software Cryptographic Providers (/kernel/crypto):
#
@@ -491,8 +490,9 @@ CPU_KMODS += cheetah cheetahplus jalapeno serrano spitfire hummingbird
#
TOD_KMODS += todds1287 todds1337 todmostek todstarfire
TOD_KMODS += todm5819 todblade todbq4802 todsg todopl
+TOD_KMODS += todm5819p_rmc todstarcat
-$(CLOSED_BUILD)CLOSED_TOD_KMODS += todm5819p_rmc todstarcat todm5823
+$(CLOSED_BUILD)CLOSED_TOD_KMODS += todm5823
#
# Performance Counter BackEnd Modules (/usr/kernel/pcbe):
diff --git a/usr/src/uts/sun4u/blade/Makefile.blade.shared b/usr/src/uts/sun4u/blade/Makefile.blade.shared
index 6e24b19f6f..a89230bde3 100644
--- a/usr/src/uts/sun4u/blade/Makefile.blade.shared
+++ b/usr/src/uts/sun4u/blade/Makefile.blade.shared
@@ -21,7 +21,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# Global definitions for sun4u jbos-blade implementation specific modules.
@@ -89,8 +89,8 @@ include $(UTSTREE)/sun4u/Makefile.sun4u
# Define modules (must come after Makefile.sun4u, for CLOSED_BUILD).
#
BLADE_KMODS = platmod
-$(CLOSED_BUILD)CLOSED_BLADE_KMODS += bscbus
-$(CLOSED_BUILD)CLOSED_BLADE_KMODS += bscv
+BLADE_KMODS += bscbus
+BLADE_KMODS += bscv
LINTS_DIR = $(OBJS_DIR)
LINT_LIB_DIR = $(UTSBASE)/$(PLATFORM)/blade/lint-libs/$(OBJS_DIR)
diff --git a/usr/src/uts/sun4u/blade/Makefile.files b/usr/src/uts/sun4u/blade/Makefile.files
index d834db1711..e28eaae1e6 100644
--- a/usr/src/uts/sun4u/blade/Makefile.files
+++ b/usr/src/uts/sun4u/blade/Makefile.files
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
#
#pragma ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This Makefile defines all file modules for the directory
@@ -33,6 +32,8 @@
#
# Object lists
#
+BSCBUS_OBJS = bscbus.o
+BSCV_OBJS = bscv.o
#
# Miscellaneous
diff --git a/usr/src/uts/sun4u/blade/bscbus/Makefile b/usr/src/uts/sun4u/blade/bscbus/Makefile
new file mode 100644
index 0000000000..916901075b
--- /dev/null
+++ b/usr/src/uts/sun4u/blade/bscbus/Makefile
@@ -0,0 +1,100 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# uts/sun4u/blade/bscbus/Makefile
+#
+# This makefile drives the production of the bscbus driver kernel
+# module in the sun4u blade systems
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = bscbus
+OBJECTS = $(BSCBUS_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(BSCBUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_BLADE_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/sun4u/blade/io
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/blade/Makefile.blade
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY) $(SRC_CONFILE)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# Overrides
+#
+ALL_BUILDS = $(ALL_BUILDSONLY64)
+DEF_BUILDS = $(DEF_BUILDSONLY64)
+CLEANLINTFILES += $(LINT32_FILES)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS += -dalign
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4u/blade/Makefile.targ
diff --git a/usr/src/uts/sun4u/blade/bscv/Makefile b/usr/src/uts/sun4u/blade/bscv/Makefile
new file mode 100644
index 0000000000..6c95f9e137
--- /dev/null
+++ b/usr/src/uts/sun4u/blade/bscv/Makefile
@@ -0,0 +1,94 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the sun4u "bscv" driver module.
+#
+# sun4u implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = bscv
+OBJECTS = $(BSCV_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(BSCV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_BLADE_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/sun4u/blade/io
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/blade/Makefile.blade
+
+#
+# Overrides
+#
+ALL_BUILDS = $(ALL_BUILDSONLY64)
+DEF_BUILDS = $(DEF_BUILDSONLY64)
+CLEANLINTFILES += $(LINT32_FILES)
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY) $(SRC_CONFFILE)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4u/blade/Makefile.targ
diff --git a/usr/src/uts/sun4u/blade/io/bscbus.conf b/usr/src/uts/sun4u/blade/io/bscbus.conf
new file mode 100644
index 0000000000..a00c7f80f6
--- /dev/null
+++ b/usr/src/uts/sun4u/blade/io/bscbus.conf
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2002 Sun Microsystems, Inc.
+# All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Configuration file for "bscbus" driver
+#
+
+interrupt-priorities = 8, 8, 8, 8;
diff --git a/usr/src/uts/sun4u/blade/io/bscv.conf b/usr/src/uts/sun4u/blade/io/bscv.conf
new file mode 100644
index 0000000000..238e0ff7f3
--- /dev/null
+++ b/usr/src/uts/sun4u/blade/io/bscv.conf
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Configuration file for bscv driver
+#
+
+#
+# The DEBUG version of the bscv driver supports a debug option value.
+#
+debug=0x0;
diff --git a/usr/src/uts/sun4u/gptwo_cpu/Makefile b/usr/src/uts/sun4u/gptwo_cpu/Makefile
new file mode 100644
index 0000000000..06bb109a42
--- /dev/null
+++ b/usr/src/uts/sun4u/gptwo_cpu/Makefile
@@ -0,0 +1,115 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sun4u/gptwo_cpu/Makefile
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the cpu portion of
+# of the Safari Configurator.
+#
+# sun4u implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = gptwo_cpu
+OBJECTS = $(GPTWO_CPU_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(GPTWO_CPU_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+
+# Turn this on once compiler understands v9 in it's backend
+#INLINES += $(UTSBASE)/sun4u/io/gptwo_cpu.il
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS += -dalign
+
+#
+# Pick up defines in cheetahregs.h.
+#
+CFLAGS += -DCHEETAH_PLUS
+LINTFLAGS += -DCHEETAH_PLUS
+
+#
+# module dependencies
+#
+LDFLAGS += -dy -Nmisc/gptwocfg
+
+#
+# For now, disable these lint checks; maintainers should endeavor
+# to investigate and remove these for maximum lint coverage.
+# Please do not carry these forward to new Makefiles.
+#
+LINTTAGS += -erroff=E_STATIC_UNUSED
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4u/Makefile.targ
diff --git a/usr/src/uts/sun4u/gptwocfg/Makefile b/usr/src/uts/sun4u/gptwocfg/Makefile
new file mode 100644
index 0000000000..5fc69800a4
--- /dev/null
+++ b/usr/src/uts/sun4u/gptwocfg/Makefile
@@ -0,0 +1,95 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sun4u/gptwocfg/Makefile
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the gptwocfg Safari Configurator
+#
+# sun4u implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = gptwocfg
+OBJECTS = $(GPTWOCFG_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(GPTWOCFG_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+# Turn this on once compiler understands v9 in it's backend
+#INLINES += $(UTSBASE)/sun4u/io/gptwocfg.il
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# Turn on doubleword alignment for 64 bit registers
+#
+CFLAGS += -dalign
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4u/Makefile.targ
diff --git a/usr/src/uts/sun4u/i2bsc/Makefile b/usr/src/uts/sun4u/i2bsc/Makefile
new file mode 100644
index 0000000000..0c984165b1
--- /dev/null
+++ b/usr/src/uts/sun4u/i2bsc/Makefile
@@ -0,0 +1,112 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+# This makefile drives the production of the i2bsc nexus driver.
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = i2bsc
+OBJECTS = $(I2BSC_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(I2BSC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/sun4u/io/i2c/nexus
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE) -I$(UTSBASE)/sun4u
+
+LDFLAGS += -dy -N misc/i2c_svc
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# For now, disable these lint checks; maintainers should endeavor
+# to investigate and remove these for maximum lint coverage.
+# Please do not carry these forward to new Makefiles.
+#
+LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN
+LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW
+LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV
+
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Defines for local commands.
+#
+WLCC = wlcc
+TOUCH = touch
+WARLOCK = warlock
+
+#
+# Warlock targets
+#
+
+I2BSC = $(I2BSC_OBJS:%.o=%.ll)
+
+warlock: $(MODULE).ok
+
+%.ok: $(I2BSC_FILES)
+ $(TOUCH) $@
+
+%.ll: $(UTSBASE)/sun4u/io/i2c/nexus/i2bsc/%.c
+ $(WLCC) $(CFLAGS) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+#
+# Include common targets
+#
+include $(UTSBASE)/sun4u/Makefile.targ
diff --git a/usr/src/uts/sun4u/io/gptwo_cpu.c b/usr/src/uts/sun4u/io/gptwo_cpu.c
new file mode 100644
index 0000000000..c6b87a99b2
--- /dev/null
+++ b/usr/src/uts/sun4u/io/gptwo_cpu.c
@@ -0,0 +1,1023 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * CPU functions to the Safari Configurator (gptwo_cpu)
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/mman.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/autoconf.h>
+#include <sys/ksynch.h>
+#include <sys/promif.h>
+#include <sys/ndi_impldefs.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/machsystm.h>
+#include <sys/gp2cfg.h>
+#include <sys/gptwo_cpu.h>
+#include <sys/cheetahregs.h>
+
+#ifdef DEBUG
+int gptwo_cpu_debug = 0;
+
+static void debug(char *, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t, uintptr_t);
+
+#define GPTWO_DEBUG0(level, flag, s) if (gptwo_cpu_debug >= level) \
+ cmn_err(flag, s)
+#define GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwo_cpu_debug >= level) \
+ debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
+#define GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwo_cpu_debug >= level) \
+ debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
+#define GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
+ if (gptwo_cpu_debug >= level) \
+ debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
+#else
+#define GPTWO_DEBUG0(level, flag, s)
+#define GPTWO_DEBUG1(level, flag, fmt, a1)
+#define GPTWO_DEBUG2(level, flag, fmt, a1, a2)
+#define GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
+#endif
+
+/*
+ * Devinfo branch create arg
+ */
+struct bca {
+ spcd_t *pcd;
+ uint_t portid;
+ uint_t cpuid;
+ uint_t coreid;
+ uint_t impl;
+ dev_info_t *new_child;
+};
+
+static dev_info_t *gptwocfg_create_cpu_node(dev_info_t *, spcd_t *,
+ uint_t, uint_t, uint_t, uint_t);
+static dev_info_t *gptwocfg_create_mc_node(dev_info_t *, spcd_t *, uint_t);
+static dev_info_t *gptwocfg_create_cmp_node(dev_info_t *, spcd_t *, uint_t);
+static int gptwocfg_create_core_node(dev_info_t *, spcd_t *, uint_t, uint_t);
+static int set_mc_props(dev_info_t *new_child, void *arg, uint_t flags);
+static int set_cmp_props(dev_info_t *new_child, void *arg, uint_t flags);
+static int set_cpu_props(dev_info_t *new_child, void *arg, uint_t flags);
+static int set_cpu_common_props(dev_info_t *new_child, struct bca *bcp);
+static int set_cpu_us3_props(dev_info_t *new_child, struct bca *bcp);
+static int set_cpu_us4_props(dev_info_t *new_child, struct bca *bcp);
+static void get_new_child(dev_info_t *rdip, void *arg, uint_t flags);
+
+
+/*
+ * Module linkage information for the kernel.
+ */
+
+extern struct mod_ops mod_miscops;
+
+static struct modlmisc modlmisc = {
+ &mod_miscops, /* Type of module */
+ "gptwo->cpu configurator %I%",
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, (void *)&modlmisc, NULL
+};
+
+int
+_init(void)
+{
+ int err = 0;
+
+ /* register device with the configurator */
+ gptwocfg_register_ops(SAFPTYPE_CPU, gptwocfg_configure_cpu, NULL);
+
+ if ((err = mod_install(&modlinkage)) != 0) {
+ GPTWO_DEBUG1(1, CE_WARN, "gptwo_cpu (CPU/MC Functions) "
+ "failed to load, error=%d\n", err);
+ gptwocfg_unregister_ops(SAFPTYPE_CPU);
+ } else {
+ GPTWO_DEBUG0(1, CE_WARN, "gptwo_cpu (CPU/MC Functions) "
+ "has been loaded.\n");
+ }
+ return (err);
+}
+
+int
+_fini(void)
+{
+ /* cleanup/freeup structs with configurator */
+ gptwocfg_unregister_ops(SAFPTYPE_CPU);
+ return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+gptwo_new_nodes_t *
+gptwocfg_configure_cpu(dev_info_t *ap, spcd_t *pcd, uint_t portid)
+{
+ dev_info_t *cpu_node[AGENTS_PER_PORT], *mc_node[AGENTS_PER_PORT];
+ dev_info_t *cmp_node = NULL;
+ gptwo_new_nodes_t *new_nodes;
+ int nodes = 0;
+ int i, j = 0;
+ uint_t implementation;
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_configure_cpu: portid=%x pcd=%lx\n",
+ portid, pcd);
+
+ for (i = 0; i < AGENTS_PER_PORT; i++) {
+ cpu_node[i] = NULL;
+ mc_node[i] = NULL;
+ }
+
+ implementation = (pcd->spcd_ver_reg >> 32) & 0x000000000000ffff;
+
+ switch (implementation) {
+ case CHEETAH_IMPL:
+ case CHEETAH_PLUS_IMPL:
+ case JAGUAR_IMPL:
+ case PANTHER_IMPL:
+ break;
+ default:
+ cmn_err(CE_WARN, "Unsupported cpu implementation=0x%x : "
+ "skipping configure of portid=0x%x", implementation,
+ portid);
+ ASSERT(0);
+ return (NULL);
+ }
+
+ if (CPU_IMPL_IS_CMP(implementation)) {
+ if (cmp_node = gptwocfg_create_cmp_node(ap, pcd, portid))
+ nodes++;
+ else
+ return (NULL);
+ }
+
+ for (i = 0; i < AGENTS_PER_PORT; i++) {
+ if (pcd->spcd_agent[i] != SPCD_RSV_PASS)
+ continue;
+
+ if (cpu_node[i] = gptwocfg_create_cpu_node(cmp_node ?
+ cmp_node : ap, pcd, portid, pcd->spcd_cpuid[i], i,
+ implementation)) {
+ /*
+ * If the CPU is a CMP, the entire branch is
+ * manipulated using just the top node. Thus,
+ * the dips of the individual cores do not need
+ * to be held or stored in the new node list.
+ */
+ if (cmp_node) {
+ e_ddi_branch_rele(cpu_node[i]);
+ } else {
+ nodes++;
+ }
+ }
+ }
+
+ /* current implementations have 1 MC node per Safari port */
+ if (pcd->spcd_prsv == SPCD_RSV_PASS &&
+ (mc_node[0] = gptwocfg_create_mc_node(ap, pcd, portid)))
+ nodes++;
+
+ new_nodes = gptwocfg_allocate_node_list(nodes);
+
+ j = 0;
+ for (i = 0; i < AGENTS_PER_PORT; i++) {
+ if ((cpu_node[i] != NULL) && (!CPU_IMPL_IS_CMP(implementation)))
+ new_nodes->gptwo_nodes[j++] = cpu_node[i];
+ if (mc_node[i] != NULL)
+ new_nodes->gptwo_nodes[j++] = mc_node[i];
+ }
+
+ if (cmp_node)
+ new_nodes->gptwo_nodes[j++] = cmp_node;
+
+ return (new_nodes);
+}
+
+
+static dev_info_t *
+gptwocfg_create_cmp_node(dev_info_t *ap, spcd_t *pcd, uint_t portid)
+{
+ struct bca arg;
+ devi_branch_t b;
+
+ arg.pcd = pcd;
+ arg.portid = portid;
+ arg.cpuid = 0;
+ arg.coreid = 0;
+ arg.new_child = NULL;
+
+ b.arg = &arg;
+ b.type = DEVI_BRANCH_SID;
+ b.create.sid_branch_create = set_cmp_props;
+ b.devi_branch_callback = get_new_child;
+
+ if (e_ddi_branch_create(ap, &b, NULL, 0))
+ return (NULL);
+
+ return (arg.new_child);
+}
+
+/*ARGSUSED*/
+static int
+set_cmp_props(dev_info_t *new_child, void *arg, uint_t flags)
+{
+ struct bca *bap = (struct bca *)arg;
+ gptwo_regspec_t reg;
+ spcd_t *pcd;
+ uint_t portid;
+
+ pcd = bap->pcd;
+ portid = bap->portid;
+
+ GPTWO_DEBUG2(1, CE_CONT, "set_cmp_props: portid=%x pcd=%lx\n",
+ portid, pcd);
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "name", "cmp") != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cmp_props: failed to "
+ "create name property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "portid", portid) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cmp_props: failed to "
+ "create portid property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ reg.gptwo_phys_hi = 0x400 | (portid >> 9);
+ reg.gptwo_phys_low = (portid << 23);
+ reg.gptwo_size_hi = 0;
+ reg.gptwo_size_low = 0x10000;
+
+ if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
+ new_child, "reg", (int *)&reg,
+ sizeof (gptwo_regspec_t) / sizeof (int)) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cmp_props: failed to "
+ "create reg property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ return (DDI_WALK_TERMINATE);
+}
+
+static dev_info_t *
+gptwocfg_create_cpu_node(dev_info_t *ap, spcd_t *pcd, uint_t portid,
+ uint_t cpuid, uint_t coreid, uint_t impl)
+{
+ struct bca arg;
+ devi_branch_t b = {0};
+
+ arg.pcd = pcd;
+ arg.portid = portid;
+ arg.cpuid = cpuid;
+ arg.coreid = coreid;
+ arg.impl = impl;
+ arg.new_child = NULL;
+
+ b.arg = &arg;
+ b.type = DEVI_BRANCH_SID;
+ b.create.sid_branch_create = set_cpu_props;
+ b.devi_branch_callback = get_new_child;
+
+ if (e_ddi_branch_create(ap, &b, NULL, 0))
+ return (NULL);
+
+ return (arg.new_child);
+}
+
+/*ARGSUSED*/
+static int
+set_cpu_props(dev_info_t *new_child, void *arg, uint_t flags)
+{
+ struct bca *bcp = arg;
+ uint_t impl = bcp->impl;
+ int rc;
+
+ if (set_cpu_common_props(new_child, bcp) != DDI_WALK_CONTINUE)
+ return (DDI_WALK_ERROR);
+
+ switch (impl) {
+ case CHEETAH_IMPL:
+ case CHEETAH_PLUS_IMPL:
+ rc = set_cpu_us3_props(new_child, bcp);
+ break;
+ case JAGUAR_IMPL:
+ case PANTHER_IMPL:
+ rc = set_cpu_us4_props(new_child, bcp);
+ break;
+ default:
+ ASSERT(0);
+ return (DDI_WALK_ERROR);
+ }
+
+ return (rc);
+}
+
+/*
+ * Set properties common to cpu (non-CMP) and core (CMP) nodes.
+ *
+ * cpuid
+ * device_type
+ * manufacturer#
+ * implementation#
+ * mask#
+ * sparc-version
+ * clock-frequency
+ * #dtlb-entries
+ * #itlb-entries
+ */
+static int
+set_cpu_common_props(dev_info_t *new_child, struct bca *bcp)
+{
+ uint_t cpuid, impl;
+ spcd_t *pcd;
+ int mask, manufacturer;
+
+ cpuid = bcp->cpuid;
+ pcd = bcp->pcd;
+ impl = bcp->impl;
+
+ mask = (pcd->spcd_ver_reg >> 24) & 0x00000000000000ff;
+ manufacturer = (pcd->spcd_ver_reg >> 48) & 0x000000000000ffff;
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "cpuid", cpuid) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create cpuid property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "device_type", "cpu") != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create device_type property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child, "manufacturer#",
+ manufacturer) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create manufacturer# property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child, "implementation#",
+ impl) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create implementation# property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child, "mask#",
+ mask) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create mask# property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "sparc-version", 9) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create sparc-version property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "clock-frequency", (pcd->spcd_afreq * 1000000)) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create clock-frequency property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "#dtlb-entries", 0x10) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create #dtlb-entries property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "#itlb-entries", 0x10) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_common_props: failed "
+ "to create #itlb-entries property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * Set cpu node properties for Cheetah and Cheetah+.
+ *
+ * name
+ * portid
+ * reg
+ * icache-size
+ * icache-line-size
+ * icache-associativity
+ * dcache-size
+ * dcache-line-size
+ * dcache-associativity
+ * ecache-size
+ * ecache-line-size
+ * ecache-associativity
+ */
+static int
+set_cpu_us3_props(dev_info_t *new_child, struct bca *bcp)
+{
+ char *node_name;
+ gptwo_regspec_t reg;
+ int ecache_size, ecache_line_size;
+ int dimms, ecache_assoc;
+ spcd_t *pcd;
+ uint_t portid, impl;
+
+ pcd = bcp->pcd;
+ portid = bcp->portid;
+ impl = bcp->impl;
+
+ ASSERT(IS_CHEETAH(impl) || IS_CHEETAH_PLUS(impl));
+
+ switch (impl) {
+ case CHEETAH_IMPL:
+ ecache_assoc = CH_ECACHE_NWAY;
+ node_name = "SUNW,UltraSPARC-III";
+ break;
+ case CHEETAH_PLUS_IMPL:
+ /*
+ * Hard coding the ecache-associativity to 2 for Cheetah+.
+ * We probably should add this to the PCD.
+ */
+ ecache_assoc = CHP_ECACHE_NWAY;
+ node_name = "SUNW,UltraSPARC-III+";
+ break;
+ default:
+ GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us3_props: invalid "
+ "implementation=0x%x\n", impl);
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "name", node_name) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create name property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "portid", portid) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create portid property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ reg.gptwo_phys_hi = 0x400 | (portid >> 9);
+ reg.gptwo_phys_low = (portid << 23);
+ reg.gptwo_size_hi = 0;
+ reg.gptwo_size_low = 0x10000;
+
+ if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
+ new_child, "reg", (int *)&reg,
+ sizeof (gptwo_regspec_t) / sizeof (int)) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create reg property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "icache-size", CH_ICACHE_SIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create icache-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "icache-line-size", CH_ICACHE_LSIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create icache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "icache-associativity", CH_ICACHE_NWAY) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create icache-associativity property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "dcache-size", CH_DCACHE_SIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create dcache-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "dcache-line-size", CH_DCACHE_LSIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create dcache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "dcache-associativity", CH_DCACHE_NWAY) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create dcache-associativity property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ /*
+ * Get the External Cache Size from the Common PCD.
+ */
+ ecache_size = pcd->spcd_cache * 0x100000;
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "ecache-size", ecache_size) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create ecache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ switch (ecache_size) {
+ case CH_ECACHE_1M_SIZE:
+ ecache_line_size = 64;
+ break;
+ case CH_ECACHE_4M_SIZE:
+ ecache_line_size = 256;
+ break;
+ case CH_ECACHE_8M_SIZE:
+ ecache_line_size = 512;
+ break;
+ default:
+ GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us3_props: invalid "
+ "ecache-size 0x%x\b", ecache_size);
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "ecache-line-size", ecache_line_size) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create ecache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "ecache-associativity", ecache_assoc) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us3_props: failed "
+ "to create ecache-associativity property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ /*
+ * Create the ecache-dimm-label property.
+ */
+ dimms = 0;
+
+ while ((pcd->sprd_ecache_dimm_label[dimms] != NULL) &&
+ (dimms < MAX_DIMMS_PER_PORT))
+ dimms++;
+
+ if (dimms) {
+ (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
+ "ecache-dimm-label", (char **)pcd->sprd_ecache_dimm_label,
+ dimms);
+ }
+
+ return (DDI_WALK_TERMINATE);
+}
+
+/*
+ * Set cmp core node properties for Jaguar and Panther.
+ *
+ * name
+ * compatible
+ * reg
+ * l1-icache-size
+ * l1-icache-line-size
+ * l1-icache-associativity
+ * l1-dcache-size
+ * l1-dcache-line-size
+ * l1-dcache-associativity
+ * l2-cache-size
+ * l2-cache-line-size
+ * l2-cache-associativity
+ * l2-cache-sharing
+ * l3-cache-size
+ * l3-cache-line-size
+ * l3-cache-associativity
+ * l3-cache-sharing
+ */
+static int
+set_cpu_us4_props(dev_info_t *new_child, struct bca *bcp)
+{
+ uint_t l1_icache_size, l1_icache_line_size;
+ uint_t l2_cache_size, l2_cache_line_size, l2_cache_assoc;
+ uint_t l2_cache_share;
+ uint_t pcd_cache_size;
+ uint_t coreid, impl;
+ spcd_t *pcd;
+ char *compatible;
+ int dimms;
+ int i;
+
+ pcd = bcp->pcd;
+ coreid = bcp->coreid;
+ impl = bcp->impl;
+
+ ASSERT(IS_JAGUAR(impl) || IS_PANTHER(impl));
+
+ /*
+ * Get the External Cache Size from the Common PCD.
+ */
+ pcd_cache_size = pcd->spcd_cache * 0x100000;
+
+ switch (impl) {
+ case JAGUAR_IMPL:
+ compatible = "SUNW,UltraSPARC-IV";
+ l1_icache_size = CH_ICACHE_SIZE;
+ l1_icache_line_size = CH_ICACHE_LSIZE;
+ l2_cache_assoc = CHP_ECACHE_NWAY;
+
+ /*
+ * Jaguar has no logical sharing of L2 cache, so the sharing
+ * bit-map will represent this core only.
+ */
+ l2_cache_share = coreid ? 0x2 : 0x1;
+
+ /*
+ * Jaguar has a split ecache, so the total ecache must be
+ * divided in half to get the ecache for the individual core.
+ */
+ l2_cache_size = pcd_cache_size / 2;
+
+ switch (l2_cache_size) {
+ case JG_ECACHE_4M_SIZE:
+ l2_cache_line_size = 64;
+ break;
+ case JG_ECACHE_8M_SIZE:
+ l2_cache_line_size = 128;
+ break;
+ default:
+ GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us4_props: "
+ "invalid l2_cache-size 0x%x\n", l2_cache_size);
+ return (DDI_WALK_ERROR);
+ }
+ break;
+ case PANTHER_IMPL:
+ ASSERT(pcd_cache_size == PN_L3_SIZE);
+ compatible = "SUNW,UltraSPARC-IV+";
+ l1_icache_size = PN_ICACHE_SIZE;
+ l1_icache_line_size = PN_ICACHE_LSIZE;
+ l2_cache_size = PN_L2_SIZE;
+ l2_cache_line_size = PN_L2_LINESIZE;
+ l2_cache_assoc = PN_ECACHE_NWAY;
+
+ /*
+ * For Panther, the L2 and L3 caches are logically shared by
+ * all enabled cores, so the sharing bit-map will represent
+ * all enabled cores. Panther split-mode is still considered
+ * shared.
+ *
+ * Check the PCD status to determine enabled cores.
+ */
+ ASSERT(pcd->spcd_ptype == SAFPTYPE_CPU);
+ l2_cache_share = 0;
+ for (i = 0; i < AGENTS_PER_PORT; i++) {
+ if (pcd->spcd_agent[i] == SPCD_RSV_PASS) {
+ l2_cache_share |= (1 << i);
+ }
+ }
+
+ break;
+ default:
+ GPTWO_DEBUG1(1, CE_CONT, "set_cpu_us4_props: invalid "
+ "implementation=0x%x\n", impl);
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "name", "cpu") != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create name property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "compatible", compatible) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create compatible property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "reg", coreid) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create reg property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l1-icache-size", l1_icache_size) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l1-icache-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l1-icache-line-size", l1_icache_line_size) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create icache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l1-icache-associativity", CH_ICACHE_NWAY) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l1-icache-associativity property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l1-dcache-size", CH_DCACHE_SIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l1-dcache-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l1-dcache-line-size", CH_DCACHE_LSIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create dcache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l1-dcache-associativity", CH_DCACHE_NWAY) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l1-dcache-associativity property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l2-cache-size", l2_cache_size) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l2-cache-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l2-cache-line-size", l2_cache_line_size) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l2_cache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l2-cache-associativity", l2_cache_assoc) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l2-cache-associativity property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l2-cache-sharing", l2_cache_share) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: failed "
+ "to create l2-cache-sharing property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ /*
+ * Create the ecache-dimm-label property.
+ */
+ dimms = 0;
+
+ while ((pcd->sprd_ecache_dimm_label[dimms] != NULL) &&
+ (dimms < MAX_DIMMS_PER_PORT))
+ dimms++;
+
+ if (dimms) {
+ (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
+ "ecache-dimm-label", (char **)pcd->sprd_ecache_dimm_label,
+ dimms);
+ }
+
+ if (IS_PANTHER(impl)) {
+ int l3_cache_share = l2_cache_share;
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l3-cache-size", PN_L3_SIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
+ "failed to create l3-cache-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l3-cache-line-size", PN_L3_LINESIZE) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
+ "failed to create l3-cache-line-size property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l3-cache-associativity", PN_ECACHE_NWAY) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
+ "failed to create l3-cache-associativity "
+ "property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "l3-cache-sharing", l3_cache_share) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_cpu_us4_props: "
+ "failed to create l3-cache-sharing property\n");
+ return (DDI_WALK_ERROR);
+ }
+ }
+
+ return (DDI_WALK_TERMINATE);
+}
+
+static dev_info_t *
+gptwocfg_create_mc_node(dev_info_t *ap, spcd_t *pcd, uint_t portid)
+{
+ struct bca arg;
+ devi_branch_t b = {0};
+
+ arg.pcd = pcd;
+ arg.portid = portid;
+ arg.cpuid = portid;
+ arg.new_child = NULL;
+
+ b.arg = &arg;
+ b.type = DEVI_BRANCH_SID;
+ b.create.sid_branch_create = set_mc_props;
+ b.devi_branch_callback = get_new_child;
+
+ if (e_ddi_branch_create(ap, &b, NULL, 0))
+ return (NULL);
+
+ return (arg.new_child);
+}
+
+/*ARGSUSED*/
+static int
+set_mc_props(dev_info_t *new_child, void *arg, uint_t flags)
+{
+ struct bca *bcp = arg;
+ gptwo_regspec_t reg;
+ int banks, dimms;
+ spcd_t *pcd = bcp->pcd;
+ uint_t portid = bcp->portid;
+ uint_t cpuid = bcp->cpuid;
+
+ GPTWO_DEBUG3(1, CE_CONT, "set_mc_props: ap=0x%lx portid=0x%x "
+ "cpuid=0x%x\n", ddi_get_parent(new_child), portid, cpuid);
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "name", "memory-controller") != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create name property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "compatible", "SUNW,UltraSPARC-III,mc") != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create compatible property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
+ "device_type", "memory-controller") != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create device_type property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "portid", portid) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create portid property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (ndi_prop_update_int(DDI_DEV_T_NONE, new_child,
+ "cpuid", cpuid) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create cpuid property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ reg.gptwo_phys_hi = 0x400 | (portid >> 9);
+ reg.gptwo_phys_low = (portid << 23) | 0x400000;
+ reg.gptwo_size_hi = 0;
+ reg.gptwo_size_low = 0x48;
+
+ if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
+ new_child, "reg", (int *)&reg,
+ sizeof (gptwo_regspec_t) / sizeof (int)) != DDI_SUCCESS) {
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create reg property\n");
+ return (DDI_WALK_ERROR);
+ }
+
+ if (pcd->memory_layout) {
+ if (ndi_prop_update_byte_array(DDI_DEV_T_NONE,
+ new_child, "memory-layout", (uchar_t *)pcd->memory_layout,
+ pcd->memory_layout_size) != DDI_SUCCESS) {
+
+ GPTWO_DEBUG0(1, CE_CONT, "set_mc_props: failed "
+ "to create memory-layout property\n");
+
+ return (DDI_WALK_ERROR);
+ }
+ }
+
+ /*
+ * Create the bank-status property.
+ */
+ banks = 0;
+
+ while ((pcd->sprd_bank_rsv[banks] != NULL) &&
+ (banks < MAX_BANKS_PER_PORT))
+ banks++;
+
+ if (banks) {
+ (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
+ "bank-status", (char **)pcd->sprd_bank_rsv, banks);
+ }
+
+ /*
+ * Create the dimm-status property.
+ */
+ dimms = 0;
+
+ while ((pcd->sprd_dimm[dimms] != NULL) &&
+ (dimms < MAX_DIMMS_PER_PORT))
+ dimms++;
+
+ if (dimms) {
+ (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, new_child,
+ "dimm-status", (char **)pcd->sprd_dimm, dimms);
+ }
+
+
+ return (DDI_WALK_TERMINATE);
+}
+
+/*ARGSUSED*/
+static void
+get_new_child(dev_info_t *rdip, void *arg, uint_t flags)
+{
+ struct bca *bcp = arg;
+
+ bcp->new_child = rdip;
+
+}
+
+#ifdef DEBUG
+static void
+debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
+ uintptr_t a4, uintptr_t a5)
+{
+ cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
+}
+#endif
diff --git a/usr/src/uts/sun4u/io/gptwocfg.c b/usr/src/uts/sun4u/io/gptwocfg.c
new file mode 100644
index 0000000000..e1a2bb6347
--- /dev/null
+++ b/usr/src/uts/sun4u/io/gptwocfg.c
@@ -0,0 +1,683 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Safari Configurator (gptwocfg)
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/mman.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/autoconf.h>
+#include <sys/ksynch.h>
+#include <sys/promif.h>
+#include <sys/ndi_impldefs.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/gp2cfg.h>
+#include <sys/machsystm.h>
+#include <sys/platform_module.h>
+#pragma weak starcat_dr_name
+
+#ifdef DEBUG
+int gptwocfg_debug = 0;
+
+static void debug(char *, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t, uintptr_t);
+
+#define GPTWO_DEBUG0(level, flag, s) if (gptwocfg_debug >= level) \
+ cmn_err(flag, s)
+#define GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwocfg_debug >= level) \
+ debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
+#define GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwocfg_debug >= level) \
+ debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
+#define GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
+ if (gptwocfg_debug >= level) \
+ debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
+#else
+#define GPTWO_DEBUG0(level, flag, s)
+#define GPTWO_DEBUG1(level, flag, fmt, a1)
+#define GPTWO_DEBUG2(level, flag, fmt, a1, a2)
+#define GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
+#endif
+
+kmutex_t gptwo_handle_list_lock;
+gptwocfg_handle_list_t *gptwocfg_handle_list;
+
+static kmutex_t gptwo_config_list_lock;
+static gptwocfg_config_t *gptwo_config_list;
+
+static gptwo_new_nodes_t *
+ gptwocfg_get_obp_created_nodes(dev_info_t *, uint_t);
+
+void (*gptwocfg_unclaim_address)(uint_t);
+
+extern caddr_t efcode_vaddr;
+extern int efcode_size;
+
+#define GPTWO_NUMBER_OF_DEVICE_TYPES 6
+
+static kmutex_t gptwocfg_ops_table_lock;
+gptwocfg_ops_t *gptwocfg_ops_table[GPTWO_NUMBER_OF_DEVICE_TYPES];
+
+/*
+ * Module linkage information for the kernel.
+ */
+
+extern struct mod_ops mod_miscops;
+
+static struct modlmisc modlmisc = {
+ &mod_miscops, /* Type of module */
+ "gptwo configurator %I%",
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, (void *)&modlmisc, NULL
+};
+
+int
+_init(void)
+{
+ unsigned int i;
+
+ GPTWO_DEBUG0(1, CE_WARN, "gptwocfg (Safari Configurator) "
+ "has been loaded\n");
+
+ mutex_init(&gptwo_config_list_lock, NULL, MUTEX_DRIVER, NULL);
+ mutex_init(&gptwocfg_ops_table_lock, NULL, MUTEX_DRIVER, NULL);
+ gptwo_config_list = NULL;
+
+ mutex_init(&gptwo_handle_list_lock, NULL, MUTEX_DRIVER, NULL);
+ gptwocfg_handle_list = NULL;
+
+ for (i = 0; i < GPTWO_NUMBER_OF_DEVICE_TYPES; i++)
+ gptwocfg_ops_table[i] = NULL;
+
+ return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+ int error;
+
+ error = mod_remove(&modlinkage);
+ if (error != 0) {
+ return (error);
+ }
+ mutex_destroy(&gptwo_config_list_lock);
+ mutex_destroy(&gptwocfg_ops_table_lock);
+ mutex_destroy(&gptwo_handle_list_lock);
+
+ return (0);
+}
+
+int
+_info(modinfop)
+struct modinfo *modinfop;
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+gptwo_new_nodes_t *
+gptwocfg_allocate_node_list(int number_of_nodes)
+{
+ gptwo_new_nodes_t *gptwo_new_nodes;
+ int size;
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- %d nodes",
+ number_of_nodes);
+
+ size = sizeof (gptwo_new_nodes_t) +
+ ((number_of_nodes -1) * sizeof (dev_info_t *));
+
+ gptwo_new_nodes = kmem_zalloc(size, KM_SLEEP);
+
+ gptwo_new_nodes->gptwo_number_of_nodes = number_of_nodes;
+ gptwo_new_nodes->gptwo_version = GP2_VERSION;
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- returned %p\n",
+ gptwo_new_nodes);
+
+ return (gptwo_new_nodes);
+}
+
+void
+gptwocfg_free_node_list(gptwo_new_nodes_t *gptwo_new_nodes)
+{
+ int size;
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_free_node_list- %p %d nodes",
+ gptwo_new_nodes, gptwo_new_nodes->gptwo_number_of_nodes);
+
+ size = sizeof (gptwo_new_nodes_t) +
+ ((gptwo_new_nodes->gptwo_number_of_nodes - 1) *
+ sizeof (dev_info_t *));
+
+ kmem_free(gptwo_new_nodes, size);
+}
+
+void
+gptwocfg_register_ops(uint_t type, gptwo_cfgfunc_t *cfg_func,
+ gptwo_uncfgfunc_t *uncfg_func)
+{
+ /* KM_SLEEP guarantees success */
+ gptwocfg_ops_t *ops = kmem_zalloc(sizeof (gptwocfg_ops_t), KM_SLEEP);
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_register_ops: type=%x ops=%lx\n",
+ type, ops);
+ ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
+ ops->gptwocfg_type = type;
+ ops->gptwocfg_version = GPTWOCFG_OPS_VERSION;
+ ops->gptwocfg_configure = cfg_func;
+ ops->gptwocfg_unconfigure = uncfg_func;
+
+ mutex_enter(&gptwocfg_ops_table_lock);
+ gptwocfg_ops_table[type] = ops;
+ mutex_exit(&gptwocfg_ops_table_lock);
+}
+
+
+
+void
+gptwocfg_unregister_ops(uint_t type)
+{
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unregister_ops: type=%x\n", type);
+
+ ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
+
+ mutex_enter(&gptwocfg_ops_table_lock);
+ kmem_free(gptwocfg_ops_table[type], sizeof (gptwocfg_ops_t));
+ gptwocfg_ops_table[type] = NULL;
+ mutex_exit(&gptwocfg_ops_table_lock);
+}
+
+gptwocfg_cookie_t
+gptwocfg_configure(dev_info_t *ap, spcd_t *pcd, gptwo_aid_t id)
+{
+ gptwo_new_nodes_t *new_nodes = NULL;
+ gptwocfg_config_t *config;
+ gptwocfg_ops_t *ops;
+
+ GPTWO_DEBUG3(1, CE_CONT, "gptwocfg_configure: ap=0x%p pcd=%p id=%x\n",
+ ap, pcd, id);
+
+ /*
+ * Look to see if the port is already configured.
+ */
+ mutex_enter(&gptwo_config_list_lock);
+ config = gptwo_config_list;
+ while (config != NULL) {
+ if (&starcat_dr_name) {
+ if (starcat_dr_name(ddi_node_name(ap)) < 0) {
+ config = config->gptwo_next;
+ continue;
+ }
+ }
+ if (config->gptwo_portid == id) {
+ cmn_err(CE_WARN, "gptwocfg: gptwocfg_configure: "
+ "0x%x Port already configured\n", id);
+ mutex_exit(&gptwo_config_list_lock);
+ return (NULL);
+ }
+ config = config->gptwo_next;
+ }
+ mutex_exit(&gptwo_config_list_lock);
+
+ if (pcd == NULL) {
+ GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_configure: pcd=NULL\n");
+ return (NULL);
+ }
+
+ if ((pcd->spcd_magic != PCD_MAGIC) ||
+ (pcd->spcd_version != PCD_VERSION)) {
+ cmn_err(CE_WARN, "gptwocfg: Invalid Port "
+ "Configuration Descriptor\n");
+ return (NULL);
+ }
+
+ if (pcd->spcd_ptype >= GPTWO_NUMBER_OF_DEVICE_TYPES) {
+ cmn_err(CE_WARN,
+ "gptwocfg: Invalid device type %x", pcd->spcd_ptype);
+ return (NULL);
+ }
+
+ if (pcd->spcd_prsv != SPCD_RSV_PASS) {
+ cmn_err(CE_WARN,
+ "gptwocfg: Agent at ID %x has not passed test(s)\n", id);
+ return (NULL);
+ }
+
+ mutex_enter(&gptwocfg_ops_table_lock);
+
+ ops = gptwocfg_ops_table[pcd->spcd_ptype];
+
+ if (ops == NULL) {
+ cmn_err(CE_WARN, "gptwocfg: Ops for type %x have not been "
+ "registered\n", pcd->spcd_ptype);
+ mutex_exit(&gptwocfg_ops_table_lock);
+ return (NULL);
+ }
+
+ if (ops->gptwocfg_configure == NULL) {
+ cmn_err(CE_WARN, "gptwocfg: no configure routine registered "
+ "for sfaari type %x\n", pcd->spcd_ptype);
+ mutex_exit(&gptwocfg_ops_table_lock);
+ return (NULL);
+ }
+
+ new_nodes = ops->gptwocfg_configure(ap, pcd, id);
+
+ mutex_exit(&gptwocfg_ops_table_lock);
+
+ if (new_nodes != NULL) {
+ config = kmem_zalloc(sizeof (gptwocfg_config_t), KM_SLEEP);
+ config->gptwo_version = GP2_VERSION;
+ config->gptwo_ap = ap;
+ config->gptwo_portid = id;
+ config->gptwo_nodes = new_nodes;
+ config->gptwo_ops = ops;
+
+ /*
+ * put config on config list
+ */
+ mutex_enter(&gptwo_config_list_lock);
+ config->gptwo_next = gptwo_config_list;
+ gptwo_config_list = config;
+ mutex_exit(&gptwo_config_list_lock);
+ } else {
+ config = NULL;
+ }
+
+ return ((gptwocfg_cookie_t)config);
+}
+
+gptwocfg_cookie_t
+gptwocfg_unconfigure(dev_info_t *ap, gptwo_aid_t id)
+{
+ int i, circ;
+ int failure = 0;
+ dev_info_t *saf_dip;
+ gptwocfg_config_t *config, *temp;
+ gptwo_new_nodes_t *obp_nodes;
+ gptwocfg_ops_t *ops;
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_unconfigure: ap=0x%p id=0x%lx\n",
+ ap, id);
+
+ mutex_enter(&gptwo_config_list_lock);
+ config = gptwo_config_list;
+ while (config != NULL) {
+ if (config->gptwo_portid == id) {
+ break;
+ }
+ config = config->gptwo_next;
+ }
+ mutex_exit(&gptwo_config_list_lock);
+
+ if (config == NULL) {
+ /*
+ * There is no config structure associated with this agent id
+ * so it was probably built by firmware at start of day. We
+ * need to create a config structure before we can continue.
+ */
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: id=0x%lx "
+ "No config structure - Need to build one\n", id);
+
+ obp_nodes = gptwocfg_get_obp_created_nodes(ap, id);
+
+ if (obp_nodes != NULL) {
+ config = kmem_zalloc(sizeof (gptwocfg_config_t),
+ KM_SLEEP);
+ config->gptwo_version = GP2_VERSION;
+ config->gptwo_ap = ap;
+ config->gptwo_portid = id;
+ config->gptwo_nodes = obp_nodes;
+
+ /*
+ * put config on config list
+ */
+ mutex_enter(&gptwo_config_list_lock);
+ config->gptwo_next = gptwo_config_list;
+ gptwo_config_list = config;
+ mutex_exit(&gptwo_config_list_lock);
+ } else {
+ cmn_err(CE_WARN, "gptwocfg: gptwocfg_unconfigure: "
+ "No OBP created nodes for ap=0x%lx agent id=0x%x",
+ (long)ap, id);
+ return (NULL);
+ }
+ }
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure config=0x%lx\n",
+ config);
+
+ ops = config->gptwo_ops;
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: ops=%lx\n", ops);
+
+ ndi_devi_enter(ap, &circ);
+
+ for (i = 0; i < config->gptwo_nodes->gptwo_number_of_nodes; i++) {
+ dev_info_t *fdip = NULL;
+
+ saf_dip = config->gptwo_nodes->gptwo_nodes[i];
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure saf_dip=0x%lx\n",
+ saf_dip);
+
+ if (saf_dip == NULL) {
+ GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_unconfigure: "
+ "skipping NULLL saf device\n");
+
+ continue;
+ }
+
+ config->gptwo_nodes->gptwo_nodes[i] = NULL;
+
+ if (ops) {
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_configure "
+ "ops->gptwocfg_configure=%lx\n",
+ ops->gptwocfg_configure);
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure "
+ "ops->gptwocfg_unconfigure=%lx\n",
+ ops->gptwocfg_unconfigure);
+
+ if (ops->gptwocfg_unconfigure != NULL) {
+ config->gptwo_nodes->gptwo_nodes[i] =
+ ops->gptwocfg_unconfigure(saf_dip);
+
+ }
+ }
+
+ GPTWO_DEBUG1(1, CE_CONT, "e_ddi_branch_destroy <%s>\n",
+ ddi_get_name(saf_dip));
+
+ ASSERT(e_ddi_branch_held(saf_dip));
+
+ /*
+ * Don't hold parent busy when calling
+ * e_ddi_branch_unconfigure/destroy/referenced()
+ */
+ ndi_devi_exit(ap, circ);
+ if (e_ddi_branch_destroy(saf_dip, &fdip, 0)) {
+ char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ /*
+ * If non-NULL, fdip is held and must be released.
+ */
+ if (fdip != NULL) {
+ (void) ddi_pathname(fdip, path);
+ ddi_release_devi(fdip);
+ } else {
+ (void) ddi_pathname(saf_dip, path);
+ }
+
+ cmn_err(CE_WARN, "saf node removal failed: %s (%p)",
+ path, fdip ? (void *)fdip : (void *)saf_dip);
+
+ kmem_free(path, MAXPATHLEN);
+
+ config->gptwo_nodes->gptwo_nodes[i] = saf_dip;
+ failure = 1;
+ }
+ ndi_devi_enter(ap, &circ);
+ }
+
+ ndi_devi_exit(ap, circ);
+
+ if (!failure) {
+ gptwocfg_free_node_list(config->gptwo_nodes);
+
+ mutex_enter(&gptwo_config_list_lock);
+ if (gptwo_config_list == config) {
+ gptwo_config_list = config->gptwo_next;
+ } else {
+ temp = gptwo_config_list;
+ while (temp->gptwo_next != config) {
+ temp = temp->gptwo_next;
+ }
+ temp->gptwo_next = config->gptwo_next;
+ }
+ mutex_exit(&gptwo_config_list_lock);
+
+ kmem_free(config, sizeof (gptwocfg_config_t));
+ config = NULL;
+ }
+
+ return (config);
+}
+
+int
+gptwocfg_next_node(gptwocfg_cookie_t c, dev_info_t *previous, dev_info_t **next)
+{
+ gptwocfg_config_t *cookie;
+ int i, j;
+
+ GPTWO_DEBUG3(1, CE_WARN, "gptwocfg_next_node"
+ "(c=0x%lx, previous=0x%lx, next=0x%lx)\n", c, previous, next);
+
+ cookie = (gptwocfg_config_t *)c;
+
+ for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
+ GPTWO_DEBUG1(1, CE_WARN, "0x%lx\n",
+ cookie->gptwo_nodes->gptwo_nodes[i]);
+ }
+
+ if (previous == NULL) {
+ for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes;
+ i++) {
+ if (cookie->gptwo_nodes->gptwo_nodes[i]) {
+ *next = cookie->gptwo_nodes->gptwo_nodes[i];
+ GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
+ *next);
+ return (1);
+ }
+ }
+ return (0);
+ }
+
+ for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
+ if (cookie->gptwo_nodes->gptwo_nodes[i] == previous) {
+ for (j = i + 1;
+ j < cookie->gptwo_nodes->gptwo_number_of_nodes;
+ j++) {
+ if (cookie->gptwo_nodes->gptwo_nodes[j]) {
+ *next =
+ cookie->gptwo_nodes->gptwo_nodes[j];
+ GPTWO_DEBUG1(1, CE_WARN,
+ "returned 0x%lx\n", *next);
+ return (1);
+ }
+ }
+ *next = NULL;
+ GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
+ *next);
+ return (1);
+ }
+ }
+
+ /*
+ * previous is probably an invalid dev_info.
+ */
+ return (0);
+}
+
+static gptwo_new_nodes_t *
+gptwocfg_get_obp_created_nodes(dev_info_t *ap, uint_t id)
+{
+ gptwo_new_nodes_t *obp_nodes;
+ dev_info_t *saf_dev;
+ int i = 0, nodes = 0;
+ int circular_count;
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_obp_created_nodes - ap=0x%lx "
+ "id=0x%x\n", ap, id);
+
+ ndi_devi_enter(ap, &circular_count);
+
+ /*
+ * First go through all the children of the attachment point
+ * to count matching safari agent ids
+ */
+ saf_dev = ddi_get_child(ap);
+ while (saf_dev != NULL) {
+ if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
+ "portid", -1) == id) {
+ if (&starcat_dr_name) {
+ if (starcat_dr_name(ddi_node_name(saf_dev))
+ < 0) {
+ saf_dev = ddi_get_next_sibling(saf_dev);
+ continue;
+ }
+ }
+ nodes++;
+ }
+ saf_dev = ddi_get_next_sibling(saf_dev);
+ }
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - %d nodes "
+ "found\n", nodes);
+
+ obp_nodes = gptwocfg_allocate_node_list(nodes);
+
+ /*
+ * Then fill in the nodes structure.
+ */
+ saf_dev = ddi_get_child(ap);
+ while ((saf_dev != NULL) && (i < nodes)) {
+ if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
+ "portid", -1) == id) {
+ if (&starcat_dr_name) {
+ if (starcat_dr_name(ddi_node_name(saf_dev))
+ < 0) {
+ saf_dev = ddi_get_next_sibling(saf_dev);
+ continue;
+ }
+ }
+ /*
+ * Branch rooted at this dip must have been
+ * held by the DR driver.
+ */
+ ASSERT(e_ddi_branch_held(saf_dev));
+ obp_nodes->gptwo_nodes[i++] = saf_dev;
+ }
+ saf_dev = ddi_get_next_sibling(saf_dev);
+ }
+
+ ndi_devi_exit(ap, circular_count);
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - "
+ "Returning 0x%lx\n", obp_nodes);
+
+ return (obp_nodes);
+}
+
+void
+gptwocfg_save_handle(dev_info_t *dip, fco_handle_t fco_handle)
+{
+ gptwocfg_handle_list_t *h;
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_save_handle - "
+ "dip=%lx fco_handle=%lx\n", dip, fco_handle);
+
+ h = kmem_zalloc(sizeof (gptwocfg_handle_list_t), KM_SLEEP);
+
+ mutex_enter(&gptwo_handle_list_lock);
+
+ h->next = gptwocfg_handle_list;
+ h->dip = dip;
+ h->fco_handle = fco_handle;
+ gptwocfg_handle_list = h;
+
+ mutex_exit(&gptwo_handle_list_lock);
+}
+
+fco_handle_t
+gptwocfg_get_handle(dev_info_t *dip)
+{
+ gptwocfg_handle_list_t *h, *last;
+ fco_handle_t fco_handle;
+
+ mutex_enter(&gptwo_handle_list_lock);
+
+ h = last = gptwocfg_handle_list;
+
+ while (h != NULL) {
+ if (h->dip == dip) {
+ if (h == gptwocfg_handle_list)
+ gptwocfg_handle_list = h->next;
+ else
+ last->next = h->next;
+
+ mutex_exit(&gptwo_handle_list_lock);
+
+ fco_handle = h->fco_handle;
+
+ kmem_free(h, sizeof (gptwocfg_handle_list_t));
+
+ GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_handle - "
+ "dip=%lx fco_handle=%lx\n", dip, fco_handle);
+
+ return (fco_handle);
+ }
+ last = h;
+ h = h->next;
+ }
+
+ mutex_exit(&gptwo_handle_list_lock);
+
+ GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_handle - dip=%lx NO HANDLE\n",
+ dip);
+
+ return (0);
+}
+
+void
+gptwocfg_devi_attach_to_parent(dev_info_t *dip)
+{
+ (void) i_ndi_config_node(dip, DS_LINKED, 0);
+}
+
+#ifdef DEBUG
+static void
+debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
+ uintptr_t a4, uintptr_t a5)
+{
+ cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
+}
+#endif
diff --git a/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.c b/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.c
new file mode 100644
index 0000000000..969b8baa9e
--- /dev/null
+++ b/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.c
@@ -0,0 +1,1257 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * i2bsc.c is the nexus driver i2c traffic against devices hidden behind the
+ * Blade Support Chip (BSC). It supports both interrupt and polled
+ * mode operation, but defaults to interrupt.
+ */
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/open.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <sys/kmem.h>
+#include <sys/platform_module.h>
+#include <sys/stream.h>
+#include <sys/strlog.h>
+#include <sys/log.h>
+#include <sys/debug.h>
+#include <sys/note.h>
+
+#include <sys/bscbus.h>
+#include <sys/lom_ebuscodes.h>
+
+#include <sys/i2c/clients/i2c_client.h>
+#include <sys/i2c/misc/i2c_svc.h>
+#include <sys/i2c/misc/i2c_svc_impl.h>
+#include <sys/i2c/nexus/i2bsc_impl.h>
+
+/*
+ * static function declarations
+ */
+static void i2bsc_resume(dev_info_t *dip);
+static void i2bsc_suspend(dev_info_t *dip);
+static int i2bsc_bus_ctl(dev_info_t *dip, dev_info_t *rdip,
+ ddi_ctl_enum_t op, void *arg, void *result);
+static void i2bsc_acquire(i2bsc_t *, dev_info_t *dip,
+ i2c_transfer_t *tp);
+static void i2bsc_release(i2bsc_t *);
+static int i2bsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int i2bsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int i2bsc_open(dev_t *devp, int flag, int otyp,
+ cred_t *cred_p);
+static int i2bsc_close(dev_t dev, int flag, int otyp,
+ cred_t *cred_p);
+static int i2bsc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static int i2bsc_initchild(dev_info_t *dip, dev_info_t *cdip);
+static int i2bsc_uninitchild(dev_info_t *dip, dev_info_t *cdip);
+static int i2bsc_setup_regs(i2bsc_t *);
+static void i2bsc_start_session(i2bsc_t *);
+static void i2bsc_fail_session(i2bsc_t *);
+static int i2bsc_end_session(i2bsc_t *);
+static void i2bsc_free_regs(i2bsc_t *);
+static int i2bsc_reportdev(dev_info_t *dip, dev_info_t *rdip);
+int i2bsc_transfer(dev_info_t *dip, i2c_transfer_t *tp);
+static void i2bsc_trace(i2bsc_t *, char, const char *,
+ const char *, ...);
+static int i2bsc_notify_max_transfer_size(i2bsc_t *);
+static int i2bsc_discover_capability(i2bsc_t *);
+static void i2bsc_put8(i2bsc_t *, uint8_t, uint8_t, uint8_t);
+static uint8_t i2bsc_get8(i2bsc_t *, uint8_t, uint8_t);
+static int i2bsc_safe_upload(i2bsc_t *, i2c_transfer_t *);
+static boolean_t i2bsc_is_firmware_broken(i2bsc_t *);
+
+static struct bus_ops i2bsc_busops = {
+ BUSO_REV,
+ nullbusmap, /* bus_map */
+ NULL, /* bus_get_intrspec */
+ NULL, /* bus_add_intrspec */
+ NULL, /* bus_remove_intrspec */
+ NULL, /* bus_map_fault */
+ ddi_no_dma_map, /* bus_dma_map */
+ ddi_no_dma_allochdl, /* bus_dma_allochdl */
+ ddi_no_dma_freehdl, /* bus_dma_freehdl */
+ ddi_no_dma_bindhdl, /* bus_dma_bindhdl */
+ ddi_no_dma_unbindhdl, /* bus_unbindhdl */
+ ddi_no_dma_flush, /* bus_dma_flush */
+ ddi_no_dma_win, /* bus_dma_win */
+ ddi_no_dma_mctl, /* bus_dma_ctl */
+ i2bsc_bus_ctl, /* bus_ctl */
+ ddi_bus_prop_op, /* bus_prop_op */
+ NULL, /* bus_get_eventcookie */
+ NULL, /* bus_add_eventcall */
+ NULL, /* bus_remove_eventcall */
+ NULL, /* bus_post_event */
+ 0, /* bus_intr_ctl */
+ 0, /* bus_config */
+ 0, /* bus_unconfig */
+ 0, /* bus_fm_init */
+ 0, /* bus_fm_fini */
+ 0, /* bus_fm_access_enter */
+ 0, /* bus_fm_access_exit */
+ 0, /* bus_power */
+ i_ddi_intr_ops /* bus_intr_op */
+
+};
+
+struct cb_ops i2bsc_cb_ops = {
+ i2bsc_open, /* open */
+ i2bsc_close, /* close */
+ nodev, /* strategy */
+ nodev, /* print */
+ nodev, /* dump */
+ nodev, /* read */
+ nodev, /* write */
+ i2bsc_ioctl, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* poll */
+ ddi_prop_op, /* cb_prop_op */
+ 0, /* streamtab */
+ D_MP | D_NEW /* Driver compatibility flag */
+};
+
+static struct dev_ops i2bsc_ops = {
+ DEVO_REV,
+ 0,
+ ddi_getinfo_1to1,
+ nulldev,
+ nulldev,
+ i2bsc_attach,
+ i2bsc_detach,
+ nodev,
+ &i2bsc_cb_ops,
+ &i2bsc_busops
+};
+
+#ifdef DEBUG
+#define I2BSC_VERSION_STRING "i2bsc driver - Debug v%I%"
+#else
+#define I2BSC_VERSION_STRING "i2bsc driver v%I%"
+#endif
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* Type of module. This one is a driver */
+ I2BSC_VERSION_STRING, /* Name of the module. */
+ &i2bsc_ops, /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ &modldrv,
+ NULL
+};
+
+/*
+ * i2bsc soft state
+ */
+static void *i2bsc_state;
+
+i2c_nexus_reg_t i2bsc_regvec = {
+ I2C_NEXUS_REV,
+ i2bsc_transfer,
+};
+
+int
+_init(void)
+{
+ int status;
+
+ status = ddi_soft_state_init(&i2bsc_state, sizeof (i2bsc_t),
+ I2BSC_INITIAL_SOFT_SPACE);
+ if (status != 0) {
+ return (status);
+ }
+
+ if ((status = mod_install(&modlinkage)) != 0) {
+ ddi_soft_state_fini(&i2bsc_state);
+ }
+
+ return (status);
+}
+
+int
+_fini(void)
+{
+ int status;
+
+ if ((status = mod_remove(&modlinkage)) == 0) {
+ ddi_soft_state_fini(&i2bsc_state);
+ }
+
+ return (status);
+}
+
+/*
+ * The loadable-module _info(9E) entry point
+ */
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+static void
+i2bsc_dodetach(dev_info_t *dip)
+{
+ i2bsc_t *i2c;
+ int instance = ddi_get_instance(dip);
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+
+ if ((i2c->i2bsc_attachflags & IMUTEX) != 0) {
+ mutex_destroy(&i2c->i2bsc_imutex);
+ cv_destroy(&i2c->i2bsc_icv);
+ }
+ if ((i2c->i2bsc_attachflags & SETUP_REGS) != 0) {
+ i2bsc_free_regs(i2c);
+ }
+ if ((i2c->i2bsc_attachflags & NEXUS_REGISTER) != 0) {
+ i2c_nexus_unregister(dip);
+ }
+ if ((i2c->i2bsc_attachflags & MINOR_NODE) != 0) {
+ ddi_remove_minor_node(dip, NULL);
+ }
+
+ ddi_soft_state_free(i2bsc_state, instance);
+}
+
+static int
+i2bsc_doattach(dev_info_t *dip)
+{
+ i2bsc_t *i2c;
+ int instance = ddi_get_instance(dip);
+
+ /*
+ * Allocate soft state structure.
+ */
+ if (ddi_soft_state_zalloc(i2bsc_state, instance) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+
+ i2c->majornum = ddi_driver_major(dip);
+ i2c->minornum = instance;
+ i2c->i2bsc_dip = dip;
+ i2c->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "debug", 0);
+
+ (void) snprintf(i2c->i2bsc_name, sizeof (i2c->i2bsc_name),
+ "%s_%d", ddi_node_name(dip), instance);
+
+ if (i2bsc_setup_regs(i2c) != DDI_SUCCESS) {
+ goto bad;
+ }
+
+ i2c->i2bsc_attachflags |= SETUP_REGS;
+
+ mutex_init(&i2c->i2bsc_imutex, NULL, MUTEX_DRIVER,
+ (void *) 0);
+ cv_init(&i2c->i2bsc_icv, NULL, CV_DRIVER, NULL);
+ i2c->i2bsc_attachflags |= IMUTEX;
+
+ i2c_nexus_register(dip, &i2bsc_regvec);
+ i2c->i2bsc_attachflags |= NEXUS_REGISTER;
+
+ if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
+ DDI_NT_NEXUS, 0) == DDI_FAILURE) {
+ cmn_err(CE_WARN, "%s ddi_create_minor_node failed",
+ i2c->i2bsc_name);
+ goto bad;
+ }
+
+ i2c->i2bsc_attachflags |= MINOR_NODE;
+
+ /*
+ * Now actually start talking to the microcontroller. The first
+ * thing to check is whether the firmware is broken.
+ */
+ if (i2bsc_is_firmware_broken(i2c)) {
+ cmn_err(CE_WARN, "Underlying BSC hardware not communicating;"
+ " shutting down my i2c services");
+ goto bad;
+ }
+
+ i2c->i2bsc_attachflags |= FIRMWARE_ALIVE;
+
+ /*
+ * Now see if the BSC chip supports the i2c service we rely upon.
+ */
+ (void) i2bsc_discover_capability(i2c);
+
+ if (i2bsc_notify_max_transfer_size(i2c) == DDI_SUCCESS)
+ i2c->i2bsc_attachflags |= TRANSFER_SZ;
+
+ i2bsc_trace(i2c, 'A', "i2bsc_doattach", "attachflags %d",
+ i2c->i2bsc_attachflags);
+
+ return (DDI_SUCCESS);
+
+bad:
+ i2bsc_dodetach(dip);
+
+ return (DDI_FAILURE);
+}
+
+static int
+i2bsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ switch (cmd) {
+ case DDI_ATTACH:
+ return (i2bsc_doattach(dip));
+
+ case DDI_RESUME:
+ i2bsc_resume(dip);
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+static int
+i2bsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ switch (cmd) {
+ case DDI_DETACH:
+ i2bsc_dodetach(dip);
+ return (DDI_SUCCESS);
+
+ case DDI_SUSPEND:
+ i2bsc_suspend(dip);
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+/*ARGSUSED*/
+static int
+i2bsc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
+{
+ int instance;
+ i2bsc_t *i2c;
+
+ /*
+ * Make sure the open is for the right file type
+ */
+ if (otyp != OTYP_CHR)
+ return (EINVAL);
+
+ instance = getminor(*devp);
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+ if (i2c == NULL)
+ return (ENXIO);
+
+ /*
+ * Enforce exclusive access
+ */
+ mutex_enter(&i2c->i2bsc_imutex);
+ if (i2c->i2bsc_open) {
+ mutex_exit(&i2c->i2bsc_imutex);
+ return (EBUSY);
+ } else
+ i2c->i2bsc_open = 1;
+
+ mutex_exit(&i2c->i2bsc_imutex);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+i2bsc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
+{
+ int instance;
+ i2bsc_t *i2c;
+
+ /*
+ * Make sure the close is for the right file type
+ */
+ if (otyp != OTYP_CHR)
+ return (EINVAL);
+
+ instance = getminor(dev);
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+ if (i2c == NULL)
+ return (ENXIO);
+
+ mutex_enter(&i2c->i2bsc_imutex);
+ i2c->i2bsc_open = 0;
+ mutex_exit(&i2c->i2bsc_imutex);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+i2bsc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ i2bsc_t *i2c;
+ dev_info_t *self;
+ dev_info_t *child;
+ struct devctl_iocdata *dcp;
+ int rv;
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, getminor(dev));
+
+ if (i2c == NULL)
+ return (ENXIO);
+
+ self = (dev_info_t *)i2c->i2bsc_dip;
+
+ /*
+ * read devctl ioctl data
+ */
+ if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) {
+ return (EFAULT);
+ }
+
+ switch (cmd) {
+ case DEVCTL_BUS_DEV_CREATE:
+ rv = ndi_dc_devi_create(dcp, self, 0, NULL);
+ break;
+
+ case DEVCTL_DEVICE_REMOVE:
+ if (ndi_dc_getname(dcp) == NULL ||
+ ndi_dc_getaddr(dcp) == NULL) {
+ rv = EINVAL;
+ break;
+ }
+
+ /*
+ * lookup and hold child device
+ */
+ child = ndi_devi_find(self,
+ ndi_dc_getname(dcp), ndi_dc_getaddr(dcp));
+ if (child == NULL) {
+ rv = ENXIO;
+ break;
+ }
+
+ if ((rv = ndi_devi_offline(child, NDI_DEVI_REMOVE)) !=
+ NDI_SUCCESS) {
+ rv = (rv == NDI_BUSY) ? EBUSY : EIO;
+ }
+
+ break;
+
+ default:
+ rv = ENOTSUP;
+ }
+
+ ndi_dc_freehdl(dcp);
+
+ return (rv);
+}
+
+static int
+i2bsc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
+ void *arg, void *result)
+{
+ i2bsc_t *i2c;
+ int instance = ddi_get_instance(dip);
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+
+ i2bsc_trace(i2c, 'A', "i2bsc_bus_ctl", "dip/rdip,op/arg"
+ " %p/%p,%d/%p", dip, rdip, (int)op, arg);
+
+ switch (op) {
+ case DDI_CTLOPS_INITCHILD:
+ return (i2bsc_initchild(dip, (dev_info_t *)arg));
+
+ case DDI_CTLOPS_UNINITCHILD:
+ return (i2bsc_uninitchild(dip, (dev_info_t *)arg));
+
+ case DDI_CTLOPS_REPORTDEV:
+ return (i2bsc_reportdev(dip, rdip));
+
+ case DDI_CTLOPS_DMAPMAPC:
+ case DDI_CTLOPS_POKE:
+ case DDI_CTLOPS_PEEK:
+ case DDI_CTLOPS_IOMIN:
+ case DDI_CTLOPS_REPORTINT:
+ case DDI_CTLOPS_SIDDEV:
+ case DDI_CTLOPS_SLAVEONLY:
+ case DDI_CTLOPS_AFFINITY:
+ case DDI_CTLOPS_PTOB:
+ case DDI_CTLOPS_BTOP:
+ case DDI_CTLOPS_BTOPR:
+ case DDI_CTLOPS_DVMAPAGESIZE:
+ return (DDI_FAILURE);
+
+ default:
+ return (ddi_ctlops(dip, rdip, op, arg, result));
+ }
+}
+
+/*
+ * i2bsc_suspend() is called before the system suspends. Existing
+ * transfer in progress or waiting will complete, but new transfers are
+ * effectively blocked by "acquiring" the bus.
+ */
+static void
+i2bsc_suspend(dev_info_t *dip)
+{
+ i2bsc_t *i2c;
+ int instance;
+
+ instance = ddi_get_instance(dip);
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+
+ i2bsc_acquire(i2c, NULL, NULL);
+}
+
+/*
+ * i2bsc_resume() is called when the system resumes from CPR. It releases
+ * the hold that was placed on the i2c bus, which allows any real
+ * transfers to continue.
+ */
+static void
+i2bsc_resume(dev_info_t *dip)
+{
+ i2bsc_t *i2c;
+ int instance;
+
+ instance = ddi_get_instance(dip);
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
+
+ i2bsc_release(i2c);
+}
+
+/*
+ * i2bsc_acquire() is called by a thread wishing to "own" the I2C bus.
+ * It should not be held across multiple transfers.
+ */
+static void
+i2bsc_acquire(i2bsc_t *i2c, dev_info_t *dip, i2c_transfer_t *tp)
+{
+ mutex_enter(&i2c->i2bsc_imutex);
+ while (i2c->i2bsc_busy) {
+ cv_wait(&i2c->i2bsc_icv, &i2c->i2bsc_imutex);
+ }
+ i2c->i2bsc_busy = 1;
+ i2c->i2bsc_cur_tran = tp;
+ i2c->i2bsc_cur_dip = dip;
+ mutex_exit(&i2c->i2bsc_imutex);
+}
+
+/*
+ * i2bsc_release() is called to release a hold made by i2bsc_acquire().
+ */
+static void
+i2bsc_release(i2bsc_t *i2c)
+{
+ mutex_enter(&i2c->i2bsc_imutex);
+ i2c->i2bsc_busy = 0;
+ i2c->i2bsc_cur_tran = NULL;
+ cv_signal(&i2c->i2bsc_icv);
+ mutex_exit(&i2c->i2bsc_imutex);
+}
+
+static int
+i2bsc_initchild(dev_info_t *dip, dev_info_t *cdip)
+{
+ i2bsc_t *i2c;
+ int32_t address_cells;
+ int len;
+ int32_t regs[3];
+ int err;
+ i2bsc_ppvt_t *ppvt;
+ char name[30];
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, ddi_get_instance(dip));
+
+ i2bsc_trace(i2c, 'A', "i2bsc_initchild", "dip/cdip %p/%p", dip, cdip);
+
+ ppvt = kmem_alloc(sizeof (i2bsc_ppvt_t), KM_SLEEP);
+
+ len = sizeof (address_cells);
+
+ err = ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip,
+ DDI_PROP_CANSLEEP, "#address-cells",
+ (caddr_t)&address_cells, &len);
+ if (err != DDI_PROP_SUCCESS || len != sizeof (address_cells)) {
+ return (DDI_FAILURE);
+ }
+
+ len = sizeof (regs);
+ err = ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip,
+ DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP,
+ "reg", (caddr_t)regs, &len);
+ if (err != DDI_PROP_SUCCESS)
+ return (DDI_FAILURE);
+
+ if (address_cells == 1) {
+ ppvt->i2bsc_ppvt_bus = I2BSC_DEFAULT_BUS;
+ ppvt->i2bsc_ppvt_addr = regs[0];
+ (void) sprintf(name, "%x", regs[0]);
+ i2bsc_trace(i2c, 'A', "i2bsc_initchild", "#address-cells = 1"
+ " regs[0] = %d", regs[0]);
+ } else if (address_cells == 2) {
+ ppvt->i2bsc_ppvt_bus = regs[0];
+ ppvt->i2bsc_ppvt_addr = regs[1];
+ (void) sprintf(name, "%x,%x", regs[0], regs[1]);
+ i2bsc_trace(i2c, 'A', "i2bsc_initchild", "#address-cells = 2"
+ " regs[0] = %d, regs[1] = %d", regs[0], regs[1]);
+ } else {
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Attach the parent's private data structure to the child's devinfo
+ * node, and store the child's address on the nexus in the child's
+ * devinfo node.
+ */
+ ddi_set_parent_data(cdip, ppvt);
+ ddi_set_name_addr(cdip, name);
+
+ i2bsc_trace(i2c, 'A', "i2bsc_initchild", "success(%s)",
+ ddi_node_name(cdip));
+
+ return (DDI_SUCCESS);
+}
+
+static int
+i2bsc_uninitchild(dev_info_t *dip, dev_info_t *cdip)
+{
+ i2bsc_t *i2c;
+ i2bsc_ppvt_t *ppvt;
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, ddi_get_instance(dip));
+
+ i2bsc_trace(i2c, 'D', "i2bsc_uninitchild", "dip/cdip %p/%p", dip, cdip);
+
+ ppvt = ddi_get_parent_data(cdip);
+ kmem_free(ppvt, sizeof (i2bsc_ppvt_t));
+
+ ddi_set_parent_data(cdip, NULL);
+ ddi_set_name_addr(cdip, NULL);
+
+ i2bsc_trace(i2c, 'D', "i2bsc_uninitchild", "success(%s)",
+ ddi_node_name(cdip));
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * i2bsc_setup_regs() is called to map in registers specific to
+ * the i2bsc.
+ */
+static int
+i2bsc_setup_regs(i2bsc_t *i2c)
+{
+ int nregs;
+
+ i2c->bscbus_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+ i2c->bscbus_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+ i2c->bscbus_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+ if (ddi_dev_nregs(i2c->i2bsc_dip, &nregs) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ if (nregs < 1) {
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_regs_map_setup(i2c->i2bsc_dip, 0,
+ (caddr_t *)&i2c->bscbus_regs, 0, 0, &i2c->bscbus_attr,
+ &i2c->bscbus_handle) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * i2bsc_free_regs() frees any registers previously
+ * allocated.
+ */
+static void
+i2bsc_free_regs(i2bsc_t *i2c)
+{
+ if (i2c->bscbus_regs != NULL) {
+ ddi_regs_map_free(&i2c->bscbus_handle);
+ }
+}
+
+/*ARGSUSED*/
+static int
+i2bsc_reportdev(dev_info_t *dip, dev_info_t *rdip)
+{
+ if (rdip == (dev_info_t *)0)
+ return (DDI_FAILURE);
+
+ cmn_err(CE_CONT, "?i2bsc-device: %s@%s, %s%d\n",
+ ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip),
+ ddi_get_instance(rdip));
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * I/O Functions
+ *
+ * i2bsc_{put,get}8_once are wrapper functions to ddi_{get,put}8.
+ * i2bsc_{put,get}8 are equivalent functions but with retry code.
+ * i2bsc_bscbus_state determines underlying bus error status.
+ * i2bsc_clear_acc_fault clears the underlying bus error status.
+ *
+ * I/O Flags
+ *
+ * bscbus_fault - Error register in underlying bus for last IO operation.
+ * session_failure - Set by any failed IO command. This is a sticky flag
+ * reset explicitly using i2bsc_start_session
+ *
+ * Session Management
+ *
+ * i2bsc_{start,end}_session need to be used to detect an error across multiple
+ * gets/puts rather than having to test for an error on each get/put.
+ */
+
+static int i2bsc_bscbus_state(i2bsc_t *i2c)
+{
+ uint32_t retval;
+
+ retval = ddi_get32(i2c->bscbus_handle,
+ (uint32_t *)I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_GENERIC,
+ LOMBUS_FAULT_REG));
+ i2c->bscbus_fault = retval;
+
+ return ((retval == 0) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+static void i2bsc_clear_acc_fault(i2bsc_t *i2c)
+{
+ i2bsc_trace(i2c, '@', "i2bsc_clear_acc_fault", "clearing acc fault");
+ ddi_put32(i2c->bscbus_handle,
+ (uint32_t *)I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_GENERIC,
+ LOMBUS_FAULT_REG), 0);
+}
+
+static void
+i2bsc_start_session(i2bsc_t *i2c)
+{
+ i2bsc_trace(i2c, 'S', "i2bsc_start_session", "session started");
+ i2c->bscbus_session_failure = 0;
+}
+
+static void
+i2bsc_fail_session(i2bsc_t *i2c)
+{
+ i2bsc_trace(i2c, 'S', "i2bsc_fail_session", "session failed");
+ i2c->bscbus_session_failure = 1;
+}
+
+static int
+i2bsc_end_session(i2bsc_t *i2c)
+{
+ /*
+ * The ONLY way to get the session status is to end the session.
+ * If clients of the session interface ever wanted the status mid-way
+ * then they are really working with multiple contigious sessions.
+ */
+ i2bsc_trace(i2c, 'S', "i2bsc_end_session", "session ended with %d",
+ i2c->bscbus_session_failure);
+ return ((i2c->bscbus_session_failure) ? DDI_FAILURE : DDI_SUCCESS);
+}
+
+static boolean_t
+i2bsc_is_firmware_broken(i2bsc_t *i2c)
+{
+ int i;
+ int niterations = I2BSC_SHORT_RETRY_LIMIT;
+
+ i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken", "called");
+
+ for (i = 0; i < niterations; i++) {
+ (void) ddi_get8(i2c->bscbus_handle,
+ I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_I2C,
+ EBUS_IDX12_RESULT));
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
+ i2bsc_clear_acc_fault(i2c);
+ continue;
+ } else {
+ /*
+ * Firmware communication succeeded.
+ */
+ i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken",
+ "firmware communications okay");
+ return (B_FALSE);
+ }
+ }
+
+ /*
+ * Firmware is not communicative. Some possible causes :
+ * Broken hardware
+ * BSC held in reset
+ * Corrupt BSC image
+ * OBP incompatiblity preventing drivers loading properly
+ */
+ i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken", "%d read fails",
+ niterations);
+ return (B_TRUE);
+}
+
+static void
+i2bsc_put8(i2bsc_t *i2c, uint8_t space, uint8_t index, uint8_t value)
+{
+ int retryable = I2BSC_RETRY_LIMIT;
+
+ i2bsc_trace(i2c, '@', "i2bsc_put8", "(space,index)<-val (%d,%d)<-%d",
+ space, index, value);
+
+ i2bsc_clear_acc_fault(i2c);
+
+ /*
+ * If a session failure has already occurred, reduce the level of
+ * retries to a minimum. This is a optimization of the failure
+ * recovery strategy.
+ */
+ if (i2c->bscbus_session_failure)
+ retryable = 1;
+
+ while (retryable--) {
+ ddi_put8(i2c->bscbus_handle,
+ I2BSC_NEXUS_ADDR(i2c, space, index), value);
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
+ i2bsc_clear_acc_fault(i2c);
+ } else
+ break;
+ }
+
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
+ i2bsc_fail_session(i2c);
+
+ i2bsc_trace(i2c, '@', "i2bsc_put8", "tried %d time(s)",
+ I2BSC_RETRY_LIMIT - retryable);
+}
+
+static uint8_t
+i2bsc_get8(i2bsc_t *i2c, uint8_t space, uint8_t index)
+{
+ uint8_t value;
+ int retryable = I2BSC_RETRY_LIMIT;
+
+ i2bsc_clear_acc_fault(i2c);
+
+ /*
+ * If a session failure has already occurred, reduce the level of
+ * retries to a minimum. This is a optimization of the failure
+ * recovery strategy.
+ */
+ if (i2c->bscbus_session_failure)
+ retryable = 1;
+
+ while (retryable--) {
+ value = ddi_get8(i2c->bscbus_handle,
+ I2BSC_NEXUS_ADDR(i2c, space, index));
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
+ i2bsc_clear_acc_fault(i2c);
+ } else
+ break;
+ }
+
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
+ i2bsc_fail_session(i2c);
+
+ i2bsc_trace(i2c, '@', "i2bsc_get8", "tried %d time(s)",
+ I2BSC_RETRY_LIMIT - retryable);
+
+ i2bsc_trace(i2c, '@', "i2bsc_get8", "(space,index)->val (%d,%d)->%d",
+ space, index, value);
+ return (value);
+}
+
+static void
+i2bsc_put8_once(i2bsc_t *i2c, uint8_t space, uint8_t index, uint8_t value)
+{
+ i2bsc_trace(i2c, '@', "i2bsc_put8_once",
+ "(space,index)<-val (%d,%d)<-%d", space, index, value);
+
+ i2bsc_clear_acc_fault(i2c);
+
+ ddi_put8(i2c->bscbus_handle,
+ I2BSC_NEXUS_ADDR(i2c, space, index), value);
+
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
+ i2bsc_fail_session(i2c);
+}
+
+static uint8_t
+i2bsc_get8_once(i2bsc_t *i2c, uint8_t space, uint8_t index)
+{
+ uint8_t value;
+
+ i2bsc_clear_acc_fault(i2c);
+
+ value = ddi_get8(i2c->bscbus_handle,
+ I2BSC_NEXUS_ADDR(i2c, space, index));
+
+ if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
+ i2bsc_fail_session(i2c);
+
+ i2bsc_trace(i2c, '@', "i2bsc_get8_once",
+ "(space,index)->val (%d,%d)->%d", space, index, value);
+
+ return (value);
+}
+
+static int
+i2bsc_notify_max_transfer_size(i2bsc_t *i2c)
+{
+ /*
+ * If the underlying hardware does not support the i2c service and
+ * we are not running in fake_mode, then we cannot set the
+ * MAX_TRANSFER_SZ.
+ */
+ if (i2c->i2c_proxy_support == 0)
+ return (DDI_FAILURE);
+
+ i2bsc_start_session(i2c);
+
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_MAX_TRANSFER_SZ,
+ I2BSC_MAX_TRANSFER_SZ);
+
+ if (i2bsc_end_session(i2c) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Discover if the microcontroller implements the I2C Proxy Service this
+ * driver requires. If it does not, i2c transactions will abort with
+ * I2C_FAILURE, unless fake_mode is being used.
+ */
+static int
+i2bsc_discover_capability(i2bsc_t *i2c)
+{
+ i2bsc_start_session(i2c);
+
+ i2c->i2c_proxy_support = i2bsc_get8(i2c, EBUS_CMD_SPACE_GENERIC,
+ EBUS_IDX_CAP0);
+ i2c->i2c_proxy_support &= EBUS_CAP0_I2C_PROXY;
+
+ if (i2bsc_end_session(i2c) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ return (DDI_SUCCESS);
+}
+
+static int
+i2bsc_upload_preamble(i2bsc_t *i2c, i2c_transfer_t *tp)
+{
+ i2bsc_ppvt_t *ppvt;
+ int wr_rd;
+
+ ppvt = ddi_get_parent_data(i2c->i2bsc_cur_dip);
+
+ /* Get a lock on the i2c devices owned by the microcontroller */
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSACTION_LOCK, 1);
+ if (!i2bsc_get8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSACTION_LOCK)) {
+ /*
+ * i2c client driver must timeout retry, NOT this nexus
+ */
+ tp->i2c_result = I2C_INCOMPLETE;
+ i2bsc_trace(i2c, 'U', "i2bsc_upload_preamble",
+ "Couldn't get transaction lock");
+ return (tp->i2c_result);
+ }
+
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_BUS_ADDRESS,
+ ppvt->i2bsc_ppvt_bus);
+
+ /*
+ * The Solaris architecture for I2C uses 10-bit I2C addresses where
+ * bit-0 is zero (the read/write bit). The microcontroller uses 7 bit
+ * I2C addresses (read/write bit excluded). Hence we need to convert
+ * the address by bit-shifting.
+ */
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_CLIENT_ADDRESS,
+ ppvt->i2bsc_ppvt_addr >> 1);
+
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSFER_TYPE,
+ tp->i2c_flags);
+
+ /*
+ * We have only one register used for data input and output. When
+ * a WR_RD is issued, this means we want to do a Random-Access-Read.
+ * First a series of bytes are written which define the address to
+ * read from. In hardware this sets an address pointer. Then a series
+ * of bytes are read. The read/write boundary tells you how many
+ * bytes are to be written before reads will be issued.
+ */
+ if (tp->i2c_flags == I2C_WR_RD)
+ wr_rd = tp->i2c_wlen;
+ else
+ wr_rd = 0;
+
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_WR_RD_BOUNDARY, wr_rd);
+
+ return (I2C_SUCCESS);
+}
+
+/*
+ * Function i2bsc_upload
+ *
+ * Description This function runs the i2c transfer protocol down to the
+ * microcontroller. Its goal is to be as reliable as possible.
+ * This is achieved by making all the state-less aspects
+ * re-tryable. For stateful aspects, we take care to ensure the
+ * counters are decremented only when data transfer has been
+ * successful.
+ */
+static int
+i2bsc_upload(i2bsc_t *i2c, i2c_transfer_t *tp)
+{
+ int quota = I2BSC_MAX_TRANSFER_SZ;
+ uint8_t res;
+ int residual;
+
+ /*
+ * Total amount of data outstanding
+ */
+ residual = tp->i2c_w_resid + tp->i2c_r_resid;
+
+ /*
+ * Anything in this session *could* be re-tried without side-effects.
+ * Therefore, error exit codes are I2C_INCOMPLETE rather than
+ * I2C_FAILURE.
+ */
+ i2bsc_start_session(i2c);
+ if (i2bsc_upload_preamble(i2c, tp) != I2C_SUCCESS)
+ return (I2C_INCOMPLETE);
+ if (i2bsc_end_session(i2c) != DDI_SUCCESS)
+ return (I2C_INCOMPLETE);
+
+ /* The writes done here are not retryable */
+ while (tp->i2c_w_resid && quota) {
+ i2bsc_put8_once(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_DATA_INOUT,
+ tp->i2c_wbuf[tp->i2c_wlen - tp->i2c_w_resid]);
+ if (i2bsc_bscbus_state(i2c) == DDI_SUCCESS) {
+ tp->i2c_w_resid--;
+ quota--;
+ residual--;
+ } else {
+ i2bsc_trace(i2c, 'T', "i2bsc_upload", "write failed");
+ return (tp->i2c_result = I2C_INCOMPLETE);
+ }
+ }
+
+ /* The reads done here are not retryable */
+ while (tp->i2c_r_resid && quota) {
+ tp->i2c_rbuf[tp->i2c_rlen - tp->i2c_r_resid] =
+ i2bsc_get8_once(i2c, EBUS_CMD_SPACE_I2C,
+ EBUS_IDX12_DATA_INOUT);
+ if (i2bsc_bscbus_state(i2c) == DDI_SUCCESS) {
+ tp->i2c_r_resid--;
+ quota--;
+ residual--;
+ } else {
+ i2bsc_trace(i2c, 'T', "i2bsc_upload", "read failed");
+ return (tp->i2c_result = I2C_INCOMPLETE);
+ }
+ }
+
+ i2bsc_start_session(i2c);
+
+ /*
+ * A possible future enhancement would be to allow early breakout of the
+ * loops seen above. In such circumstances, "residual" would be non-
+ * zero. This may be useful if we want to support the interruption of
+ * transfer part way through an i2c_transfer_t.
+ */
+ i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_RESIDUAL_DATA, residual);
+ res = i2bsc_get8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_RESULT);
+ if (i2bsc_end_session(i2c) != DDI_SUCCESS)
+ return (tp->i2c_result = I2C_INCOMPLETE);
+
+ switch (res) {
+ case EBUS_I2C_SUCCESS:
+ tp->i2c_result = I2C_SUCCESS;
+ break;
+ case EBUS_I2C_FAILURE:
+ /*
+ * This is rare but possible. A retry may still fix this
+ * so lets allow that by returning I2C_INCOMPLETE.
+ * "hifTxRing still contains 1 bytes" is reported by the
+ * microcontroller when this return value is seen.
+ */
+ i2bsc_trace(i2c, 'T', "i2bsc_upload", "EBUS_I2C_FAILURE"
+ " but returning I2C_INCOMPLETE for possible re-try");
+ tp->i2c_result = I2C_INCOMPLETE;
+ break;
+ case EBUS_I2C_INCOMPLETE:
+ tp->i2c_result = I2C_INCOMPLETE;
+ break;
+ default:
+ tp->i2c_result = I2C_FAILURE;
+ }
+
+ return (tp->i2c_result);
+}
+
+/*
+ * Function i2bsc_safe_upload
+ *
+ * Description This function is called "safe"-upload because it attempts to
+ * do transaction re-tries for cases where state is not spoiled
+ * by a transaction-level retry.
+ */
+static int
+i2bsc_safe_upload(i2bsc_t *i2c, i2c_transfer_t *tp)
+{
+ int retryable = I2BSC_RETRY_LIMIT;
+ int result;
+
+ i2bsc_trace(i2c, 'T', "i2bsc_safe_upload", "Transaction %s",
+ (tp->i2c_flags == I2C_WR_RD) ? "retryable" : "single-shot");
+
+ /*
+ * The only re-tryable transaction type is I2C_WR_RD. If we don't
+ * have this we can only use session-based recovery offered by
+ * i2bsc_upload.
+ */
+ if (tp->i2c_flags != I2C_WR_RD)
+ return (i2bsc_upload(i2c, tp));
+
+ while (retryable--) {
+ result = i2bsc_upload(i2c, tp);
+ if (result == I2C_INCOMPLETE) {
+ /* Have another go */
+ tp->i2c_r_resid = tp->i2c_rlen;
+ tp->i2c_w_resid = tp->i2c_wlen;
+ tp->i2c_result = I2C_SUCCESS;
+ i2bsc_trace(i2c, 'T', "i2bsc_safe_upload",
+ "Retried (%d)", I2BSC_RETRY_LIMIT - retryable);
+ continue;
+ } else {
+ i2bsc_trace(i2c, 'T', "i2bsc_safe_upload",
+ "Exiting while loop on result %d", result);
+ return (result);
+ }
+ }
+
+ i2bsc_trace(i2c, 'T', "i2bsc_safe_upload", "Exiting on %d", result);
+ return (result);
+}
+
+/*
+ * Function i2bsc_transfer
+ *
+ * Description This is the entry-point that clients use via the Solaris i2c
+ * framework. It kicks off the servicing of i2c transfer requests.
+ */
+int
+i2bsc_transfer(dev_info_t *dip, i2c_transfer_t *tp)
+{
+ i2bsc_t *i2c;
+
+ i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state,
+ ddi_get_instance(ddi_get_parent(dip)));
+
+ i2bsc_acquire(i2c, dip, tp);
+
+ tp->i2c_r_resid = tp->i2c_rlen;
+ tp->i2c_w_resid = tp->i2c_wlen;
+ tp->i2c_result = I2C_SUCCESS;
+
+ i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction i2c_version/flags"
+ " %d/%d", tp->i2c_version, tp->i2c_flags);
+ i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction buffer rlen/wlen"
+ " %d/%d", tp->i2c_rlen, tp->i2c_wlen);
+ i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction ptrs wbuf/rbuf"
+ " %p/%p", tp->i2c_wbuf, tp->i2c_rbuf);
+
+ if (i2c->i2c_proxy_support)
+ (void) i2bsc_safe_upload(i2c, tp);
+ else
+ tp->i2c_result = I2C_FAILURE;
+
+ i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Residual writes/reads"
+ " %d/%d", tp->i2c_w_resid, tp->i2c_r_resid);
+ i2bsc_trace(i2c, 'T', "i2bsc_transfer", "i2c_result"
+ " %d", tp->i2c_result);
+
+ i2bsc_release(i2c);
+
+ return (tp->i2c_result);
+}
+
+/*
+ * General utility routines ...
+ */
+
+#ifdef DEBUG
+
+static void
+i2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
+ const char *fmt, ...)
+{
+ char buf[256];
+ char *p;
+ va_list va;
+
+ if (ssp->debug & (1 << (code-'@'))) {
+ p = buf;
+ (void) snprintf(p, sizeof (buf) - (p - buf),
+ "%s/%s: ", ssp->i2bsc_name, caller);
+ p += strlen(p);
+
+ va_start(va, fmt);
+ (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
+ va_end(va);
+
+ buf[sizeof (buf) - 1] = '\0';
+ (void) strlog(ssp->majornum, ssp->minornum, code, SL_TRACE,
+ buf);
+ }
+}
+
+#else /* DEBUG */
+
+_NOTE(ARGSUSED(0))
+static void
+i2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
+ const char *fmt, ...)
+{
+}
+
+#endif /* DEBUG */
diff --git a/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.conf b/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.conf
new file mode 100644
index 0000000000..6608ada6b9
--- /dev/null
+++ b/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.conf
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# Configuration file for i2bsc driver
+#
+
+# 64-bit Debug bit-vector; requires DEBUG driver to be installed
+debug=0;
diff --git a/usr/src/uts/sun4u/io/todm5819p_rmc.c b/usr/src/uts/sun4u/io/todm5819p_rmc.c
new file mode 100644
index 0000000000..e9bda93105
--- /dev/null
+++ b/usr/src/uts/sun4u/io/todm5819p_rmc.c
@@ -0,0 +1,409 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * tod driver module for ALI M5819P part
+ */
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/open.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#include <sys/todm5819p.h>
+#include <sys/rmc_comm_dp.h>
+#include <sys/rmc_comm_drvintf.h>
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <sys/clock.h>
+#include <sys/reboot.h>
+#include <sys/machsystm.h>
+
+static timestruc_t todm5819p_rmc_get(void);
+static void todm5819p_rmc_set(timestruc_t);
+static uint_t todm5819p_rmc_set_watchdog_timer(uint_t);
+static uint_t todm5819p_rmc_clear_watchdog_timer(void);
+static void todm5819p_rmc_set_power_alarm(timestruc_t);
+static void todm5819p_rmc_clear_power_alarm(void);
+static uint64_t todm5819p_rmc_get_cpufrequency(void);
+
+extern uint64_t find_cpufrequency(volatile uint8_t *);
+
+/*
+ * External variables
+ */
+extern int watchdog_enable;
+extern int watchdog_available;
+extern int boothowto;
+
+/*
+ * Global variables
+ */
+int m5819p_debug_flags;
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modlmisc modlmisc = {
+ &mod_miscops, "tod module for ALI M5819P"
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, (void *)&modlmisc, NULL
+};
+
+static todinfo_t rtc_to_tod(struct rtc_t *);
+static void read_rtc(struct rtc_t *);
+static void write_rtc_time(struct rtc_t *);
+static void write_rtc_alarm(struct rtc_t *);
+
+
+int
+_init(void)
+{
+ if (strcmp(tod_module_name, "todm5819p_rmc") == 0) {
+ M5819P_ADDR_REG = RTC_B;
+ M5819P_DATA_REG = (RTC_DM | RTC_HM);
+
+ tod_ops.tod_get = todm5819p_rmc_get;
+ tod_ops.tod_set = todm5819p_rmc_set;
+
+ tod_ops.tod_set_watchdog_timer =
+ todm5819p_rmc_set_watchdog_timer;
+ tod_ops.tod_clear_watchdog_timer =
+ todm5819p_rmc_clear_watchdog_timer;
+ tod_ops.tod_set_power_alarm = todm5819p_rmc_set_power_alarm;
+ tod_ops.tod_clear_power_alarm = todm5819p_rmc_clear_power_alarm;
+ tod_ops.tod_get_cpufrequency = todm5819p_rmc_get_cpufrequency;
+ if (boothowto & RB_DEBUG) {
+ cmn_err(CE_WARN, "todm5819p_rmc: kernel debugger "
+ "detected: hardware watchdog disabled");
+ }
+ }
+
+ return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+ if (strcmp(tod_module_name, "todm5819p_rmc") == 0)
+ return (EBUSY);
+
+ return (mod_remove(&modlinkage));
+}
+
+/*
+ * The loadable-module _info(9E) entry point
+ */
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+/*
+ * Read the current time from the clock chip and convert to UNIX form.
+ * Assumes that the year in the clock chip is valid.
+ * Must be called with tod_lock held.
+ */
+static timestruc_t
+todm5819p_rmc_get(void)
+{
+ int i;
+ int s;
+ timestruc_t ts;
+ struct rtc_t rtc;
+
+ ASSERT(MUTEX_HELD(&tod_lock));
+
+ /* set the hw watchdog timer if it's been activated */
+ if (watchdog_activated) {
+ int ret = 0;
+ ret = tod_ops.tod_set_watchdog_timer(0);
+ /*
+ * The empty set_watchdog routine returns a 0. So if a
+ * coded routine fails we will look for a -1 for a failure.
+ */
+ if (ret == -1)
+ cmn_err(CE_WARN, "todm5819p: failed to set hardware "
+ "watchdog timer.");
+ }
+
+ /*
+ * Read current time from the tod. If the tod isn't accessible, wait and
+ * retry.
+ * Run critical in the time critical section to avoid being interrupted
+ */
+ for (i = 0; i < TODM5819_UIP_RETRY_THRESH; i++) {
+ s = ddi_enter_critical();
+ M5819P_ADDR_REG = RTC_A;
+ if (!(M5819P_DATA_REG & RTC_UIP)) {
+ read_rtc(&rtc);
+ ddi_exit_critical(s);
+ break;
+ }
+ ddi_exit_critical(s);
+ drv_usecwait(TODM5819_UIP_WAIT_USEC);
+ }
+ if (i == TODM5819_UIP_RETRY_THRESH) {
+ /*
+ * tod is inaccessible: just return current software time
+ */
+ tod_fault_reset();
+ return (hrestime);
+ }
+
+ ts.tv_sec = tod_to_utc(rtc_to_tod(&rtc));
+ ts.tv_nsec = 0;
+ return (ts);
+}
+
+static todinfo_t
+rtc_to_tod(struct rtc_t *rtc)
+{
+ todinfo_t tod;
+
+ /*
+ * tod_year is base 1900 so this code needs to adjust the true year
+ * retrieved from the rtc's century and year fields.
+ */
+ tod.tod_year = rtc->rtc_year + (rtc->rtc_century * 100) - 1900;
+ tod.tod_month = rtc->rtc_mon;
+ tod.tod_day = rtc->rtc_dom;
+ tod.tod_dow = rtc->rtc_dow;
+ tod.tod_hour = rtc->rtc_hrs;
+ tod.tod_min = rtc->rtc_min;
+ tod.tod_sec = rtc->rtc_sec;
+
+ return (tod);
+}
+
+static void
+read_rtc(struct rtc_t *rtc)
+{
+ M5819P_ADDR_REG = RTC_SEC;
+ rtc->rtc_sec = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_ASEC;
+ rtc->rtc_asec = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_MIN;
+ rtc->rtc_min = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_AMIN;
+ rtc->rtc_amin = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_HRS;
+ rtc->rtc_hrs = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_AHRS;
+ rtc->rtc_ahrs = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_DOW;
+ rtc->rtc_dow = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_DOM;
+ rtc->rtc_dom = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_MON;
+ rtc->rtc_mon = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_YEAR;
+ rtc->rtc_year = M5819P_DATA_REG;
+ M5819P_ADDR_REG = RTC_CENTURY;
+ rtc->rtc_century = M5819P_DATA_REG;
+
+ /* Read date alarm */
+ M5819P_ADDR_REG = RTC_ADOM_REG;
+ rtc->rtc_adom = (M5819P_DATA_REG) & RTC_ADOM;
+}
+
+/*
+ * Write the specified time into the clock chip.
+ * Must be called with tod_lock held.
+ */
+static void
+todm5819p_rmc_set(timestruc_t ts)
+{
+ struct rtc_t rtc;
+ todinfo_t tod = utc_to_tod(ts.tv_sec);
+ int year;
+ rmc_comm_msg_t request;
+ dp_set_date_time_t set_time_msg;
+
+ ASSERT(MUTEX_HELD(&tod_lock));
+
+ /* tod_year is base 1900 so this code needs to adjust */
+ year = 1900 + tod.tod_year;
+ rtc.rtc_year = year % 100;
+ rtc.rtc_century = year / 100;
+ rtc.rtc_mon = (uint8_t)tod.tod_month;
+ rtc.rtc_dom = (uint8_t)tod.tod_day;
+ rtc.rtc_dow = (uint8_t)tod.tod_dow;
+ rtc.rtc_hrs = (uint8_t)tod.tod_hour;
+ rtc.rtc_min = (uint8_t)tod.tod_min;
+ rtc.rtc_sec = (uint8_t)tod.tod_sec;
+
+ write_rtc_time(&rtc);
+
+ set_time_msg.year = year - 1900;
+ set_time_msg.month = tod.tod_month - 1;
+ set_time_msg.day = tod.tod_day;
+ set_time_msg.hour = tod.tod_hour;
+ set_time_msg.minute = tod.tod_min;
+ set_time_msg.second = tod.tod_sec;
+
+ request.msg_type = DP_SET_DATE_TIME;
+ request.msg_len = sizeof (set_time_msg);
+ request.msg_buf = (caddr_t)&set_time_msg;
+
+ (void) rmc_comm_request_nowait(&request, 0);
+}
+
+void
+write_rtc_time(struct rtc_t *rtc)
+{
+ uint8_t regb;
+
+ /*
+ * Freeze
+ */
+ M5819P_ADDR_REG = RTC_B;
+ regb = M5819P_DATA_REG;
+ M5819P_DATA_REG = (regb | RTC_SET);
+
+ M5819P_ADDR_REG = RTC_SEC;
+ M5819P_DATA_REG = rtc->rtc_sec;
+ M5819P_ADDR_REG = RTC_MIN;
+ M5819P_DATA_REG = rtc->rtc_min;
+ M5819P_ADDR_REG = RTC_HRS;
+ M5819P_DATA_REG = rtc->rtc_hrs;
+ M5819P_ADDR_REG = RTC_DOW;
+ M5819P_DATA_REG = rtc->rtc_dow;
+ M5819P_ADDR_REG = RTC_DOM;
+ M5819P_DATA_REG = rtc->rtc_dom;
+ M5819P_ADDR_REG = RTC_MON;
+ M5819P_DATA_REG = rtc->rtc_mon;
+ M5819P_ADDR_REG = RTC_YEAR;
+ M5819P_DATA_REG = rtc->rtc_year;
+ M5819P_ADDR_REG = RTC_CENTURY;
+ M5819P_DATA_REG = rtc->rtc_century;
+
+ /*
+ * Unfreeze
+ */
+ M5819P_ADDR_REG = RTC_B;
+ M5819P_DATA_REG = regb;
+}
+
+void
+write_rtc_alarm(struct rtc_t *rtc)
+{
+ M5819P_ADDR_REG = RTC_ASEC;
+ M5819P_DATA_REG = rtc->rtc_asec;
+ M5819P_ADDR_REG = RTC_AMIN;
+ M5819P_DATA_REG = rtc->rtc_amin;
+ M5819P_ADDR_REG = RTC_AHRS;
+ M5819P_DATA_REG = rtc->rtc_ahrs;
+
+ M5819P_ADDR_REG = RTC_ADOM_REG;
+ M5819P_DATA_REG = rtc->rtc_adom;
+}
+
+/*
+ * program the rtc registers for alarm to go off at the specified time
+ */
+static void
+todm5819p_rmc_set_power_alarm(timestruc_t ts)
+{
+ todinfo_t tod;
+ uint8_t regb;
+ struct rtc_t rtc;
+
+ ASSERT(MUTEX_HELD(&tod_lock));
+ tod = utc_to_tod(ts.tv_sec);
+
+ /*
+ * disable alarms and clear AF flag by reading reg C
+ */
+ M5819P_ADDR_REG = RTC_B;
+ regb = M5819P_DATA_REG;
+ M5819P_DATA_REG = regb & ~RTC_AIE;
+ M5819P_ADDR_REG = RTC_C;
+ (void) M5819P_DATA_REG;
+
+ rtc.rtc_asec = (uint8_t)tod.tod_sec;
+ rtc.rtc_amin = (uint8_t)tod.tod_min;
+ rtc.rtc_ahrs = (uint8_t)tod.tod_hour;
+ rtc.rtc_adom = (uint8_t)tod.tod_day;
+
+ /*
+ * Write alarm values and enable alarm
+ */
+ write_rtc_alarm(&rtc);
+
+ M5819P_ADDR_REG = RTC_B;
+ M5819P_DATA_REG = regb | RTC_AIE;
+}
+
+/*
+ * clear alarm interrupt
+ */
+static void
+todm5819p_rmc_clear_power_alarm(void)
+{
+ uint8_t regb;
+
+ ASSERT(MUTEX_HELD(&tod_lock));
+
+ M5819P_ADDR_REG = RTC_B;
+ regb = M5819P_DATA_REG;
+ M5819P_DATA_REG = regb & ~RTC_AIE;
+}
+
+/*
+ * Determine the cpu frequency by watching the TOD chip rollover twice.
+ * Cpu clock rate is determined by computing the ticks added (in tick register)
+ * during one second interval on TOD.
+ */
+uint64_t
+todm5819p_rmc_get_cpufrequency(void)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+ M5819P_ADDR_REG = RTC_SEC;
+ return (find_cpufrequency(v_rtc_data_reg));
+}
+
+/*ARGSUSED*/
+static uint_t
+todm5819p_rmc_set_watchdog_timer(uint_t timeoutval)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+ return (0);
+}
+
+static uint_t
+todm5819p_rmc_clear_watchdog_timer(void)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+ return (0);
+}
diff --git a/usr/src/uts/sun4u/io/todstarcat.c b/usr/src/uts/sun4u/io/todstarcat.c
new file mode 100644
index 0000000000..a203ee27e6
--- /dev/null
+++ b/usr/src/uts/sun4u/io/todstarcat.c
@@ -0,0 +1,263 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * tod driver module for Starcat
+ * This module implements a soft tod since
+ * starcat has no tod part.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/modctl.h>
+#include <sys/autoconf.h>
+#include <sys/debug.h>
+#include <sys/clock.h>
+#include <sys/cmn_err.h>
+#include <sys/promif.h>
+#include <sys/cpuvar.h>
+#include <sys/sunddi.h>
+#include <sys/iosramio.h>
+#include <sys/domaind.h>
+
+#define abs(x) ((x) < 0 ? -(x) : (x))
+
+#define TODSC_SET_THRESHOLD 30
+
+static timestruc_t todsc_get(void);
+static void todsc_set(timestruc_t);
+static uint_t todsc_set_watchdog_timer(uint_t);
+static uint_t todsc_clear_watchdog_timer(void);
+static void todsc_set_power_alarm(timestruc_t);
+static void todsc_clear_power_alarm(void);
+static uint64_t todsc_get_cpufrequency(void);
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modlmisc modlmisc = {
+ &mod_miscops, "Soft tod module for Sun Fire 15000"
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, (void *)&modlmisc, NULL
+};
+
+static uint32_t heartbeat = 0;
+
+int
+_init(void)
+{
+ if (strcmp(tod_module_name, "todstarcat") == 0) {
+ uint32_t ssc_time32 = 0;
+ char obp_string[40];
+
+ /*
+ * To obtain the initial start of day time, we use an
+ * OBP callback; this is because the iosram is not yet
+ * accessible from the OS at this early stage of startup.
+ */
+
+ /*
+ * Set the string to pass to OBP
+ * for now, we assume we always get a 32bit value
+ */
+ (void) sprintf(obp_string, "h# %p unix-gettod",
+ (void *) &ssc_time32);
+
+ prom_interpret(obp_string, 0, 0, 0, 0, 0);
+
+ hrestime.tv_sec = (time_t)ssc_time32;
+
+ /*
+ * A date of zero causes the root filesystem driver
+ * to try to set the date from the last shutdown.
+ */
+
+ /*
+ * Check for a zero date.
+ */
+ if (ssc_time32 == 0) {
+ cmn_err(CE_WARN, "Initial date is invalid.");
+ cmn_err(CE_CONT, "Attempting to set the date and time "
+ "based on the last shutdown.\n");
+ cmn_err(CE_CONT, "Please inspect the date and time and "
+ "correct if necessary.\n");
+ }
+
+ /*
+ * Check that the date has not overflowed a 32-bit integer.
+ */
+ if (TIMESPEC_OVERFLOW(&hrestime)) {
+ cmn_err(CE_WARN, "Date overflow detected.");
+ cmn_err(CE_CONT, "Attempting to set the date and time "
+ "based on the last shutdown.\n");
+ cmn_err(CE_CONT, "Please inspect the date and time and "
+ "correct if necessary.\n");
+
+ hrestime.tv_sec = (time_t)0;
+ }
+
+ tod_ops.tod_get = todsc_get;
+ tod_ops.tod_set = todsc_set;
+ tod_ops.tod_set_watchdog_timer = todsc_set_watchdog_timer;
+ tod_ops.tod_clear_watchdog_timer = todsc_clear_watchdog_timer;
+ tod_ops.tod_set_power_alarm = todsc_set_power_alarm;
+ tod_ops.tod_clear_power_alarm = todsc_clear_power_alarm;
+ tod_ops.tod_get_cpufrequency = todsc_get_cpufrequency;
+
+ /*
+ * Flag warning if user tried to use hardware watchdog
+ */
+ if (watchdog_enable) {
+ cmn_err(CE_WARN, "Hardware watchdog unavailable");
+ }
+ }
+
+ return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+ if (strcmp(tod_module_name, "todstarcat") == 0)
+ return (EBUSY);
+ else
+ return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+/*
+ * Starcat tod_get is simplified to return hrestime and to
+ * update the domain heartbeat.
+ * Must be called with tod_lock held.
+ */
+static timestruc_t
+todsc_get(void)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+
+ heartbeat++;
+ (void) iosram_wr(DOMD_MAGIC, DOMD_HEARTBEAT_OFFSET,
+ sizeof (uint32_t), (caddr_t)&heartbeat);
+ return (hrestime);
+}
+
+/*
+ * Must be called with tod_lock held.
+ *
+ * When running NTP, tod_set is called at least once per second in order
+ * to update the hardware clock - for Starcat, we don't want to sync
+ * the non-existent hardware clock, and only want to record significant
+ * time changes on the SC (i.e. when date(1M) is run). So, we have a
+ * threshold requirement before recording the time change.
+ */
+/* ARGSUSED */
+static void
+todsc_set(timestruc_t ts)
+{
+ char obp_string[40];
+
+ ASSERT(MUTEX_HELD(&tod_lock));
+
+ heartbeat++;
+ (void) iosram_wr(DOMD_MAGIC, DOMD_HEARTBEAT_OFFSET,
+ sizeof (uint32_t), (caddr_t)&heartbeat);
+
+ if (abs(hrestime.tv_sec - ts.tv_sec) > TODSC_SET_THRESHOLD) {
+ /*
+ * Update the SSC with the new UTC domain time
+ */
+ (void) sprintf(obp_string, "h# %x unix-settod",
+ (int)ts.tv_sec);
+
+ prom_interpret(obp_string, 0, 0, 0, 0, 0);
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "todsc_set: new domain time 0x%lx\n",
+ ts.tv_sec);
+#endif
+ }
+}
+
+/*
+ * No watchdog function.
+ */
+/* ARGSUSED */
+static uint_t
+todsc_set_watchdog_timer(uint_t timeoutval)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+ return (0);
+}
+
+/*
+ * No watchdog function
+ */
+static uint_t
+todsc_clear_watchdog_timer(void)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+ return (0);
+}
+
+/*
+ * Null function.
+ */
+/* ARGSUSED */
+static void
+todsc_set_power_alarm(timestruc_t ts)
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+}
+
+/*
+ * Null function
+ */
+static void
+todsc_clear_power_alarm()
+{
+ ASSERT(MUTEX_HELD(&tod_lock));
+}
+
+/*
+ * Get clock freq from the cpunode. This function is only called
+ * when use_stick = 0, otherwise, system_clock_freq gets used instead.
+ */
+uint64_t
+todsc_get_cpufrequency(void)
+{
+ return (cpunodes[CPU->cpu_id].clock_freq);
+}
diff --git a/usr/src/uts/sun4u/todm5819p_rmc/Makefile b/usr/src/uts/sun4u/todm5819p_rmc/Makefile
new file mode 100644
index 0000000000..7725458687
--- /dev/null
+++ b/usr/src/uts/sun4u/todm5819p_rmc/Makefile
@@ -0,0 +1,89 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of todm5819p_rmc kernel module.
+#
+# sun4u implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = todm5819p_rmc
+OBJECTS = $(TODM5819P_RMC_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(TODM5819P_RMC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_TOD_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+LDFLAGS += -dy -Ndrv/rmc_comm -Ndrv/pmugpio
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4u/Makefile.targ
+
+
diff --git a/usr/src/uts/sun4u/todstarcat/Makefile b/usr/src/uts/sun4u/todstarcat/Makefile
new file mode 100644
index 0000000000..f7fd26cc89
--- /dev/null
+++ b/usr/src/uts/sun4u/todstarcat/Makefile
@@ -0,0 +1,88 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sun4u/todstarcat/Makefile
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the todstarcat
+# kernel module.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = todstarcat
+OBJECTS = $(TODSTARCAT_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(TODSTARCAT_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_TOD_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4u/Makefile.sun4u
+
+INC_PATH += -I$(UTSBASE)/sun4u/starcat
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# module dependencies
+#
+LDFLAGS += -dy -Ndrv/sbbc -Ndrv/iosram
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4u/Makefile.targ