diff options
author | gd78059 <none@none> | 2007-04-30 10:50:04 -0700 |
---|---|---|
committer | gd78059 <none@none> | 2007-04-30 10:50:04 -0700 |
commit | 1c42de6d020629af774dd9e9fc81be3f3ed9398e (patch) | |
tree | 15cbf9112a829bff65ac3785ece9f853d9923b34 /usr/src/uts/sun4u | |
parent | d937e6eba72212175f797019b27df74950ec78cd (diff) | |
download | illumos-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.files | 7 | ||||
-rw-r--r-- | usr/src/uts/sun4u/Makefile.sun4u.shared | 8 | ||||
-rw-r--r-- | usr/src/uts/sun4u/blade/Makefile.blade.shared | 6 | ||||
-rw-r--r-- | usr/src/uts/sun4u/blade/Makefile.files | 9 | ||||
-rw-r--r-- | usr/src/uts/sun4u/blade/bscbus/Makefile | 100 | ||||
-rw-r--r-- | usr/src/uts/sun4u/blade/bscv/Makefile | 94 | ||||
-rw-r--r-- | usr/src/uts/sun4u/blade/io/bscbus.conf | 31 | ||||
-rw-r--r-- | usr/src/uts/sun4u/blade/io/bscv.conf | 33 | ||||
-rw-r--r-- | usr/src/uts/sun4u/gptwo_cpu/Makefile | 115 | ||||
-rw-r--r-- | usr/src/uts/sun4u/gptwocfg/Makefile | 95 | ||||
-rw-r--r-- | usr/src/uts/sun4u/i2bsc/Makefile | 112 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/gptwo_cpu.c | 1023 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/gptwocfg.c | 683 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/i2c/nexus/i2bsc.c | 1257 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/i2c/nexus/i2bsc.conf | 31 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/todm5819p_rmc.c | 409 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/todstarcat.c | 263 | ||||
-rw-r--r-- | usr/src/uts/sun4u/todm5819p_rmc/Makefile | 89 | ||||
-rw-r--r-- | usr/src/uts/sun4u/todstarcat/Makefile | 88 |
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 *)®, + 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 *)®, + 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 *)®, + 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 |