summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorWilliam Bryan <wilbryan@us.ibm.com>2015-08-03 12:38:58 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2015-08-03 15:32:27 -0500
commit420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch)
treec9f6691eddba39193e39aa769367e1267fb9fc86 /src/lib
parentadade8c8ef30ed519322674c762d95663009c5d4 (diff)
downloadtalos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz
talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/lib')
-rwxr-xr-xsrc/lib/Makefile71
-rwxr-xr-xsrc/lib/assert.c47
-rw-r--r--src/lib/common/Makefile57
-rw-r--r--src/lib/common/README.txt1
-rw-r--r--src/lib/common/kernel.h363
-rw-r--r--src/lib/common/libcommonfiles.mk54
-rw-r--r--[-rwxr-xr-x]src/lib/common/memcpy.c (renamed from src/lib/memcpy.c)26
-rw-r--r--[-rwxr-xr-x]src/lib/common/memset.c (renamed from src/lib/memset.c)26
-rw-r--r--src/lib/common/rand.h124
-rw-r--r--src/lib/common/rand32.c384
-rw-r--r--[-rwxr-xr-x]src/lib/common/string.c (renamed from src/lib/string.c)27
-rw-r--r--src/lib/common/string.h88
-rw-r--r--src/lib/common/sync.c294
-rw-r--r--src/lib/common/sync.h167
-rwxr-xr-xsrc/lib/ctype.c22
-rwxr-xr-xsrc/lib/errno.h25
-rwxr-xr-xsrc/lib/gpe.h78
-rwxr-xr-xsrc/lib/gpe_control.h171
-rwxr-xr-xsrc/lib/gpe_control.pS160
-rwxr-xr-xsrc/lib/gpe_data.h672
-rwxr-xr-xsrc/lib/gpe_data.pS1585
-rwxr-xr-xsrc/lib/gpe_pba.c148
-rw-r--r--src/lib/gpe_pba.h116
-rwxr-xr-xsrc/lib/gpe_pba_pgas.pS110
-rw-r--r--src/lib/gpe_scom.h471
-rw-r--r--src/lib/gpe_scom.pS709
-rwxr-xr-xsrc/lib/gpsm.c600
-rwxr-xr-xsrc/lib/gpsm.h191
-rwxr-xr-xsrc/lib/gpsm_dcm.c753
-rwxr-xr-xsrc/lib/gpsm_dcm.h192
-rwxr-xr-xsrc/lib/gpsm_dcm_fast_handler.S147
-rwxr-xr-xsrc/lib/gpsm_init.c1639
-rwxr-xr-xsrc/lib/heartbeat.c328
-rwxr-xr-xsrc/lib/heartbeat.h46
-rwxr-xr-xsrc/lib/libfiles.mk57
-rwxr-xr-xsrc/lib/libgpefiles.mk30
-rwxr-xr-xsrc/lib/libssx.h20
-rw-r--r--src/lib/occlib/Makefile57
-rw-r--r--src/lib/occlib/README.txt1
-rw-r--r--src/lib/occlib/ipc_api.h519
-rw-r--r--src/lib/occlib/ipc_async_cmd.h49
-rw-r--r--src/lib/occlib/ipc_core.c484
-rw-r--r--src/lib/occlib/ipc_init.c153
-rw-r--r--src/lib/occlib/ipc_macros.h197
-rw-r--r--src/lib/occlib/ipc_msgq.c108
-rw-r--r--src/lib/occlib/ipc_ping.c96
-rw-r--r--src/lib/occlib/ipc_ping.h53
-rw-r--r--src/lib/occlib/ipc_structs.h226
-rw-r--r--src/lib/occlib/liboccfiles.mk53
-rw-r--r--src/lib/occlib/occhw_scom_cmd.h93
-rw-r--r--src/lib/occlib/occhw_shared_data.h93
-rw-r--r--src/lib/occlib/occhw_xir_dump.c60
-rw-r--r--src/lib/occlib/occhw_xir_dump.h70
-rwxr-xr-xsrc/lib/pgas.h1153
-rwxr-xr-xsrc/lib/pgas_ppc.h529
-rwxr-xr-xsrc/lib/pgp_config.h108
-rwxr-xr-xsrc/lib/pmc_dcm.c425
-rwxr-xr-xsrc/lib/pmc_dcm.h102
-rw-r--r--src/lib/polling.c73
-rwxr-xr-xsrc/lib/pore_hooks.h171
-rw-r--r--src/lib/ppc405lib/Makefile57
-rw-r--r--src/lib/ppc405lib/README.txt4
-rw-r--r--src/lib/ppc405lib/assert.c71
-rw-r--r--src/lib/ppc405lib/byte_pool.c1442
-rw-r--r--src/lib/ppc405lib/byte_pool.h166
-rw-r--r--src/lib/ppc405lib/chip_config.h109
-rw-r--r--src/lib/ppc405lib/ctype.c46
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/ctype.h (renamed from src/lib/ctype.h)24
-rw-r--r--src/lib/ppc405lib/ctype_table.c (renamed from src/lib/ctype_table.c)24
-rw-r--r--src/lib/ppc405lib/errno.h49
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/fgetc.c (renamed from src/lib/fgetc.c)24
-rw-r--r--src/lib/ppc405lib/initcall.c70
-rw-r--r--src/lib/ppc405lib/initcall.h116
-rw-r--r--src/lib/ppc405lib/lfsr.c50
-rw-r--r--src/lib/ppc405lib/lfsr.h46
-rw-r--r--src/lib/ppc405lib/libppc405files.mk74
-rw-r--r--src/lib/ppc405lib/libssx.h44
-rw-r--r--src/lib/ppc405lib/mutex.c129
-rw-r--r--src/lib/ppc405lib/mutex.h164
-rw-r--r--src/lib/ppc405lib/periodic_semaphore.c114
-rw-r--r--src/lib/ppc405lib/periodic_semaphore.h152
-rw-r--r--src/lib/ppc405lib/polling.c97
-rw-r--r--src/lib/ppc405lib/polling.h (renamed from src/lib/polling.h)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/printf.c (renamed from src/lib/printf.c)24
-rw-r--r--src/lib/ppc405lib/progress.c743
-rw-r--r--src/lib/ppc405lib/progress.h177
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/puts.c (renamed from src/lib/puts.c)24
-rw-r--r--src/lib/ppc405lib/rtx_stdio.c149
-rw-r--r--src/lib/ppc405lib/rtx_stdio.h74
-rw-r--r--src/lib/ppc405lib/rtx_stdio_addresses.h55
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/simics_stdio.c (renamed from src/lib/simics_stdio.c)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/simics_stdio.h (renamed from src/lib/simics_stdio.h)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/simics_stdio_addresses.h (renamed from src/lib/simics_stdio_addresses.h)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/sprintf.c (renamed from src/lib/sprintf.c)24
-rw-r--r--src/lib/ppc405lib/ssx_dump.c (renamed from src/lib/ssx_dump.c)24
-rw-r--r--src/lib/ppc405lib/ssx_dump.h (renamed from src/lib/ssx_dump.h)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/ssx_io.c (renamed from src/lib/ssx_io.c)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/ssx_io.h (renamed from src/lib/ssx_io.h)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/stdlib.c (renamed from src/lib/stdlib.c)24
-rw-r--r--src/lib/ppc405lib/strcasecmp.c (renamed from src/lib/strcasecmp.c)24
-rw-r--r--src/lib/ppc405lib/strdup.c63
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/string_stream.c (renamed from src/lib/string_stream.c)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/string_stream.h (renamed from src/lib/string_stream.h)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/strtox.c (renamed from src/lib/strtox.c)24
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/strtox.h (renamed from src/lib/strtox.h)24
-rw-r--r--src/lib/ppc405lib/sxlock.c494
-rw-r--r--src/lib/ppc405lib/sxlock.h108
-rw-r--r--[-rwxr-xr-x]src/lib/ppc405lib/time.c (renamed from src/lib/time.c)24
-rwxr-xr-xsrc/lib/pstates.c410
-rwxr-xr-xsrc/lib/pstates.h835
-rw-r--r--src/lib/special_wakeup.c149
-rw-r--r--src/lib/special_wakeup.h32
-rwxr-xr-xsrc/lib/strdup.c39
-rwxr-xr-xsrc/lib/string.h64
-rwxr-xr-xsrc/lib/vrm.c394
-rwxr-xr-xsrc/lib/vrm.h59
116 files changed, 9285 insertions, 12936 deletions
diff --git a/src/lib/Makefile b/src/lib/Makefile
deleted file mode 100755
index 2d257a6..0000000
--- a/src/lib/Makefile
+++ /dev/null
@@ -1,71 +0,0 @@
-# $Id: Makefile,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-#
-# This Makefile currently builds a single archive, 'libssx.a', from
-# various library source files.
-#
-# Beware that although this library can be built standalone, parts of
-# its behavior are controlled by options that may be configured in
-# the optional "ssx_app_cfg.h", so it is best to build the library as
-# part of the complete application build.
-#
-# The object files stored in the archive are loaded 'on demand'.
-# It may be possible to save a little code space therefore by splitting up
-# the implementation of a header file into multiple files whose
-# functions are not necessarily called together.
-
-SSX = ../ssx
-PGP = $(SSX)/pgp
-LIB = .
-
-include ./libfiles.mk
-include ./libgpefiles.mk
-INCLUDES =
-
-include $(PGP)/ssx.mk
-
-libssx.a: $(LIBSSX_OBJECTS)
- $(AR) crs libssx.a $(LIBSSX_OBJECTS)
-
-clean:
- rm -f *.o *.a *.d *.d.* *.lst *.hooks.cc
- rm -f $(TEST_EXECUTABLES)
-
-disassemble: libssx.a
- $(OBJDUMP) -d libssx.a
-
-
-# The targets 'push_updates_to_lab' and 'diff_with_lab' require that an
-# environment variable P8PROCS be defined. You can also define this on the
-# 'make' command line, for example
-#
-# make P8PROCS=<... path to your P8 procedures sandbox ...> \
-# push_updates_to_lab
-
-# LIB-TO-PROCS-FILES are files kept here that need to go there, where 'there'
-# is the top-level procedures directory.
-
-LIB-TO-PROCS-FILES = pgas.h pgas_ppc.h
-
-push_updates_to_lab:
- if [ -z "$(P8PROCS)" ]; then echo "P8PROCS is not defined"; exit 1; fi
- cp -u $(LIB-TO-PROCS-FILES) $(P8PROCS)
-
-diff_with_lab:
- if [ -z "$(P8PROCS)" ]; then echo "P8PROCS is not defined"; exit 1; fi
-
- for file in $(LIB-TO-PROCS-FILES); do \
- echo "@@@ $$file"; \
- diff $$file $(P8PROCS)/$$file; \
- done; exit 0
-
-
-ifneq ($(MAKECMDGOALS),clean)
-ifneq ($(MAKECMDGOALS),push_updates_to_lab)
-ifneq ($(MAKECMDGOALS),diff_with_lab)
-include $(C-SOURCES:.c=.d)
-include $(S-SOURCES:.S=.d)
-include $(if $(filter -DOCC_FIRMWARE=1,$(DEFS)),$(if $(PGAS_PPC),$(pS-SOURCES:.pS=.d),),$(pS-SOURCES:.pS=.d))
-endif
-endif
-endif
-
diff --git a/src/lib/assert.c b/src/lib/assert.c
deleted file mode 100755
index 36e3caf..0000000
--- a/src/lib/assert.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// $Id: assert.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/assert.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file assert.c
-/// \brief Implementation of library routines implied by <assert.h>
-
-#include "ssx.h"
-#include "ssx_io.h"
-#include "libssx.h"
-
-/// The __assert_fail() function is used to implement the assert() interface
-/// of ISO POSIX (2003). The __assert_fail() function prints the given \a
-/// file filename, \a line line number, \a function function name and a
-/// message on the standard error stream then causes a kernel panic. If there
-/// is no standard error stream then the error message is printed on the \a
-/// ssxout (printk()) stream.
-///
-/// If function is NULL, __assert_fail() omits information about the
-/// function. The aguments \a assertion, \a file, and \a line must be
-/// non-NULL.
-
-void
-__assert_fail(const char *assertion,
- const char *file,
- unsigned line,
- const char *function)
-{
- FILE *stream;
-
- stream = stderr;
- if (stream == 0) {
- stream = ssxout;
- }
-
- fprintf(stream, "%s:%u:%s%s Assertion '%s' failed\n",
- file, line,
- function ? function : "", function ? ":" : "",
- assertion);
-
- SSX_PANIC(ASSERTION_FAILURE);
-}
-
diff --git a/src/lib/common/Makefile b/src/lib/common/Makefile
new file mode 100644
index 0000000..5147b59
--- /dev/null
+++ b/src/lib/common/Makefile
@@ -0,0 +1,57 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/common/Makefile $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# This Makefile currently builds a single archive, 'libcommon.a', from
+# various library source files.
+#
+# part of the complete application build.
+#
+
+#all generated files from this makefile will end up in obj/$(IMAGE_NAME)/common
+export SUB_OBJDIR = /commonlib
+
+include img_defs.mk
+include libcommonfiles.mk
+
+OBJS := $(addprefix $(OBJDIR)/, $(LIBCOMMON_OBJECTS))
+
+libcommon.a: local
+ $(AR) crs $(OBJDIR)/libcommon.a $(OBJDIR)/*.o
+
+.PHONY: clean
+
+local: $(OBJS)
+
+$(OBJS) $(OBJS:.o=.d): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+clean:
+ rm -fr $(OBJDIR)
+
+ifneq ($(MAKECMDGOALS),clean)
+#include $(OBJS:.o=.d)
+endif
+
diff --git a/src/lib/common/README.txt b/src/lib/common/README.txt
new file mode 100644
index 0000000..760da25
--- /dev/null
+++ b/src/lib/common/README.txt
@@ -0,0 +1 @@
+This directory contains code that can run on any PPE or 405 processor.
diff --git a/src/lib/common/kernel.h b/src/lib/common/kernel.h
new file mode 100644
index 0000000..063d35c
--- /dev/null
+++ b/src/lib/common/kernel.h
@@ -0,0 +1,363 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/kernel.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __KERNEL_H__
+#define __KERNEL_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file kernel.h
+/// \brief Kernel agnostic macros that allow the same code to work with
+/// different kernels.
+///
+/// Programmers can include this instead of pk.h or ssx.h
+///
+///
+#ifndef __ASSEMBLER__
+#ifdef __SSX__
+
+/// ----------------------- Use SSX kernel interfaces --------------------------
+
+#include "ssx.h"
+
+//Types
+#define KERN_SEMAPHORE SsxSemaphore
+#define KERN_SEMAPHORE_COUNT SsxSemaphoreCount
+#define KERN_DEQUE SsxDeque
+#define KERN_THREAD SsxThread
+#define KERN_THREAD_PRIORITY SsxThreadPriority
+#define KERN_THREAD_STATE SsxThreadState
+#define KERN_THREAD_ROUTINE SsxThreadRoutine
+#define KERN_THREAD_FLAGS SsxThreadFlags
+#define KERN_ADDRESS SsxAddress
+#define KERN_TIMER SsxTimer
+#define KERN_TIMER_CALLBACK SsxTimerCallback
+#define KERN_INTERVAL SsxInterval
+#define KERN_TIMEBASE SsxTimebase
+#define KERN_IRQ_ID SsxIrqId
+#define KERN_MACHINE_CONTEXT SsxMachineContext
+
+//Constants
+#define KERN_SEMAPHORE_PEND_TIMED_OUT SSX_SEMAPHORE_PEND_TIMED_OUT
+#define KERN_SEMAPHORE_PEND_NO_WAIT SSX_SEMAPHORE_PEND_NO_WAIT
+#define KERN_NONCRITICAL SSX_NONCRITICAL
+#define KERN_CRITICAL SSX_CRITICAL
+#define KERN_SUPERCRITICAL SSX_SUPERCRITICAL
+#define KERN_ERROR_CHECK_API SSX_ERROR_CHECK_API
+#define KERN_NO_WAIT SSX_NO_WAIT
+#define KERN_WAIT_FOREVER SSX_WAIT_FOREVER
+
+//Functions
+#define KERN_SECONDS(s) SSX_SECONDS(s)
+#define KERN_MILLISECONDS(m) SSX_MILLISECONDS(m)
+#define KERN_MICROSECONDS(u) SSX_MICROSECONDS(u)
+#define KERN_NANOSECONDS(n) SSX_NANOSECONDS(n)
+
+#define KERN_TIMEBASE_GET() ssx_timebase_get()
+#define KERN_TIMEBASE_SET(tb) ssx_timebase_set(tb)
+
+#define KERN_INTERRUPT_PREEMPTION_ENABLE() ssx_interrupt_preemption_enable()
+#define KERN_INTERRUPT_PREEMPTION_DISABLE() ssx_interrupt_preemption_disable()
+
+#define KERN_TIMER_CREATE(timer, callback, arg) \
+ ssx_timer_create(timer, callback, arg)
+#define KERN_TIMER_CREATE_NONPREEMPTIBLE(timer, callback, arg) \
+ ssx_timer_create_nonpreemptible(timer, callback, arg)
+#define KERN_TIMER_SCHEDULE_ABSOLUTE(timer, time, period) \
+ ssx_timer_schedule_absolute(timer, time, period)
+#define KERN_TIMER_SCHEDULE(timer, interval, period) \
+ ssx_timer_schedule(timer, interval, period)
+#define KERN_TIMER_CANCEL(timer) \
+ ssx_timer_cancel(timer)
+#define KERN_TIMER_INFO_GET(timer, timeout, active) \
+ ssx_timer_info_get(timer, timeout, active)
+
+#define KERN_THREAD_CREATE(thread, thread_routine, arg, stack, stack_size, priority) \
+ ssx_thread_create(thread, thread_routine, arg, stack, stack_size, priority)
+#define KERN_THREAD_INFO_GET(thread, state, priority, runnable) \
+ ssx_thread_info_get(thread, state, priority, runnable)
+#define KERN_THREAD_PRIORTY_CHANGE(thread, new_priority, old_priority) \
+ ssx_thread_priority_change(thread, new_priority, old_priority)
+#define KERN_THREAD_AT_PRIORITY(priority, thread) \
+ ssx_thread_at_priority(priority, thread)
+#define KERN_THREAD_PRIORITY_SWAP(thread_a, thread_b) \
+ ssx_thread_priority_swap(thread_a, thread_b)
+
+#define KERN_START_THREADS() ssx_start_threads()
+#define KERN_THREAD_RESUME(thread) ssx_thread_resume(thread)
+#define KERN_THREAD_SUSPEND(thread) ssx_thread_suspend(thread)
+#define KERN_THREAD_DELETE(thread) ssx_thread_delete(thread)
+#define KERN_COMPLETE() ssx_complete()
+#define KERN_SLEEP_ABSOLUTE(time) ssx_sleep_absolute(time)
+#define KERN_SLEEP(interval) ssx_sleep(interval)
+
+#define KERN_SEMAPHORE_CREATE(semaphore, initial_count, max_count) \
+ ssx_semaphore_create(semaphore, initial_count,max_count)
+#define KERN_SEMAPHORE_STATIC_CREATE(sem, initial_count, max_count) \
+ SSX_SEMAPHORE(sem, initial_count, max_count)
+#define KERN_SEMAPHORE_INITIALIZATION(_initial_count, _max_count) \
+ SSX_SEMAPHORE_INITIALIZATION(_initial_count, _max_count)
+#define KERN_SEMAPHORE_INFO_GET(semaphore, count, pending) \
+ ssx_semaphore_info_get(semaphore, count, pending)
+
+#define KERN_SEMAPHORE_POST(semaphore) \
+ ssx_semaphore_post(semaphore)
+#define KERN_SEMAPHORE_PEND(semaphore, timeout) \
+ ssx_semaphore_pend(semaphore, timeout)
+#define KERN_SEMAPHORE_RELEASE_ALL(semaphore) \
+ ssx_semaphore_release_all(semaphore)
+#define KERN_SEMAPHORE_POST_HANDLER(arg, irq, priority) \
+ ssx_semaphore_post_handler(arg, irq, priority)
+
+
+#define KERN_HALT() \
+ ssx_halt()
+#define KERN_PANIC(code) \
+ SSX_PANIC(code)
+
+#define KERN_DEQUE_SENTINEL_CREATE(deque) \
+ ssx_deque_sentinel_create(deque)
+#define KERN_DEQUE_SENTINEL_STATIC_CREATE(deque) \
+ SSX_DEQUE_SENTINEL_STATIC_CREATE(deque)
+#define KERN_DEQUE_SENTINEL_INIT(dq_addr) \
+ SSX_DEQUE_SENTINEL_INIT(dq_addr)
+#define KERN_DEQUE_ELEMENT_CREATE(element) \
+ ssx_deque_element_create(element)
+#define KERN_DEQUE_ELEMENT_STATIC_CREATE(deque) \
+ SSX_DEQUE_ELEMENT_STATIC_CREATE(deque)
+#define KERN_DEQUE_ELEMENT_INIT() \
+ SSX_DEQUE_ELEMENT_INIT()
+#define KERN_DEQUE_IS_EMPTY(deque) \
+ ssx_deque_is_empty(deque)
+#define KERN_DEQUE_IS_QUEUED(element) \
+ ssx_deque_is_queued(element)
+#define KERN_DEQUE_PUSH_BACK(deque, element) \
+ ssx_deque_push_back(deque, element)
+#define KERN_DEQUE_PUSH_FRONT(deque, element) \
+ ssx_deque_push_front(deque, element)
+#define KERN_DEQUE_POP_FRONT(deque) \
+ ssx_deque_pop_front(deque)
+#define KERN_DEQUE_DELETE(element) \
+ ssx_deque_delete(element)
+
+#define KERN_IRQ_HANDLER(f) \
+ SSX_IRQ_HANDLER(f)
+#define KERN_IRQ_SETUP(irq, polarity, trigger) \
+ ssx_irq_setup(irq, polarity, trigger)
+#define KERN_IRQ_HANDLER_SET(irq, handler, arg, priority) \
+ ssx_irq_handler_set(irq, handler, arg, priority)
+#define KERN_IRQ_ENABLE(irq) \
+ ssx_irq_enable(irq)
+#define KERN_IRQ_DISABLE(irq) \
+ ssx_irq_disable(irq)
+#define KERN_IRQ_STATUS_CLEAR(irq) \
+ ssx_irq_status_clear(irq)
+#define KERN_IRQ_STATUS_SET(irq, value) \
+ ssx_irq_status_set(irq, value)
+#define KERN_IRQ_FAST2FULL(fast_handler, full_handler) \
+ SSX_IRQ_FAST2FULL(fast_handler, full_handler)
+
+#define KERN_CRITICAL_SECTION_ENTER(priority, pctx) \
+ ssx_critical_section_enter(priority, pctx)
+#define KERN_CRITICAL_SECTION_EXIT(pctx) \
+ ssx_critical_section_exit(pctx)
+#define KERN_CONTEXT_CRITICAL_INTERRUPT() \
+ __ssx_kernel_context_critical_interrupt()
+
+#define KERN_ERROR_IF(condition, code) SSX_ERROR_IF(condition, code)
+
+#define KERN_CAST_POINTER(t, p) SSX_CAST_POINTER(t, p)
+
+#define KERN_STATIC_ASSERT(cond) SSX_STATIC_ASSERT(cond)
+
+#elif defined(__PK__)
+
+/// ----------------------- Use PK kernel interfaces --------------------------
+
+#include "pk.h"
+
+//Types
+#define KERN_SEMAPHORE PkSemaphore
+#define KERN_SEMAPHORE_COUNT PkSemaphoreCount
+#define KERN_DEQUE PkDeque
+#define KERN_THREAD PkThread
+#define KERN_THREAD_PRIORITY PkThreadPriority
+#define KERN_THREAD_STATE PkThreadState
+#define KERN_THREAD_ROUTINE PkThreadRoutine
+#define KERN_THREAD_FLAGS PkThreadFlags
+#define KERN_ADDRESS PkAddress
+#define KERN_TIMER PkTimer
+#define KERN_TIMER_CALLBACK PkTimerCallback
+#define KERN_INTERVAL PkInterval
+#define KERN_TIMEBASE PkTimebase
+#define KERN_IRQ_ID PkIrqId
+#define KERN_MACHINE_CONTEXT PkMachineContext
+
+//Constants
+#define KERN_SEMAPHORE_PEND_TIMED_OUT PK_SEMAPHORE_PEND_TIMED_OUT
+#define KERN_SEMAPHORE_PEND_NO_WAIT PK_SEMAPHORE_PEND_NO_WAIT
+#define KERN_NONCRITICAL 0
+#define KERN_CRITICAL 0
+#define KERN_SUPERCRITICAL 0
+#define KERN_ERROR_CHECK_API PK_ERROR_CHECK_API
+#define KERN_NO_WAIT PK_NO_WAIT
+#define KERN_WAIT_FOREVER PK_WAIT_FOREVER
+
+//Functions
+#define KERN_SECONDS(s) PK_SECONDS(s)
+#define KERN_MILLISECONDS(m) PK_MILLISECONDS(m)
+#define KERN_MICROSECONDS(u) PK_MICROSECONDS(u)
+#define KERN_NANOSECONDS(n) PK_NANOSECONDS(n)
+
+#define KERN_TIMEBASE_GET() pk_timebase_get()
+#define KERN_TIMEBASE_SET(tb) pk_timebase_set(tb)
+
+#define KERN_INTERRUPT_PREEMPTION_ENABLE() pk_interrupt_preemption_enable()
+#define KERN_INTERRUPT_PREEMPTION_DISABLE() pk_interrupt_preemption_disable()
+
+#define KERN_TIMER_CREATE(timer, callback, arg) \
+ pk_timer_create(timer, callback, arg)
+#define KERN_TIMER_CREATE_NONPREEMPTIBLE(timer, callback, arg) \
+ pk_timer_create_nonpreemptible(timer, callback, arg)
+#define KERN_TIMER_SCHEDULE_ABSOLUTE(timer, time, period) \
+ pk_timer_schedule_absolute(timer, time, period)
+#define KERN_TIMER_SCHEDULE(timer, interval, period) \
+ pk_timer_schedule(timer, interval, period)
+#define KERN_TIMER_CANCEL(timer) \
+ pk_timer_cancel(timer)
+#define KERN_TIMER_INFO_GET(timer, timeout, active) \
+ pk_timer_info_get(timer, timeout, active)
+
+#define KERN_THREAD_CREATE(thread, thread_routine, arg, stack, stack_size, priority) \
+ pk_thread_create(thread, thread_routine, arg, stack, stack_size, priority)
+#define KERN_THREAD_INFO_GET(thread, state, priority, runnable) \
+ pk_thread_info_get(thread, state, priority, runnable)
+#define KERN_THREAD_PRIORTY_CHANGE(thread, new_priority, old_priority) \
+ pk_thread_priority_change(thread, new_priority, old_priority)
+#define KERN_THREAD_AT_PRIORITY(priority, thread) \
+ pk_thread_at_priority(priority, thread)
+#define KERN_THREAD_PRIORITY_SWAP(thread_a, thread_b) \
+ pk_thread_priority_swap(thread_a, thread_b)
+
+#define KERN_START_THREADS() pk_start_threads()
+#define KERN_THREAD_RESUME(thread) pk_thread_resume(thread)
+#define KERN_THREAD_SUSPEND(thread) pk_thread_suspend(thread)
+#define KERN_THREAD_DELETE(thread) pk_thread_delete(thread)
+#define KERN_COMPLETE() pk_complete()
+#define KERN_SLEEP_ABSOLUTE(time) pk_sleep_absolute(time)
+#define KERN_SLEEP(interval) pk_sleep(interval)
+
+#define KERN_SEMAPHORE_CREATE(semaphore, initial_count, max_count) \
+ pk_semaphore_create(semaphore, initial_count,max_count)
+#define KERN_SEMAPHORE_STATIC_CREATE(sem, initial_count, max_count) \
+ PK_SEMAPHORE(sem, initial_count, max_count)
+#define KERN_SEMAPHORE_INITIALIZATION(_initial_count, _max_count) \
+ PK_SEMAPHORE_INITIALIZATION(_initial_count, _max_count)
+#define KERN_SEMAPHORE_INFO_GET(semaphore, count, pending) \
+ pk_semaphore_info_get(semaphore, count, pending)
+
+#define KERN_SEMAPHORE_POST(semaphore) \
+ pk_semaphore_post(semaphore)
+#define KERN_SEMAPHORE_PEND(semaphore, timeout) \
+ pk_semaphore_pend(semaphore, timeout)
+#define KERN_SEMAPHORE_RELEASE_ALL(semaphore) \
+ pk_semaphore_release_all(semaphore)
+#define KERN_SEMAPHORE_POST_HANDLER(arg, irq, priority) \
+ pk_semaphore_post_handler(arg, irq, priority)
+
+
+#define KERN_HALT() \
+ pk_halt()
+#define KERN_PANIC(code) \
+ PK_PANIC(code)
+
+#define KERN_DEQUE_SENTINEL_CREATE(deque) \
+ pk_deque_sentinel_create(deque)
+#define KERN_DEQUE_SENTINEL_STATIC_CREATE(deque) \
+ PK_DEQUE_SENTINEL_STATIC_CREATE(deque)
+#define KERN_DEQUE_SENTINEL_INIT(dq_addr) \
+ PK_DEQUE_SENTINEL_INIT(dq_addr)
+#define KERN_DEQUE_ELEMENT_CREATE(element) \
+ pk_deque_element_create(element)
+#define KERN_DEQUE_ELEMENT_STATIC_CREATE(deque) \
+ PK_DEQUE_ELEMENT_STATIC_CREATE(deque)
+#define KERN_DEQUE_ELEMENT_INIT() \
+ PK_DEQUE_ELEMENT_INIT()
+#define KERN_DEQUE_IS_EMPTY(deque) \
+ pk_deque_is_empty(deque)
+#define KERN_DEQUE_IS_QUEUED(element) \
+ pk_deque_is_queued(element)
+#define KERN_DEQUE_PUSH_BACK(deque, element) \
+ pk_deque_push_back(deque, element)
+#define KERN_DEQUE_PUSH_FRONT(deque, element) \
+ pk_deque_push_front(deque, element)
+#define KERN_DEQUE_POP_FRONT(deque) \
+ pk_deque_pop_front(deque)
+#define KERN_DEQUE_DELETE(element) \
+ pk_deque_delete(element)
+
+#define KERN_IRQ_HANDLER(f) \
+ PK_IRQ_HANDLER(f)
+#define KERN_IRQ_SETUP(irq, polarity, trigger) \
+ pk_irq_setup(irq, polarity, trigger)
+#define KERN_IRQ_HANDLER_SET(irq, handler, arg, priority) \
+ pk_irq_handler_set(irq, handler, arg)
+#define KERN_IRQ_ENABLE(irq) \
+ pk_irq_enable(irq)
+#define KERN_IRQ_DISABLE(irq) \
+ pk_irq_disable(irq)
+#define KERN_IRQ_STATUS_CLEAR(irq) \
+ pk_irq_status_clear(irq)
+#define KERN_IRQ_STATUS_SET(irq, value) \
+ pk_irq_status_set(irq, value)
+#define KERN_IRQ_FAST2FULL(fast_handler, full_handler) \
+ PK_IRQ_FAST2FULL(fast_handler, full_handler)
+
+#define KERN_CRITICAL_SECTION_ENTER(priority, pctx) \
+ pk_critical_section_enter(pctx)
+#define KERN_CRITICAL_SECTION_EXIT(pctx) \
+ pk_critical_section_exit(pctx)
+#define KERN_CONTEXT_CRITICAL_INTERRUPT() \
+ (0)
+
+#define KERN_ERROR_IF(condition, code) PK_ERROR_IF(condition, code)
+
+#define KERN_CAST_POINTER(t, p) PK_CAST_POINTER(t, p)
+
+#define KERN_STATIC_ASSERT(cond) PK_STATIC_ASSERT(cond)
+
+#else
+
+/// ----------------------- Kernel type not defined --------------------------
+
+#error "Kernel type must be defined in img_defs.mk"
+
+#endif /*__SSX__*/
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __KERNEL_H__ */
diff --git a/src/lib/common/libcommonfiles.mk b/src/lib/common/libcommonfiles.mk
new file mode 100644
index 0000000..9fe7592
--- /dev/null
+++ b/src/lib/common/libcommonfiles.mk
@@ -0,0 +1,54 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/common/libcommonfiles.mk $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# @file libcommonfiles.mk
+#
+# @brief mk for libcommon.a object files
+#
+# @page ChangeLogs Change Logs
+# @section ofiles.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+#
+# @endverbatim
+#
+##########################################################################
+# INCLUDES
+##########################################################################
+
+C-SOURCES = \
+ memcpy.c \
+ memset.c \
+ rand32.c \
+ string.c \
+ sync.c
+
+
+S-SOURCES =
+
+LIBCOMMON_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/memcpy.c b/src/lib/common/memcpy.c
index ab508ea..77827dc 100755..100644
--- a/src/lib/memcpy.c
+++ b/src/lib/common/memcpy.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/memcpy.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: memcpy.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/memcpy.c,v $
//-----------------------------------------------------------------------------
@@ -9,7 +33,7 @@
/// \file memcpy.c
/// \brief The memcpy() function
-#include "ssx.h"
+#include "kernel.h"
/// The memcpy() function copies \a n bytes from memory area \a src to memory
/// area \a dest. The memory areas should not overlap. Use memmove(3) if the
diff --git a/src/lib/memset.c b/src/lib/common/memset.c
index 98fdda2..1d98677 100755..100644
--- a/src/lib/memset.c
+++ b/src/lib/common/memset.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/memset.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: memset.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/memset.c,v $
//-----------------------------------------------------------------------------
@@ -9,7 +33,7 @@
/// \file memset.c
/// \brief The memset() function
-#include "ssx.h"
+#include "kernel.h"
/// The memset() function fills the first \a n bytes of the memory area
/// pointed to by \a s with the constant byte \a c. The memset() function
diff --git a/src/lib/common/rand.h b/src/lib/common/rand.h
new file mode 100644
index 0000000..369b8fd
--- /dev/null
+++ b/src/lib/common/rand.h
@@ -0,0 +1,124 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/rand.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __RAND_H__
+#define __RAND_H__
+
+// $Id$
+
+/// \file rand.h
+/// \brief Random number generation
+
+#include <stdint.h>
+
+// Error/Panic codes
+
+#define RAND64_UNIMPLEMENTED 0x00726301
+
+
+/// RAND32_ALL is used as the \a limit argument to rand32() and _rand32() to
+/// request the return of a full 32-bit random unsigned integer.
+
+#define RAND32_ALL 0
+
+extern uint32_t _seed32;
+
+uint32_t
+_rand32(uint32_t *seed, uint32_t limit);
+
+uint32_t
+rand32(uint32_t limit);
+
+void
+srand32(uint32_t seed);
+
+
+/// RAND64_ALL is used as the \a limit argument to rand64() and _rand64() to
+/// request the return of a full 64-bit random unsigned integer.
+
+#define RAND64_ALL 0
+
+extern uint64_t _seed64;
+
+//void
+//davidmult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l);
+
+uint64_t
+_rand64(uint64_t *seed, uint64_t limit);
+
+uint64_t
+rand64(uint64_t limit);
+
+void
+srand64(uint64_t seed);
+
+
+/// A random weighting map for integer selections
+///
+/// See rand_map_int() for details.
+
+typedef struct {
+
+ /// The relative weight of this selection
+ ///
+ /// The final weight of the map array \e must be 0 to terminate the map.
+ unsigned weight;
+
+ /// The selection
+ int selection;
+
+} RandMapInt;
+
+
+/// A random weighting map for pointer selections
+///
+/// See rand_map_ptr() for details.
+
+typedef struct {
+
+ /// The relative weight of this selection
+ ///
+ /// The final weight of the map array \e must be 0 to terminate the map.
+ unsigned weight;
+
+ /// The selection
+ void *selection;
+
+} RandMapPtr;
+
+
+int
+_rand_map_int(uint32_t *seed, RandMapInt *map, int *index);
+
+int
+rand_map_int(RandMapInt *map);
+
+void *
+_rand_map_ptr(uint32_t *seed, RandMapPtr *map, int *index);
+
+void *
+rand_map_ptr(RandMapPtr *map);
+
+
+#endif /* __RAND_H__ */
diff --git a/src/lib/common/rand32.c b/src/lib/common/rand32.c
new file mode 100644
index 0000000..c75fc76
--- /dev/null
+++ b/src/lib/common/rand32.c
@@ -0,0 +1,384 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/rand32.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file rand32.c
+/// \brief 32-bit unsigned pseudo-random number generation
+
+#include "rand.h"
+
+/// The default seed for rand32()
+
+uint32_t _seed32 = 405405405;
+
+
+/// Generate a random 32-bit unsigned integer from an explicit seed
+///
+/// \param seed A pointer to the random seed (updated by this routine).
+///
+/// \param limit The (exclusive) upper bound of the range of generated random
+/// integers. The (inclusive) lower bound is always 0.
+///
+/// \retval A pseudo-random unsigned 32-bit integer uniformly selected from
+/// the range 0 to \a limit - 1 (inclusive). However if the \a limit parameter
+/// is \c RAND32_ALL (0), then the return value is a full 32-bit random bit
+/// vector.
+///
+/// This is a 32-bit linear congruential generator, taken from the 'ranqd1'
+/// generator from "Numerical Recipes in C". The authors' only praise for
+/// this generator is that it is "\e very fast"; the quality of random numbers
+/// is deemed "entirely adequate for many uses".
+///
+/// The initial 32 pseudo-random result is treated as a 32-bit binary fraction
+/// that is multipled by the limit to yield the final random 32-bit
+/// integer. If the limit is 0, then the full 32-bit result is returned. As
+/// with all LCG, do not count on the low-order bits to be particularly
+/// random.
+
+uint32_t
+_rand32(uint32_t *seed, uint32_t limit)
+{
+ uint64_t x;
+
+ *seed = (*seed * 1664525) + 1013904223;
+ if (limit == RAND32_ALL) {
+ return *seed;
+ } else {
+ x = (uint64_t)(*seed) * limit;
+ return x >> 32;
+ }
+}
+
+
+/// Generate a random 32-bit unsigned integer from a system-wide seed
+///
+/// \param limit The (exclusive) upper bound of the range of generated random
+/// integers. The (inclusive) lower bound is always 0.
+///
+/// \retval A pseudo-random unsigned 32-bit integer uniformly selected from
+/// the range 0 to \a limit - 1 (inclusive). However if the \a limit parameter
+/// is \c RAND32_ALL (0), then the return value is a full 32-bit random bit
+/// vector.
+///
+/// rand32() is not thread safe. There is a small possibility that multiple
+/// threads may observe the same random numbers, and it is also possible that
+/// the random sequence may appear to repeat due to thread interactions. If
+/// these are concerns then the application should either call rand32() from
+/// within a critical section, or provide a unique seed to each thread or
+/// process and use the underlying _rand32() API explicitly.
+
+uint32_t
+rand32(uint32_t limit)
+{
+ return _rand32(&_seed32, limit);
+}
+
+
+/// Set the global random seed for rand32()
+
+void
+srand32(uint32_t seed)
+{
+ _seed32 = seed;
+}
+
+
+/// Select an integer from a weighted distribution using a specific seed
+///
+/// \param seed A 32-bit unsigned random seed (accumulator)
+///
+/// \param map An array of RandMapInt structures, the final element of which
+/// must have the \a weight field = 0. This array will typically be allocated
+/// statically.
+///
+/// \param index An optional pointer to an integer which will recieve the
+/// index of the item selected. NULL \a index are ignored. This is provided
+/// for appplications that require statistics on selections.
+///
+/// \retval One of the \a selection from the array with a non-0 \a weight. If
+/// the weight array is NULL (= {{0, \<dont care\>}}), then by convention the
+/// return value is 0, and the return index is -1.
+///
+/// This routine selects items from the \a map randomly, given the weighting
+/// implied by (map[i].weight / SUM(i = 0,...,N, map[i].weight)). For
+/// example, the following two maps are equivalent in that they select 'a' and
+/// 'c' with 25% probability, and 'b' with 50% probability:
+///
+/// RandMapInt map0[] = {{1, 'a'}, {2, 'b'}, {1, 'c'}, {0, 0}};
+///
+/// RandMapInt map1[] = {{25, 'a'}, {50, 'b'}, {25, 'c'}, {0, 0}};
+///
+/// Note that several errors including negative weights, or the overflow of
+/// the sum of weights as an \a unsigned number are neither detected nor
+/// reported.
+///
+/// \todo We could probably merge the code for the integer and pointer versions
+/// somewhat. This is a great example of where C++ would be nice, as we could
+/// easily cache the sum of weights when the map was constructed.
+
+int
+_rand_map_int(uint32_t *seed, RandMapInt *map, int *index)
+{
+ unsigned weight, sum;
+ RandMapInt *p;
+ uint32_t rand;
+ int i = -1;
+ int selection = 0;
+
+ sum = 0;
+ p = map;
+ while (p->weight != 0) {
+ sum += p->weight;
+ p++;
+ }
+
+ if (sum != 0) {
+
+ rand = _rand32(seed, sum);
+
+ weight = 0;
+ p = map;
+ i = 0;
+ while (p->weight != 0) {
+ weight += p->weight;
+ if (rand < weight) {
+ selection = p->selection;
+ break;
+ }
+ p++;
+ i++;
+ }
+ }
+
+ if (index != 0) {
+ *index = i;
+ }
+
+ return selection;
+}
+
+
+/// Select an integer from a weighted distribution using the system-side seed
+/// \a _seed32
+///
+/// See _rand_map_int() for documentation
+
+int
+rand_map_int(RandMapInt *map)
+{
+ return _rand_map_int(&_seed32, map, 0);
+}
+
+
+/// Select a pointer from a weighted distribution using a specific seed
+///
+/// \param seed A 32-bit unsigned random seed (accumulator)
+///
+/// \param map An array of RandMapPtr structures, the final element of which
+/// must have the \a weight field = 0. This array will typically be allocated
+/// statically.
+///
+/// \param index An optional pointer to an integer which will recieve the
+/// index of the item selected. NULL \a index are ignored. This is provided
+/// for appplications that require statistics on selections.
+///
+/// \retval One of the \a selection from the array with a non-0 \a weight. If
+/// the weight array is NULL (= {{0, \<dont care\>}}), then by convention the
+/// return value is 0, and the return index is -1;
+///
+/// This routine selects items from the \a map randomly, given the weighting
+/// implied by (map[i].weight / SUM(i = 0,...,N, map[i].weight)). For
+/// example, the following two maps are equivalent in that they select &a and
+/// &c with 25% probability, and &b with 50% probability:
+///
+/// RandMapPtr map0[] = {{1, &a}, {2, &b}, {1, &c}, {0, 0}};
+///
+/// RandMapPtr map1[] = {{25, &a}, {50, &b}, {25, &c}, {0, 0}};
+///
+/// Note that several errors including negative weights, or the overflow of
+/// the sum of weights as an \a unsigned number are neither detected nor
+/// reported.
+
+
+void *
+_rand_map_ptr(uint32_t *seed, RandMapPtr *map, int *index)
+{
+ unsigned weight, sum;
+ RandMapPtr *p;
+ uint32_t rand;
+ int i = -1;
+ void *selection = 0;
+
+ sum = 0;
+ p = map;
+ while (p->weight != 0) {
+ sum += p->weight;
+ p++;
+ }
+
+ if (sum != 0) {
+
+ rand = _rand32(seed, sum);
+
+ weight = 0;
+ p = map;
+ i = 0;
+ while (p->weight != 0) {
+ weight += p->weight;
+ if (rand < weight) {
+ selection = p->selection;
+ break;
+ }
+ p++;
+ i++;
+ }
+ }
+
+ if (index != 0) {
+ *index = i;
+ }
+
+ return selection;
+}
+
+
+/// Select a pointer from a weighted distribution using the system-side seed
+/// \a _seed32
+///
+/// See _rand_map_ptr() for documentation
+
+void *
+rand_map_ptr(RandMapPtr *map)
+{
+ return _rand_map_ptr(&_seed32, map, 0);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef __TEST_RAND_C__
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef RANDOM_MAP
+
+// Weighted distribution testing
+
+int a, b, c;
+int aa, bb, cc;
+
+int x[3];
+
+RandMapPtr map0[] = {{1, &a}, {2, &b}, {1, &c}, {0, 0}};
+RandMapPtr map1[] = {{25, &aa}, {50, &bb}, {25, &cc}, {0, 0}};
+
+RandMapInt map2[] = {{25, 0}, {50, 1}, {25, 2}, {0, 0}};
+
+int
+main()
+{
+ int i, j;
+ int *p;
+
+ for (i = 0; i < 1000000; i++) {
+ p = (int *)(rand_map_ptr(map0));
+ *p = *p + 1;
+ p = (int *)(rand_map_ptr(map1));
+ *p = *p + 1;
+ j = rand_map_int(map2);
+ x[j]++;
+ }
+
+ printf("%d %d %d\n", a, b, c);
+ printf("%d %d %d\n", aa, bb, cc);
+ printf("%d %d %d\n", x[0], x[1], x[2]);
+
+ return 0;
+}
+
+#endif /* RANDOM_MAP */
+
+
+#ifdef BASIC_TEST
+
+// Simple self-checking uniform distrubution tests for rand32.
+
+void
+test(int *a, int size, int count, double max_error)
+{
+ int i;
+ double error;
+
+ for (i = 0; i < size; i++) {
+ a[i] = 0;
+ }
+
+ for (i = 0; i < size * count; i++) {
+ a[rand32(size)]++;
+ }
+
+ for (i = 0; i < size; i++) {
+ error = (a[i] / (double)count) - 1.0;
+ printf("a[%4d] : %10d %.5f\n", i, a[i], error);
+ if (abs(error) > max_error) {
+ printf("Too much error\n");
+ exit(1);
+ }
+ }
+}
+
+#define MAX_SIZE 128
+
+int
+main()
+{
+ int a[MAX_SIZE];
+ int count = 1000000;
+ double max_error = .005;
+ int i;
+
+ for (i = 2; i <= MAX_SIZE; i *= 2) {
+ printf("\nTest %d\n\n", i);
+ test(a, i, count, max_error);
+ }
+
+ srand32(0);
+ for (i = 2; i <= MAX_SIZE; i *= 2) {
+ printf("\nTest %d\n\n", i);
+ test(a, i, count, max_error);
+ }
+
+ srand32(0xdeadbeef);
+ for (i = 2; i <= MAX_SIZE; i *= 2) {
+ printf("\nTest %d\n\n", i);
+ test(a, i, count, max_error);
+ }
+}
+
+#endif /* BASIC_TEST */
+
+#endif /* __TEST_RAND_C__ */
+
diff --git a/src/lib/string.c b/src/lib/common/string.c
index 81d1778..7c82653 100755..100644
--- a/src/lib/string.c
+++ b/src/lib/common/string.c
@@ -1,5 +1,27 @@
-// $Id: string.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string.c,v $
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/string.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2013
// *! All Rights Reserved -- Property of IBM
@@ -9,7 +31,6 @@
/// \file string.c
/// \brief strlen(), strcmp() etc. functions
-#include "ssx.h"
#include "string.h"
/// Compute the length of a string
diff --git a/src/lib/common/string.h b/src/lib/common/string.h
new file mode 100644
index 0000000..5cfa470
--- /dev/null
+++ b/src/lib/common/string.h
@@ -0,0 +1,88 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/string.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __STRING_H__
+#define __STRING_H__
+
+// $Id: string.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file string.h
+/// \brief Replacement for <string.h>
+///
+/// The SSX library does not implement the entire <string.h> function.
+/// However the real reason for this header was the finding that under certain
+/// optimization modes, we were geting errors from the default <string.h>
+/// supplied with the MPC environment. So we created this replacement that
+/// only calls out what is implemented, exactly as it is implemented for SSX.
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+
+// APIs inmplemented by string.c
+
+size_t
+strlen(const char *s);
+
+int
+strcmp(const char* s1, const char* s2);
+
+int
+strncmp(const char* s1, const char* s2, size_t n);
+
+int
+strcasecmp(const char* s1, const char* s2);
+
+int
+strncasecmp(const char* s1, const char* s2, size_t n);
+
+char *
+strcpy(char *dest, const char *src);
+
+char *
+strncpy(char *dest, const char *src, size_t n);
+
+void *
+memcpy(void *dest, const void *src, size_t n);
+
+void *
+memset(void *s, int c, size_t n);
+
+int
+memcmp(const void* s1, const void* s2, size_t n);
+
+// APIs implemented by strdup.c
+
+char *
+strdup(const char* s);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __STRING_H__ */
diff --git a/src/lib/common/sync.c b/src/lib/common/sync.c
new file mode 100644
index 0000000..a489be8
--- /dev/null
+++ b/src/lib/common/sync.c
@@ -0,0 +1,294 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/sync.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file sync.c
+/// \brief A library of higher-level synchronization primitives based on
+/// low-level kernel services.
+///
+/// The APIs provided here are currently based on kernel services, but the
+/// specifications should allow applications to be ported to other
+/// environments if required. Note that like kernel services, data
+/// structures manipulated by this code are protected in KERN_NONCRITICAL
+/// critical sections.
+
+#include "kernel.h"
+#include "sync.h"
+
+/// Create a Barrier
+///
+/// \param barrier A pointer to an uninitialized or currently unused Barrier
+///
+/// \param count The number of threads required to pend at the barrier before
+/// all threads are released again for execution. Note that \a count values
+/// of 0 and 1 are treated as equivalent - threads will not pend at all in
+/// these cases. Also note that if a watchdog thread is being used, the
+/// watchdog thread should not be included in the count.
+///
+/// \retval 0 Success
+///
+/// \retval -SYNC_INVALID_OBJECT The \a barrier is NULL (0)
+
+int
+barrier_create(Barrier *barrier, KERN_SEMAPHORE_COUNT count)
+{
+ if (KERN_ERROR_CHECK_API) {
+ KERN_ERROR_IF(barrier == 0, SYNC_INVALID_OBJECT);
+ }
+
+ barrier->entry_sem = &(barrier->sem[0]);
+ barrier->exit_sem = &(barrier->sem[1]);
+
+ KERN_SEMAPHORE_CREATE((KERN_SEMAPHORE *)(barrier->entry_sem), 0, 0);
+ KERN_SEMAPHORE_CREATE((KERN_SEMAPHORE *)(barrier->exit_sem), 0, 0);
+
+ barrier->entry_count = 0;
+ barrier->exit_count = 0;
+ barrier->target_count = count;
+
+ barrier->watchdog_pending = 0;
+ barrier->watchdog_entries = 0;
+
+ barrier->callback = 0;
+ barrier->arg = 0;
+ barrier->run_callback = 0;
+
+ return 0;
+}
+
+
+/// Install a barrier callback
+///
+/// \param barrier A pointer to an initialized Barrier object
+///
+/// \param callback A function taking a single (void *) argument, to be
+/// executed in the context of the first thread to exit the barrier when the
+/// barrier condition is met.
+///
+/// \param arg The argument of the \a callback.
+///
+/// The Barrier object supports an optional callback function. The callback
+/// (with the customary single (void *) parameter) is made when the barrier
+/// condition is met, in the thread context of the first (highest priority)
+/// thread to exit the barrier. The callback is made inside the barrier_pend()
+/// call, but outside of a critical section. The specification of the callback
+/// is not part of the barrier_create() call, but is provided later by this
+/// API. Setting a NULL (0) callback disables the callback mechanism.
+///
+/// \retval 0 Success
+///
+/// \retval -SYNC_INVALID_OBJECT The \a barrier is NULL (0)
+
+int
+barrier_callback_set(Barrier *barrier,
+ BarrierCallback callback,
+ void *arg)
+{
+ KERN_MACHINE_CONTEXT ctx;
+
+ if (KERN_ERROR_CHECK_API) {
+ KERN_ERROR_IF(barrier == 0, SYNC_INVALID_OBJECT);
+ }
+
+ KERN_CRITICAL_SECTION_ENTER(KERN_NONCRITICAL, &ctx);
+
+ barrier->callback = callback;
+ barrier->arg = arg;
+
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ return 0;
+}
+
+
+static int
+_barrier_pend(Barrier *barrier, int watchdog)
+{
+ KERN_MACHINE_CONTEXT ctx;
+ int rc = 0;
+ KERN_SEMAPHORE *temp_sem;
+ BarrierCallback callback = 0; /* Make GCC Happy */
+ void *arg = 0; /* Make GCC Happy */
+ int run_callback;
+
+ if (KERN_ERROR_CHECK_API) {
+ KERN_ERROR_IF(barrier == 0, SYNC_INVALID_OBJECT);
+ }
+
+ KERN_CRITICAL_SECTION_ENTER(KERN_NONCRITICAL, &ctx);
+
+ // A normal thread will pend at the entry unless 1) the thread satisfies
+ // the barrier condition, or 2) a watchdog thread is pending here. A
+ // watchdog thread only pends if no other threads are pending.
+
+ if (watchdog) {
+ barrier->watchdog_entries++;
+ }
+
+ barrier->entry_count++;
+ if (!barrier->watchdog_pending &&
+ ((watchdog && (barrier->entry_count == 1)) ||
+ (!watchdog && (barrier->entry_count < barrier->target_count)))) {
+
+ if (watchdog) {
+ barrier->watchdog_pending = 1;
+ }
+
+ // The thread must pend here
+
+ rc = KERN_SEMAPHORE_PEND((KERN_SEMAPHORE *)(barrier->entry_sem),
+ KERN_WAIT_FOREVER);
+ if (rc) {
+ goto exit_critical;
+ }
+
+ } else {
+
+ // The barrier condition is met - or the watchdog thread is blocked
+ // here. The entry and exit semaphores and counts are swapped. The
+ // callback is marked to be called.
+
+ // If the barrier is used incorrectly, or threads are deleted without
+ // adjusting the barrier target count then the following condition
+ // could become true, which could lead to bad behavior.
+
+ if (barrier->exit_count != 0) {
+ KERN_PANIC(SYNC_BARRIER_INVARIANT);
+ }
+
+ barrier->entry_count--; // Undo preincrement above
+ barrier->watchdog_pending = 0;
+
+ temp_sem = (KERN_SEMAPHORE *)(barrier->exit_sem);
+ barrier->exit_sem = barrier->entry_sem;
+ barrier->entry_sem = temp_sem;
+
+ barrier->exit_count = barrier->entry_count;
+ barrier->entry_count = 0;
+
+ barrier->run_callback = 1;
+ }
+
+ // This thread either continues to run or just woke up after having
+ // blocked at the barrier. The current thread makes the next thread (if
+ // any) runnable as well. Normally the current thread will be of a higher
+ // priority than any blocked threads, so no context switch will occur. The
+ // thread that satisfies the barrier condition \e will cause a context
+ // switch here, unless it just happens to be the highest priority thread
+ // in the barrier group.
+
+ if (barrier->exit_count != 0) {
+ barrier->exit_count--;
+ rc = KERN_SEMAPHORE_POST((KERN_SEMAPHORE *)(barrier->exit_sem));
+ }
+
+exit_critical:
+
+ if (rc) {
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+ return rc;
+ }
+
+ // In the case of a satisfied barrier condition, the first thread to exit
+ // the critical section will be the higest priority thread blocked at the
+ // barrier. This thread is tasked with executing the callback, outside of
+ // the critical section.
+
+ run_callback = barrier->run_callback;
+ barrier->run_callback = 0;
+ if (run_callback) {
+ callback = barrier->callback;
+ arg = (void *)(barrier->arg); /* Cast away 'volatile' */
+ }
+
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ if (run_callback && callback) {
+ callback(arg);
+ }
+
+ return 0;
+}
+
+
+/// Pend at a Barrier
+///
+/// \param barrier An initialized barrier object
+///
+/// A thread will pend at a barrier until \a count number of threads (supplied
+/// in the call of barrier_create()) are pending. If \a count is 0 or 1, the
+/// API always returns immediately.
+///
+/// If barrier watchdog thread is being used (correctly), then the watchdog
+/// will cause thread pending on the barrier to be released whenever all
+/// threads in the group are blocked, regardless of whether some of the
+/// group's threads are blocked elesewhere.
+///
+/// \retval 0 Success
+///
+/// \retval -SYNC_INVALID_OBJECT The \a barrier is NULL (0)
+///
+/// Other errors may be returned by the embedded call of ssx_semephore_pend().
+/// In particular this API will fail if called outside of a thread context
+/// since it requires blocking indefinitely on a semaphore.
+///
+/// \bug The semaphore should be able to provide the number of pending threads
+/// - which we should really be using here instead of the barrier counts. The
+/// current implementation can produce some strange behavior if threads are
+/// deleted.
+
+int
+barrier_pend(Barrier *barrier)
+{
+ return _barrier_pend(barrier, 0);
+}
+
+
+/// Barrier watchdog thread
+///
+/// \param arg A pointer to the Barrier object this thread should manage.
+///
+/// A barrier_watchdog() thread is attached to a Barrier object, and forces
+/// the barrier condition to be met whenever it runs. This thread is designed
+/// to be mapped at a priority immediately below the priorities of a group of
+/// threads that pend on the barrier.
+///
+/// In this way, should every thread in the group become blocked, the watchdog
+/// will allow any threads that are blocked on the barrier to run. If all the
+/// threads are blocked elsewhere, then the watchdog blocks on the barrier,
+/// and as soon as any thread pends again at the barrier the thread remains
+/// runnable and the watchdog becomes runnable.
+///
+/// The barrier_watchdog() thread is not required. Without the watchdog,
+/// otherwise runnable threads in the barrier group will remain blocked on the
+/// barrier as long as any of their cohorts remain blocked elsewhere.
+
+void
+barrier_watchdog(void *arg)
+{
+ do {
+ _barrier_pend((Barrier *)arg, 1);
+ } while (1);
+}
diff --git a/src/lib/common/sync.h b/src/lib/common/sync.h
new file mode 100644
index 0000000..5657c78
--- /dev/null
+++ b/src/lib/common/sync.h
@@ -0,0 +1,167 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/sync.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SYNC_H__
+#define __SYNC_H__
+
+// $Id$
+
+/// \file sync.h
+/// \brief A library of higher-level synchronization primitives based on
+/// low-level kernel services.
+///
+/// The APIs provided here are currently based on SSX services, but the
+/// specifications should allow applications to be fairly easily ported to
+/// other environments if required.
+///
+/// \todo Consider implementing a subset of the POSIX pthreads standards
+/// instead of these non-standard synchronization primitives. Ideally all
+/// synchronization primitives would be part of the SSX kernel so that they
+/// would correctly handle thread suspension and deletion while pending.
+
+#include "kernel.h"
+
+// Error/panic codes
+
+#define SYNC_INVALID_OBJECT 0x00896201
+#define SYNC_INVALID_ARGUMENT 0x00896202
+#define SYNC_BARRIER_PEND_TIMED_OUT 0x00896203
+#define SYNC_BARRIER_OVERFLOW 0x00896204
+#define SYNC_BARRIER_UNDERFLOW 0x00896205
+#define SYNC_BARRIER_INVARIANT 0x00896206
+#define SYNC_SHARED_UNDERFLOW 0x00896207
+
+////////////////////////////////////////////////////////////////////////////
+// Barrier
+////////////////////////////////////////////////////////////////////////////
+
+typedef void (*BarrierCallback)(void *);
+
+/// A thread barrier object
+///
+/// A Barrier allows multiple threads to pend until a group of threads are all
+/// pending at the barrier. Once all threads are pending at the barrier, all
+/// threads are released again for execution. The barrier guarantees that
+/// once released, lower-priority threads will have the chance to execute
+/// before the barrier condition is satisfied again. Thus the Barrier can be
+/// used as a form of fair scheduling for a group of threads that execute in a
+/// loop of doing work followed by pending at the barrier.
+///
+/// Although the barrier guarantees fairness, it can not by itself guarantee
+/// progress. If several threads in a barrier group are
+/// pending at the barrier while other threads in the group are blocked away
+/// from the barrier, the threads at the barrier should be running (if allowed
+/// by the priority mappings etc.). The only way to guarantee constant
+/// progress by any unblocked thread in a group is to created another,
+/// 'watchdog' thread that has lower priority than the other threads in the
+/// group. The watchdog thread only executes when all threads in the group
+/// are blocked, and ensures progress. This implementation provides a
+/// watchdog thread routine as barrier_watchdog().
+///
+/// Normally the threads in a barrier group will be assigned consecutive
+/// priorities - otherwise various forms of priority inversion can arise. The
+/// watchdog thread, if any, will normally be assigned the priority
+/// immediately lower than the lowest priority thread in the group.
+///
+/// The Barrier object supports an optional callback function. The callback
+/// (with the customary single (void *) parameter) is made when the barrier
+/// condition is met, in the thread context of the first (highest priority)
+/// thread to exit the barrier. The callback is made inside the barrier_pend()
+/// call, but outside of a critical section. The specification of the callback
+/// is not part of the barrier_create() call, but is provided later by the
+/// barrier_callback_set() call. A NULL (0) callback (the default) is ignored.
+///
+/// NB: All barrier APIs (other than barrier_create()) must be made from
+/// thread mode - they will fail if called from interrupt handlers or before
+/// threads have started.
+
+typedef struct Barrier {
+
+ /// Semaphore array; see \a entry_sem and \a exit_sem;
+ KERN_SEMAPHORE sem[2];
+
+ /// The entry semaphore.
+ ///
+ /// Threads pending at the barrier initially block here. Once all of the
+ /// threads in the group are pending here, the entry and exit semaphores
+ /// are swapped and threads are released (in priority order) from the new
+ /// exit semaphore.
+ volatile KERN_SEMAPHORE *entry_sem;
+
+ /// The exit semaphore.
+ volatile KERN_SEMAPHORE *exit_sem;
+
+ /// The current count of threads pending at \a entry_sem.
+ volatile KERN_SEMAPHORE_COUNT entry_count;
+
+ /// The current count of threads pending at \a exit_sem.
+ volatile KERN_SEMAPHORE_COUNT exit_count;
+
+ /// The target number of threads required to release the barrier
+ volatile KERN_SEMAPHORE_COUNT target_count;
+
+ /// A flag - Is the watchdog thread pending at the barrier?
+ volatile int watchdog_pending;
+
+ /// Statistics - The number of times the watchdog has entered the barrier.
+ volatile uint32_t watchdog_entries;
+
+ /// The barrier condition callback function
+ volatile BarrierCallback callback;
+
+ /// The argument of the callback function
+ volatile void *arg;
+
+ /// This flag is set to tell the first thread to exit the barrier to
+ /// execute the callback (if any).
+ volatile int run_callback;
+
+} Barrier;
+
+int
+barrier_create(Barrier *barrier, KERN_SEMAPHORE_COUNT count);
+
+int
+barrier_callback_set(Barrier *barrier,
+ BarrierCallback callback,
+ void *arg);
+
+int
+barrier_pend(Barrier *barrier);
+
+void
+barrier_watchdog(void *arg);
+
+
+#endif // __SYNC_H__
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/ctype.c b/src/lib/ctype.c
deleted file mode 100755
index 5b10635..0000000
--- a/src/lib/ctype.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// $Id: ctype.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ctype.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file ctype.c
-/// \brief Replacement for <ctype.h> functions
-///
-/// This file contains entry point equivalents for the "ctype.h" macros.
-/// These would only ever be used by assembler programs, therefore it's likely
-/// that the object file will never be linked into an image.
-
-#define __CTYPE_C__
-#include "ctype.h"
-#undef __CTYPE_C__
-
-
-
-
diff --git a/src/lib/errno.h b/src/lib/errno.h
deleted file mode 100755
index a45bb84..0000000
--- a/src/lib/errno.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __ERRNO_H__
-#define __ERRNO_H__
-
-// $Id: errno.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/errno.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file errno.h
-/// \brief Replacement for <errno.h>
-///
-/// SSX does not support a per-thread or global 'errno'. The standard Unix
-/// errno values returned by library functions are defined here. The prefix
-/// code is the 'telephone code' for "errn".
-
-#define EINVAL 0x00377601
-#define EBADF 0x00377602
-#define EAGAIN 0x00377603
-#define ENXIO 0x00377604
-#define ENOMEM 0x00377605
-
-#endif /* __ERRNO_H__ */
diff --git a/src/lib/gpe.h b/src/lib/gpe.h
deleted file mode 100755
index e759c7d..0000000
--- a/src/lib/gpe.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef __GPE_H__
-#define __GPE_H__
-
-// $Id: gpe.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe.h
-/// \brief Useful PGAS macros for PORE-GPE procedures
-
-#include "pgas.h"
-
-#ifdef __ASSEMBLER__
-#ifdef __PGAS__
-
-// Required to guarantee that the .purgem below always works. .purgem on
-// undefined macros causes an error; There appears to be no way to determine
-// if a macro is defined.
-#include "ppc32_asm.h"
-
-
- // All GPE code should be assembled in the .text.pore section, and
- // all GPE data should be assembled in the .data.pore section.
-
- .macro .text.pore
- .section .text.pore, "ax", @progbits
- .balign 4
- .endm
-
-
- .macro .data.pore
- .section .data.pore, "a", @progbits
- .balign 8
- .endm
-
- .purgem .function
- .macro .function symbol
- .text.pore
- .align 2
- .endm
-
- .purgem .global_function
- .macro .global_function symbol
- .text.pore
- .align 2
- .global \symbol
- .endm
-
-
- // Get the CFAM Id right-justified in a Dx register, scratching a Px
- // register in the process.
-
- .macro cfam_id, Dx:req, Px:req
- ..data (\Dx)
- ..pervasive_chiplet_id (\Px)
- lpcs (\Px), 0x000f000f
- ldandi (\Dx), 0x000f000f, (\Px), 0xffffffff00000000
- rols (\Dx), (\Dx), 32
- .endm
-
-
- // This macro defines structure offsets for PORE assembler-versions of
- // structures.
-
- .macro .gpeStructField, field:req, size=8
-\field\():
- .struct \field + (\size)
- .endm
-
-
-#endif // __PGAS__
-#endif // __ASSEMBLER__
-
-#endif // __GPE_H__
diff --git a/src/lib/gpe_control.h b/src/lib/gpe_control.h
deleted file mode 100755
index 355330f..0000000
--- a/src/lib/gpe_control.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef __GPE_CONTROL_H__
-#define __GPE_CONTROL_H__
-
-// $Id: gpe_control.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_control.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_control.h
-/// \brief GPE procedures for control
-
-#include "pstates.h"
-#include "pgp_config.h"
-
-////////////////////////////////////////////////////////////////////////////
-// PcbsPstateRegs
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASSEMBLER__
-
-/// Per-core Pstate control registers
-///
-/// Firmware maintains a vector of PcbsPstateRegs structures - one for
-/// each core on the chip - and updates the register fields in place. The GPE
-/// procedure gpe_set_pstates() is run periodically to update the core
-/// chiplets from this data structure. The array can (should) be cleared
-/// initially.
-
-typedef struct {
-
- /// The clipping register
- pcbs_power_management_bounds_reg_t pmbr;
-
- /// The idle control register
- pcbs_power_management_idle_control_reg_t pmicr;
-
- /// The Pstate control register
- pcbs_power_management_control_reg_t pmcr;
-
-} PcbsPstateRegs;
-
-#endif /* __ASSEMBLER__ */
-
-// Offsets into PcbsPstateRegs
-
-#define PCBSPSTATEREGS_PMBR 0x00
-#define PCBSPSTATEREGS_PMICR 0x08
-#define PCBSPSTATEREGS_PMCR 0x10
-
-#define SIZEOF_PCBSPSTATEREGS 0x18
-
-
-#ifndef __ASSEMBLER__
-
-/// Set a chiplet Pmax clipping Pstate
-static inline void
-set_chiplet_pmax(PcbsPstateRegs *regs, int chiplet, Pstate pmax)
-{
- regs[chiplet].pmbr.fields.pmax_clip = pmax;
-}
-
-/// Set a chiplet Pmin clipping Pstate
-static inline void
-set_chiplet_pmin(PcbsPstateRegs *regs, int chiplet, Pstate pmin)
-{
- regs[chiplet].pmbr.fields.pmin_clip = pmin;
-}
-
-/// Set chiplet Global and Local Pstate requests
-static inline void
-set_chiplet_pstate(PcbsPstateRegs *regs, int chiplet,
- Pstate global, Pstate local)
-{
- regs[chiplet].pmcr.fields.global_pstate_req = global;
- regs[chiplet].pmcr.fields.local_pstate_req = local;
-}
-
-/// Enable/Disable/Configure chiplet Nap Pstates
-static inline void
-set_chiplet_nap_pstate(PcbsPstateRegs *regs, int chiplet,
- Pstate pstate, int enable, int global, int latency)
-{
- regs[chiplet].pmicr.fields.nap_pstate_req = pstate;
- regs[chiplet].pmicr.fields.nap_pstate_en = (enable != 0);
- regs[chiplet].pmicr.fields.nap_global_en = (global != 0);
- regs[chiplet].pmicr.fields.nap_latency = latency;
-}
-
-/// Enable/Disable/Configure chiplet Sleep Pstates
-static inline void
-set_chiplet_sleep_pstate(PcbsPstateRegs *regs, int chiplet,
- Pstate pstate, int enable, int global, int latency)
-{
- regs[chiplet].pmicr.fields.sleep_pstate_req = pstate;
- regs[chiplet].pmicr.fields.sleep_pstate_en = (enable != 0);
- regs[chiplet].pmicr.fields.sleep_global_en = (global != 0);
- regs[chiplet].pmicr.fields.sleep_latency = latency;
-}
-
-/// Enable/Disable/Configure chiplet Winkle Pstates
-static inline void
-set_chiplet_winkle_pstate(PcbsPstateRegs *regs, int chiplet,
- Pstate pstate, int enable, int global, int latency)
-{
- regs[chiplet].pmicr.fields.winkle_pstate_req = pstate;
- regs[chiplet].pmicr.fields.winkle_pstate_en = (enable != 0);
- regs[chiplet].pmicr.fields.winkle_global_en = (global != 0);
- regs[chiplet].pmicr.fields.winkle_latency = latency;
-}
-
-#endif /* __ASSEMBLER__ */
-
-/// \bug These need to be defined and documented
-
-#define SLEEP_LATENCY_DISABLED 0
-#define SLEEP_LATENCY_CLOCKS_OFF 1
-#define SLEEP_LATENCY_FAST 2
-#define SLEEP_LATENCY_DEEP 3
-
-#define WINKLE_LATENCY_DISABLED 0
-#define WINKLE_LATENCY_CLOCKS_OFF 1
-#define WINKLE_LATENCY_FAST 2
-#define WINKLE_LATENCY_DEEP 3
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_set_pstates()
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASSEMBLER__
-
-/// Parameters for the GPE procedure gpe_set_pstates()
-
-typedef struct {
-
- // The chip configuration (for actuation purposes). Only those core
- // chiplets with bits set in the mask will be actuated.
- ChipConfig config;
-
- /// This mask, comprised of a logical OR of the GPE_SET_PSTATE_*
- /// macros, controls which register(s) is(are) actuated for each core.
- uint64_t select;
-
- /// The 32-bit pointer to the array of PcbsPstateRegs holding the register
- /// data, coerced to a 64-bit unsigned. The real 32-bit pointer must be
- /// the low-order 32 bits of this value.
- uint64_t regs;
-
-} GpeSetPstatesParms;
-
-PoreEntryPoint gpe_set_pstates;
-
-#endif /* __ASSEMBLER__ */
-
-// Parameter offsets for gpe_set_pstates()
-
-#define GPESETPSTATESPARMS_CONFIG 0x00
-#define GPESETPSTATESPARMS_SELECT 0x08
-#define GPESETPSTATESPARMS_REGS 0x10
-
-// Register/Function select masks for gpe_set_pstates()
-
-#define GPE_SET_PSTATES_PMBR 0x01
-#define GPE_SET_PSTATES_PMICR 0x02
-#define GPE_SET_PSTATES_PMCR 0x04
-#define GPE_SET_PSTATES_SYNC 0x08
-
-#endif /* __GPE_CONTROL_H__ */
diff --git a/src/lib/gpe_control.pS b/src/lib/gpe_control.pS
deleted file mode 100755
index 3f3c790..0000000
--- a/src/lib/gpe_control.pS
+++ /dev/null
@@ -1,160 +0,0 @@
-// $Id: gpe_control.pS,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_control.pS,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_control.S
-/// \brief GPE procedures for control
-
- .nolist
-
-#include "ssx.h"
-#include "pgas.h"
-#include "gpe.h"
-#include "gpe_control.h"
-
- .list
-
- .oci
- .text.pore
-
-/// \fn gpe_set_pstates(GpeSetPstatesParms *parms)
-/// \brief Set core chiplet Pstate registers
-///
-/// This routine loops through an array of PcbsPstateRegs structures
-/// holding the register images to be actuated. A pointer to the array is
-/// provided as the \a registers parameter. For every core chiplet
-/// appearing in the \a cfg parameter, those registers marked in the \a select
-/// parameter are updated.
-///
-/// When the PMBR is being updated, an option is provided to
-/// set PCBS_PCBSPM_MODE_REG[enable_pmax_sync_interrupt] around the
-/// update of PMBR. This will cause a SYNC interrupt from each
-/// core. This mode currently does not set up the sync protocol in the PMC -
-/// the caller must do that.
-///
-/// Note that actuating the PMCR and PMICR using this method requires that the
-/// PCB Slave bit PMGP0_REG.pm_spr_override_en is set.
-#ifdef DOXYGEN_ONLY
-void gpe_set_pstates(GpeSetPstatesParms *parms);
-#endif
-/// \cond
-
- // Register usage:
- //
- // A1 : Holds the (constant) pointer to the paramaters
- // A0 : Holds the (varying) pointer to the next register block
- // D1 : Holds the (varying) ChipConfig mask
- // D0 : Scratch
- // P0 : Holds the (varying) chiplet id
-
- .global gpe_set_pstates
-
-gpe_set_pstates:
-
- // Set up registers. The chiplet part of the ChipConfig is left
- // justified in D1, which will be rotated on each loop.
-
- mr A1, ETR
- ld D0, GPESETPSTATESPARMS_REGS, A1
- mr A0, D0
- ld D0, GPESETPSTATESPARMS_CONFIG, A1
- mr D1, D0
- left_justify_core_config D1
- lpcs P0, 0x10000000 # Load P0 with core chiplet 0 address
- ls CTR, PGP_NCORES
- bra start_loop
-
-set_pstates_loop:
- // If the chiplet is not configured, simply continue
-
- andi D0, D1, 0x8000000000000000
- braz D0, set_pstates_continue
-
- // Test/actuate each register in order
-
- ldandi D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_PMBR
- braz D0, pmicr
-
- // PMBR.
-
- // If SYNCing, the register write is wrapped by a read-modify-write of
- // the PCBS_PCBSPM_MODE_REG which enables the PMAX Sync
- // acknowledge. Note that the original PCBSPM mode reg is saved and
- // restored.
-pmbr:
- ldandi D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_SYNC
- braz D0, nosync
-
-sync:
- ld D0, PCBS_PCBSPM_MODE_REG, P0
- la A1, gsp_pcbs_pcbspm_mode_reg
- std D0, 0, A1
- ori D0, D0, PCBS_PCBSPM_MODE_REG_ENABLE_PMC_PMAX_SYNC_NOTIFICATION
- std D0, PCBS_PCBSPM_MODE_REG, P0
-
- ld D0, PCBSPSTATEREGS_PMBR, A0
- std D0, PCBS_POWER_MANAGEMENT_BOUNDS_REG, P0
-
- ld D0, 0, A1
- std D0, PCBS_PCBSPM_MODE_REG, P0
- // restore A1
- mr A1, ETR
- bra pmicr
-
-nosync:
- ld D0, PCBSPSTATEREGS_PMBR, A0
- std D0, PCBS_POWER_MANAGEMENT_BOUNDS_REG, P0
-
- // PMICR
-pmicr:
- ldandi D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_PMICR
- braz D0, pmcr
- ld D0, PCBSPSTATEREGS_PMICR, A0
- std D0, PCBS_POWER_MANAGEMENT_IDLE_CONTROL_REG, P0
-
- // PMCR
-pmcr:
- ldandi D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_PMCR
- braz D0, set_pstates_continue
- ld D0, PCBSPSTATEREGS_PMCR, A0
- std D0, PCBS_POWER_MANAGEMENT_CONTROL_REG, P0
-
-set_pstates_continue:
-
- // Increment the chiplet index and data pointer, then loop or halt.
-
- adds P0, P0, 1
- adds A0, A0, SIZEOF_PCBSPSTATEREGS
- rotldi D1, D1, 1
-start_loop:
- loop set_pstates_loop
-
- halt
-
- .epilogue gpe_set_pstates
-
-/// \endcond
-
-/// Data storage for procedures.
-/// Placing data in the .rodata section to prevent the 405 from stomping them.
- .section .rodata
- .balign 8
-/// data for gpe_set_pstates
-
-
-
-
-
-
-
-
-
-/// \cond
-
-gsp_pcbs_pcbspm_mode_reg:
- .quad 0
-/// \endcond
diff --git a/src/lib/gpe_data.h b/src/lib/gpe_data.h
deleted file mode 100755
index 790d82b..0000000
--- a/src/lib/gpe_data.h
+++ /dev/null
@@ -1,672 +0,0 @@
-#ifndef __GPE_DATA_H__
-#define __GPE_DATA_H__
-
-// $Id: gpe_data.h,v 820.1 2014/08/22 16:33:56 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/fw820/procedures/lib/gpe_data.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_data.h
-/// \brief Data structures for the GPE programs that collect raw data defined
-/// in gpe_data.S. The data structure layouts are also documented in the
-/// spreadsheet "Pgp Procedures.ods" in lib/doc.
-///
-/// \todo Add SPURR Fraction update as an option
-
-#include "ssx.h"
-#include "gpe.h"
-#include "pgp_config.h"
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_core_data()
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASSEMBLER__
-
-/// Paramaters for gpe_get_core_data() & gpe_get_per_core_data()
-
-typedef struct {
-
- /// gpe_get_core_data() and gpe_get_per_core_data() only collects data for
- /// core chiplets configured in this mask.
- ChipConfig config;
-
- /// This mask, comprised of a logical OR of the GPE_GET_CORE_DATA_*
- /// macros, controls which data groups are collected.
- uint64_t select;
-
- /// This is the 32-bit pointer (cast to a uint64_t) to the core chiplet
- /// raw data area to be filled by this invocation of gpe_get_core_data().
- ///
- /// For gpe_get_core_data() (used by the lab thread coreData) this is a
- /// pointer to an array of CoreData structures, with one structure
- /// allocated for each possible core supported by the architecture.
- ///
- /// For gpe_get_per_core_data() (used by OCC FW) this is a pointer to a
- /// single CoreData structure to be filled in by the routine.
- uint64_t data;
-
-} GpeGetCoreDataParms;
-
-// Get data for all cores, placing data at an index into
-// GpeGetCoreDataParms->data pointer, depending on the core which got data.
-PoreEntryPoint gpe_get_core_data;
-
-// Get data for first core in GpeGetCoreDataParms->config, placing data
-// directly into GpeGetCoreDataParms->data pointer
-PoreEntryPoint gpe_get_per_core_data;
-
-#endif /* __ASSEMBLER__ */
-
-// Parameter offsets for gpe_get_core_data()
-
-#define GPEGETCOREDATAPARMS_CONFIG 0x00
-#define GPEGETCOREDATAPARMS_SELECT 0x08
-#define GPEGETCOREDATAPARMS_DATA 0x10
-
-// Data group select masks for gpe_get_core_data()
-
-#define GPE_GET_CORE_DATA_EMPATH 0x0001
-#define GPE_GET_CORE_DATA_MEMORY 0x0002
-#define GPE_GET_CORE_DATA_THROTTLE 0x0004
-#define GPE_GET_CORE_DATA_THREAD 0x0008
-#define GPE_GET_CORE_DATA_DTS_CPM 0x0010
-#define GPE_GET_CORE_DATA_PCB_SLAVE 0x0020
-
-#define GPE_GET_CORE_DATA_ALL 0x003f
-
-// Per-core data area offsets
-
-#define CORE_DATA_EMPATH_BASE 0
-#define CORE_DATA_EMPATH_SIZE 40
-
-#define CORE_DATA_MEMORY_BASE \
- (CORE_DATA_EMPATH_BASE + CORE_DATA_EMPATH_SIZE)
-#define CORE_DATA_MEMORY_SIZE 24
-
-#define CORE_DATA_THROTTLE_BASE \
- (CORE_DATA_MEMORY_BASE + CORE_DATA_MEMORY_SIZE)
-#define CORE_DATA_THROTTLE_SIZE 24
-
-#define CORE_DATA_THREAD_BASE(t) \
- (CORE_DATA_THROTTLE_BASE + CORE_DATA_THROTTLE_SIZE + (24 * (t)))
-#define CORE_DATA_THREAD_SIZE (24 * 8)
-
-#define CORE_DATA_DTS_CPM_BASE \
- (CORE_DATA_THREAD_BASE(0) + CORE_DATA_THREAD_SIZE)
-#define CORE_DATA_DTS_CPM_SIZE 40
-
-#define CORE_DATA_PCB_SLAVE_BASE \
- (CORE_DATA_DTS_CPM_BASE + CORE_DATA_DTS_CPM_SIZE)
-#define CORE_DATA_PCB_SLAVE_SIZE 32
-
-#define CORE_DATA_OHA_BASE \
- (CORE_DATA_PCB_SLAVE_BASE + CORE_DATA_PCB_SLAVE_SIZE)
-#define CORE_DATA_OHA_SIZE 8
-
-#define CORE_DATA_SIZE (CORE_DATA_OHA_BASE + CORE_DATA_OHA_SIZE)
-
-// Data area components. Each data group is marked with the TOD captured just
-// before each data group capture. Data groups that may have some relation to
-// frequency are also tagged with the current raw cycles reading. The offsets
-// are _byte_ offsets into a byte array. The user needs to be aware of
-// whether each datum represents a 32- or 64-bit integer.
-
-#define CORE_DATA_EMPATH_UNUSED (CORE_DATA_EMPATH_BASE + 0x00)
-#define CORE_DATA_EMPATH_TOD (CORE_DATA_EMPATH_BASE + 0x04)
-#define CORE_DATA_DISPATCH (CORE_DATA_EMPATH_BASE + 0x08)
-#define CORE_DATA_COMPLETION (CORE_DATA_EMPATH_BASE + 0x0c)
-#define CORE_DATA_FREQ_SENS_BUSY (CORE_DATA_EMPATH_BASE + 0x10)
-#define CORE_DATA_FREQ_SENS_FINISH (CORE_DATA_EMPATH_BASE + 0x14)
-#define CORE_DATA_RUN_CYCLES (CORE_DATA_EMPATH_BASE + 0x18)
-#define CORE_DATA_RAW_CYCLES (CORE_DATA_EMPATH_BASE + 0x1c)
-#define CORE_DATA_MEM_A (CORE_DATA_EMPATH_BASE + 0x20)
-#define CORE_DATA_MEM_B (CORE_DATA_EMPATH_BASE + 0x24)
-
-#define CORE_DATA_MEMORY_RAW_CYCLES (CORE_DATA_MEMORY_BASE + 0x00)
-#define CORE_DATA_MEMORY_TOD (CORE_DATA_MEMORY_BASE + 0x04)
-#define CORE_DATA_MEMORY_COUNT(p) (CORE_DATA_MEMORY_BASE + 0x08 + ((p) * 4))
-
-#define CORE_DATA_THROTTLE_RAW_CYCLES (CORE_DATA_THROTTLE_BASE + 0x00)
-#define CORE_DATA_THROTTLE_TOD (CORE_DATA_THROTTLE_BASE + 0x04)
-#define CORE_DATA_THROTTLE_IFU_THROTTLE (CORE_DATA_THROTTLE_BASE + 0x08)
-#define CORE_DATA_THROTTLE_ISU_THROTTLE (CORE_DATA_THROTTLE_BASE + 0x10)
-#define CORE_DATA_THROTTLE_IFU_ACTIVE (CORE_DATA_THROTTLE_BASE + 0x18)
-
-#define CORE_DATA_THREAD_RAW_CYCLES(t) (CORE_DATA_THREAD_BASE(t) + 0x00)
-#define CORE_DATA_THREAD_TOD(t) (CORE_DATA_THREAD_BASE(t) + 0x04)
-#define CORE_DATA_THREAD_RUN_CYCLES(t) (CORE_DATA_THREAD_BASE(t) + 0x08)
-#define CORE_DATA_THREAD_COMPLETION(t) (CORE_DATA_THREAD_BASE(t) + 0x0c)
-#define CORE_DATA_THREAD_MEM_A(t) (CORE_DATA_THREAD_BASE(t) + 0x10)
-#define CORE_DATA_THREAD_MEM_B(t) (CORE_DATA_THREAD_BASE(t) + 0x14)
-
-#define CORE_DATA_DTS_CPM_UNUSED (CORE_DATA_DTS_CPM_BASE + 0x00)
-#define CORE_DATA_DTS_CPM_TOD (CORE_DATA_DTS_CPM_BASE + 0x04)
-#define CORE_DATA_SENSOR_V0 (CORE_DATA_DTS_CPM_BASE + 0x08)
-#define CORE_DATA_SENSOR_V1 (CORE_DATA_DTS_CPM_BASE + 0x10)
-#define CORE_DATA_SENSOR_V8 (CORE_DATA_DTS_CPM_BASE + 0x18)
-#define CORE_DATA_SENSOR_V9 (CORE_DATA_DTS_CPM_BASE + 0x20)
-
-#define CORE_DATA_PCB_SLAVE_UNUSED (CORE_DATA_PCB_SLAVE_BASE + 0x00)
-#define CORE_DATA_PCB_SLAVE_TOD (CORE_DATA_PCB_SLAVE_BASE + 0x04)
-#define CORE_DATA_PMCR (CORE_DATA_PCB_SLAVE_BASE + 0x08)
-#define CORE_DATA_PMSR (CORE_DATA_PCB_SLAVE_BASE + 0x10)
-#define CORE_DATA_PM_HISTORY (CORE_DATA_PCB_SLAVE_BASE + 0x18)
-
-#define CORE_DATA_OHA_RO_STATUS_REG (CORE_DATA_OHA_BASE + 0x00)
-
-
-#ifndef __ASSEMBLER__
-
-// The GPE routine requires that the structure of core data collected by
-// gpe_get_core_data() be represented as the offsets defined above. This set
-// of structures represents the equivalent C-structure form of the data. Note
-// that the procedure formats the TOD as a 32-bit, 2 MHz timebase.
-
-typedef struct {
- uint32_t unused;
- uint32_t tod_2mhz;
- uint32_t dispatch;
- uint32_t completion;
- uint32_t freq_sens_busy;
- uint32_t freq_sens_finish;
- uint32_t run_cycles;
- uint32_t raw_cycles;
- uint32_t mem_a;
- uint32_t mem_b;
-} CoreDataEmpath;
-
-typedef struct {
- uint32_t raw_cycles;
- uint32_t tod_2mhz;
- uint32_t count[4];
-} CoreDataPerPartitionMemory;
-
-typedef struct {
- uint32_t raw_cycles;
- uint32_t tod_2mhz;
- uint32_t ifu_throttle;
- uint32_t isu_throttle;
- uint32_t ifu_active;
- uint32_t undefined;
-} CoreDataThrottle;
-
-typedef struct {
- uint32_t raw_cycles;
- uint32_t tod_2mhz;
- uint32_t run_cycles;
- uint32_t completion;
- uint32_t mem_a;
- uint32_t mem_b;
-} CoreDataPerThread;
-
-typedef struct {
- uint32_t unused;
- uint32_t tod_2mhz;
- sensors_v0_t sensors_v0;
- sensors_v1_t sensors_v1;
- sensors_v8_t sensors_v8;
- sensors_v9_t sensors_v9;
-} CoreDataDtsCpm;
-
-typedef struct {
- uint32_t unused;
- uint32_t tod_2mhz;
- pcbs_power_management_control_reg_t pmcr;
- pcbs_power_management_status_reg_t pmsr;
- pcbs_pmstatehistocc_reg_t pm_history;
-} CoreDataPcbSlave;
-
-typedef struct {
- oha_ro_status_reg_t oha_ro_status_reg;
-} CoreDataOha;
-
-typedef struct {
- CoreDataEmpath empath;
- CoreDataPerPartitionMemory per_partition_memory;
- CoreDataThrottle throttle;
- CoreDataPerThread per_thread[8];
- CoreDataDtsCpm dts_cpm;
- CoreDataPcbSlave pcb_slave;
- CoreDataOha oha;
-} CoreData;
-
-#endif // __ASSEMBLER__
-
-
-/// \defgroup core_data_status_bits Core Data Status Bits
-///
-/// These bits are set (if appropriate) in the low-order reserved area of the
-/// OHA_RO_STATUS_REG image stored in the CoreData structure.
-///
-/// @{
-
-/// This bit is set if SCOM access to the OHA returns a non-0 PIB return code
-/// when trying to write the OHA_CPM_HIST_RESET_REG to set up PC-only special
-/// wakeup.
-#define CORE_DATA_CPM_HIST_RESET_ACCESS_FAILED 0x01
-
-/// This bit is set if access to the OHA returns a non-0 PIB return code when
-/// trying to read the OHA_RO_STATUS_REG to determine core status.
-#define CORE_DATA_OHA_RO_STATUS_ACCESS_FAILED 0x02
-
-/// This bit is set if EMPATH data was requested to be collected and was
-/// collected. If this bit is not set then any EMPATH data requested to be
-/// collected will be 0.
-///
-/// If EMPATH data was requested but was not collected, then one of the bits
-/// CORE_DATA_EXPECTED_EMPATH_ERROR or CORE_DATA_UNEXPECTED_EMPATH_ERROR will
-/// be set, and the error code is stored in the OHA_RO_STATUS register image.
-#define CORE_DATA_EMPATH_COLLECTED 0x04
-
-/// This bit is set if core sensor data (DTS/CPM) was collected. If this bit
-/// is not set then core DTS/CPM data will be 0.
-#define CORE_DATA_CORE_SENSORS_COLLECTED 0x08
-
-/// This bit is set if L3 sensor data (DTS/CPM) was collected. If this bit is
-/// not set then L3 DTS/CPM data will be 0.
-#define CORE_DATA_L3_SENSORS_COLLECTED 0x10
-
-/// If this bit is set, then an "expected" error was encountered while
-/// collecting EMPATH data. Given that the procedure has gone through the
-/// PC-only special wakeup protocol, the only "expected" error is the
-/// intermittant PCB error code #4 due to HW280375.
-#define CORE_DATA_EXPECTED_EMPATH_ERROR 0x20
-
-/// If this bit is set, then an "unexpected" error was encountered while
-/// collecting EMPATH data. Given that the procedure has gone through the
-/// PC-only special wakeup protocol, the only "expected" error is the
-/// intermittant PCB error code #4 due to HW280375. If this bit is set it
-/// indicates a serious problem.
-#define CORE_DATA_UNEXPECTED_EMPATH_ERROR 0x40
-
-/// The first bit of the 4-bit PCB parity + error code, in the event a PCB
-/// error is encountered during EMPATH processing.
-#define CORE_DATA_EMPATH_ERROR_LOCATION 52
-
-#define CORE_DATA_EMPATH_ERROR_BITS 4
-
-/// @}
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_core_data_fast()
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASSEMBLER__
-
-/// Paramaters for gpe_get_chip_data_fast()
-
-typedef struct {
-
- /// gpe_get_core_data_fast() only collects data for chiplets configured in
- /// this mask.
- ChipConfig config;
-
- /// This mask, comprised of a logical OR of the GPE_GET_CORE_DATA_FAST_*
- /// macros, controls which data groups are collected.
- uint64_t select;
-
- /// This is the 32-bit pointer (cast to a uint64_t) to the chiplet raw
- /// data area to be filled by this invocation of gpe_get_core_data_fast().
- uint64_t data;
-
-} GpeGetChipDataFastParms;
-
-PoreEntryPoint gpe_get_core_data_fast;
-
-#endif /* __ASSEMBLER__ */
-
-// Parameter offsets for gpe_get_core_data()
-
-#define GPEGETCOREDATAFASTPARMS_CONFIG 0x00
-#define GPEGETCOREDATAFASTPARMS_SELECT 0x08
-#define GPEGETCOREDATAFASTPARMS_DATA 0x10
-
-// Data group select masks for gpe_get_core_data_fast()
-
-#define GPE_GET_CORE_DATA_FAST_FREQ_TARGET 0x0001
-
-#define CORE_DATA_FAST_FREQ_TARGET_BASE 0x0
-#define CORE_DATA_FAST_FREQ_TARGET_SIZE (8 + (PGP_NCORES * 8))
-
-#define CORE_DATA_FAST_SIZE \
- (CORE_DATA_FAST_FREQ_TARGET_BASE + CORE_DATA_FAST_FREQ_TARGET_SIZE)
-
-#define CORE_DATA_FAST_FREQ_TARGET_UNUSED (CORE_DATA_FAST_FREQ_TARGET_BASE + 0)
-#define CORE_DATA_FAST_FREQ_TARGET_TOD (CORE_DATA_FAST_FREQ_TARGET_BASE + 4)
-#define CORE_DATA_FAST_FREQ_TARGET_LPFTSR(n) (CORE_DATA_FAST_FREQ_TARGET_BASE + 8 + ((n) * 8))
-
-#ifndef __ASSEMBLER__
-
-typedef struct {
- uint32_t unused;
- uint32_t tod_2mhz;
- pcbs_local_pstate_frequency_target_status_reg_t lpftsr[PGP_NCORES];
-} CoreDataFast;
-
-#endif // __ASSEMBLER__
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_chip_data()
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASSEMBLER__
-
-/// Paramaters for gpe_get_chip_data()
-
-typedef struct {
-
- /// This mask, comprised of a logical OR of the GPE_GET_CHIP_DATA_*
- /// macros, controls which data groups are collected.
- uint64_t select;
-
- /// This is the 32-bit pointer (cast to a uint64_t) to the chiplet raw
- /// data area to be filled by this invocation of gpe_get_chip_data().
- uint64_t data;
-
-} GpeGetChipDataParms;
-
-PoreEntryPoint gpe_get_chip_data;
-
-#endif /* __ASSEMBLER__ */
-
-// Parameter offsets for gpe_get_chip_data()
-
-#define GPEGETCHIPDATAPARMS_SELECT 0x00
-#define GPEGETCHIPDATAPARMS_DATA 0x08
-
-// Data group select masks for gpe_get_chip_data()
-
-#define GPE_GET_CHIP_DATA_OVERCOMMIT 0x0001
-
-#define CHIP_DATA_OVERCOMMIT_BASE 0
-#define CHIP_DATA_OVERCOMMIT_SIZE 56
-
-#define CHIP_DATA_SIZE (CHIP_DATA_OVERCOMMIT_BASE + CHIP_DATA_OVERCOMMIT_SIZE)
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_mem_data()
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASSEMBLER__
-
-/// Paramaters for gpe_get_mem_data()
-
-typedef struct {
-
- /// The index (0 .. PGP_NCENTAUR - 1) of the Centaur whose sensor cache
- /// data to collect, or -1 to bypass collection.
- uint64_t collect;
-
- /// The index (0 .. PGP_NCENTAUR - 1) of the Centaur to "poke" to cause it
- /// to begin collecting the next round of data into its sensor cache, or
- /// -1 to bypass updating.
- uint64_t update;
-
- /// This is the 32-bit pointer (cast to a uint64_t) to the chiplet raw
- /// data area to be filled by this invocation of gpe_get_mem_data(). This
- /// pointer need not be valid if the \a collect field of the structure is
- /// -1.
- uint64_t data;
-
- /// The return code returned by the last invocation of the procedure; See
- /// \ref gpe_get_mem_date_rc.
- uint64_t rc;
-
- /// The 'update' timestamp
- ///
- /// This is the value of the chip TOD at the time the 'update' phase of
- /// the procedure is run, as close as possible to the "poke" of the
- /// Centaur. This timestamp indicates the time that the Centaur sensor
- /// cache line collection was kicked off. The timestamp is collected even
- /// if the \a update field of the structure is -1. Consistent with
- /// gpe_get_core_data() the timestamp is reduced to a 32-bit, 2MHz
- /// timestamp, and stored in the low-order half of a doubleword.
- uint32_t pad;
- uint32_t tod_2mhz;
-
-} GpeGetMemDataParms;
-
-PoreEntryPoint gpe_get_mem_data;
-
-#endif /* __ASSEMBLER__ */
-
-// Parameter offsets for gpe_get_mem_data()
-
-#define GPEGETMEMDATAPARMS_COLLECT 0x00
-#define GPEGETMEMDATAPARMS_UPDATE 0x08
-#define GPEGETMEMDATAPARMS_DATA 0x10
-#define GPEGETMEMDATAPARMS_RC 0x18
-#define GPEGETMEMDATAPARMS_PAD_TOD 0x20
-#define SIZEOF_GPEGETMEMDATAPARMS 0x28
-
-
-/// \defgroup gpe_mem_data_rc gpe_get_mem_data() Error Return Codes
-///
-/// The gpe_get_mem_data() procedure deposits a non-0 return code into the \a
-/// rc field of its parameter structure in the event of failure. Note that the
-/// procedure stops on the first failure, and in particular the TOD timestamp
-/// is not valid in the event of failure.
-///
-/// @{
-
-/// The procedure died, but no other information is available. This would have
-/// signalled an error interrupt and the PORE flex request will contain FFDC
-/// about the failure.
-#define GPE_GET_MEM_DATA_DIED 1
-
-/// The \a collect parameter was invalid, i.e. it either was an illegal index
-/// or the index of an unconfigured MCS or Centaur.
-#define GPE_GET_MEM_DATA_COLLECT_INVALID 2
-
-/// The \a update parameter was invalid, i.e. it either was an illegal index
-/// or the index of an unconfigured MCS or Centaur.
-#define GPE_GET_MEM_DATA_UPDATE_INVALID 3
-
-/// The global G_centaurConfiguration is not valid
-#define GPE_GET_MEM_DATA_NOT_CONFIGURED 4
-
-/// The workaround for HW256773 failed. To diagnose the failure look at the
-/// 'rc' field of the global variable G_hw256773.
-#define GPE_GET_MEM_DATA_HW256773_FAILED 5
-
-/// This code is established in the RC field prior to collecting the Centaur
-/// sensor cache data. If this RC is observed on a hard failure it most likely
-/// indicates an error assiciated with the Centaur whose data was being
-/// collected.
-#define GPE_GET_MEM_DATA_SENSOR_CACHE_FAILED 6
-
-/// This code is established in the RC field prior to "poking" the Centaur (if
-/// any) that is being updated this pass. If this RC is observed on a hard
-/// failure it most likely indicates an error associated with the Centaur
-/// being updated.
-#define GPE_GET_MEM_DATA_UPDATE_FAILED 7
-
-/// @}
-
-
-#ifndef __ASSEMBLER__
-
-// The GPE routine requires that the structure of centaur data collected by
-// gpe_get_mem_data() be represented as the offsets defined above. This set
-// of structures represent the equivalent C-structure form of the data. Note
-// that the procedure formats the TOD as a 32-bit, 2 MHz timebase.
-
-/// Layout of data collected from MCS
-///
-/// This is currently empty, however to avoid code rewrites if any data is
-/// ever collected here the structure is declared and placed in the larger
-/// MemData structure. The fact that the structure is empty does not seem to
-/// cause problems.
-
-typedef struct {
-} MemDataMcs;
-
-/// The layout of a Centaur chip thermal sensor
-///
-/// \todo Centaur spec. has no doc. on layout of these bits; Waiting for more
-/// info from Centaur team.
-
-typedef union {
- uint16_t value;
- struct {
- uint16_t value;
- } fields;
-} centaur_sensor_t;
-
-/// The layout of a Centaur DIMM sensor
-///
-/// Mnemonic macros for the 2-bit status codes (DIMM_SENSOR_STATUS_*) are
-/// currently defined in ssx/pgp/pgp_common.h
-///
-/// \todo Waiting for more info from Centaur team on how to interpret
-
-typedef union {
- uint16_t value;
- struct {
-#ifdef _BIG_ENDIAN
- uint16_t crit_trip : 1;
- uint16_t alarm_trip : 1;
- uint16_t below_trip : 1;
- uint16_t sign_bit : 1;
- uint16_t temperature : 8;
- uint16_t temp_fraction : 2;
- uint16_t status : 2;
-#else
- uint16_t status : 2;
- uint16_t temp_fraction : 2;
- uint16_t temperature : 8;
- uint16_t sign_bit : 1;
- uint16_t below_trip : 1;
- uint16_t alarm_trip : 1;
- uint16_t crit_trip : 1;
-#endif
- } fields;
-} centaur_dimm_sensor_t;
-
-/// The layout of the status bits of the sensor cache line
-///
-/// The sensor cache-line aggregator gets each element of the sensor cache
-/// line by an internal SCOM. The individual PCB return codes for each SCOM
-/// are collected here (3 bits each) - note that many of the 32-bit registers
-/// come back in a single 64-bit internal SCOM. Normally this register will
-/// always read as 0 indicating all data was collected successfully. The PCB
-/// error codes (PCB_ERROR_*) are currently defined in ssx/pgp/pgp_common.h.
-
-typedef union {
- uint64_t value;
- struct {
-#ifdef _BIG_ENDIAN
- uint64_t mba01_rw : 3; /// mba01_rd[+ wr]
- uint64_t mba01_ap : 3; /// mba01_act[+ powerups]
- uint64_t mba23_rw : 3; /// mba23_rd[+ wr]
- uint64_t mba23_ap : 3; /// mba23_act[+ powerups]
- uint64_t mba_sc : 3; /// mba01[+ 23]_spec_cancels
- uint64_t lp2_exits : 3; /// lp2_exits
- uint64_t frame_count : 3; /// frame_count
- uint64_t mba01_chrw : 3; /// mba01_cache_hits_rd[+ wr]
- uint64_t mba23_chrw : 3; /// mba23_cache_hits_rd[+ wr]
- uint64_t mba01_iac_bl : 3; /// mba01_intreq_arr_cnt_base[+ low]
- uint64_t mba01_iac_mh : 3; /// mba01_intreq_arr_cnt_med[+ high]
- uint64_t mba23_iac_bl : 3; /// mba23_intreq_arr_cnt_base[+ low]
- uint64_t mba23_iac_mh : 3; /// mba23_intreq_arr_cnt_med[+ high]
- uint64_t iac_high_latency : 3; /// intereq_arr_cnt_high_latency
- uint64_t centaur01 : 3; /// centaur_thermal_sensor[0 - 1]
- uint64_t dimm03 : 3; /// dimm_thermal_sensor[0 - 3]
- uint64_t dimm47 : 3; /// dimm_thermal_sensor[4 - 7]
- uint64_t reserved : 13;
-#else
- uint64_t reserved : 13;
- uint64_t dimm47 : 3; /// dimm_thermal_sensor[4 - 7]
- uint64_t dimm03 : 3; /// dimm_thermal_sensor[0 - 3]
- uint64_t centaur01 : 3; /// centaur_thermal_sensor[0 - 1]
- uint64_t iac_high_latency : 3; /// intereq_arr_cnt_high_latency
- uint64_t mba23_iac_mh : 3; /// mba23_intreq_arr_cnt_med[+ high]
- uint64_t mba23_iac_bl : 3; /// mba23_intreq_arr_cnt_base[+ low]
- uint64_t mba01_iac_mh : 3; /// mba01_intreq_arr_cnt_med[+ high]
- uint64_t mba01_iac_bl : 3; /// mba01_intreq_arr_cnt_base[+ low]
- uint64_t mba23_chrw : 3; /// mba23_cache_hits_rd[+ wr]
- uint64_t mba01_chrw : 3; /// mba01_cache_hits_rd[+ wr]
- uint64_t frame_count : 3; /// frame_count
- uint64_t lp2_exits : 3; /// lp2_exits
- uint64_t mba_sc : 3; /// mba01[+ 23]_spec_cancels
- uint64_t mba23_ap : 3; /// mba23_act[+ powerups]
- uint64_t mba23_rw : 3; /// mba23_rd[+ wr]
- uint64_t mba01_ap : 3; /// mba01_act[+ powerups]
- uint64_t mba01_rw : 3; /// mba01_rd[+ wr]
-#endif
- } fields;
-} centaur_scom_status_t;
-
-/// The layout of the Centaur sensor cache line
-
-typedef struct {
- uint32_t mba01_rd; // PP1/MBA01 Reads
- uint32_t mba01_wr; // PP1/MBA01 Writes
- uint32_t mba01_act; // PP1/MBA01 Activations
- uint32_t mba01_powerups; // PP1/MBA01 PowerUps
-
- uint32_t mba23_rd; // PP2/MBA23 Reads
- uint32_t mba23_wr; // PP2/MBA23 Writes
- uint32_t mba23_act; // PP2/MBA23 Activations
- uint32_t mba23_powerups; // PP2/MBA23 PowerUps
-
- uint32_t mba01_spec_cancels; // PP1/MBA01 Speculative Cancels
- uint32_t mba23_spec_cancels; // PP2/MBA23 Speculative Cancels
-#ifdef _BIG_ENDIAN
- uint32_t eventn :4; // EVENTN
- uint32_t reserved_0 :20; // Reserved
- uint32_t lp2_exits :8; // LP2 Exits
-#else
- uint32_t lp2_exits :8; // LP2 Exits
- uint32_t reserved_0 :20; // Reserved
- uint32_t eventn :4; // EVENTN
-#endif
- uint32_t frame_count; // Frame Count (timestamp)
-
- uint32_t mba01_cache_hits_rd; // PP1/MBA01 Cache Hits Reads
- uint32_t mba01_cache_hits_wr; // PP1/MBA01 Cache Hits Writes
- uint32_t mba23_cache_hits_rd; // PP2/MBA23 Cache Hits Reads
- uint32_t mba23_cache_hits_wr; // PP2/MBA23 Cache Hits Writes
-
- uint32_t mba01_intreq_arr_cnt_base; // PP1/MBA01 Inter-Req Arrival Count Base
- uint32_t mba01_intreq_arr_cnt_low; // PP1/MBA01 Inter-Req Arrival Count Low
- uint32_t mba01_intreq_arr_cnt_med; // PP1/MBA01 Inter-Req Arrival Count Med
- uint32_t mba01_intreq_arr_cnt_high; // PP1/MBA01 Inter-Req Arrival Count High
-
- uint32_t mba23_intreq_arr_cnt_base; // PP2/MBA23 Inter-Req Arrival Count Base
- uint32_t mba23_intreq_arr_cnt_low; // PP2/MBA23 Inter-Req Arrival Count Low
- uint32_t mba23_intreq_arr_cnt_med; // PP2/MBA23 Inter-Req Arrival Count Med
- uint32_t mba23_intreq_arr_cnt_high; // PP2/MBA23 Inter-Req Arrival Count High
-
- uint32_t intreq_arr_cnt_high_latency; // Inter-Req Arrival Count High Latency
- centaur_sensor_t centaur_thermal_sensor[2]; // Centaur Thermal Sensors 0-1
- centaur_dimm_sensor_t dimm_thermal_sensor[8]; // DIMM Thermal Sensors 0-7
- centaur_scom_status_t status; // Aggregated internal SCOM status
-} MemDataSensorCache;
-
-typedef struct {
- MemDataMcs mcs; // TODO: Not collected yet
- MemDataSensorCache scache; // OCC Centaur Sensor Cache Line (128 bytes)
-} MemData;
-
-#endif // __ASSEMBLER__
-
-
-// Data offsets for gpe_get_mem_data()
-
-#define MEM_DATA_MCS_BASE 0
-#define MEM_DATA_MCS_SIZE 0
-
-#define MEM_DATA_CENTAUR_BASE (MEM_DATA_MCS_BASE + MEM_DATA_MCS_SIZE)
-#define MEM_DATA_CENTAUR_SIZE 128
-
-#define MEM_DATA_SIZE (MEM_DATA_MCS_SIZE + MEM_DATA_CENTAUR_SIZE)
-
-#endif /* __GPE_DATA_H__ */
diff --git a/src/lib/gpe_data.pS b/src/lib/gpe_data.pS
deleted file mode 100755
index 2338276..0000000
--- a/src/lib/gpe_data.pS
+++ /dev/null
@@ -1,1585 +0,0 @@
-// $Id: gpe_data.pS,v 820.1 2014/08/22 16:33:56 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/fw820/procedures/lib/gpe_data.pS,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_data.S
-/// \brief GPE procedures for raw data collection
-
- .nolist
-
-#include "ssx.h"
-#include "pgas.h"
-#include "pgp_config.h"
-#include "gpe.h"
-#include "gpe_pba.h"
-#include "gpe_data.h"
-#include "gpe_scom.h"
-
- .list
-
- .oci
- .text.pore
-
- .revision_string G_gpe_data_pS_revision, "$Revision: 820.1 $"
-
-/// \cond
-
-////////////////////////////////////////////////////////////////////////////
-// Common Macros
-////////////////////////////////////////////////////////////////////////////
-
- // Get a full 64-bit SCOM and write to OCI space. Clobbers a Data
- // register.
-
- .macro get_scom, dx, scom, chiplet_base, oci_offset, oci_base
-
- ld (\dx), (\scom), (\chiplet_base)
- std (\dx), (\oci_offset), (\oci_base)
-
- .endm
-
-
- // Tag a data group with TOD[24..56]. This macro clobbers a data
- // register.
-
- .macro tag_data_group, base, dx, oci_base, tod_chiplet
-
- ld (\dx), TOD_VALUE_REG, (\tod_chiplet)
- extrdi (\dx), (\dx), 32, 24
- std (\dx), (\base), (\oci_base)
-
- .endm
-
-
- // An OCI - OCI copy. Dx gets clobbered
-
- .macro ocicopy, dx, src_offset, src_base, dst_offset, dst_base
-
- ld (\dx), (\src_offset), (\src_base)
- std (\dx), (\dst_offset), (\dst_base)
-
- .endm
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_core_data()
-////////////////////////////////////////////////////////////////////////////
-
- // Macros for gpe_get_core_data().
-
- // Tag a core data group with TOD[24..56], and optionally with the raw
- // cycle count. Always clobbers D0 and D1. If called with store=0, the
- // tag ends up in D0.
-
- .macro tag_core_data_group, base, oci_base, pc_chiplet, tod_chiplet, \
- raw=1, store=1
-
- ld D0, TOD_VALUE_REG, (\tod_chiplet)
- extrdi D0, D0, 32, 24
- .if (\raw)
- sti PC_OCC_SPRC, (\pc_chiplet), SPRN_CORE_RAW_CYCLE
- ld D1, PC_OCC_SPRD, (\pc_chiplet)
- rotldi D1, D1, 32
- or D0, D0, D1
- .endif
- .if (\store)
- std D0, (\base), (\oci_base)
- .endif
- .endm
-
-
- // Get a pair of SCOMs from PC, packing them into a single 64-bit value
- // and writing them to OCI space. Clobbers D0 and D1. Assumes that
- // PC_OCC_SPRC is set up for autoincrement access as well.
- //
- // This macro takes advantage of the fact that PC-unit SCOMs only
- // define the lower 32 bits, and the high-32 are 0.
-
- .macro get_pc_pair, offset, oci_base, chiplet_base
-
- ld D0, PC_OCC_SPRD, (\chiplet_base)
- ld D1, PC_OCC_SPRD, (\chiplet_base)
- rotldi D0, D0, 32
- or D0, D0, D1
- std D0, (\offset), (\oci_base)
-
- .endm
-/// \endcond
-
-
-
-
-/// \fn gpe_get_core_data(GpeGetCoreDataParms *parms);
-/// \brief Get core chiplet raw data on performance/thermal timescale
-///
-/// This routine uses get_per_core_raw_data() to collect raw data for one or
-/// more cores. The \a data field of the GpeGetCoreDataParms parameter
-/// contains a pointer to an array of CoreData* pointers. Data for every core
-/// configured in the configuration mask is collected - it is assumed that the
-/// data area for the data exists.
-///
-/// This entry point is used by the lab thread 'coreData'.
-#ifdef DOXYGEN_ONLY
-void gpe_get_core_data(GpeGetCoreDataParms *parms);
-#endif
-/// \cond
-
- // Register usage:
- //
- // ETR : At entry, holds the parameter pointer.
- // A1 : Holds the pointer to the paramaters
- // A0 : Holds the (varying) pointer to the data area for the
- // current core.
- // P1 : Holds the (constant) chiplet id of the TOD
- // P0 : Holds the (varying) chiplet id of the current core
- // SPRG0 : Temporary storage of the chiplet mask as it rotates.
- // CTR : Loops through core chiplets indices
- // D1 : Scratch
- // D0 : Scratch
-
- .global gpe_get_core_data
-
-gpe_get_core_data:
-
- // Set up registers. The chiplet part of the ChipConfig is left
- // justified then stored in SPRG0, where it will be maintained as we
- // rotate through it. Note that SPRG0 is 32 bits, so it needs to be
- // manipulated from the low-order portion of a data register.
-
- mr D0, ETR
- la A1, core_data_parms
- std D0, 0, A1
- mr A1, D0
-
- ld D0, GPEGETCOREDATAPARMS_DATA, A1
- mr A0, D0
-
- ld D0, GPEGETCOREDATAPARMS_CONFIG, A1
- left_justify_core_config D0
- rotldi D0, D0, 32
- mr SPRG0, D0
-
- lpcs P1, TOD_VALUE_REG
- ls P0, 0x10
- ls CTR, (PGP_NCORES - 1) # PORE does test, then decr. and branch
-
-core_data_loop:
-
- // Load/test the chiplet mask, and store the rotated mask back to
- // SPRG0. If the chiplet is not configured, simply continue.
-
- mr D0, SPRG0
- andi D1, D0, 0x80000000
- rotldi D0, D0, 1
- mr SPRG0, D0
- braz D1, core_data_continue
-
- // Collect Raw Data for Core specified by P0, stored at A0
-
- bsr get_per_core_raw_data
-
-core_data_continue:
-
- // Increment the core chiplet index and data pointer, then loop or
- // halt.
-
- adds P0, P0, 1
- adds A0, A0, CORE_DATA_SIZE
- loop core_data_loop
-
- halt
-
- .epilogue gpe_get_core_data
-
-/// \endcond
-
-
-
-/// \fn gpe_get_per_core_data(GpeGetCoreDataParms *parms);
-/// \brief Get core chiplet raw data for a single core
-///
-/// This routine uses get_per_core_raw_data() to collect raw data for a single
-/// core. Regardless of the configuration mask setting, this routine exits
-/// after collecting data for a single core. The \a data field of the
-/// GpeGetCoreDataParms contains a pointer to a single CoreData object.
-///
-/// This entry point is used by OCC product firmware.
-#ifdef DOXYGEN_ONLY
-void gpe_get_per_core_data(GpeGetCoreDataParms *parms);
-#endif
-/// \cond
-
- // Register usage:
- //
- // A1 : Holds the pointer to the paramaters
- // A0 : Holds the (varying) pointer to the data area for the
- // current core, as well as the data pointer-pointer while
- // searching for a configured core.
- // P1 : Holds the (constant) chiplet id of the TOD
- // P0 : Holds the (varying) chiplet id of the current core
- // SPRG0 : Temporary storage of the chiplet mask as it rotates.
- // CTR : Loops through core chiplets indices
- // D1 : Scratch
- // D0 : Scratch
-
- .global gpe_get_per_core_data
-
-gpe_get_per_core_data:
-
- // Set up registers. A1 gets the parameters (which must also be
- // stored in memory), the the ETR is replaced by the data
- // pointer-pointer. The chiplet part of the ChipConfig is left
- // justified then stored in SPRG0, where it will be maintained as we
- // rotate through it. Note that SPRG0 is 32 bits, so it needs to be
- // manipulated from the low-order portion of a data register.
-
- mr D0, ETR
- la A1, core_data_parms
- std D0, 0, A1
- mr A1, D0
-
- ld D0, GPEGETCOREDATAPARMS_DATA, A1
- mr A0, D0
-
- ld D0, GPEGETCOREDATAPARMS_CONFIG, A1
- left_justify_core_config D0
- rotldi D0, D0, 32
- mr SPRG0, D0
-
- lpcs P1, TOD_VALUE_REG
- ls P0, 0x10
- ls CTR, (PGP_NCORES - 1) # PORE does test, then decr. and branch
-
-per_core_data_loop:
-
- // Load/test the chiplet mask, and store the rotated mask back to
- // SPRG0. If the chiplet is not configured, simply continue.
-
- mr D0, SPRG0
- andi D1, D0, 0x80000000
- rotldi D0, D0, 1
- mr SPRG0, D0
- braz D1, per_core_data_continue
-
- // Collect Raw Data for Core specified by P0, stored at A0
-
- bsr get_per_core_raw_data
-
- // Exit GPE after gathering data for one core
- bra per_core_data_complete
-
-per_core_data_continue:
-
- // Increment the core chiplet index and data pointer, then loop or
- // halt.
- adds P0, P0, 1
- loop per_core_data_loop
-
-per_core_data_complete:
- halt
-
- .epilogue gpe_get_per_core_data
-
-/// \endcond
-
-/// \fn gpe_get_per_core_raw_data();
-/// \brief Get core chiplet raw data for one core
-///
-/// This routine collects raw data from the core designated by P0. Data is
-/// grouped into logical groups, and the collection of any group is enabled by
-/// a group select mask. All data and thread groups (except the PCB Slave
-/// group) are tagged with the TOD and raw cycle counts sampled immediately
-/// before the group data are sampled.
-///
-/// The final PCB Slave data group should always be selected (but \e is
-/// configurable) as it contains the PCB Slave Power Management history
-/// register. This register value is required to determine how to interpret
-/// the other data items.
-///
-/// The PC counters are collected using the SPRC/SPRD autoincrement
-/// mechanism. Be very cautious about changing this code or the data layout
-/// because the counter order is fixed by hardware and the data layout
-/// reflects the most natural way to collect the data based on the
-/// hardware. Note that SPRC/SPRD autoincrement IS NOT OPTIONAL for the OCC
-/// registers, regardless of how it may be documented in the PC workbook, or
-/// the fact that the procedure redundantly sets up auto-increment. That is,
-/// the hardware always does auto-increment for these SPRC/SPRD reads.
-///
-/// The data structure includes a TOD/Raw cycles word for each set of counters
-/// for each thread. Due to the amount of time it may take to collect
-/// per-thread data for 8 threads, errors of 1% or more could accrue at thread
-/// 7 if each thread group were not individually tagged. To avoid having to
-/// SCOM the TOD plus a SCOMC/SCOMD pair to create each thread group header
-/// however, we instead tag thread0 with actual data, then tag the remaining
-/// thread groups with interpolated TOD/Raw cycle values computed by obtaining
-/// a tag at the end of all threads. This takes only a little more time than
-/// the simpler expedient of copying the Tod/Raw Cycles count from thread0 to
-/// threads 1-7.
-///
-/// At the entry point of the routine, the code must go through the PC-ONLY
-/// special wakeup procedure to ensure that we can SCOM a napping core. This
-/// has to be done carefully as it's possible that SCOM access to the OHA will
-/// result in a 0x1 PIB response if the core is coming out of deep
-/// sleep/winkle. This PIB response would discombobulate the PORE engine so we
-/// have to run these SCOMs with error handling done manually. If a core is
-/// inaccessible due to an idle state we clear all of the configured EMPATH
-/// counts, per-thread counts and DTS and CPM for the core. If the core is
-/// only asleep (not winkled) then we attempt to read the DTS and CPM for the
-/// L3. Note that TOD timestamps are always collected, even if the data is
-/// simply zeroed.
-///
-/// A modified copy of the OHA_RO_STATUS_REG read during the PC-only SPWU
-/// protocol is stored with the data. Several low-order reserved bits of the
-/// register image are programmed with the following masks. See the
-/// documentation for these bits for full details.
-///
-/// - CORE_DATA_CPM_HIST_RESET_ACCESS_FAILED
-/// - CORE_DATA_OHA_RO_STATUS_ACCESS_FAILED
-/// - CORE_DATA_EMPATH_COLLECTED
-/// - CORE_DATA_CORE_SENSORS_COLLECTED
-/// - CORE_DATA_L3_SENSORS_COLLECTED
-/// - CORE_DATA_EXPECTED_EMPATH_ERROR
-/// - CORE_DATA_UNEXPECTED_EMPATH_ERROR
-///
-/// In the event of expected or unexpected errors during EMPATH data
-/// collection the 3-bit PCB error code will also be stored at bit
-/// CORE_DATA_EMPATH_ERROR_LOCATION.
-///
-/// This is the PC-ONLY Special Wakeup + processing Sequence
-///
-/// 1. Switch to manual error handling mode and disable PIB errors.
-///
-/// 2. Write OHA_CPM_HIST_RESET_REG.pconly_special_wakeup = 1. If the write
-/// fails, note the failure and go to the bypass routine.
-///
-/// 3. Read OHA_RO_STATUS_REG. If the SCOM fails, access is impossible and
-/// noted. If the special wakeup complete is not immediately set that error is
-/// also noted. If either test fails then go to the bypass routine. Otherwise
-/// note success and continue.
-///
-/// 4. Attempt to collect sensor (DTS/CPM) data for the core and L3. This must
-/// be done with manual error handling as these SCOMs are not protected by
-/// PC-only SPWU.
-///
-/// 5. Switch to a private error handling table setup that allows the
-/// procedure to catch PCB data errors during EMPATH processing. This is
-/// required as a workaround for HW280375.
-///
-/// 6. Collect EMPATH data.
-///
-/// 7. Restore error handling; Clear the PC-only SPWU bit.
-///
-/// 8. Collect PCB Slave data.
-///
-/// When the core is inaccessible a similar "bypass" sequence to the data
-/// collection sequence is run, however all data other than timestamps and the
-/// PCB Slave data are stored as 0, and the PC-Only SPWU bit is cleared before
-/// error handling is re-enabled. The bypass routine will also take care of
-/// attempting to collect L3 DTS/CPM data for sleeping cores.
-///
-/// Note that the PCB slave data must be collected after the removal of
-/// PC-only special wakeup, otherwise a napping core will always appear to be
-/// in the run state.
-///
-/// Several global variables are required. Thus this procedure and its callers
-/// are not reentrant.
-#ifdef DOXYGEN_ONLY
- void get_per_core_raw_data();
-#endif
-/// \cond
-
-get_per_core_raw_data:
-
- // At entry:
- //
- // P0 : The chiplet to access (invariant)
- // A0 : Pointer to the data area for the core (invariant)
- // SPRG0 : Reserved to the caller (invariant)
- // CTR : Reserved to the caller (invariant)
- //
- // core_data_parms: Holds the pointer to the parameters
- //
- // At exit:
- //
- // All other registers are scratched by this routine
-
- // (1) Switch to manual error handling mode and disable PIB errors.
-
- mr D0, EMR
- la A1, saved_emr
- std D0, 0, A1
-
- andi D0, D0, ~(PORE_ERROR_MASK_ENABLE_ERR_HANDLER0 | \
- PORE_ERROR_MASK_ENABLE_ERR_OUTPUT0 | \
- PORE_ERROR_MASK_ENABLE_FATAL_ERR_OUTPUT0 | \
- PORE_ERROR_MASK_STOP_EXE_ON_ERROR0)
- mr EMR, D0
- la A1, manual_emr
- std D0, 0, A1
-
-
- // (2) Write OHA_CPM_HIST_RESET_REG.pconly_special_wakeup = 1. If the
- // write fails, note the failure and go to the bypass routine.
-
- sti OHA_CPM_HIST_RESET_REG, P0, \
- OHA_CPM_HIST_RESET_REG_PCONLY_SPECIAL_WAKEUP
- tprcbz D0, 3f
-
- sti CORE_DATA_OHA_RO_STATUS_REG, A0, \
- CORE_DATA_CPM_HIST_RESET_ACCESS_FAILED
- bra bypass_core_data
-
-
- // 3. Read OHA_RO_STATUS_REG. If the SCOM fails, access is impossible
- // and noted. If the special wakeup complete is not immediately set
- // that error is also noted. If either test fails then go to the
- // bypass routine. Otherwise note success and continue.
-
-3:
- ld D0, OHA_RO_STATUS_REG, P0
- tprcbz D1, 31f
-
- sti CORE_DATA_OHA_RO_STATUS_REG, A0, \
- CORE_DATA_OHA_RO_STATUS_ACCESS_FAILED
- bra bypass_core_data
-
-31:
- std D0, CORE_DATA_OHA_RO_STATUS_REG, A0
-
- // If either access is impossible we go to bypass. The bypass code
- // will read the L3 DTS/CPM data if it is possible.
-
- andi D1, D0, (OHA_RO_STATUS_REG_CORE_ACCESS_IMPOSSIBLE | \
- OHA_RO_STATUS_REG_ECO_ACCESS_IMPOSSIBLE)
- branz D1, bypass_core_data
-
- andi D1, D0, OHA_RO_STATUS_REG_SPECIAL_WAKEUP_COMPLETED
- braz D1, bypass_core_data
-
-
- // 4. Attempt to collect sensor (DTS/CPM) data. This must be done with
- // manual error handling (in effect here) as these SCOMs are not
- // protected by a PC-only SPWU.
-
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
- bsr getSensors
-
-
- // 5. Switch to a private error handling table setup that allows the
- // procedure to catch PCB errors during EMPATH processing.
-
- // NB: We know that this is being run as a PoreFlex job from OCC FW on
- // either GPE0 or GPE1. We also know that the default error mask does
- // not handle any errors with a table.
-
- tebngpe0 D0, 1f
- la A1, PORE_GPE0_TABLE_BASE_ADDR
- bra 2f
-1:
- la A1, PORE_GPE1_TABLE_BASE_ADDR
-2:
- la D0, empathErrorHandlers
- std D0, 0, A1
-
- la A1, saved_emr
- ld D0, 0, A1
- ori D0, D0, PORE_ERROR_MASK_ENABLE_ERR_HANDLER0
- andi D0, D0, ~(PORE_ERROR_MASK_ENABLE_ERR_OUTPUT0 | \
- PORE_ERROR_MASK_ENABLE_FATAL_ERR_OUTPUT0 | \
- PORE_ERROR_MASK_STOP_EXE_ON_ERROR0)
- mr EMR, D0
-
-#if INJECT_HW280375_ERRORS
-
- // This code is used to test the workaround for HW280375. The
- // undiagnosed hardware bug causes PCB error 4 to occur intermittantly
- // when accessing EMPATH registers. The appearance of the defect is
- // actually quite rare in practice, therefore this code remains in
- // case future development and testing of this procedure is necessary.
-
- // The test generates PCB error 4 by reading a non-existant OHA
- // register of the current core, once every 1024 samples on
- // average. The LFSR modifies A0 so we need to shuffle A0 <->
- // A1. (Note the LFSR code is not delivered to OCC FW).
-
- mr A1, A0
-
- la A0, testHw280375Lfsr
- ld D0, 0, A0
- bsr pore_rand64
- la A0, testHw280375Lfsr
- std D0, 0, A0
-
- mr A0, A1
-
- andi D0, D0, 0x3ff
- branz D0, 1f
- ld D0, 0x200ff, P0 # Force PCB error 4
-1:
-
-#endif
-
- // 6. Collect EMPATH data
-
- // Test/collect each data group in order. First reload the parameter
- // pointer into A1.
-
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
- // EMPATH
-empath:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_EMPATH
- braz D0, 1f
-
- .set _BASE, CORE_DATA_EMPATH_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- sti PC_OCC_SPRC, P0, \
- (SPRN_CORE_INSTRUCTION_DISPATCH | SPRN_PC_AUTOINCREMENT)
-
- get_pc_pair (_BASE + 0x08), A0, P0
- get_pc_pair (_BASE + 0x10), A0, P0
- get_pc_pair (_BASE + 0x18), A0, P0
- get_pc_pair (_BASE + 0x20), A0, P0
-
- // Per-Core (partition) Memory Counters
-per_core_memory:
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_MEMORY
- braz D0, 1f
-
- .set _BASE, CORE_DATA_MEMORY_BASE
- tag_core_data_group _BASE, A0, P0, P1
-
- sti PC_OCC_SPRC, P0, \
- (SPRN_CORE_MEM_C_LPAR(0) | SPRN_PC_AUTOINCREMENT)
-
- get_pc_pair (_BASE + 0x08), A0, P0
- get_pc_pair (_BASE + 0x10), A0, P0
-
- // Throttling Counters
-throttling:
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_THROTTLE
- braz D0, 1f
-
- .set _BASE, CORE_DATA_THROTTLE_BASE
- tag_core_data_group _BASE, A0, P0, P1
-
- sti PC_OCC_SPRC, P0, \
- (SPRN_IFU_THROTTLE_COUNTER | SPRN_PC_AUTOINCREMENT)
-
- get_pc_pair (_BASE + 0x08), A0, P0
- get_pc_pair (_BASE + 0x10), A0, P0
-
- // Per-Thread Counters
-per_thread:
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_THREAD
- braz D0, 1f
-
- .set _BASE, CORE_DATA_THREAD_BASE(0)
- tag_core_data_group _BASE, A0, P0, P1
-
- sti PC_OCC_SPRC, P0, \
- (SPRN_THREAD_RUN_CYCLES(0) | SPRN_PC_AUTOINCREMENT)
-
- get_pc_pair (_BASE + 0x08), A0, P0 # Run/Completion T0
- get_pc_pair (_BASE + 0x10), A0, P0 # Mem A/B T0
- // (_BASE + 0x18), A0, P0 # Tag T1
- get_pc_pair (_BASE + 0x20), A0, P0 # Run/Completion T1
- get_pc_pair (_BASE + 0x28), A0, P0 # Mem A/B T1
- // (_BASE + 0x30), A0, P0 # Tag T2
- get_pc_pair (_BASE + 0x38), A0, P0 # Run/Completion T2
- get_pc_pair (_BASE + 0x40), A0, P0 # Mem A/B T2
- // (_BASE + 0x48), A0, P0 # Tag T3
- get_pc_pair (_BASE + 0x50), A0, P0 # Run/Completion T3
- get_pc_pair (_BASE + 0x58), A0, P0 # Mem A/B T3
- // (_BASE + 0x60), A0, P0 # Tag T4
- get_pc_pair (_BASE + 0x68), A0, P0 # Run/Completion T4
- get_pc_pair (_BASE + 0x70), A0, P0 # Mem A/B T4
- // (_BASE + 0x78), A0, P0 # Tag T5
- get_pc_pair (_BASE + 0x80), A0, P0 # Run/Completion T5
- get_pc_pair (_BASE + 0x88), A0, P0 # Mem A/B T5
- // (_BASE + 0x90), A0, P0 # Tag T6
- get_pc_pair (_BASE + 0x98), A0, P0 # Run/Completion T6
- get_pc_pair (_BASE + 0xa0), A0, P0 # Mem A/B T6
- // (_BASE + 0xa8), A0, P0 # Tag T7
- get_pc_pair (_BASE + 0xb0), A0, P0 # Run/Completion T7
- get_pc_pair (_BASE + 0xb8), A0, P0 # Mem A/B T7
-
-
- // Interpolation of TOD and Raw Cycles over 8 threads. First collect
- // a new tag, then compute the difference with the thread0 tag. The
- // differences are then divided by 8 to form the interpolation
- // increment, and interpolation takes places in an unrolled loop.
- //
- // Note that we're doing parallel arithmetic here, and ignoring the
- // fact that there may be a carry/borrow from the low-order TOD into
- // the high-order cycle count. A single LSB is noise for the cycle
- // count, but would be significant for the TOD, which is why the
- // TOD is placed in the low-order part of the doubleword. Given that
- // a single LSB is noise for the cycle count there is no reason to
- // expend the time/code space to do the arithmetic 'correctly'.
-
-interpolate:
- tag_core_data_group 0, 0, P0, P1, store=0 # D0 contains the _NOW_ tag
-
- ld D1, CORE_DATA_THREAD_BASE(0), A0 # D1 will be used for interp.
- sub D0, D0, D1
- andi D0, D0, 0xfffffff8fffffff8 # Mask off bad bits and div. by 8.
- rotrdi D0, D0, 3
-
- .macro interpolate, thread
- add D1, D0, D1
- std D1, CORE_DATA_THREAD_BASE(\thread), A0
- .endm
-
- interpolate 1
- interpolate 2
- interpolate 3
- interpolate 4
- interpolate 5
- interpolate 6
- interpolate 7
-
-
- // If we made it here there were no errors - Yippee! If we were asked
- // to collect any EMPATH data then acknowledge that we did.
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, \
- (GPE_GET_CORE_DATA_EMPATH | \
- GPE_GET_CORE_DATA_MEMORY | \
- GPE_GET_CORE_DATA_THROTTLE | \
- GPE_GET_CORE_DATA_THREAD)
- braz D0, 1f
-
- ld D0, CORE_DATA_OHA_RO_STATUS_REG, A0
- ori D0, D0, CORE_DATA_EMPATH_COLLECTED
- std D0, CORE_DATA_OHA_RO_STATUS_REG, A0
-
-
- // 7. Restore error handling; Clear the PC-Only SPWU bit
-1:
- la A1, saved_emr
- ld D0, 0, A1
- mr EMR, D0
-
- sti OHA_CPM_HIST_RESET_REG, P0, 0
-
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
-
- // 8. Collect PCB-Slave data
-pcb_slave:
-
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_PCB_SLAVE
- braz D0, 1f
-
- .set _BASE, CORE_DATA_PCB_SLAVE_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- get_scom D0, PCBS_POWER_MANAGEMENT_CONTROL_REG, P0, CORE_DATA_PMCR, A0
- get_scom D0, PCBS_POWER_MANAGEMENT_STATUS_REG, P0, CORE_DATA_PMSR, A0
- get_scom D0, PCBS_PMSTATEHISTOCC_REG, P0, CORE_DATA_PM_HISTORY, A0
-
-1:
- ret
-
-
- //////////////////////////////////////////////////////////////////////
- // getSensors
- //////////////////////////////////////////////////////////////////////
- //
- // Try to get core and L3 sensor (DTS/CPM) data
- //
- // At Entry:
- //
- // We are in manual PIB error handling mode
- // A0 : Base address of core data area
- // A1 : Address of the parameter block
- // P0 : Chiplet
- //
- // At exit:
- //
- // A0, P0 unchanged
- // D0, D1 scratched
- //
- // Note that due to HW279433, we can not read the CPM sensors without
- // the possiblity of a FIR bit being set due to a PCB timeout. Since
- // the CPMs are currently not in plan for P8, these fields of the data
- // structure are simply zeroed.
-
-getSensors:
-
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_DTS_CPM
- braz D0, getSensorsDone
-
- // HW279433, see above
- ls D0, 0
- std D0, CORE_DATA_SENSOR_V8, A0
- std D0, CORE_DATA_SENSOR_V9, A0
-
- .set _BASE, CORE_DATA_DTS_CPM_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- // First try the core
-
- ld D0, SENSORS_CORE_V0, P0
- tprcbnz D1, coreSensorsFailed
- std D0, CORE_DATA_SENSOR_V0, A0
-
- ld D0, CORE_DATA_OHA_RO_STATUS_REG, A0
- ori D0, D0, CORE_DATA_CORE_SENSORS_COLLECTED
- std D0, CORE_DATA_OHA_RO_STATUS_REG, A0
-
- bra tryL3
-
-coreSensorsFailed:
-
- la A1, G_ggcd_coreSensorFail
- std D1, 0, A1
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
- ls D0, 0
- std D0, CORE_DATA_SENSOR_V0, A0
-
- // Now try the L3
-tryL3:
- ld D0, SENSORS_CORE_V1, P0
- tprcbnz D1, l3SensorsFailed
- std D0, CORE_DATA_SENSOR_V1, A0
-
- ld D0, CORE_DATA_OHA_RO_STATUS_REG, A0
- ori D0, D0, CORE_DATA_L3_SENSORS_COLLECTED
- std D0, CORE_DATA_OHA_RO_STATUS_REG, A0
-
- bra getSensorsDone
-
-l3SensorsFailed:
-
- la A1, G_ggcd_l3SensorFail
- std D1, 0, A1
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
- ls D0, 0
- std D0, CORE_DATA_SENSOR_V1, A0
-
-getSensorsDone:
- ret
-
-
- //////////////////////////////////////////////////////////////////////
- // gpcrdError0
- //
- // Trap error 0 during EMPATH processing, and set a bit indicating if
- // this is an "expected" or "unexpected" error. The only expected
- // error is a PCB error #4 due to HW280375.
- //
- // Note that PORE treats error branches as subroutine calls. We need
- // to pop the HW stack before continuing. We assume we are running on
- // either GPE0 or GPE1.
- ////////////////////////////////////////////////////////////////////////////
-
- .global empathErrorHandlers
-empathErrorHandlers:
- bra gpcrdError0
-
-gpcrdError0:
-
- // Set A1 for current engine
-
- tebngpe0 D0, 1f
- la A1, PORE_GPE0_OCI_BASE
- bra 2f
-1:
- la A1, PORE_GPE1_OCI_BASE
-2:
-
- // Extract PCB parity error + 3-bit code and compare. Apparently the
- // PCB error code is not set in the IFR when we take the error branch,
- // so we have to get it from the debug register. The error code is
- // used to decide if the error is "expected" or "unexpected".
-
- ld D0, PORE_DBG0_OFFSET, A1
- extrdi D0, D0, 4, 32
-
- ld D1, CORE_DATA_OHA_RO_STATUS_REG, A0
- cmpibraeq D0, 1f, 4
-
- // This error is "unexpected"
-
- ori D1, D1, CORE_DATA_UNEXPECTED_EMPATH_ERROR
- bra 2f
-
- // This error (#4) is "expected"
-1:
- ori D1, D1, CORE_DATA_EXPECTED_EMPATH_ERROR
-
- // Insert the error code into the OHA_RO_STATUS image
-2:
- insrdi D1, D0, \
- CORE_DATA_EMPATH_ERROR_BITS, CORE_DATA_EMPATH_ERROR_LOCATION
- std D1, CORE_DATA_OHA_RO_STATUS_REG, A0
-
-
- // Pop the hardware stack. The easiest way to do this is to modify the
- // current stack pointer and "return" to a local label.
-
- la D0, 1f
- sldi D0, D0, 16
- std D0, PORE_PC_STACK0_OFFSET, A1
- ret
-1:
-
- // Clear the debug registers.
-
- ls D0, 0
- std D0, PORE_DBG0_OFFSET, A1
- std D0, PORE_DBG1_OFFSET, A1
-
- // Bypass EMPATH data (that routine will restore the default error
- // handling and re-establish A1)
-
- bra bypass_core_data
-
-
- //////////////////////////////////////////////////////////////////////
- // bypass_core_data
- //////////////////////////////////////////////////////////////////////
- //
- // This entry point is used when the core is inaccessible due to idle
- // modes or other conditions. At entry we are in manual SCOM error
- // handling mode. The routine will first attempt to collect the
- // core and L3 DTS/CPM for Sleeping cores, then restore error
- // handling and zero out the EMPATH data before collecting PCBS data.
-
- // HW243646: We never read EMPATH counters here. The
- // counters are all zeroed and all calls of tag_core_data_group
- // specify raw=0.
-
-bypass_core_data:
-
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
- bsr getSensors
-
- // Clear the PC-Only SPWU bit and restore SCOM error handling. Then
- // reload the parameter pointer into A1.
-
- sti OHA_CPM_HIST_RESET_REG, P0, 0
-
- la A1, saved_emr
- ld D0, 0, A1
- mr EMR, D0
-
- la A1, core_data_parms
- ld D0, 0, A1
- mr A1, D0
-
- // Bypass core data
-
- // EMPATH
-
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_EMPATH
- braz D0, 1f
-
- .set _BASE, CORE_DATA_EMPATH_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- ls D0, 0
- std D0, (_BASE + 0x08), A0
- std D0, (_BASE + 0x10), A0
- std D0, (_BASE + 0x18), A0
- std D0, (_BASE + 0x20), A0
-
-
- // Per-Core Memory Counters
-
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_MEMORY
- braz D0, 1f
-
- .set _BASE, CORE_DATA_MEMORY_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- ls D0, 0
- std D0, (_BASE + 0x08), A0
- std D0, (_BASE + 0x10), A0
-
-
- // Throttling Counters
-
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_THROTTLE
- braz D0, 1f
-
- .set _BASE, CORE_DATA_THROTTLE_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- ls D0, 0
- std D0, (_BASE + 0x08), A0
- std D0, (_BASE + 0x10), A0
-
-
- // Per-Thread Counters
-
-1:
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_THREAD
- braz D0, 1f
-
- .set _BASE, CORE_DATA_THREAD_BASE(0)
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- ls D0, 0
- std D0, (_BASE + 0x08), A0 # Run/Completion T0
- std D0, (_BASE + 0x10), A0 # Mem A/B T0
- // (_BASE + 0x18), A0 # Tag T1
- std D0, (_BASE + 0x20), A0 # Run/Completion T1
- std D0, (_BASE + 0x28), A0 # Mem A/B T1
- // (_BASE + 0x30), A0 # Tag T2
- std D0, (_BASE + 0x38), A0 # Run/Completion T2
- std D0, (_BASE + 0x40), A0 # Mem A/B T2
- // (_BASE + 0x48), A0 # Tag T3
- std D0, (_BASE + 0x50), A0 # Run/Completion T3
- std D0, (_BASE + 0x58), A0 # Mem A/B T3
- // (_BASE + 0x60), A0 # Tag T4
- std D0, (_BASE + 0x68), A0 # Run/Completion T4
- std D0, (_BASE + 0x70), A0 # Mem A/B T4
- // (_BASE + 0x78), A0 # Tag T5
- std D0, (_BASE + 0x80), A0 # Run/Completion T5
- std D0, (_BASE + 0x88), A0 # Mem A/B T5
- // (_BASE + 0x90), A0 # Tag T6
- std D0, (_BASE + 0x98), A0 # Run/Completion T6
- std D0, (_BASE + 0xa0), A0 # Mem A/B T6
- // (_BASE + 0xa8), A0 # Tag T7
- std D0, (_BASE + 0xb0), A0 # Run/Completion T7
- std D0, (_BASE + 0xb8), A0 # Mem A/B T7
-
-
- // Interpolation of TOD and Raw Cycles over 8 threads. First collect
- // a new tag, then compute the difference with the thread0 tag. The
- // differences are then divided by 8 to form the interpolation
- // increment, and interpolation takes places in an unrolled loop.
- //
- // Note that we're doing parallel arithmetic here, and ignoring the
- // fact that there may be a carry/borrow from the low-order TOD into
- // the high-order cycle count. A single LSB is noise for the cycle
- // count, but would be significant for the TOD, which is why the
- // TOD is placed in the low-order part of the doubleword. Given that
- // a single LSB is noise for the cycle count there is no reason to
- // expend the time/code space to do the arithmetic 'correctly'.
-
- tag_core_data_group 0, 0, P0, P1, raw=0, store=0 # D0 contains _NOW_ tag
-
- ld D1, CORE_DATA_THREAD_BASE(0), A0 # D1 will be used for interp.
- sub D0, D0, D1
- andi D0, D0, 0xfffffff8fffffff8 # Mask off bad bits and div. by 8.
- rotrdi D0, D0, 3
-
- interpolate 1
- interpolate 2
- interpolate 3
- interpolate 4
- interpolate 5
- interpolate 6
- interpolate 7
-
-
- // Per-Core PCB Slave Registers
-get_pcbs_data:
-
- ldandi D0, GPEGETCOREDATAPARMS_SELECT, A1, GPE_GET_CORE_DATA_PCB_SLAVE
- braz D0, 1f
-
- .set _BASE, CORE_DATA_PCB_SLAVE_BASE
- tag_core_data_group _BASE, A0, P0, P1, raw=0
-
- get_scom D0, PCBS_POWER_MANAGEMENT_CONTROL_REG, P0, CORE_DATA_PMCR, A0
- get_scom D0, PCBS_POWER_MANAGEMENT_STATUS_REG, P0, CORE_DATA_PMSR, A0
- get_scom D0, PCBS_PMSTATEHISTOCC_REG, P0, CORE_DATA_PM_HISTORY, A0
-
-1:
- ret
-
-/// \endcond
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_core_data_fast()
-////////////////////////////////////////////////////////////////////////////
-
-/// \fn gpe_get_core_data_fast(GpeGetChipDataFastParms *parms);
-/// \brief Get chip raw data on fastest possible timescale
-///
-/// This routine collects raw data for the entire chip on the fastest possible
-/// timescale. Where chiplet data is collected, the configured chiplets are
-/// specified in the configuration mask parameter. Data is grouped
-/// into logical groups, and the collection of any group is enabled by a group
-/// select mask. All data groups are tagged with the TOD.
-#ifdef DOXYGEN_ONLY
-void gpe_get_core_data_fast(GpeGetChipDataFastParms *parms);
-#endif
-/// \cond
-
- // Register usage:
- //
- // A1 : Holds the (constant) pointer to the paramaters
- // A0 : Holds the (varying) pointer to the data area for the current
- // data group or datum.
- // P1 : Holds the (constant) chiplet id of the TOD
- // P0 : Holds the (varying) chiplet id of interest
- // CTR : Loops through chiplet indices
- // D1 : Holds/rotates configuration mask
- // D0 : Scratch
-
- .global gpe_get_core_data_fast
-
-gpe_get_core_data_fast:
-
- // Set up registers. A0 must follow the target OCI address as each core
- // chiplet is considered. Since we're only doing a single
- // getscom/putOCI, we can keep the chiplet mask in D1. The data group
- // is tagged with the TOD.
-
- mr A1, ETR
- ld D0, GPEGETCOREDATAFASTPARMS_CONFIG, A1
- left_justify_core_config D0
- mr D1, D0
- lpcs P1, TOD_VALUE_REG
- ld D0, GPEGETCOREDATAFASTPARMS_DATA, A1
- mr A0, D0
-
- tag_data_group CORE_DATA_FAST_FREQ_TARGET_BASE, D0, A0, P1
- adds A0, A0, 8
-
- ls P0, 0x10
- ls CTR, (PGP_NCORES - 1) # PORE does test, then decr. and branch
-
-freq_target_loop:
-
- // Test the chiplet mask. If the chiplet is not configured, simply
- // continue.
-
- andi D0, D1, 0x8000000000000000
- rotldi D1, D1, 1
- braz D0, freq_target_continue
-
- get_scom D0, PCBS_LOCAL_PSTATE_FREQUENCY_TARGET_STATUS_REG, P0, \
- 0x00, A0
-
-freq_target_continue:
-
- // Increment the core chiplet index and data pointer, then loop or
- // carry on.
-
- adds P0, P0, 1
- adds A0, A0, 8
- loop freq_target_loop
-
-1:
- halt
-
-/// \endcond
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_chip_data()
-////////////////////////////////////////////////////////////////////////////
-
-/// \fn gpe_get_chip_data(GpeGetChipDataParms *parms);
-/// \brief Get chip-level raw data
-///
-/// This routine collects chip-level raw data. Data is grouped into logical
-/// groups, and the collection of any group is enabled by a group select
-/// mask. All data groups are tagged with the TOD.
-#ifdef DOXYGEN_ONLY
-void gpe_get_chip_data(GpeGetChipDataParms *parms);
-#endif
-/// \cond
-
- // Register usage:
- //
- // A0 : Holds the (varying) pointer to the data area for the current
- // data group or datum.
- // P1 : Holds the (constant) chiplet id of the TOD
- // D1 : Holds the (constant) select mask
-
- .global gpe_get_chip_data
-
-gpe_get_chip_data:
-
- // Set up registers.
-
- mr A1, ETR
- ld D0, GPEGETCHIPDATAPARMS_SELECT, A1
- mr D1, D0
- lpcs P1, TOD_VALUE_REG
- ld D0, GPEGETCHIPDATAPARMS_DATA, A1
- mr A0, D0
-
- // Overcommit data.
-
- andi D0, D1, GPE_GET_CHIP_DATA_OVERCOMMIT
- braz D0, 1f
- tag_data_group CHIP_DATA_OVERCOMMIT_BASE, D0, A0, P1
-
- // Overcommit data consists of PBA_PBOCR(0)...PBA_PBOCR(5), all stored
- // at 8-byte offsets
-
- la A1, PBA_PBOCRN(0)
- ocicopy D0, 0x00, A1, 0x08, A0
- ocicopy D0, 0x08, A1, 0x10, A0
- ocicopy D0, 0x10, A1, 0x18, A0
- ocicopy D0, 0x18, A1, 0x20, A0
- ocicopy D0, 0x20, A1, 0x28, A0
- ocicopy D0, 0x28, A1, 0x30, A0
-
-1:
- halt
-
- .epilogue gpe_get_chip_data
-
-/// \endcond
-
-
-////////////////////////////////////////////////////////////////////////////
-// gpe_get_mem_data()
-////////////////////////////////////////////////////////////////////////////
-
-/// \fn gpe_get_mem_data(GpeGetMemDataParms *parms);
-/// \brief Get memory (MCS/Centaur) data for a particular MCS/Centaur
-///
-/// This routine collects data for the MCS/Centaur named (by instance ID,
-/// (0...PGP_NCENTAUR -1)) in the \a collect field of the \a parms parameter,
-/// unless \a collect is -1 in which case the data collection is bypassed.
-/// Once data has been collected, if the \a update field of the a \parms is
-/// not -1 then that numbered Centaur will be "poked" to start the sensor
-/// cache update. Once data collection (if any) and "poking" (if any) are
-/// finished the parameter block is timestamped with the TOD (at the standard
-/// 2MHz). This means that the TOD timestamp marks the "poke" time (when data
-/// collection starts), not the data collection time.
-///
-/// This procedure requires that the global G_centaurConfiguration structure
-/// must be present and have been properly initialized by
-/// centaur_configuration_create(). The procedure returns a return code -
-/// Either 0 for success, or a non zero value for failure. The failure codes
-/// are documented here: \ref gpe_get_mem_data_rc. Since the parameter block
-/// is read and written by GPE code it is strongly recommended to allocate
-/// instances of this structure in non-cacheable data sections, with the
-/// caveat that data structures assigned to non-default data sections must
-/// always be initialized. For example:
-///
-/// \code
-///
-/// static GpeGetMemDataParms S_parms SECTION_ATTRIBUTE(".noncacheable") = {0};
-///
-/// \endcode
-///
-/// NB: SW273814 documents a request to be able to differentiate which of the 2
-/// Centaurs is responsible for a hard failure. That's why we take pains to
-/// set up the RC prior to collection/poking to enable recovery code to make
-/// this determination.
-#ifdef DOXYGEN_ONLY
-void gpe_get_mem_data(GpeGetMemDataParms *parms);
-#endif
-/// \cond
-
- .global gpe_get_mem_data
-gpe_get_mem_data:
-
- // At entry:
- //
- // ETR : parms
- //
- // Invariants:
- //
- // ETR : parms
- // A1 : parms (except when scratched by subroutines, always restored)
-
- // Begin by marking the procedure as having died
-
- mr A1, ETR
- sti GPEGETMEMDATAPARMS_RC, A1, GPE_GET_MEM_DATA_DIED
-
- // Next check to make sure the G_centaurConfiguration is properly
- // initialized (.configRc == 0).
- //
- // A1 : parms
-
- la A0, G_centaurConfiguration
- ld D0, CENTAUR_CONFIGURATION_CONFIG_RC, A0
- braz D0, 1f
-
- ls D0, GPE_GET_MEM_DATA_NOT_CONFIGURED
- bra ggmdExit
-
-1:
- // Set up the PBA for Centaur sensor cache access
- //
- // A1 : parms
- // A0 : &G_centaurConfiguration ==> &G_centaurConfiguration.dataParms;
-
- adds A0, A0, CENTAUR_CONFIGURATION_DATA_PARMS
- bsr gpe_pba_reset
- bsr gpe_pba_setup
- mr A1, ETR # Re-establish invariant
-
-
- // See if we're collecting data this pass. If so validate that the
- // MCS/Centaur index is valid according to G_centaurConfiguration.
- //
- // A1 : parms
-
- ld D0, GPEGETMEMDATAPARMS_COLLECT, A1
- cmpibraeq D0, ggmdUpdate, -1
-
- bsr ggmdDataSetup
- mr A1, ETR # Re-establish invariant
- braz D0, 1f
-
- ls D0, GPE_GET_MEM_DATA_COLLECT_INVALID
- bra ggmdExit
-
-1:
- // A0 has the base address of the sensor cache as a PowerBus
- // mapping. Load A1 with the user data pointer and collect the data.
- //
- // A1 : parms ==> &MemData
-
- sti GPEGETMEMDATAPARMS_RC, A1, GPE_GET_MEM_DATA_SENSOR_CACHE_FAILED
-
- ld D0, GPEGETMEMDATAPARMS_DATA, A1
- mr A1, D0
-
- ocicopy D0, 0x00, A0, 0x00, A1
- ocicopy D0, 0x08, A0, 0x08, A1
- ocicopy D0, 0x10, A0, 0x10, A1
- ocicopy D0, 0x18, A0, 0x18, A1
- ocicopy D0, 0x20, A0, 0x20, A1
- ocicopy D0, 0x28, A0, 0x28, A1
- ocicopy D0, 0x30, A0, 0x30, A1
- ocicopy D0, 0x38, A0, 0x38, A1
- ocicopy D0, 0x40, A0, 0x40, A1
- ocicopy D0, 0x48, A0, 0x48, A1
- ocicopy D0, 0x50, A0, 0x50, A1
- ocicopy D0, 0x58, A0, 0x58, A1
- ocicopy D0, 0x60, A0, 0x60, A1
- ocicopy D0, 0x68, A0, 0x68, A1
- ocicopy D0, 0x70, A0, 0x70, A1
- ocicopy D0, 0x78, A0, 0x78, A1
-
- mr A1, ETR # Re-establish invariant
-
- sti GPEGETMEMDATAPARMS_RC, A1, GPE_GET_MEM_DATA_DIED
-
- // See if we're poking Centaur this pass. If so validate that the
- // MCS/Centaur index is valid according to G_centaurConfiguration.
- //
- // A1 : parms
-ggmdUpdate:
-
- ld D0, GPEGETMEMDATAPARMS_UPDATE, A1
- cmpibraeq D0, ggmdTimestamp, -1
-
- bsr ggmdDataSetup
- mr A1, ETR # Re-establish invariant
- braz D0, 1f
-
- ls D0, GPE_GET_MEM_DATA_UPDATE_INVALID
- bra ggmdExit
-
-1:
- // Poke it
-
- sti GPEGETMEMDATAPARMS_RC, A1, GPE_GET_MEM_DATA_UPDATE_FAILED
-
- ls D0, 0
- std D0, 0, A0
-
- sti GPEGETMEMDATAPARMS_RC, A1, GPE_GET_MEM_DATA_DIED
-
- // Collect the timestamp and reduce the 64-bit 512MHz timestamp to a
- // 32-bit 2MHz timestamp. Then we're out...
- //
- // A1 : parms
-ggmdTimestamp:
-
- lpcs P0, TOD_VALUE_REG
- ld D0, TOD_VALUE_REG, P0
- extrdi D0, D0, 32, 24
- std D0, GPEGETMEMDATAPARMS_PAD_TOD, A1
-
-
- ////////////////////////////////////////////////////////////////////
- // Not so fast... If this is Centaur DD1 then we did not actually
- // collect the Centaur internal temperatures due to HW256773. So we
- // will go collect them now "manually" by calling _gpe_scom_centaur
- // with a hard-coded setup to collect SCOM 0x02050000. We then
- // splice this result into the accumulated cache-line data.
- //
- // A1 : Parms
- ////////////////////////////////////////////////////////////////////
-
- // Nothing to do if we're not collecting data. Otherwise pull out the
- // CFAM ID and compare for Centaur DD1
-
- ld D0, GPEGETMEMDATAPARMS_COLLECT, A1
- cmpibraeq D0, ggmdCleanExit, -1
-
- sldi D0, D0, 3 # Multiply by 8 for a byte offset
-
- la D1, G_centaurConfiguration
- adds D1, D1, CENTAUR_CONFIGURATION_DEVICE_ID
- add D0, D0, D1
- mr A0, D0
- ld D0, 0, A0
- extrdi D0, D0, 32, 0
-
- cmpibrane D0, ggmdCleanExit, CFAM_CHIP_ID_CENTAUR_10
-
- // This is DD1. Set up the parameters and call _gpe_scom_centaur.
- // Since we can only do 8-byte stores we read-modify-write the first
- // entry of the scomList_t. Then call for the SCOM. If it failed set
- // the failure code. All registers must be restored after the
- // subroutine call.
-
- la A0, G_ggmdHw256773
- ld D0, SCOM_LIST_COMMAND, A0
- ld D1, GPEGETMEMDATAPARMS_COLLECT, A1
- scom_list_set_instance_number D0, D1
- std D0, SCOM_LIST_COMMAND, A0
-
- la A0, G_hw256773
- bsr _gpe_scom_centaur
-
- la A0, G_hw256773
- mr A1, ETR
-
- ld D0, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
- gpe_scom_parms_get_rc D0, D0
- braz D0, 1f
-
- ls D0, GPE_GET_MEM_DATA_HW256773_FAILED
- bra ggmdExit
-
-1:
- // The SCOM succeeded. The data needs to be moved from the
- // gpe_scom_centaur data into the sensor-cache data area. Since there
- // are only 32 bits we need to read-modify-write the SRAM. This is
- // doubleword 12 of the sensor cache. The 32 bits of the SCOM we need
- // are the high-order bits, copied into the low-order bits of the
- // sensor-cache doubleword. Finally fall through to the clean exit.
-
- la A0, G_ggmdHw256773
- ld D0, SCOM_LIST_DATA, A0
-
- ld D1, GPEGETMEMDATAPARMS_DATA, A1
- mr A0, D1
- ld D1, 0x60, A0
- rldimi D1, D0, 32, 32, 63
- std D1, 0x60, A0
-
-
-ggmdCleanExit:
- ls D0, 0
-ggmdExit:
- std D0, GPEGETMEMDATAPARMS_RC, A1
- halt
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // ggmdDataSetup
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // At entry:
- //
- // D0 : The Centaur instance number to set up
- //
- // At exit:
- //
- // A0 : On success, the OCI base address to use to access the
- // sensor cache.
- // D0 : 0 = Success; 1 = Failure - the caller will supply the
- // correct error code back to the user.
- //
- // This routine checks the Centaur instance number for validity. If
- // the instance number is valid then the PBA is programmed to access
- // the sensor cache address. This requires reprogramming the PBA
- // because part of the data address, which varies by Centaur, must be
- // stored as the extended address field of the PBA slave control
- // register. It is not necessary to reset the PBA slave for each data
- // operation.
-ggmdDataSetup:
-
- // Check the Centaur instance number (D0) for validity.
-
- ls D1, PGP_NCENTAUR
- sub D1, D0, D1
- tfbult D1, 1f
-
- ls D0, 1
- ret # Centaur instance too big
-
-1:
- // Check to make sure the Centaur is configured by testing the base
- // address for 0. The instance number is first multiplied by 8 to
- // create an array offset.
-
- sldi D0, D0, 3
- la D1, G_centaurConfiguration
- adds D1, D1, CENTAUR_CONFIGURATION_BASE_ADDRESS
- add D0, D0, D1
- mr A0, D0
- ld D0, 0, A0
- branz D0, 1f
-
- ls D0, 1
- ret # Base address is 0
-
-1:
- // We have the Centaur base address in D0, and convert it to the full
- // PowerBus address for the inband sensor cache access. Bit 27 is set
- // to indicate OCC (vs. FSP) access. Bit 28 is set to indicate a
- // sensor cache access.
-
- ori D0, D0, 0x0000001800000000
-
-#if 1
- la A0, G_ggmd_lastDataAddress # Debug
- std D0, 0, A0
-#endif
-
- // The OCI address is always 0, decorated with the PBA BAR number.
-
- la A0, (PBA_BAR_CENTAUR << 28)
-
- // Bits 23:36 of the address go into the extended address field (35:
- // 48) of the PBA slave control register by a read-modify-write
- // operation. Note: We're using rldimi explicitly here - not an
- // extended mnemonic - to save having to justify the data.
-
- la A1, G_centaurConfiguration
- ld D1, \
- (CENTAUR_CONFIGURATION_DATA_PARMS + \
- GPEPBAPARMS_SLVCTL_ADDRESS), \
- A1
- mr A1, D1
- ld D1, 0, A1
- rldimi D1, D0, 64 - (35 - 23), 35, 48
- std D1, 0, A1
-
-#if 1
- la A1, G_ggmd_lastSlaveControl # Debug
- std D1, 0, A1
- mr D1, A0
- la A1, G_ggmd_lastOciAddress
- std D1, 0, A1
-#endif
-
- // Clear D0 to signal success and we're out
-
- ls D0, 0
- ret
- .epilogue gpe_get_mem_data
-
-/// \endcond
-
-
-////////////////////////////////////////////////////////////////////////////
-// Global Data
-////////////////////////////////////////////////////////////////////////////
-
-
-
-/// \cond
-
- .data.pore
-
- // Data storage for gpe_get_core_data()
-
-core_data_parms:
- .quad 0
-saved_emr:
- .quad 0
-manual_emr:
- .quad 0
-hw243646:
-#if 0
- .quad 0x3 # Determined + Required
-#else
- .quad 0x2 # Determined + Not Required
-#endif
-
- // Used to debug the workaround for HW280375
-
-testHw280375Lfsr:
- .quad 0xdeadbeef # Initial state of LFSR
-
- // Debug/Info: Failure codes when sensor reads fail
-
- .global G_ggcd_coreSensorFail
-G_ggcd_coreSensorFail:
- .quad 0
-
- .global G_ggcd_l3SensorFail
-G_ggcd_l3SensorFail:
- .quad 0
-
-
- // Debug only, the last values computed by ggmdDataSetup.
-
- .global G_ggmd_lastDataAddress
-G_ggmd_lastDataAddress:
- .quad 0
-
- .global G_ggmd_lastSlaveControl
-G_ggmd_lastSlaveControl:
- .quad 0
-
- .global G_ggmd_lastOciAddress
-G_ggmd_lastOciAddress:
- .quad 0
-
-
- // Required for Centaur DD1. This is an assembler layout of a
- // GpeScomParms structure pointing to a scomList_t structure to read
- // Centaur SCOM 0x02050000. See the code comments for more details.
-
- .global G_ggmdHw25773
-G_ggmdHw256773:
- .long 0x02050000 # SCOM
- .byte 0 # Reserved
- .byte 0 # Error flags (output)
- .byte 0 # Instance Number (input)
- .byte GPE_SCOM_READ # Command
- .quad 0 # Mask (unused)
- .quad 0 # Data (output)
-
- .global G_hw256773
-G_hw256773:
- .long 0 # (32-bit addresses)
- .long G_ggmdHw256773 # scomList
- .long 1 # Entries in the scomList
- .long 0 # Options
- .long 0 # rc (output)
- .long 0 # errorIndex (output)
-
-/// \endcond
diff --git a/src/lib/gpe_pba.c b/src/lib/gpe_pba.c
deleted file mode 100755
index c3b0a00..0000000
--- a/src/lib/gpe_pba.c
+++ /dev/null
@@ -1,148 +0,0 @@
-// $Id: gpe_pba.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_pba.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe.c
-/// \brief Generic PORE-GPE support procesures (outside of the kernel
-/// drivers).
-
-#include "ssx.h"
-#include "gpe.h"
-#include "gpe_pba.h"
-
-/// Create/initialize a GpePbaParms structure
-///
-/// \param parms A unused or uninitialized GpePbaParms structure
-///
-/// \param slave The PBA slave port to program. For production code this will
-/// normally be PBA_SLAVE_PORE_GPE, however for test/verification code it
-/// could be any PBA slave.
-///
-/// \param write_ttype One of PBA_WRITE_TTYPE_* (see pgp_pba.h). Use
-/// PBA_WRITE_TTYPE_DC (don't care) if the GPE application does not do writes.
-///
-/// \param write_tsize One of PBA_WRITE_TSIZE_* (see pgp_pba.h). The \a
-/// write_tsize is only relevant for \a write_ttype == PBA_WRITE_TTYPE_LCO_M,
-/// where the macro PBA_WRITE_TSIZE_CHIPLET() is used to specify the target
-/// chiplet, and \a write_ttype == PBA_WRITE_TTYPE_ATOMIC_RMW, where the \a
-/// write_tsize specifies the atomic operation. Otherwise use
-/// PBA_WRITE_TTYPE_DC (don't care).
-///
-/// \param read_ttype One of PBA_READ_TTYPE_* (see pgp_pba.h). Normally this
-/// will be PBA_READ_TTYPE_CL_READ_NC (or PBA_READ_TTYPE_DC if you don't
-/// care.)
-///
-/// \param flags Two flags are provided that override default
-/// behavior. GPE_PBA_PARMS_READ_INVALIDATE specifies read buffer invalidation
-/// after every read. This is always selected when the read Ttype is a
-/// cache-inhibited partial read, but may be optionally specified for test
-/// purposes.
-///
-/// Similarly, GPE_PBA_PARMS_DISABLE_WRITE_GATHER specifies that write
-/// gathering for write Ttype DMA partial write is disabled. Note that
-/// GPE_PBA_PARMS_DISABLE_WRITE_GATHER disables write gathering in the sense
-/// that writes pass through the PBA immediately without being buffered. This
-/// is different from using the PBA_WRITE_GATHER_TIMEOUT_DISABLE option to \a
-/// write_gather_timeout, which specifies that writes are gathered until an
-/// entire line is filled.
-///
-/// This API initializes the GpePbaParms structure used by every GPE program
-/// that accesses mainstore via PBA. It creates an image of a PBA_SLVCTL
-/// register to be applied under a mask.
-///
-/// \note Read buffer invalidation is always enforced for cache-inhibited
-/// partial reads. This also forces prefetching to be disabled for the
-/// slave. Our procedures currently do not support save/restore of prefetch
-/// controls as different tasks reprogram the PBA Slave. Thus any access of a
-/// shared slave that is also used to do CI_PR_RD will have prefetching
-/// disabled.
-///
-/// \retval 0 Success
-///
-/// \retval -GPE_INVALID_OBJECT The \a parms pointer is NULL (0) or othewise
-/// invalid.
-///
-/// \retval -GPE_INVALID_ARGUMENT One of the arguments is invalid in some way.
-
-int
-gpe_pba_parms_create(GpePbaParms *parms,
- int slave,
- int write_ttype,
- int write_tsize,
- int read_ttype)
-{
- pba_slvctln_t *slvctl, *mask;
- pba_slvrst_t* slvrst;
- pba_slvrst_t* slvrst_in_progress;
- uint64_t all1 = 0xffffffffffffffffull;
-
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((parms == 0), GPE_INVALID_OBJECT);
- SSX_ERROR_IF((slave < 0) ||
- (slave >= PBA_SLAVES),
- GPE_INVALID_ARGUMENT);
- }
-
- parms->slave_id = slave;
-
- slvctl = &(parms->slvctl);
- mask = &(parms->mask);
- slvrst = &(parms->slvrst);
- slvrst_in_progress = &(parms->slvrst_in_progress);
-
- parms->slvctl_address = PBA_SLVCTLN(slave);
-
- slvrst->value = 0;
- slvrst->fields.set = PBA_SLVRST_SET(slave);
-
- slvrst_in_progress->value = 0;
- slvrst_in_progress->fields.in_prog = PBA_SLVRST_IN_PROG(slave);
-
- slvctl->value = 0;
- mask->value = 0;
-
- slvctl->fields.enable = 1;
- mask->fields.enable = all1;
-
- slvctl->fields.write_ttype = write_ttype;
- mask->fields.write_ttype = all1;
-
- slvctl->fields.write_tsize = write_tsize;
- mask->fields.write_tsize = all1;
-
- slvctl->fields.read_ttype = read_ttype;
- mask->fields.read_ttype = all1;
-
- if (read_ttype == PBA_READ_TTYPE_CI_PR_RD) {
-
- slvctl->fields.buf_invalidate_ctl = 1;
- mask->fields.buf_invalidate_ctl = all1;
-
- slvctl->fields.read_prefetch_ctl = PBA_READ_PREFETCH_NONE;
- mask->fields.read_prefetch_ctl = all1;
-
- } else {
-
- slvctl->fields.buf_invalidate_ctl = 0;
- mask->fields.buf_invalidate_ctl = all1;
- }
-
- mask->value = ~(mask->value);
-
- return 0;
-}
-
-
-
-
-
-
-
-
-
-
diff --git a/src/lib/gpe_pba.h b/src/lib/gpe_pba.h
deleted file mode 100644
index 5f8ea2c..0000000
--- a/src/lib/gpe_pba.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifndef __GPE_PBA_H__
-#define __GPE_PBA_H__
-
-// $Id: gpe_pba.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_pba.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_pba.h
-/// \brief PBA subroutines for PORE-GPE procedures
-
-// Error/Panic codes
-
-#define GPE_INVALID_OBJECT 0x00473001
-#define GPE_INVALID_ARGUMENT 0x00473002
-
-
-#ifndef __ASSEMBLER__
-
-/// Encapsulated PBA setup for GPE programs
-///
-/// All GPE programs that access mainstore via PBA utilize a common parameter
-/// structure that encapsulates the required setup. This is required due to
-/// the unusual architecture of the PBA which interprets OCI addresses and the
-/// associated PowerBus transaction type based on which OCI \e master issued
-/// the OCI transaction, not based on the OCI \a address (or PowerBus
-/// address). The final complication is that each OCI master is assigned a
-/// unique PBA "slave port", so any reprogramming must be done on the PBA
-/// registers associated with the particular port assigned to the particular
-/// PORE engine.
-///
-/// In product code the PBA slave port assignment for the PORE-GPE engines
-/// will be fixed; however this structure assumes the most general case and
-/// allows for an arbitraray and dynamic assignment, and even allows mainstore
-/// programs to run on the PORE-SLW. However the procedure that creates this
-/// structure (gpe_pba_parms_create()) must know which engine/port will run
-/// the program in order to set up the parameters.
-///
-/// The PBA software interface is not friendly for dynamic programming of the
-/// PBA slave setup, especially from the PORE. The slave setup is modifed by a
-/// read-modify-write under mask. gpa_pba_parms_create() does not allow
-/// specification of which read buffers, prefetch modes or write timeouts to
-/// use as these have global implications. Only the values that affect the
-/// particular mode can be programmed there (but of course can be later
-/// overridden if required).
-///
-/// Note that there is an assumption that PORE engines have exclusive access
-/// to their PBA ports. All GPE procedures that access the PowerBus follow a
-/// protocol that makes no assumptions about how the PBA is set up - they set
-/// up the PBA for their own use, then leave it to subsequent procedures to
-/// re-setup the PBA as necessary for subsequent use. Also note that only one
-/// GPE thread can be designated to run programs that access the PBA,
-/// as they share an OCI master ID, and hence a PBA slave port.
-///
-/// Another - perhaps obvious - complication has to do with PBA slave reset. A
-/// PORE engine executing from main memory can not modify the PBA slave read
-/// parameter setup, as this would corrupt the instruction stream. Currently
-/// GPE procedures that need to modify the PBA read parameter setup execute
-/// from SRAM, and the SLW executing from main memeory never changes its read
-/// setup.
-///
-/// This structure is read-only to the GPE routines that access it.
-
-typedef struct {
-
- /// The 32-bit OCI address of the PBA_SLVCTLn register to set up
- uint64_t slvctl_address;
-
- /// An image of the relevant parts of the PBA_SLVCTLn register in effect
- /// for this procedure
- pba_slvctln_t slvctl;
-
- /// The mask in effect for this update of the PBA_SLVCTL
- pba_slvctln_t mask;
-
- /// The value to write to the PBA_SLVRST register to reset the slave
- pba_slvrst_t slvrst;
-
- /// The bit to AND-poll to check for slave reset in progress
- pba_slvrst_t slvrst_in_progress;
-
- /// The slave id (0 - 3)
- uint64_t slave_id;
-
-} GpePbaParms;
-
-int
-gpe_pba_parms_create(GpePbaParms *parms,
- int slave,
- int write_ttype,
- int write_tsize,
- int read_ttype);
-
-#endif /* __ASSEMBLER__ */
-
-// Parameter offset for GpePbaParms
-
-#define GPEPBAPARMS_SLVCTL_ADDRESS 0x00
-#define GPEPBAPARMS_SLVCTL 0x08
-#define GPEPBAPARMS_MASK 0x10
-#define GPEPBAPARMS_SLVRST 0x18
-#define GPEPBAPARMS_SLVRST_IN_PROGRESS 0x20
-#define GPEPBAPARMS_SLAVE_ID 0x28
-
-#define SIZEOF_GPEPBAPARMS 0x30
-
-
-// Flags for gpe_pba_parms_setup()
-
-#define GPE_PBA_PARMS_READ_INVALIDATE 0x01
-#define GPE_PBA_PARMS_DISABLE_WRITE_GATHER 0x02
-
-#endif /* __GPE_H__ */
diff --git a/src/lib/gpe_pba_pgas.pS b/src/lib/gpe_pba_pgas.pS
deleted file mode 100755
index 346234d..0000000
--- a/src/lib/gpe_pba_pgas.pS
+++ /dev/null
@@ -1,110 +0,0 @@
-// $Id: gpe_pba_pgas.pS,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_pba_pgas.pS,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_pba.pS
-/// \brief PBA subroutines for PORE-GPE procedures
-
- .nolist
-#include "ssx.h"
-#include "pgas.h"
-#include "pgp_config.h"
-#include "gpe.h"
-#include "gpe_pba.h"
- .list
-
- .oci
-
- .text.pore
-
- // Reset a PBA slave from a GpePbaParms structure. A setup sequence
- // looks like
- //
- // gpe_pba_reset
- // gpe_pba_setup
- //
- // The subroutine gpe_pba_reset can also be called by itself to insure
- // that all write data has been flushed to mainstore.
- //
- // Note that any PORE program that reads or writes Centaur will need
- // to execute its code from SRAM since it is not possible to set up
- // the slave for reading from Centaur while executing from main memory.
- //
- // Slave reset for PBA is a complex issue, especially in cases like
- // this where the entity requesting the reset may be executing from
- // main memory - i.e., continuing to read from the slave being
- // reset. To work around potential issues the code that polls for
- // reset is PowerBus cache-line aligned, and we re-hit the reset
- // button each time we get an unsuccessful poll for the reset being
- // done. This should guarantee that the slave will go to reset
- // status as soon as any PowerBus blockages (if any) clear. For
- // details see HW228485.
- //
- // At entry :
- //
- // A0 : The (constant) address of the GpePbaParms structure
- //
- // Clobbered:
- //
- // D0 : scratched
- // D1 : scratched
- // A1 : Holds PBA_SLVRST
-
- .global gpe_pba_reset
-
- .balign 128
-gpe_pba_reset:
- la A1, PBA_SLVRST
- ld D0, GPEPBAPARMS_SLVRST, A0
- std D0, 0, A1
-
- ld D0, GPEPBAPARMS_SLVRST_IN_PROGRESS, A0
- ld D1, 0, A1
- and D0, D0, D1
- branz D0, gpe_pba_reset
-
- ret
-
- .epilogue gpe_pba_reset
-
-
- // Set up a PBA slave from a GpePbaParms structure. A setup sequence
- // looks like
- //
- // gpe_pba_reset
- // gpe_pba_setup
- //
- // At entry :
- //
- // A0 : The (constant) address of the GpePbaParms structure
- //
- // Clobbered:
- //
- // D0 : scratch
- // A1 : Holds PBA_SLVCTL address for the indicated slave
-
-
- .global gpe_pba_setup
-gpe_pba_setup:
-
- // Write the new SLVCTL value under MASK
-
- ld D0, GPEPBAPARMS_SLVCTL_ADDRESS, A0
- mr A1, D0
-
- ld D0, 0, A1
- ld D1, GPEPBAPARMS_MASK, A0
- and D0, D0, D1
-
- ld D1, GPEPBAPARMS_SLVCTL, A0
- or D0, D0, D1
-
- std D0, 0, A1
-
- ret
-
- .epilogue gpe_pba_setup
diff --git a/src/lib/gpe_scom.h b/src/lib/gpe_scom.h
deleted file mode 100644
index 3f8f26e..0000000
--- a/src/lib/gpe_scom.h
+++ /dev/null
@@ -1,471 +0,0 @@
-#ifndef __GPE_SCOM_H__
-#define __GPE_SCOM_H__
-
-// $Id: gpe_scom.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_scom.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_scom.h
-/// \brief Generic SCOM procedures for PORE-GPE
-///
-/// We provide 2 generic SCOM procedures for PORE-GPE, one for P8 SCOMs and
-/// another for Centaur SCOMS. The setup and control of the procedures is
-/// roughly modeled after the way the simple SCOM-ing programs were described
-/// and implemented by the P7 OCA unit. This facility was written primarily to
-/// support SCOM-ing Centaur from OCC (which requires a complex setup),
-/// however for some core applications it may also be simpler to use a generic
-/// procedure rather than creating a custom GPE program to read/write P8 SCOM
-/// registers.
-///
-/// SCOM programs are set up and controlled through a GpeScomParms
-/// structure. This structure contains overall control and status information,
-/// as well as a pointer to an array of scomList_t structures which decribes
-/// the program. Each entry of the scomList_t describes one of several
-/// operations that can be performed on a SCOM address including read, write,
-/// and read-modify-write. Special control-only entries are also supported
-/// including a NOP, a programmable wait delay, timestamping with the TOD and
-/// special "SYNC" commands for Centaur. For more on the commands and their
-/// actions please see \ref gpe_scom_commands.
-///
-/// Each scomList_t entry also includes a data field and a mask field. The
-/// data field contains the data to write for SCOM writes and
-/// read-modify-writes, holds the data returned for SCOM reads, or contains a
-/// pointer to a data vector for vector commands. The mask is used in the case
-/// of read-modify-write to indicate which bits of the SCOM to modify. Control
-/// commands may also interpret these fields in different ways.
-
-
-#ifndef __ASSEMBLER__
-
-/// A SCOM command descriptor for gpe_scom_centaur amd gpe_scom_p8.
-///
-/// For an introduction to the use of this structure and the procedures that
-/// use please see the commants for the file gpe_scom.h
-///
-/// The \a scom field is the full 32-bit SCOM address of the targeted SCOM,
-/// initialized by the caller. SCOM addresses for P8 core SCOMs can be
-/// created from the chiplet-0 address using the macro
-/// CORE_CHIPLET_ADDRESS(). Multicast addresses for P8 can be generated using
-/// the macro MC_ADDRESS(). The notions of internal "chiplets" and "multicast"
-/// are not supported for Centaur SCOM addreses, so for Centaur this is always
-/// a simple SCOM address. The procedure gpe_scom_centaur() does support an
-/// iterative notion of multicast however. Some special control commands do
-/// not use this field at all; see \ref gpe_scom_commands.
-///
-/// The \a errorFlags field contains error status associated with the
-/// (attempted) SCOM access. This field is set by the procedure. For futher
-/// informaton on error handling please see each individual procedure.
-///
-/// The \a instanceNumber field is currently only used by
-/// gpe_scom_centaur(). For further details please see the documentation for
-/// gpe_scom_centaur().
-///
-/// The \a commandType field is initialized by the caller. For command
-/// documentation see \ref gpe_scom_commands and the individual procedures.
-///
-/// The \a data field is used to hold write data for SCOM write and
-/// read-modify-write commands (including the "all" forms), contains the
-/// returned read data for scalar SCOM read commands, and contains a pointer
-/// to a data vector for vector commands. Other commands may also use the \a
-/// data field for other purposes as documented with each command.
-///
-/// The \a mask field contains a positive bit mask used to identify the fields
-/// to update for SCOM read-modify-write. Other commands may also use the \a
-/// mask field for other purposes as documented with each command.
-///
-/// \note Because this structure is read and written by the GPE engine it is
-/// strongly recommended to allocate instances of this structure in
-/// non-cacheable data sections, with the caveat that data structures assigned
-/// to non-default data sections must always be initialized. For example:
-///
-/// \code
-///
-/// static scomList_t S_scomList[10]
-/// SECTION_ATTRIBUTE(".noncacheable") = {0};
-///
-/// \endcode
-
-typedef struct {
- union
- {
- struct {
- uint32_t scom;
- uint8_t reserved;
- uint8_t errorFlags;
- uint8_t instanceNumber;
- uint8_t commandType;
- };
- uint64_t command;
- };
- uint64_t mask;
- union
- {
- uint64_t data;
- struct {
- uint32_t unused;
- uint64_t* pData;
- };
- };
-} scomList_t;
-
-#else // __ASSEMBLER__
-
- // scomList_t structure offsets
-
- .set SCOM_LIST_COMMAND, 0x0
- .set SCOM_LIST_MASK, 0x8
- .set SCOM_LIST_DATA, 0x10
- .set SIZEOF_SCOM_LIST_T, 0x18
-
- // PGAS macros to extract fields of the scomList_t command. The source
- // and target must be data registers, and they can be the same data
- // register.
-
- .macro scom_list_get_scom, target:req, source:req
- extrdi \target, \source, 32, 0
- .endm
-
- .macro scom_list_get_instance_number, target:req, source:req
- extrdi \target, \source, 8, 48
- .endm
-
- .macro scom_list_get_command_type, target:req, source:req
- extrdi \target, \source, 8, 56
- .endm
-
- // PGAS macros to update fields of the scomList_t command. The source
- // and target must be different data registers. The target is the
- // current value and is updated with the new field held
- // right-justified in the source. The source register is effectively
- // destroyed by these operations.
-
- .macro scom_list_set_error_flags, target:req, source:req
- insrdi \target, \source, 8, 40
- .endm
-
- .macro scom_list_set_instance_number, target:req, source:req
- insrdi \target, \source, 8, 48
- .endm
-
-#endif // __ASSEMBLER__
-
-/// \defgroup gpe_scom_commands GPE SCOM Procedure Commands
-///
-/// \note Command 0 is not defined on purpose to trap errors.
-/// @{
-
-/// No operation
-#define GPE_SCOM_NOP 1
-
-/// Read from SCOM, depositing read data into the \a data field of the
-/// scomList_t.
-#define GPE_SCOM_READ 2
-
-/// Write to SCOM, taking write data from the \a data field of the scomList_t.
-#define GPE_SCOM_WRITE 3
-
-/// Read-Modify-Write.
-///
-/// This operation first reads the SCOM. Bits under the \a mask field of the
-/// scomList_t are then cleared in the read data. The masked read data is then
-/// ORed with the contents of the \a data field of the scomList_t and the
-/// result is written back to the SCOM address.
-///
-/// \note This command \e does \e not apply the mask to the data from the \a
-/// data field of the scomList_t. The caller should do this (if necessary)
-/// when setting up the scomList_t.
-///
-/// \note The procedures do not provide a way to distinguish errors that may
-/// have occurred on the initial read vs. those that may have occurred on the
-/// subsequenct write.
-#define GPE_SCOM_RMW 4
-
-/// For gpe_scom_centaur(), the \a data field of the scomList_t contains a
-/// 32-bit pointer (cast to a uint64_t) to an array of PGP_NCENTAUR uint64_t
-/// values. SCOM read data for each configured Centaur (MCS) is deposited in
-/// this array. Array entries for unconfigured Centaur are zeroed.
-#define GPE_SCOM_READ_VECTOR 5
-
-/// For gpe_scom_centaur(), write the \a data field of the scomList_t to
-/// all configured Centaur. Currently unsupported for gpe_scom_p8().
-#define GPE_SCOM_WRITE_ALL 6
-
-/// For gpe_scom_centaur(), perform read-modify write for all configured
-/// Centaur. Currently unsupported for gpe_scom_p8().
-#define GPE_SCOM_RMW_ALL 7
-
-/// Programmable wait delay
-///
-/// This command simply waits for an interval of time specified by the \a data
-/// field of the scomList_t. Use the macro GPE_SCOM_WAIT_DELAY() to convert
-/// SSX (OCC timebase) ticks into the correct units for this command. For
-/// example use GPE_SCOM_WAIT_DELAY(SSX_MILLISECONDS(10)) to wait 10 ms.
-///
-/// \note This operation blocks the GPE from completing any other work until
-/// the delay is finished.
-///
-/// \note This time delay can not be implemented with extreme precision due to
-/// the lack of a programmable wait delay in the PORE architecture, plus
-/// procedure overhead, bus and bus interface contention, etc. For
-/// applications requiring extremely precise timing it will be best to code
-/// those by hand in PORE assembler and run them in a dedicated lab-only
-/// setting.
-#define GPE_SCOM_WAIT 8
-
-/// Issue a generic Centaur SYNC
-///
-/// This command is only valid for gpe_scom_centaur(). This command creates
-/// and issues a generic SYNC command to Centaur. The caller is completely
-/// responsible for creating the contents of the data packet sent as part of
-/// the Centaur SYNC. The data packet is taken verbatim from the \a data field
-/// of the scomList_t, and sent to the MCS designated as the SYNC MCS in the
-/// global G_centaurConfiguration. For further details see the comments with
-/// the procedure gpe_scom_centaur() and the CentaurConfiguration structure.
-#define GPE_SCOM_CENTAUR_SYNC 9
-
-/// Issue a Centaur SYNC to all configured Centaur
-///
-/// This command is only valid for gpe_scom_centaur(). This command creates
-/// and issues a SYNC command to all configured Centaur. The data packet is
-/// taken from the \a data field of the scomList_t, and sent to the MCS
-/// designated as the SYNC MCS in the global G_centaurConfiguration. The
-/// caller is responsible for setting the SYNC command bits (bits 8:N); The
-/// procedure will fill bits 0:7 with a mask of all configured Centaur. For
-/// further details see the comments with the procedure gpe_scom_centaur() and
-/// the CentaurConfiguration structure.
-#define GPE_SCOM_CENTAUR_SYNC_ALL 10
-
-/// Read the TOD clock
-///
-/// This command reads the TOD clock and deposits the value into the \a data
-/// field of the scomList_t.
-#define GPE_SCOM_TOD 11
-
-/// @}
-
-
-#ifndef __ASSEMBLER__
-
-/// \defgroup centaur_sync_commands Centaur SYNC Command Bits
-///
-/// The Centaur SYNC command is an 8-byte word written to a specific in-band
-/// address. SYNC commands are generated by the gpe_scom_centaur() procedure
-/// in response to the GPE_SCOM_CENTAUR_SYNC and GPE_SCOM_CENTAUR_SYNC_ALL
-/// commands (which see).
-///
-/// \note From the MCS Unit Workbook: Note that only the N/M Throttle sync
-/// command will be used operationally in P-series, although if will be
-/// possible to test all the sync commands in P-series lab testing. Z-series
-/// will use all specified sync command types. ... Valid combinations of bits
-/// (8:15) are: b00000000, bVVVVVV0V, and b00000010, where V = 0 or 1.
-///
-/// @{
-
-#define CENTAUR_GENERATE_REFRESH_COUNTER_SYNC 0x0080000000000000ull
-#define CENTAUR_RESET_CALIBRATION_COUNTER_1_SYNC 0x0040000000000000ull
-#define CENTAUR_RESET_CALIBRATION_COUNTER_2_SYNC 0x0020000000000000ull
-#define CENTAUR_RESET_CALIBRATION_COUNTER_3_SYNC 0x0010000000000000ull
-#define CENTAUR_RESET_N_M_THROTTLE_COUNTER_SYNC 0x0008000000000000ull
-#define CENTAUR_RESET_MB_TIMEBASE_SYNC 0x0004000000000000ull
-#define CENTAUR_SUPER_SYNC 0x0002000000000000ull
-#define CENTAUR_MYSTERY_SYNC 0x0001000000000000ull
-
-/// \todo Figure out what is the "mystery sync"
-
-/// @}
-
-
-/// Convert an SsxInterval to a delay specification for gpe_scom_*()
-
-// Yes, Virginia, the PORE engine takes 20 cycles to decrement and branch :(
-#define GPE_SCOM_WAIT_DELAY(x) ((x) / 20)
-
-
-/// Parameters for gpe_scom_centaur() and gpe_scom_p8().
-///
-/// A pointer to an initialized GpeScomParms structure is passed as the
-/// parameter to the GPE procedures gpe_scom_centaur() and gpe_scom_p8.
-///
-/// \note Because this structure is read and written by the GPE engine it is
-/// strongly recommended to allocate instances of this structure in
-/// non-cacheable data sections, with the caveat that data structures assigned
-/// to non-default data sections must always be initialized. For example:
-///
-/// \code
-///
-/// static GpeScomParms S_scomParms
-/// SECTION_ATTRIBUTE(".noncacheable") = {0};
-///
-/// \endcode
-
-typedef struct {
-
- /// Input: The SCOM list
- ///
- /// This is a right-justfied pointer to an array of scomList_t structures
- /// describing the sequence of commands to execute.
- uint64_t scomList;
-
- /// Input: The number of entries in the scomList.
- ///
- /// \note It is considered an error if \a entries is 0, under the
- /// assumption that the caller must have neglected to initialize the
- /// structure.
- uint32_t entries;
-
- /// Input: Procedure options
- ///
- /// An OR-mask of option flags; See \ref gpe_scom_options;
- uint32_t options;
-
- /// Output: The procedure return code
- ///
- /// This field will contain 0 in the event of a successful return, and a
- /// non-zero value in the event of an error. See \ref gpe_scom_rc for
- /// documentation of the possible return codes.
- uint32_t rc;
-
- /// Output: The index of the entry that failed
- ///
- /// In the event that \a rc != 0, this field will contain the 0-based
- /// index of the \a scomList entry that was being processed at the time of
- /// the failure, or -1 for failures associated with the parameters or
- /// setup of the procedure.
- int32_t errorIndex;
-
-} GpeScomParms;
-
-#else // __ASSEMBLER__
-
- // Offsets into the GpeScomParms structure
-
- .set GPE_SCOM_PARMS_SCOM_LIST, 0x00
- .set GPE_SCOM_PARMS_ENTRIES_OPTIONS, 0x08
- .set GPE_SCOM_PARMS_RC_ERROR_INDEX, 0x10
-
- // PGAS macros to extract fields of the GpeScomParms. The source
- // and target must be data registers, and they can be the same data
- // register.
-
- .macro gpe_scom_parms_get_entries, target:req, source:req
- extrdi \target, \source, 32, 0
- .endm
-
- .macro gpe_scom_parms_get_options, target:req, source:req
- extrdi \target, \source, 32, 32
- .endm
-
- .macro gpe_scom_parms_get_rc, target:req, source:req
- extrdi \target, \source, 32, 0
- .endm
-
- // PGAS macros to update fields of the GpeScomParms. The source
- // and target must be different data registers. The target is the
- // current value and is updated with the new field held
- // right-justified in the source. The source register is effectively
- // destroyed by these operations.
-
- .macro gpe_scom_parms_set_rc, target:req, source:req
- insrdi \target, \source, 32, 0
- .endm
-
- .macro gpe_scom_parms_set_error_index, target:req, source:req
- insrdi \target, \source, 32, 32
- .endm
-
-#endif // __ASSEMBLER__
-
-
-/// \defgroup gpe_scom_rc Return Codes From GPE SCOM Procedures
-///
-/// @{
-
-/// Successful completion of a GPE SCOM program
-#define GPE_SCOM_SUCCESS 0
-
-/// An error occurred during setup of the PBA for Centaur access. If this
-/// error code is returned then the \a errorIndex field of the GpeScomParms
-/// structure will be set to -1.
-#define GPE_SCOM_SETUP_ERROR 1
-
-/// One of the fields of the GpeScomParms structure is invalid. In the case of
-/// gpe_scom_centaur(), this code may also be returned if there is a problem
-/// with the global structure G_centaurConfiguration. If this error code is
-/// returned then the \a errorIndex field of the GpeScomParms structure will
-/// be set to -1 if the error occurred before command processing begins.
-#define GPE_SCOM_INVALID_ARGUMENT 2
-
-/// The procedure died. Since GPE procedures do not trap errors by default
-/// they will typically die on the first hardware-detected error, and GPE
-/// error recovery procedures will clean up the failed job. If this error code
-/// is returned then the \a errorIndex field of the GpeScomParms structure
-/// will indicate the \a scomList entry being processed at the time of the
-/// failure.
-#define GPE_SCOM_DIED 3
-
-/// The \a commandType field of the scomList_t was not valid for the procedure.
-/// When this error is signalled then the \a errorIndex field of the
-/// GpeScomParms structure contains the index of the failing entry.
-#define GPE_SCOM_INVALID_COMMAND 4
-
-/// Signalled only by gpe_scom_centaur(), the \a instanceNumber field of the
-/// scomList_t did not index a valid (configured) Centaur. This error is only
-/// signalled by the GPE_SCOM_READ, GPE_SCOM_WRITE and GPE_SCOM_RMW commands
-/// that require a valid Centaur to be specified. When this error is signalled
-/// then the \a errorIndex field of the GpeScomParms structure contains the
-/// index of the failing entry.
-#define GPE_SCOM_INVALID_CENTAUR 5
-
-/// @}
-
-
-/// Execute a SCOM program for Centaur SCOMs
-///
-/// \param[in,out] io_parms A pointer to an initialized GpeScomParms
-/// structure. Since this structure is used both for input of parameterization
-/// and output of return codes it is imperitive that this structure is
-/// allocated in non-cacheable memory to avoid cache-related bugs. See the
-/// documentation for the fields of GpeScomParms for more information.
-///
-/// gpe_scom_centaur() is a GPE program that takes a pointer to an initialized
-/// GpeScomParms structure as input and executes the list of SCOMs and other
-/// commands. Return codes are returned in the GpeScomParms.
-///
-/// The following notes relate to the fields of the scomList_t structure when
-/// used by gpe_scom_centaur().
-///
-/// - \a instanceNumber : This field must be set to the index (0 - 7) of the
-/// Centaur (MCS) to access for the commands GPE_SCOM_READ, GPE_SCOM_WRITE and
-/// GPE_SCOM_RMW. This field is ignored by other commands.
-///
-/// - \a commandType : gpe_scom_centaur() supports the special command types
-/// GPE_SCOM_CENTAUR_SYNC and GPE_CENTAUR_SYNC_ALL as documented in \ref
-/// gpe_scom_commands.
-///
-/// - \a data : The commands GPE_SCOM_CENTAUR_SYNC and
-/// GPE_SCOM_CENTAUR_SYNC_ALL require a unique format for the \a data field as
-/// documented with the command.
-#ifdef DOXYGEN_ONLY
-void gpe_scom_centaur(GpeScomParms *io_parms);
-#endif
-
-#ifndef __ASSEMBLER__
-
-// Procedure entry points
-
-PoreEntryPoint gpe_scom_centaur;
-PoreEntryPoint gpe_scom_p8;
-
-// Debugging symbols
-
-extern uint64_t G_gsc_lastSlaveControl SECTION_ATTRIBUTE(".data.pore");
-extern uint64_t G_gsc_lastScomAddress SECTION_ATTRIBUTE(".data.pore");
-extern uint64_t G_gsc_lastOciAddress SECTION_ATTRIBUTE(".data.pore");
-
-#endif // __ASSEMBLER__
-
-#endif // __GPE_SCOM_H__
diff --git a/src/lib/gpe_scom.pS b/src/lib/gpe_scom.pS
deleted file mode 100644
index 2df1b78..0000000
--- a/src/lib/gpe_scom.pS
+++ /dev/null
@@ -1,709 +0,0 @@
-// $Id: gpe_scom.pS,v 1.2 2013/12/13 23:04:33 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_scom.pS,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpe_scom.pS
-/// \brief Generic SCOM procedures for PORE-GPE
-
- .nolist
-
-#include "ssx.h"
-#include "pgas.h"
-#include "pgp_config.h"
-#include "gpe.h"
-#include "gpe_pba.h"
-#include "gpe_scom.h"
-
- .list
-
- .oci
- .text.pore
-
-
-//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-// Common Routines
-//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gsWait
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // The wait loop is implemented as a decrement and branch guaranteed
- // to hit in the I-cache. This is used both by gpe_scom_centaur() and
- // gpe_scom_p8().
-gsWait:
- ld D0, SCOM_LIST_DATA, A1
- braz D0, gsWaitDone
- bra gsWaitLoop
-
- .set PORE_INSTRUCTION_BUFFER_SIZE, 8 # Should be global?
- .balign PORE_INSTRUCTION_BUFFER_SIZE
-gsWaitLoop:
- subs D0, D0, 1
- branz D0, gsWaitLoop
-
-gsWaitDone:
- ret
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gsTod
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-gsTod:
- lpcs P0, TOD_VALUE_REG
- ld D0, TOD_VALUE_REG, P0
- std D0, SCOM_LIST_DATA, A1
- ret
-
-
-//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-// gpe_scom_centaur
-//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-// gpe_scom_centaur() has 2 entry points: The first, gpe_scom_centaur(), is for
-// the "normal" case that the job is kicked off by the async drivers. The
-// second, _gpe_scom_centaur() is for use as a subroutine call.
-
-// Implementation note: Correctness requires that gpe_scom_centaur() maintins
-// strict control over the PBA slave as the command list is processed. At
-// entry the slave is reset, and then set up to do the cache-inibited partial
-// writes used for Centaur inband SCOM. Prior to every access the extended
-// address portion of the slave control register needs to be modified as it
-// contains part of the address that actually goes out on the PowerBus. For
-// reads there is no issue with setting the extended address at any
-// time. Since cache-inhibited partial reads are not prefetched, once a read
-// completes to the GPE the extended address is no longer in play. This is
-// not the case for writes. Just because a write completes on the OCI does not
-// mean that the write has completed at Centaur, and it is possible that
-// modifying the extended address before the write completes at Centaur can
-// cause a write to be corrrupted. The means that in general we need to reset
-// the slave prior to modifying the extended address to guarantee that any
-// outstanding write has made it to Centaur. As a run-time optimization we
-// only reset the slave after doing write operations.
-
-// At entry (gpe_scom_centaur):
-//
-// ETR : Contains a pointer to the GpeScomParms structure to interpret.
-//
-// At entry (_gpe_scom_centaur):
-//
-// A0 : Contains a pointer to the GpeScomParms structure to interpret.
-//
-// The caller should assume that all register state is destroyed by
-// calling _gpe_scom_centaur
-
- .macro gscExit
- la A0, gscCalledAsSubroutine
- ld D0, 0, A0
- braz D0, 4723948f
- ret
-4723948:
- halt
- .endm
-
-
- .global gpe_scom_centaur
- .global _gpe_scom_centaur
-
-gpe_scom_centaur:
- mr D0, ETR
- ls D1, 0
- bra gpe_scom_centaur_begin
-
-_gpe_scom_centaur:
- mr D0, A0
- ls D1, 1
-
-gpe_scom_centaur_begin:
- la A0, gscParameters
- std D0, 0, A0
- la A0, gscCalledAsSubroutine
- std D1, 0, A0
- mr A1, D0
-
- // Establish the "invalid argument" return code and check that the
- // global centaur configuration is valid and the number of entries is
- // non-zero and the pointer to the scomList is non-zero.
-
- la A0, G_centaurConfiguration
-
- ls D0, GPE_SCOM_INVALID_ARGUMENT
- gpe_scom_parms_set_rc D1, D0
- ls D0, -1
- gpe_scom_parms_set_error_index D1, D0
- std D1, GPE_SCOM_PARMS_RC_ERROR_INDEX, A1
-
- ld D0, CENTAUR_CONFIGURATION_CONFIG_RC, A0
- braz D0, 1f
- gscExit # Configuration RC != 0 (Structure is invalid)
-
-1:
- ld D0, GPE_SCOM_PARMS_ENTRIES_OPTIONS, A1
- gpe_scom_parms_get_entries D1, D0
- branz D1, 1f
- gscExit # entries == 0
-
-1:
- ld D0, GPE_SCOM_PARMS_SCOM_LIST, A1
- branz D1, 1f
- gscExit # scomList == 0
-
-1:
- // Establish the "setup error" return code and error index for the PBA
- // Slave reset, then reset the slave.
- //
- // At entry:
- //
- // A0 = &G_centaurConfiguration
- // A1 = &GpeScomParms
-
- ls D0, GPE_SCOM_SETUP_ERROR
- gpe_scom_parms_set_rc D1, D0
- ls D0, -1
- gpe_scom_parms_set_error_index D1, D0
- std D1, GPE_SCOM_PARMS_RC_ERROR_INDEX, A1
-
- adds A0, A0, CENTAUR_CONFIGURATION_SCOM_PARMS
- bsr gpe_pba_reset
- bsr gpe_pba_setup
-
-
- // Establish the "procedure died" return code, establish variables
- // used during the iteration over the scomList, then begin iteration:
- //
- // GpeScomParms.[rc, errorIndex]
- // CTR : The number of entries left to process.
- // A1 : The address of the scomList_t being processed
-
- la A0, gscParameters
- ld D0, 0, A0
- mr A0, D0
-
- ls D0, GPE_SCOM_DIED
- gpe_scom_parms_set_rc D1, D0
- ls D0, 0
- gpe_scom_parms_set_error_index D1, D0
- std D1, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
-
- ld D0, GPE_SCOM_PARMS_SCOM_LIST, A0
- mr A1, D0
-
- ld D0, GPE_SCOM_PARMS_ENTRIES_OPTIONS, A0
- gpe_scom_parms_get_entries D0, D0
- mr CTR, D0
- loop gscLoop # We know CTR != 0, so this is a branch to
- # gscLoop w/side effect of CTR--
-
- // Loop over the scomList, dispatching the commands.
- //
- // Loop invariants:
- //
- // GpeScomParms.entries has the number of entries processed so
- // far.
- //
- // A1 : The address of the scomList_t being processed
- //
- // CTR : Counting down the entries left to process.
- //
- // Command dispatch invariants
- //
- // A1 : Holds the pointer to the scomList being processed
-gscLoop:
- ld D1, SCOM_LIST_COMMAND, A1
- scom_list_get_command_type D0, D1
-
- // Commands listed in rough order of expected use
-
- cmpibraeq D0, gscReadVector, GPE_SCOM_READ_VECTOR
- cmpibraeq D0, gscWriteAll, GPE_SCOM_WRITE_ALL
- cmpibraeq D0, gscRMWAll, GPE_SCOM_RMW_ALL
- cmpibraeq D0, gscRead, GPE_SCOM_READ
- cmpibraeq D0, gscSyncAll, GPE_SCOM_CENTAUR_SYNC_ALL
- cmpibraeq D0, gscWrite, GPE_SCOM_WRITE
- cmpibraeq D0, gscRMW, GPE_SCOM_RMW
- cmpibraeq D0, gscSync, GPE_SCOM_CENTAUR_SYNC
- cmpibraeq D0, gscTod, GPE_SCOM_TOD
- cmpibraeq D0, gscWait, GPE_SCOM_WAIT
- cmpibraeq D0, gscContinue, GPE_SCOM_NOP
-
- bra gscInvalidCommand
-
-
- // Continue the loop. Update the index number and scomList pointer.
-gscContinue:
- la A0, gscParameters
- ld D0, 0, A0
- mr A0, D0
-
- ld D0, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
- adds D0, D0, 1 # errorIndex is in low-order word
- std D0, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
-
- adds A1, A1, SIZEOF_SCOM_LIST_T
-
- loop gscLoop
-
- // We completed successfully. Set the final rc to 0 and halt.
-
- ls D0, 0
- std D0, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
- gscExit
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscWrite
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // Do a single Centaur in-band SCOM write. The actual SCOM write is
- // coded as a subroutine for use by the write-all as well.
-gscWrite:
- ld D0, SCOM_LIST_COMMAND, A1
- scom_list_get_instance_number D0, D0
- bsr gscScomSetup
- branz D0, gscInvalidCentaur
-
- bsr gscWrite1
- bsr gscResetSlave
- bra gscContinue
-
-
-gscWrite1:
- ld D0, SCOM_LIST_DATA, A1
- std D0, 0, A0
- ret
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscWriteAll
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // It is simplest here to simply unroll a loop that does the SCOM
- // write for all Centaur indices that pass as being valid.
-gscWriteAll:
- .set __CENTAUR__, 0
- .rept PGP_NCENTAUR
- ls D0, __CENTAUR__
- bsr gscScomSetup
- branz D0, 1f
- bsr gscWrite1
- bsr gscResetSlave
-1:
- .set __CENTAUR__, __CENTAUR__ + 1
- .endr
-
- bra gscContinue
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscRMW
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // Do a single Centaur in-band SCOM read-modify-write. SCOM data is
- // ANDed with the inverted mask, then the new data is OR-ed in and
- // stored back to SCOM. The actual RMW is coded as a subroutine for
- // use by the RMW-all as well.
-gscRMW:
- ld D0, SCOM_LIST_COMMAND, A1
- scom_list_get_instance_number D0, D0
- bsr gscScomSetup
- branz D0, gscInvalidCentaur
-
- bsr gscRMW1
- bsr gscResetSlave
- bra gscContinue
-
-
-gscRMW1:
- ld D0, 0, A0
- ld D1, SCOM_LIST_MASK, A1
- xori D1, D1, 0xffffffffffffffff
- and D0, D0, D1
- ld D1, SCOM_LIST_DATA, A1
- or D0, D0, D1
- std D0, 0, A0
-
- ret
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscRMWAll
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // It is simplest here to simply unroll a loop that does the SCOM
- // RMW for all Centaur indices that pass as being valid.
-gscRMWAll:
- .set __CENTAUR__, 0
- .rept PGP_NCENTAUR
- ls D0, __CENTAUR__
- bsr gscScomSetup
- branz D0, 1f
- bsr gscRMW1
- bsr gscResetSlave
-1:
- .set __CENTAUR__, __CENTAUR__ + 1
- .endr
-
- bra gscContinue
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscRead
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // Do a single Centaur in-band SCOM read
-gscRead:
- ld D0, SCOM_LIST_COMMAND, A1
- scom_list_get_instance_number D0, D0
- bsr gscScomSetup
- branz D0, gscInvalidCentaur
-
- ld D0, 0, A0
- std D0, SCOM_LIST_DATA, A1
- bra gscContinue
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscReadVector
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // It is simplest here to simply unroll a loop that does the SCOM
- // read for all Centaur indices that pass as being valid.
-gscReadVector:
- .set __CENTAUR__, 0
- .rept PGP_NCENTAUR
- ls D0, __CENTAUR__
- bsr gscScomSetup
- ls D1, __CENTAUR__ * 8 # Byte offset
- bsr gscReadVector1
- .set __CENTAUR__, __CENTAUR__ + 1
- .endr
-
- bra gscContinue
-
-
-gscReadVector1:
- // At entry, A1 points to the scomList_t, and D1 has the index of the
- // Centaur being processed. If D0 == 0 then the read is indicated and
- // A0 contains the address to dereference to accomplish the read. If
- // D0 != 0, then the Centaur is invalid and we'll zero the data.
-
- braz D0, 1f
-
- // No read indicated. Load the data pointer, convert to an indexed
- // address and store a 0. We can scratch A0 here.
-
- ld D0, SCOM_LIST_DATA, A1
- add D0, D0, D1
- mr A0, D0
- ls D0, 0
- std D0, 0, A0
- ret
-
- // A read is indicated. Load the data pointer and convert to an
- // indexed address in D1. Then load the SCOM data into D0 and store it
- // back at the indexed address.
-1:
- ld D0, SCOM_LIST_DATA, A1
- add D1, D0, D1
- ld D0, 0, A0
- mr A0, D1
- std D0, 0, A0
- ret
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscSync
- // gscSyncAll
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // These commands only differ in whether the user fills in the mask of
- // valid Centaurs or the procedure fills in the mask of valid Centaurs
- // from the global configuration. The extended address needed for the
- // sync is stored in the global data structure, and it is only
- // necessary to update the slave and store to the base address of the
- // PBA BAR to accomplish the SYNC.
-gscSync:
- bsr gscSyncSetup
- ld D0, SCOM_LIST_DATA, A1
- bra gscSyncContinue
-
-gscSyncAll:
- bsr gscSyncSetup
- la A0, G_centaurConfiguration
- ld D0, CENTAUR_CONFIGURATION_CONFIG, A0
- left_justify_centaur_config D0
- ld D1, SCOM_LIST_DATA, A1
- or D0, D0, D1
- bra gscSyncContinue
-
-
- // To set up the SYNC we only have to update the extended address
- // field (bits 35:48) of the slave control register from the slave
- // control register image held in the G_centaurConfiguration. We can't
- // destroy A1 so it's a little tedious as we have to load the slave
- // control register address twice.
-gscSyncSetup:
- la A0, G_centaurConfiguration
- ld D1, \
- (CENTAUR_CONFIGURATION_SCOM_PARMS + \
- GPEPBAPARMS_SLVCTL_ADDRESS), \
- A0
- mr A0, D1
- ld D0, 0, A0
-
- la A0, G_centaurConfiguration
- ld D1, CENTAUR_CONFIGURATION_SYNC_SLAVE_CONTROL, A0
- rldimi D0, D1, 0, 35, 48
-
- la A0, G_centaurConfiguration
- ld D1, \
- (CENTAUR_CONFIGURATION_SCOM_PARMS + \
- GPEPBAPARMS_SLVCTL_ADDRESS), \
- A0
- mr A0, D1
- std D0, 0, A0
-
- ret
-
-
- // Once it's set up, simply issue a store to complete the sync. The
- // caller has placed the correct data in D0.
-gscSyncContinue:
- la A0, (PBA_BAR_CENTAUR << 28)
- std D0, 0, A0
- bsr gscResetSlave
- bra gscContinue
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscWait
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-gscWait:
- bsr gsWait
- bra gscContinue
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscTod
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-gscTod:
- bsr gsTod
- bra gscContinue
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscScomSetup
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // At entry:
- //
- // A1 : The address of the scomList_t being processed
- // D0 : The Centaur instance number to set up
- //
- // At exit:
- //
- // PBA : Programmed to do the SCOM
- // A1 : The address of the scomList_t being processed
- // A0 : On success, the OCI address to load/store to do the SCOM
- // D0 : 0 = Success, otherwise an error code
- //
- // This routine checks the Centaur instance number for validity. If
- // the instance number is valid then the PBA is programmed to access
- // the SCOM address held in the scomList_t. This requires
- // reprogramming the PBA because part of the SCOM address must be
- // stored as the extended address field of the PBA slave control
- // register. It is not necessary to reset the PBA slave for each SCOM
- // operation. The way SCOM operations are set up they "complete
- // immediately" in the PBA so there is no issue with lingering state.
- //
- // Note: this routine is written this way (separating setup from
- // execution) to support the Centaur "multicast" and read-modify-write
- // operations. The multicast loop simply tries all Centaur and ignores
- // the ones that fail.
-gscScomSetup:
-
- // Check the Centaur instance number (D0) for validity.
-
- ls D1, PGP_NCENTAUR
- sub D1, D0, D1
- tfbult D1, 1f
-
- ls D0, GPE_SCOM_INVALID_ARGUMENT
- ret # Centaur instance too big
-
-1:
- // Check to make sure the Centaur is configured by testing the base
- // address for 0. The instance number is first multiplied by 8 to
- // create an array offset.
-
- rotldi D0, D0, 3
- la D1, G_centaurConfiguration
- adds D1, D1, CENTAUR_CONFIGURATION_BASE_ADDRESS
- add D0, D0, D1
- mr A0, D0
- ld D0, 0, A0
- branz D0, 1f
-
- ls D0, GPE_SCOM_INVALID_ARGUMENT
- ret # Base address is 0
-
-1:
- // We have the Centaur base address in D0, and convert it to the full
- // PowerBus address for the inband SCOM. Bit 27 is set to indicate OCC
- // (vs. FSP) access. Bit 28 remains 0 to indicate a SCOM (vs. sensor
- // cache) access. Bits 29:60 are the SCOM address. (The SCOM address
- // is shifted up by 3 bit positions). We need to save A1 to SPRG0 to
- // continue from here.
-
- ori D0, D0, 0x0000001000000000
- ld D1, SCOM_LIST_COMMAND, A1
- scom_list_get_scom D1, D1
- rotldi D1, D1, 3
- or D0, D0, D1
-
- mr SPRG0, A1
-
-#if 1
- la A1, G_gsc_lastScomAddress # Debug
- std D0, 0, A1
-#endif
-
- // The low-order 27 bits of the PowerBus address are OR-ed with the
- // PBA BAR base address and go into A0 as the returned OCI address.
-
- andi D1, D0, 0x7ffffff
- ori D1, D1, (PBA_BAR_CENTAUR << 28)
- mr A0, D1
-
- // Bits 23:36 of the address go into the extended address field (35:
- // 48) of the PBA slave control register by a read-modify-write
- // operation. Note: We're using rldimi explicitly here - not an
- // extended mnemonic - to save having to justify the data.
-
- la A1, G_centaurConfiguration
- ld D1, \
- (CENTAUR_CONFIGURATION_SCOM_PARMS + \
- GPEPBAPARMS_SLVCTL_ADDRESS), \
- A1
- mr A1, D1
- ld D1, 0, A1
- rldimi D1, D0, 64 - (35 - 23), 35, 48
- std D1, 0, A1
-
-#if 1
- la A1, G_gsc_lastSlaveControl # Debug
- std D1, 0, A1
- mr D1, A0
- la A1, G_gsc_lastOciAddress
- std D1, 0, A1
-#endif
-
- // Restore A1 to its invariant state, clear D0 to signal success and
- // we're out
-
- mr A1, SPRG0
- ls D0, 0
- ret
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscResetSlave
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // Reset the PBA slave after a write. This requires saving and
- // restoring A1. To avoid PORE stack overflow we have to inline
- // gpe_pba_reset() here. See the file gpe_pba_pgas.pS for comments on
- // why the slave reset is written like this.
-
-gscResetSlave:
- la A0, gscSaveA1
- mr D0, A1
- std D0, 0, A0
-
- la A0, G_centaurConfiguration + CENTAUR_CONFIGURATION_SCOM_PARMS
- bra gscGpePbaReset
-
- .balign 128
-gscGpePbaReset:
- la A1, PBA_SLVRST
- ld D0, GPEPBAPARMS_SLVRST, A0
- std D0, 0, A1
-
- ld D0, GPEPBAPARMS_SLVRST_IN_PROGRESS, A0
- ld D1, 0, A1
- and D0, D0, D1
- branz D0, gscGpePbaReset
-
- la A0, gscSaveA1
- ld D0, 0, A0
- mr A1, D0
-
- ret
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gscInvalidCommand
- // gscInvalidCentaur
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- //
- // Set the rc field. The errorIndex has already been set.
-
-gscInvalidCommand:
- ls D1, GPE_SCOM_INVALID_COMMAND
- bra 1f
-gscInvalidCentaur:
- ls D1, GPE_SCOM_INVALID_CENTAUR
-1:
- la A0, gscParameters
- ld D0, 0, A0
- mr A0, D0
-
- ld D0, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
- gpe_scom_parms_set_rc D0, D1
- std D0, GPE_SCOM_PARMS_RC_ERROR_INDEX, A0
- gscExit
-
-
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- // gpe_scom_centaur Global Data
- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- .data.pore
-
- // Set to 0/1 when gpe_scom_centaur() is called via
- // gpe_scom_centaur (ASYNC) / _gpe_scom_centaur (Subroutine)
-
-gscCalledAsSubroutine:
- .quad 0
-
-
- // Used to store the parameter block pointer
-
-gscParameters:
- .quad 0
-
-
- // Used to store A1 during the inner loop when we need to reset the
- // slave after a write
-
-gscSaveA1:
- .quad 0
-
-
- // Debug only, the last values computed by gscScomSetup.
-
- .global G_gsc_lastSlaveControl
-G_gsc_lastSlaveControl:
- .quad 0
-
- .global G_gsc_lastScomAddress
-G_gsc_lastScomAddress:
- .quad 0
-
- .global G_gsc_lastOciAddress
-G_gsc_lastOciAddress:
- .quad 0
diff --git a/src/lib/gpsm.c b/src/lib/gpsm.c
deleted file mode 100755
index e2b71d6..0000000
--- a/src/lib/gpsm.c
+++ /dev/null
@@ -1,600 +0,0 @@
-// $Id: gpsm.c,v 1.2 2014/02/03 01:30:24 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpsm.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpsm.c
-/// \brief Global Pstate Mechanism procedures
-///
-/// \todo : Should we initialize any/all iVRM delays in gpsm_lpsa_install()?
-
-#include "ssx.h"
-#include "pstates.h"
-#include "gpe_control.h"
-#include "gpsm.h"
-#include "vrm.h"
-
-/// The semaphore used to block threads waiting for GPSM protocol actions
-
-SsxSemaphore G_gpsm_protocol_semaphore;
-
-
-////////////////////////////////////////////////////////////////////////////
-// Private Utilities
-////////////////////////////////////////////////////////////////////////////
-
-// The mechanical transition to Firmware Pstate Mode - Not a procedure
-
-static void
-_gpsm_fw_mode(void)
-{
- pmc_mode_reg_t pmr;
-
- pmr.value = in32(PMC_MODE_REG);
- pmr.fields.enable_hw_pstate_mode = 0;
- pmr.fields.enable_fw_auction_pstate_mode = 0;
- pmr.fields.enable_fw_pstate_mode = 1;
- out32(PMC_MODE_REG, pmr.value);
-}
-
-
-// The mechanical transition to Firmware Auction Pstate Mode - Not a procedure
-
-static void
-_gpsm_fw_auction_mode(void)
-{
- pmc_mode_reg_t pmr;
-
- pmr.value = in32(PMC_MODE_REG);
- pmr.fields.enable_hw_pstate_mode = 0;
- pmr.fields.enable_fw_auction_pstate_mode = 1;
- pmr.fields.enable_fw_pstate_mode = 0;
- out32(PMC_MODE_REG, pmr.value);
-}
-
-
-// The mechanical transition to Hardware Pstate Mode - Not a procedure.
-// Disable voltage change via safe_mode_without_spivid
-// before enter hw mode to prevent possible glitch that
-// hw momentarily flush turbo to pstate actual,
-// After enter hw mode, we will enable back the spivid
-
-static void
-_gpsm_hw_mode(void)
-{
- pmc_mode_reg_t pmr;
-
- if (!gpsm_dcm_slave_p()) {
- pmr.value = in32(PMC_MODE_REG);
- pmr.fields.safe_mode_without_spivid = 1;
- out32(PMC_MODE_REG, pmr.value);
- }
-
- pmr.value = in32(PMC_MODE_REG);
- pmr.fields.enable_hw_pstate_mode = 1;
- pmr.fields.enable_fw_auction_pstate_mode = 0;
- pmr.fields.enable_fw_pstate_mode = 0;
- out32(PMC_MODE_REG, pmr.value);
-
- if (!gpsm_dcm_slave_p()) {
- pmr.value = in32(PMC_MODE_REG);
- pmr.fields.safe_mode_without_spivid = 0;
- out32(PMC_MODE_REG, pmr.value);
- }
-
-}
-
-
-////////////////////////////////////////////////////////////////////////////
-// Private Sub-Procedures
-////////////////////////////////////////////////////////////////////////////
-
-// By definition, quiescing the GPSM always leaves the system in firmware
-// Pstate mode. This is necessary for a consistent specification due to the
-// fact that in general, Hardware Pstate mode can not be quiesced without
-// leaving that mode.
-
-// To quiesce the GPSM in firmware or firmware auction mode requires waiting
-// for both the voltage and frequency changes to be complete. Note that they
-// will never be ongoing simultaneously. This predicate is used for all
-// firmware-mode quiesce, even though normally only one part or the other
-// (voltage/protocol) is active.
-//
-// Recall that PMC interrupts are level-low, so if ongoing status is clear,
-// the operation is ongoing.
-
-static int
-gpsm_fw_quiesce(void)
-{
- int rc = 0;
-
- if (!ssx_irq_status_get(PGP_IRQ_PMC_PROTOCOL_ONGOING)) {
- ssx_irq_enable(PGP_IRQ_PMC_PROTOCOL_ONGOING);
- rc = ssx_semaphore_pend(&G_gpsm_protocol_semaphore, SSX_WAIT_FOREVER);
- }
-
- if ((!rc) && !ssx_irq_status_get(PGP_IRQ_PMC_VOLTAGE_CHANGE_ONGOING)) {
- ssx_irq_enable(PGP_IRQ_PMC_VOLTAGE_CHANGE_ONGOING);
- rc = ssx_semaphore_pend(&G_gpsm_protocol_semaphore, SSX_WAIT_FOREVER);
- }
-
- if (!rc) {
- _gpsm_fw_mode();
- }
-
- return rc;
-}
-
-
-// To quiesce the GPSM in hardware mode requires waiting for any ongoing
-// Pstate change to be complete. Note that there is no guarantee that this
-// condition will ever be true in general unless something external to PMC
-// ensures that Global bids stop coming in to the GPSM. An alternative used
-// here is to 'lock' the GPSM temporarily by setting the rail bounds min and
-// max to the current Global Pstate Actual. The GPSM will eventually quiesce
-// at the global actual, and we can safely move to Firmware Pstate mode and
-// release the lock.
-//
-// Recall that PMC 'ongoing' interrupts are level-low, so if ongoing status is
-// clear, the operation is ongoing.
-
-static int
-gpsm_hw_quiesce(void)
-{
- int rc = 0;
- pmc_rail_bounds_register_t prbr, original_prbr;
- pmc_pstate_monitor_and_ctrl_reg_t ppmacr;
-
- ppmacr.value = in32(PMC_PSTATE_MONITOR_AND_CTRL_REG);
-
- original_prbr.value = prbr.value = in32(PMC_RAIL_BOUNDS_REGISTER);
- prbr.fields.pmin_rail = ppmacr.fields.gpsa;
- prbr.fields.pmax_rail = ppmacr.fields.gpsa;
- out32(PMC_RAIL_BOUNDS_REGISTER, prbr.value);
-
- rc = _gpsm_hw_quiesce();
-
- if (!rc) {
- _gpsm_fw_mode();
- out32(PMC_RAIL_BOUNDS_REGISTER, original_prbr.value);
- }
-
- return rc;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// Public Predicates
-////////////////////////////////////////////////////////////////////////////
-
-/// Is the Global Pstate Mechanism quiesced?
-///
-/// This predicate can only truly be answered 'true' if we are not in
-/// hardware Pstate mode.
-///
-/// \retval 0 Either we're in Hardware Pstate Mode, or a Voltage/Frequency
-/// operation is ongoing.
-///
-/// \retval 1 We're not in Hardware Pstate Mode and no Voltage/Frequency
-/// operation is ongoing.
-
-int
-gpsm_quiesced_p(void)
-{
- return !(gpsm_hw_mode_p() ||
- !ssx_irq_status_get(PGP_IRQ_PMC_PROTOCOL_ONGOING) ||
- !ssx_irq_status_get(PGP_IRQ_PMC_VOLTAGE_CHANGE_ONGOING));
-}
-
-/// Predicate: Is the PMC in hardware Pstate mode?
-///
-/// \returns 0/1
-
-int
-gpsm_hw_mode_p(void)
-{
- pmc_mode_reg_t pmr;
-
- pmr.value = in32(PMC_MODE_REG);
- return (pmr.fields.enable_hw_pstate_mode != 0);
-}
-
-
-/// Predicate: Is the PMC in firmware auction Pstate mode?
-///
-/// \returns 0/1
-
-int
-gpsm_fw_auction_mode_p(void)
-{
- pmc_mode_reg_t pmr;
-
- pmr.value = in32(PMC_MODE_REG);
- return (pmr.fields.enable_fw_auction_pstate_mode != 0);
-}
-
-
-/// Predicate: Is the PMC in firmware Pstate mode?
-///
-/// \returns 0/1
-
-int
-gpsm_fw_mode_p(void)
-{
- pmc_mode_reg_t pmr;
-
- pmr.value = in32(PMC_MODE_REG);
- return (pmr.fields.enable_fw_pstate_mode != 0);
-}
-
-
-/// Predicate: Is the chip configured as a DCM?
-///
-/// \returns 0/1
-
-int
-gpsm_dcm_mode_p(void)
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- return pmc_mode_reg.fields.enable_interchip_interface;
-}
-
-
-/// Predicate: Is the chip configured as a DCM Slave?
-///
-/// \returns 0/1
-
-int
-gpsm_dcm_master_p(void)
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- return
- pmc_mode_reg.fields.enable_interchip_interface &&
- pmc_mode_reg.fields.interchip_mode;
-}
-
-
-/// Predicate: Is the chip configured as a DCM Slave?
-///
-/// \returns 0/1
-
-int
-gpsm_dcm_slave_p(void)
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- return
- pmc_mode_reg.fields.enable_interchip_interface &&
- (pmc_mode_reg.fields.interchip_mode == 0);
-}
-
-
-
-
-////////////////////////////////////////////////////////////////////////////
-// Procedures
-////////////////////////////////////////////////////////////////////////////
-
-/// Recover the GlobalPstateTable object from the PMC
-///
-/// \note It is assumed that the pointer to the Global Pstate table installed
-/// in the PMC is actually a pointer to a complete GlobalPstateTable object
-/// (which contains a Global Pstate table as its first element).
-///
-/// \returns A pointer to the currently active GlobalPstateTable object.
-
-GlobalPstateTable*
-gpsm_gpst(void)
-{
- pmc_parameter_reg1_t ppr1;
-
- ppr1.value = in32(PMC_PARAMETER_REG1);
- return (GlobalPstateTable*)
- (ppr1.fields.ba_sram_pstate_table << GLOBAL_PSTATE_TABLE_ALIGNMENT);
-}
-
-
-/// Quiesce the GPSM to firmware mode from any other mode
-///
-/// At the exit of this procedure, the PMC will be in Firmware Pstate Mode and
-/// there will be no ongoing voltage or frequency transitions.
-int
-gpsm_quiesce(void)
-{
- int rc;
-
- if (gpsm_hw_mode_p()) {
- rc = gpsm_hw_quiesce();
- } else {
- rc = gpsm_fw_quiesce();
- }
-
- return rc;
-}
-
-/// Quiesce the GPSM in Hardware Pstate Mode
-///
-/// In general there is no guarantee that the GPSM will ever quiesce, or
-/// remain quiesced in Hardware Pstate Mode unless something like the
-/// procedure in gpsm_hw_quiesce() is used. This procedure is provided for
-/// the benefit of applications that are in complete control of Pstates
-/// (including idle state Pstates) to simply wait for the Pstate protocol to
-/// quiesce, without quiescing and entering Firmware Pstate mode like
-/// gpsm_hw_quiesce().
-
-int
-_gpsm_hw_quiesce(void)
-{
- int rc;
-
- do {
- rc = 0;
-
- if (!gpsm_hw_mode_p()) {
- rc = -GPSM_ILLEGAL_MODE_HW_QUIESCE;
- break;
- }
-
- if (!ssx_irq_status_get(PGP_IRQ_PMC_PROTOCOL_ONGOING)) {
- ssx_irq_enable(PGP_IRQ_PMC_PROTOCOL_ONGOING);
- rc = ssx_semaphore_pend(&G_gpsm_protocol_semaphore,
- SSX_WAIT_FOREVER);
- if (rc) break;
- }
- } while (0);
-
- return rc;
-}
-
-
-/// Change to GPSM firmware mode from any mode
-
-int
-gpsm_fw_mode(void)
-{
- return gpsm_quiesce();
-}
-
-
-/// Change to GPSM firmware auction mode from any mode
-
-int
-gpsm_fw_auction_mode(void)
-{
- int rc;
-
- rc = gpsm_quiesce();
- if (!rc) {
- _gpsm_fw_auction_mode();
- }
- return rc;
-}
-
-
-/// Change to Hardware Pstate Mode
-///
-/// The (unchecked) assumption behind this procedure is that the caller has
-/// run through Pstate intialization and enablement, and the system is in a
-/// state where the entry to Hardware Pstate Mode is safe once the GPSM is
-/// quiesced.
-
-int
-gpsm_hw_mode(void)
-{
- int rc;
-
- TRACE_GPSM(TRACE_GPSM_HW_MODE);
-
- rc = gpsm_quiesce();
- if (!rc) {
- _gpsm_hw_mode();
- }
- return rc;
-}
-
-
-/// The default GPSM auction procedure
-///
-/// The default auction returns the value of
-/// PMC_HARDWARE_AUCTION_PSTATE_REG.haps.
-
-Pstate
-gpsm_default_auction(void)
-{
- pmc_hardware_auction_pstate_reg_t phapr;
-
- phapr.value = in32(PMC_HARDWARE_AUCTION_PSTATE_REG);
- return phapr.fields.haps;
-}
-
-
-/// Update a user-supplied vector of Pstates with the current Global bid of
-/// each core.
-///
-/// \param[out] o_bids A vector of Pstates; The vector must be large enough to
-/// hold the bid of every possible core.
-///
-/// This routine is provided for use by non-default Global Pstate auction
-/// procedures.
-
-void
-gpsm_get_global_bids(Pstate *o_bids)
-{
- // This takes advantage of the implicit layout of the
- // PMC_CORE_PSTATE_REG<n>.
-
- uint32_t *bids32 = (uint32_t *)o_bids;
-
- bids32[0] = in32(PMC_CORE_PSTATE_REG0);
- bids32[1] = in32(PMC_CORE_PSTATE_REG1);
- bids32[2] = in32(PMC_CORE_PSTATE_REG2);
- bids32[3] = in32(PMC_CORE_PSTATE_REG3);
-}
-
-
-/// Update a current Global bid of each core from a user supplied vector.
-///
-/// \param[in] i_bids An array of Global Pstate bids.
-///
-/// This routine is provided for use by test procedures; there is likely no
-/// product-level energy management application for this procedure.
-
-void
-gpsm_set_global_bids(const Pstate *i_bids)
-{
- // This takes advantage of the implicit layout of the
- // PMC_CORE_PSTATE_REG<n>.
-
- uint32_t *bids32 = (uint32_t *)i_bids;
-
- out32(PMC_CORE_PSTATE_REG0, bids32[0]);
- out32(PMC_CORE_PSTATE_REG1, bids32[1]);
- out32(PMC_CORE_PSTATE_REG2, bids32[2]);
- out32(PMC_CORE_PSTATE_REG3, bids32[3]);
-}
-
-
-/// Application-controlled Global Actual Broadcast
-///
-/// \param[in] i_pstate The Global Actual Pstate to broadcast
-///
-/// \param[in] i_entry A gpst_entry_t containing the information to be used by
-/// the iVRM. If iVRM are not enabled then \a entry can be initialized to 0.
-///
-/// This API is provided for advanced applications to have complete control
-/// over a firmware-mode Global Actual broadcast. There is no error
-/// checking. Most applications in Firware Pstate mode will use the
-/// higher-level gpsm_broadcast_global_actual() API.
-
-void
-_gpsm_broadcast_global_actual(const Pstate i_pstate,
- const gpst_entry_t i_entry)
-{
- pmc_pstate_monitor_and_ctrl_reg_t ppmacr;
- pmc_eff_global_actual_voltage_reg_t pegavr;
-
- ppmacr.value = 0;
- ppmacr.fields.gpsa = i_pstate;
- out32(PMC_PSTATE_MONITOR_AND_CTRL_REG, ppmacr.value);
-
- pegavr.value = 0;
- pegavr.fields.maxreg_vdd = i_entry.fields.maxreg_vdd;
- pegavr.fields.maxreg_vcs = i_entry.fields.maxreg_vcs;
- pegavr.fields.eff_evid_vdd = i_entry.fields.evid_vdd_eff;
- pegavr.fields.eff_evid_vcs = i_entry.fields.evid_vcs_eff;
- out32(PMC_EFF_GLOBAL_ACTUAL_VOLTAGE_REG, pegavr.value);
-
- TRACE_GPSM(TRACE_GPSM_BROADCAST_GLOBAL_ACTUAL);
-}
-
-
-/// Broadcast the Global Actual Pstate in firmware Pstate mode.
-///
-/// \param[in] i_gpst An initialized GlobalPstateTable structure used to
-/// define the legal Pstate range, and to provide the voltage settings
-/// (maxreg_vxx and eff_evid_vxx) for the internal VRM.
-///
-/// \param[in] i_pstate The pstate specfiying the Global Actual Pstate to be
-/// broadast to the core chiplets.
-///
-/// \param[in] i_bias This is a signed bias used to obtain the voltage Pstate,
-/// <em> in addition to the \a undervolting_bias already built into the Pstate
-/// table </em>. The iVRM information sent with the Global Actual Pstate comes
-/// from the \a pstate - \a undervolting_bias + \a bias entry of the Pstate
-/// table.
-///
-/// This API can be used in firware Pstate mode to broadcast a Global Actual
-/// Pstate and iVRM settings to the core chiplets. The API also supports
-/// optional under/over-volting. The requested Pstate will be broadcast along
-/// with the voltage information from the associated Pstate table entry.
-///
-/// Under/over-volting is specified by setting the \a bias to a non-0
-/// (signed) value. For example, to undervfolt by one Pstate (if possible),
-/// call the API with \a bias = -1.
-///
-/// This API always waits for the Global Pstate Machine to quiesce before
-/// proceeding with the Global Actual broadcast. Therefore it can only be
-/// called from thread mode, or from a non-thread mode guaranteed by the
-/// caller to have quiesced.
-///
-/// \note The application can use the _gpsm_broadcast_global_actual() API for
-/// complete control over the information transmitted to the cores.
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -GPST_PSTATE_CLIPPED_HIGH_GPSM_BGA The requested Pstate does not
-/// exist in the table. The maximum Pstate entry in the table has been
-/// broadcast as the voltage Pstate.
-///
-/// \retval -GPST_PSTATE_CLIPPED_LOW_GPSM_BGA The requested Pstate does not
-/// exist in the table. The minimum Pstate entry in the table has been
-/// broadcast as the voltage Pstate.
-///
-/// The following return codes are considered errors:
-///
-/// \retval -GPSM_INVALID_OBJECT The Global Pstate Table is either null (0) or
-/// otherwise invalid.
-///
-/// \retval -GPSM_INVALID_ARGUMENT One or more arguments are invalid or
-/// inconsistent in some way.
-///
-/// \retval -GPSM_ILLEGAL_MODE_BGA The PMC is not in firmware pstate mode.
-///
-/// This API may also return errors from the SSX semaphore operations that
-/// implement the wait for quiescence.
-
-int
-gpsm_broadcast_global_actual(const GlobalPstateTable* i_gpst,
- const Pstate i_pstate,
- const int i_bias)
-{
- int rc, bias_rc, entry_rc;
- gpst_entry_t entry;
- Pstate voltage_pstate;
-
- do {
-
- if (!gpsm_fw_mode_p()) {
- rc = GPSM_ILLEGAL_MODE_BGA;
- break;
- }
-
- // Bias the pstate, fetch the Pstate entry, quiesce and broadcast.
- // bias_pstate() only returns saturation warnings. These are turned
- // into bounds warnings if necessary (indicating that the Pstate
- // saturated but the PMAX or PMIN was also a legal entry in the
- // table).
-
- bias_rc = bias_pstate(i_pstate, i_bias, &voltage_pstate);
- entry_rc = gpst_entry(i_gpst, voltage_pstate, 0, &entry);
- if (entry_rc &&
- (entry_rc != -GPST_PSTATE_CLIPPED_LOW_GPST_ENTRY) &&
- (entry_rc != -GPST_PSTATE_CLIPPED_HIGH_GPST_ENTRY)) {
- rc = entry_rc;
- break;
- }
-
- rc = gpsm_quiesce();
- if (rc) break;
-
- _gpsm_broadcast_global_actual(i_pstate, entry);
-
- if (entry_rc != 0) {
- rc = entry_rc;
- } else if (bias_rc == -PSTATE_OVERFLOW_BIAS_PS) {
- rc = -GPST_PSTATE_CLIPPED_HIGH_GPSM_BGA;
- } else if (bias_rc == -PSTATE_UNDERFLOW_BIAS_PS) {
- rc = -GPST_PSTATE_CLIPPED_LOW_GPSM_BGA;
- }
- } while (0);
-
- return rc;
-}
-
-
diff --git a/src/lib/gpsm.h b/src/lib/gpsm.h
deleted file mode 100755
index 5af2e8d..0000000
--- a/src/lib/gpsm.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef __GPSM_H__
-#define __GPSM_H__
-
-// $Id: gpsm.h,v 1.2 2014/02/03 01:30:24 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpsm.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpsm.h
-/// \brief PgP Global Pstate Machine (Mechanism)
-
-#include "ssx.h"
-#include "gpe_control.h"
-#include "pgp_async.h"
-#include "pstates.h"
-
-// GPSM modes
-
-#define GPSM_MODE_HW 1
-#define GPSM_MODE_FW_AUCTION 2
-#define GPSM_MODE_FW 3
-
-// Misc./Error/Panic codes
-
-#define GPSM_INVALID_OBJECT 0x00477601
-#define GPSM_INVALID_ARGUMENT_GPST_INSTALL 0x00477602
-#define GPSM_INVALID_ARGUMENT_LPST_INSTALL 0x00477603
-#define GPSM_INVALID_ARGUMENT_RCLK_INSTALL 0x00477604
-#define GPSM_INVALID_ARGUMENT_EPSS 0x00477605
-#define GPSM_ILLEGAL_MODE_HW_QUIESCE 0x00477606
-#define GPSM_ILLEGAL_MODE_BGA 0x00477607
-#define GPSM_ILLEGAL_MODE_GPST_INSTALL 0x00477608
-#define GPSM_ILLEGAL_MODE_LPST_INSTALL 0x00477609
-#define GPSM_ILLEGAL_MODE_RCLK_INSTALL 0x0047760a
-#define GPSM_ILLEGAL_MODE_GPSM_INIT 0x0047760b
-#define GPSM_ILLEGAL_MODE_EPSM 0x0047760c
-#define GPSM_ILLEGAL_MODE_EPSS 0x0047760d
-#define GPSM_SYNC_ERROR 0x0047760e
-#define GPSM_PSTATE_CLIPPED 0x0047760f
-#define GPSM_BUG 0x00477610
-#define GPSM_CONFIGURATION_ERROR 0x00477611
-#define GPSM_ERROR_BREAK 0x00477612
-#define GPSM_INVALID_MAGIC 0x00477613
-#define GPSM_IVRM_CALIBRATION_TIMEOUT 0x00477614
-#define GPSM_IVRM_GROSS_OR_FINE 0x00477615
-#define GPSM_PSTATE_ENABLED 0x00477616
-#define GPSM_BABYSTEPPER_SYNC_TIMEOUT 0x00477617
-#ifndef __ASSEMBLER__
-
-// Lab/VBU/VPO debugging
-
-#if 0
-#include "trace.h"
-#define TRACE_GPSM(i_code) trace_tbl_bbbb(1, i_code, 0, 0, 0);
-#define TRACE_GPSM_B(i_code, i_b0) trace_tbl_bbbb(1, i_code, i_b0, 0, 0);
-#define TRACE_GPSM_H(i_code, i_h0) trace_tbl_bbh(1, i_code, 0, i_h0);
-#else
-#define TRACE_GPSM(i_code)
-#define TRACE_GPSM_B(i_code, i_b0)
-#define TRACE_GPSM_H(i_code, i_h0)
-#endif
-
-
-/// Information required by an SCM or a DCM master to be passed from
-/// gpsm_enable_pstates_master() to gpsm_enable_pstates_slave().
-
-typedef struct {
-
- /// Indicates whether or not gpsm_enable_pstates_slave() should move the
- /// voltage.
- ///
- /// If 0, it means that the master has already moved the voltage and only
- /// the frequency needs to move. If 1, voltage is moved after frequency
- /// moves.
- int move_voltage;
-
- /// The current and target external voltage settings as VRM11 VID codes.
- Vid11 currentVdd, currentVcs, targetVdd, targetVcs;
-
-} GpsmEnablePstatesMasterInfo;
-
-
-/// A GpsmAuctionProcedure is any function of no arguments that returns a
-/// Pstate
-
-typedef Pstate (*GpsmAuctionProcedure)();
-
-extern SsxSemaphore G_gpsm_protocol_semaphore;
-
-extern uint8_t G_gpsm_initialized;
-
-// APIs defined in gpsm_init.c
-
-int
-gpsm_gpst_install(GlobalPstateTable* o_gpst,
- const GlobalPstateTable* i_source);
-
-int
-gpsm_lpsa_install(const LocalPstateArray* i_lpsa,
- const PstateOptions* i_options);
-
-int
-gpsm_resclk_install(const ResonantClockingSetup* i_resclk,
- const GlobalPstateTable* i_gpst,
- const PstateOptions* i_options);
-
-int
-gpsm_initialize(const PstateSuperStructure* i_pss,
- GlobalPstateTable* o_gpst);
-
-int
-gpsm_enable_pstates_master(GpsmEnablePstatesMasterInfo* o_info,
- Pstate* o_voltage_pstate,
- Pstate* o_frequency_pstate);
-
-int
-gpsm_enable_pstates_slave(const GpsmEnablePstatesMasterInfo* i_info,
- const Pstate i_voltage_pstate,
- const Pstate i_frequency_pstate);
-
-// APIs defined in gpsm.c
-
-int
-gpsm_quiesced_p(void);
-
-int
-gpsm_hw_mode_p(void);
-
-int
-gpsm_fw_auction_mode_p(void);
-
-int
-gpsm_fw_mode_p(void);
-
-int
-gpsm_dcm_mode_p(void);
-
-int
-gpsm_dcm_master_p(void);
-
-int
-gpsm_dcm_slave_p(void);
-
-GlobalPstateTable*
-gpsm_gpst();
-
-int
-gpsm_quiesce(void);
-
-int
-_gpsm_hw_quiesce(void);
-
-int
-gpsm_fw_mode(void);
-
-int
-gpsm_fw_auction_mode(void);
-
-int
-gpsm_hw_mode(void);
-
-Pstate
-gpsm_default_auction(void);
-
-void
-gpsm_get_global_bids(Pstate* o_bids);
-
-void
-gpsm_set_global_bids(const Pstate* i_bids);
-
-void
-_gpsm_broadcast_global_actual(const Pstate i_pstate,
- const gpst_entry_t i_entry);
-
-int
-gpsm_broadcast_global_actual(const GlobalPstateTable *i_gpst,
- const Pstate i_pstate,
- const int i_bias);
-
-int
-gpsm_set_pstate(const Pstate i_pstate);
-
-int
-gpsm_hold_auction(const GpsmAuctionProcedure i_procedure);
-
-#endif /* __ASSEMBLER__ */
-
-#endif /* __GPSM_H__ */
diff --git a/src/lib/gpsm_dcm.c b/src/lib/gpsm_dcm.c
deleted file mode 100755
index 452f7cf..0000000
--- a/src/lib/gpsm_dcm.c
+++ /dev/null
@@ -1,753 +0,0 @@
-// $Id: gpsm_dcm.c,v 1.2 2014/02/03 01:30:24 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpsm_dcm.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpsm_dcm.h
-/// \brief PgP Global PState Machine (Mechanism) in Dual Chip Model
-
-#include "ssx.h"
-#include "pmc_dcm.h"
-#include "gpsm_dcm.h"
-#include "gpsm.h"
-
-/// Timeout object and methods
-
-typedef struct {
- SsxTimebase timeout;
-} Timeout;
-
-static void
-timeout_start(Timeout* t, SsxInterval timeout_period)
-{
- t->timeout = ssx_timebase_get() + timeout_period;
-}
-
-static int
-timeout_timed_out(Timeout* t)
-{
- return ssx_timebase_get() > t->timeout;
-}
-
-
-/// Internal API : Send packet with timeout
-///
-/// \param hwPacket pointer to the packet to be sent
-///
-/// \param timeout_period The SSX timeout variable
-///
-/// This API sends \a hwPacket within \a timeout_period
-/// if timed out, the function returns an error code
-///
-/// \retval GPSM_DCM_SUCCESS
-///
-/// \retval GPSM_DCM_SEND_PACKET_TIMEOUT
-///
-
-static int
-_gpsm_dcm_send(PmcDcmPacket* hwPacket,
- SsxInterval timeout_period)
-{
- int rc = GPSM_DCM_SUCCESS;
- Timeout timeout;
-
- //set timeout
- timeout_start(&timeout, timeout_period);
-
- //try to send packet within timeout
- while( (rc=pmc_dcm_send(hwPacket)) == PMC_DCM_OUTSTANDING_TRANSFER ) {
- if( timeout_timed_out(&timeout)) {
- rc = GPSM_DCM_SEND_PACKET_TIMEOUT;
- break;
- }
- }
-
- return rc;
-}
-
-/// Internal API : Receive packet with timeout
-///
-/// \param hwPacket pointer to the packet structure to receive
-///
-/// \param timeout_period The SSX timeout variable
-///
-/// This API receives a \a hwPacket within \a timeout
-/// if timed out, the function returns an error code
-///
-/// \retval GPSM_DCM_SUCCESS
-///
-/// \retval GPSM_DCM_RECV_PACKET_TIMEOUT
-///
-
-static int
-_gpsm_dcm_receive(PmcDcmPacket* hwPacket,
- SsxInterval timeout_period)
-{
- int rc = GPSM_DCM_SUCCESS;
- Timeout timeout;
-
- //set timeout
- timeout_start(&timeout, timeout_period);
-
- //try to receive packet within timeout
- while( (rc=pmc_dcm_receive(hwPacket)) == PMC_DCM_RECEIVE_NOT_DETECTED ) {
- if( timeout_timed_out(&timeout)) {
- rc = GPSM_DCM_RECV_PACKET_TIMEOUT;
- break;
- }
- }
-
- return rc;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// High-level GPSM-DCM Interfaces
-////////////////////////////////////////////////////////////////////////////
-
-/// Abstract non-blocking send over the DCM interchip link
-///
-/// The GPSM-DCM abstract interface guarantees that the PMC-DCM link is always
-/// clear for use by the master sender. This API (which should be called from
-/// a thread context) transmits an abstract packet, then polls for the hardware
-/// ACK - which must always indicate that the packet was received. This ACK
-/// will always occur very quickly.
-///
-/// \param fwPacket a GpsmDcmPacket structure to be sent as part of the
-/// PmcDcmPacket/hwPacket of MSG type via PMC interchip link.
-/// The fwPacket includes a firmware command and 16 bits payload.
-/// The firmware command will be filled in the cmd_ext field of the
-/// hwPacket structure, and payload 0,1 will be filled in the
-/// corresponding slots also in hwPacket structure.
-/// This argument is provided by the caller and passed in as reference.
-///
-/// hwPacket:
-///
-/// cmd_code | cmd_ext | payload 0 | payload 1 | ECC
-/// [0:3] | [4:7] | [8:15] | [16:23] | [24:31]
-///
-/// fwPacket:
-///
-/// | command | payload 0 | payload 1 |
-/// | [4:7] | [8:15] | [16:23] |
-///
-/// firmware command:
-///
-/// GPSM_DCM_DATA 0 //0b0000
-/// GPSM_DCM_WRITE 1 //0b0001
-/// GPSM_DCM_ENABLE_PSTATES 2 //0b0010
-/// GPSM_DCM_ENTER_HW_PSTATE_MODE 3 //0b0011
-///
-/// This API implements the lower level pmc_dcm_send API to send a firmware
-/// command as part of the PMC interchip message packet.
-///
-/// This API is working under a default time out, if send cannot be completed
-/// within the default timeout period due to possible busy interchip link,
-/// the function will exit with returning an error code:
-/// \a GPSM_DCM_SEND_PACKET_TIMEOUT
-///
-/// Prerequisite: The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// and lower level PMC-DCM API is required to use this
-/// high level GPSM-DCM API.
-/// Also, the hardware must be in DCM setup.
-///
-/// Note: This API must be called by the DCM Master, meaning the firmware
-/// command can only be given by the master to the slave.
-/// Also the API will check if the firmware command to be sent is valid.
-///
-/// \retval SUCCESS
-///
-/// \retval GPSM_DCM_ARG_INVALID_OBJ_SND
-///
-/// \retval GPSM_DCM_PKT_INVALID_CMD_SND
-///
-/// \retval GPSM_DCM_CMD_NOT_FROM_MASTER
-///
-
-int
-gpsm_dcm_send(GpsmDcmPacket* fwPacket) {
-
- int rc = GPSM_DCM_SUCCESS;
- PmcDcmPacket hwPacket;
-
- TRACE_GPSM_B(TRACE_GPSM_DCM_SEND, fwPacket->command);
-
- do {
-
- //check if argument is NULL
- SSX_ERROR_IF_CHECK_API(
- (fwPacket == 0),
- GPSM_DCM_ARG_INVALID_OBJ_SND);
-
- //check if firmware command is valid
- SSX_ERROR_IF_CHECK_API(
- (fwPacket->command >= GPSM_DCM_NUMBER_OF_COMMANDS ||
- fwPacket->command == GPSM_IC_DATA),
- GPSM_DCM_PKT_INVALID_CMD_SND);
-
- //check if is dcm master, note only master can send command to slave
- SSX_ERROR_IF_CHECK_API(
- (!pmc_dcm_if_dcm_master()),
- GPSM_DCM_CMD_NOT_FROM_MASTER);
-
- //form hardware packet from given firmware packet
- hwPacket.value = 0;
- hwPacket.fields.cmd_code = PMC_IC_MSG_CC;
- hwPacket.fields.cmd_ext = fwPacket->command;
- hwPacket.fields.payload[0] = fwPacket->payload.u8[0];
- hwPacket.fields.payload[1] = fwPacket->payload.u8[1];
-
- //send hardware packet
- rc = _gpsm_dcm_send(&hwPacket, GPSM_DCM_DEFAULT_TIMEOUT);
-
- } while (0);
-
- TRACE_GPSM(TRACE_GPSM_DCM_SENT);
-
- return rc;
-}
-
-
-/// Abstract blocking/non-blocking receive over the DCM interchip link
-///
-/// \param fwPacket A GpsmDcmPacket structure as the part of the
-/// PmcDcmPacket/hwPacket received from PMC interchip link.
-/// This argument is passed by the caller as reference. The corresponding
-/// fields of the received packet will filled in this data structure.
-///
-/// \param timeout_period A SsxInterval variable for time out period
-///
-/// This API implements the lower level pmc_dcm_receive API to receive a firmware
-/// command as part of the PMC interchip message packet.
-///
-/// This API is working under a user given time out, if receive cannot be
-/// completed within the given timeout period,
-/// the function will exit with returning an error code:
-/// \a GPSM_DCM_RECV_PACKET_TIMEOUT
-///
-/// Prerequisite: The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// and lower level PMC-DCM API is required to use this
-/// high level GPSM-DCM API.
-/// Also, the hardware must be in DCM setup.
-///
-/// Note: This API must be called by the DCM Slave, meaning the firmware
-/// command can only be received by the slave.
-/// Also the API will check if the received firmware command is valid.
-//
-/// \retval GPSM_DCM_SUCCESS
-///
-/// \retval GPSM_DCM_ARG_INVALID_OBJ_RCV
-///
-/// \retval GPSM_DCM_CMD_SHOULD_TO_SLAVE
-///
-/// \retval GPSM_DCM_PKT_INVALID_CMD_RCV
-///
-
-int
-gpsm_dcm_receive(GpsmDcmPacket* fwPacket,
- SsxInterval timeout_period) {
-
- int rc = GPSM_DCM_SUCCESS;
- PmcDcmPacket hwPacket;
-
- TRACE_GPSM(TRACE_GPSM_DCM_RECEIVE);
-
- do {
-
- //check if argument is NULL
- SSX_ERROR_IF_CHECK_API(
- (fwPacket == 0),
- GPSM_DCM_ARG_INVALID_OBJ_RCV);
-
- //check if is dcm slave, note only slave receives command from master
- SSX_ERROR_IF_CHECK_API(
- (pmc_dcm_if_dcm_master()),
- GPSM_DCM_CMD_SHOULD_TO_SLAVE);
-
- //receive hardware packet
- hwPacket.value = 0;
- rc = _gpsm_dcm_receive(&hwPacket, timeout_period);
- if( rc ) break;
-
- //check if the received command is valid
- fwPacket->command = hwPacket.fields.cmd_ext;
- SSX_ERROR_IF_CHECK_API(
- (fwPacket->command >= GPSM_DCM_NUMBER_OF_COMMANDS ||
- fwPacket->command == 0),
- GPSM_DCM_PKT_INVALID_CMD_RCV);
-
- //load payload from hardware packet into firmware packet
- fwPacket->payload.u8[0] = hwPacket.fields.payload[0];
- fwPacket->payload.u8[1] = hwPacket.fields.payload[1];
-
- } while (0);
-
- TRACE_GPSM_B(TRACE_GPSM_DCM_RECEIVED, fwPacket->command);
-
- return rc;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// Generic communication using GPSM-DCM 'write' command
-////////////////////////////////////////////////////////////////////////////
-///
-/// These APIs allow applications to perform generic communication over the
-/// GPSM-DCM link using the GPSM-DCM 'write' command. Like all GPSM-DCM
-/// commands, communication is always controlled/initiated by the master. The
-/// infrastructure assumes that the master and slave applications argee on the
-/// maximum amount of data that may be transmitted generically as a single
-/// abstract transaction. It is legal for the data transmission size to be 0.
-///
-/// In the following APIs, the \a timeout parameter is a timeout for any
-/// single send/receive transaction to complete, not a timeout covering the
-/// entire send/receive. The timeout may be specified as SSX_WAIT_FOREVER to
-/// indicate no timeout.
-///
-/// One typical use of these APIs would be to implement a polled 'ping' of the
-/// slave from the master. This sequence might be implemented as follows:
-///
-/// - Master: Calls gpsm_dcm_write() with 0 size [ping]
-/// - Master: Blocks on gpsm_dcm_read [Wait for ping response]
-/// - Slave: GpsmSlaveControl.write_handler() is activated to handle the ping
-/// - Slave: write_handler() responds by calling gpsm_dcm_write()
-/// - Master: Unblocks and processes ping reqponse
-
-
-/// Send an arbitrary amount of data (max 2^16 - 1 bytes) using GPSM-DCM
-///
-/// This API is typically used by the master to initiate generic
-/// communication. When received by the slave the application-specific
-/// callback is activated on the slave to handle the write.
-/// The slave will only use this API when it is known that the master is
-/// expecting a communication from the slave and has blocked on a call of
-/// gpsm_dcm_read().
-///
-/// The receiver must be prepared to accept \a size bytes of data, otherwise
-/// the call will fail immediately.
-///
-/// \param buf The buffer contains the sending message prepared by the caller
-///
-/// \param size The size of a message, in number of bytes, given by the caller
-///
-/// \param timeout_period The SSX timeout variable
-///
-/// The firmware level API for sending a generic PMC interchip message
-/// This API sends the message by calling lower level API: pmc_dcm_send
-///
-/// The API times out upon \a timeout_period.
-///
-/// Prerequisite: The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// and lower level PMC-DCM API is required to use this
-/// high level GPSM-DCM API.
-/// Also, the hardware must be in DCM setup.
-///
-/// Note: When this API is called by the DCM Master,
-/// the slave will need to provide its own write_handler to process
-/// the receiving message, The counterpart gpsm_dcm_read API of this
-/// gpsm_dcm_write API is not designed for slave to read the master
-/// sending message.
-///
-/// \retval GPSM_DCM_SUCCESS
-///
-/// \retval GPSM_DCM_ARG_INVALID_OBJ_WRT
-///
-
-int
-gpsm_dcm_write(void* buf,
- uint16_t size,
- SsxInterval timeout_period)
-{
- int rc = GPSM_DCM_SUCCESS;
- PmcDcmPacket hwPacket;
- GpsmDcmFastData fastData;
-
- TRACE_GPSM_H(TRACE_GPSM_DCM_WRITE, size);
-
- //setup send irq
- ssx_irq_setup(PGP_IRQ_PMC_INTERCHIP_MSG_SEND_ONGOING,
- SSX_IRQ_POLARITY_ACTIVE_LOW,
- SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
- do {
-
- //check if buffer is allocated
- SSX_ERROR_IF_CHECK_API(
- (buf == 0 && size != 0),
- GPSM_DCM_ARG_INVALID_OBJ_WRT);
-
- //form initial hardware packet as header packet
- hwPacket.value = 0;
- hwPacket.fields.cmd_code = PMC_IC_MSG_CC;
- hwPacket.fields.cmd_ext = GPSM_IC_WRITE;
- hwPacket.value += SET_PAYLOAD_FIELD(size);
-
- //setup data structure for fast write handler
- fastData.buffer_pointer = buf;
- fastData.remaining_size = size;
- ssx_semaphore_create(&(fastData.fast_semaphore), 0, 1);
-
- //setup fast write handler for send irq
- ssx_irq_handler_set(PGP_IRQ_PMC_INTERCHIP_MSG_SEND_ONGOING,
- gpsm_dcm_fast_write,
- (void*)(&fastData),
- SSX_NONCRITICAL);
-
- //send header packet
- rc = _gpsm_dcm_send(&hwPacket, timeout_period);
- if( rc ) break;
-
- //enable interrupt and semaphore
- ssx_irq_enable(PGP_IRQ_PMC_INTERCHIP_MSG_SEND_ONGOING);
- ssx_semaphore_pend(&(fastData.fast_semaphore), timeout_period);
-
- } while (0);
-
- TRACE_GPSM(TRACE_GPSM_DCM_WRITE_COMPLETE);
-
- return rc;
-}
-
-
-/// Receive a transmission from the slave
-///
-/// This API is only called on the master, as part of an application-specific
-/// protocol where a transmission is expected from the slave.
-///
-/// The call will fail immediately if the slave attempts to send more than \a
-/// buf_size bytes. The actual number of bytes received is returned as \a
-/// data_size.
-///
-/// \param buf The buffer for storing the incoming messages,
-/// return to caller as reference
-///
-/// \param buf_size The maximum size of the buffer, given by caller
-/// fail operation if data_size > buf_size
-///
-/// \param data_size The size of acutal receiving message,
-/// return to caller as refernce
-///
-/// \param timeout_period The SSX timeout variable
-///
-/// The firmware level API for receiving a PMC interchip message
-/// This API recevies the message by calling lower level API: pmc_dcm_receive
-/// and then checks \a buf_size and \a data_size for unexpected message size
-/// if the size overflow, the function will exit with returning an error code:
-/// \a GPSM_DCM_DAT_BIGGER_THAN_BUF
-/// The valid receive message will be placed into \a buf and return with
-/// the actual \a data_size. The API times out upon \a timeout.
-///
-/// Prerequisite: The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// and lower level PMC-DCM API is required to use this
-/// high level GPSM-DCM API.
-/// Also, the hardware must be in DCM setup.
-///
-/// Note: This API is only designed for master to read/receive a message from
-/// slave (slave will have its own write_handler). Therefore, this API
-/// can only called by DCM master, and the API will check if the received
-/// message is from a write command.
-///
-/// \retval GPSM_DCM_SUCCESS
-///
-/// \retval GPSM_DCM_ARG_INVALID_OBJ_RED
-///
-/// \retval GPSM_DCM_READ_RECV_NOT_WRITE
-///
-/// \retval GPSM_DCM_DAT_BIGGER_THAN_BUF
-///
-
-int
-gpsm_dcm_read(void* buf,
- uint16_t buf_size,
- uint16_t* data_size,
- SsxInterval timeout_period)
-{
- int rc = GPSM_DCM_SUCCESS;
- PmcDcmPacket hwPacket;
- GpsmDcmFastData fastData;
-
- TRACE_GPSM(TRACE_GPSM_DCM_READ);
-
- //setup receive irq
- ssx_irq_setup(PGP_IRQ_PMC_INTERCHIP_MSG_RECV,
- SSX_IRQ_POLARITY_ACTIVE_HIGH,
- SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
-
- do {
-
- //check if buffer is allocated
- SSX_ERROR_IF_CHECK_API(
- (buf == 0 && buf_size != 0),
- GPSM_DCM_ARG_INVALID_OBJ_RED);
-
- //try to receive the header packet
- hwPacket.value = 0;
- rc = _gpsm_dcm_receive(&hwPacket, timeout_period);
- if( rc ) break;
-
- //check if command code of header packet is valid
- SSX_ERROR_IF_CHECK_API(
- (hwPacket.fields.cmd_ext != GPSM_IC_WRITE),
- GPSM_DCM_READ_RECV_NOT_WRITE);
-
- //load size from header packet
- *data_size = GET_PAYLOAD_FIELD(hwPacket.value);
-
- //check if data size will fit in the buffer
- if( *data_size > buf_size ) {
- rc = GPSM_DCM_DAT_BIGGER_THAN_BUF;
- break;
- }
-
- //check if data size is 0
- if( *data_size == 0 )
- break;
-
- //setup data structure for fast read
- fastData.buffer_pointer = buf;
- fastData.remaining_size = *data_size;
- ssx_semaphore_create(&(fastData.fast_semaphore), 0, 1);
-
- //setup fast read handler for receive irq
- ssx_irq_handler_set(PGP_IRQ_PMC_INTERCHIP_MSG_RECV,
- gpsm_dcm_fast_read,
- (void*)(&fastData),
- SSX_NONCRITICAL);
-
- //enable interrupt and semaphore
- ssx_irq_enable(PGP_IRQ_PMC_INTERCHIP_MSG_RECV);
- ssx_semaphore_pend(&(fastData.fast_semaphore), timeout_period);
-
- } while (0);
-
- TRACE_GPSM_H(TRACE_GPSM_DCM_READ_COMPLETE, *data_size);
-
- return rc;
-}
-
-/// Method to sync between two chips using write/read API
-///
-/// This API can be called before a piece of application code to sync
-/// between master and slave to enter the same code block together
-/// as well as after a piece of code to sync on exiting the block of code
-///
-/// \param state use 0 for enter and use 1 for exit
-///
-/// \retval GPSM_DCM_SUCCESS
-///
-
-int
-gpsm_dcm_sync(int state)
-{
- int rc = GPSM_DCM_SUCCESS;
- int master = pmc_dcm_if_dcm_master();
- uint16_t buf_size = sizeof(uint16_t);
- uint16_t wbuf = 0x7962; //SYNC
- uint16_t rbuf;
- uint16_t size;
- SsxMachineContext smc;
-
- do {
-
- ssx_critical_section_enter(SSX_NONCRITICAL, &smc);
-
- if( master ^ state ) {
- rc = gpsm_dcm_write((void*)&wbuf,buf_size,SSX_WAIT_FOREVER);
- if(rc) break;
- rc = gpsm_dcm_read((void*)&rbuf,buf_size,&size,SSX_WAIT_FOREVER);
- if(rc) break;
- } else {
- rc = gpsm_dcm_read((void*)&rbuf,buf_size,&size,SSX_WAIT_FOREVER);
- if(rc) break;
- rc = gpsm_dcm_write((void*)&wbuf,buf_size,SSX_WAIT_FOREVER);
- if(rc) break;
- }
-
- ssx_critical_section_exit(&smc);
-
- } while (0);
-
- return rc;
-}
-
-
-/// GPSM DCM Slave function
-///
-/// This function must be called from a thread, as if a command is available
-/// it may always be necessary for the thread to block during command
-/// execution. The \a wait argument indicates whether the caller is willing to
-/// wait for a command indefinitely, or prefers for gpsm_dcm_slave() to retun
-/// immediately if no command is available. \a wait would normally be non-0 if
-/// \a gpsm_dcm_slave() were used as a standalone thread body, and 0 if
-/// gpsm_dcm_slave() were called from another thread.
-///
-/// \param control The callback table structure that allows the user to
-/// implement callback function in addition to completion of each command.
-///
-/// \param wait The SsxInterval type timeout variable
-///
-/// This API is the control function running on a slave thread. The function
-/// will first try to receive a message from master, and then take the
-/// corresponding action according to the command in the message. Upon
-/// completion of the default action designed for each command, any user
-/// provided callback function for that command in the control structure will
-/// be called.
-///
-/// Prerequisite: This API must be called from a DCM slave SSX thread
-/// The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// and lower level PMC-DCM API is required to use this
-/// high level GPSM-DCM API.
-/// Also, the hardware must be in DCM setup.
-///
-/// Similar to other SSX drivers, the callback is always called regardless of
-/// whether the slave command succeeds or fails.
-///
-/// \retval 0 Success
-///
-/// \retval GPSM_DCM_SLAVE_TIMEOUT The call timed out before a packet was
-/// received from the master. The application may or may not treat this as an
-/// error.
-///
-/// \retval GPSM_DCM_SLAVE_ERROR In the event of a this return code, the
-/// application will need to query 3 return codes stored in the \a control
-/// structure to understand the source of the error. The \a
-/// control->protocol_rc contains the return code for all GPSM-DCM protocol
-/// actions, other than the simple timeout mentioned above. The \a
-/// control->slave_rc is the return code for the slave action commanded by the
-/// master. This is also the code sent back to the master as an
-/// acknowledgement. The control->callback_rc is the return code from the
-/// callback, if any.
-///
-/// The return value of the function is either 0,
-/// GPSM_DCM_SLAVE_TIMEOUT, or
-/// GPSM_DCM_SLAVE_ERROR.
-///
-
-int
-gpsm_dcm_slave(GpsmSlaveControl *control,
- SsxInterval wait)
-{
- GpsmDcmPacket fwPacket;
- int rc, protocolRc, slaveRc, callbackRc;
-
- TRACE_GPSM(TRACE_GPSM_DCM_SLAVE);
-
- protocolRc = 0;
- slaveRc = 0;
- callbackRc = 0;
-
- do {
- protocolRc = gpsm_dcm_receive(&fwPacket, wait);
- if(protocolRc) {
- control->command = GPSM_IC_NO_COMMAND;
- break;
- }
-
- control->command = fwPacket.command;
-
- switch (fwPacket.command) {
-
- case GPSM_IC_ENABLE_PSTATES:
-
- slaveRc = gpsm_enable_pstates_slave(0,
- fwPacket.payload.pstate[0],
- fwPacket.payload.pstate[1]);
-
- if(control->gpsm_dcm_callback_enable_pstates != 0) {
- callbackRc =
- control->gpsm_dcm_callback_enable_pstates(&fwPacket);
- }
-
- break;
-
- case GPSM_IC_HW_PSTATE_MODE:
-
- slaveRc = gpsm_hw_mode();
-
- if(control->gpsm_dcm_callback_hw_pstate_mode != 0) {
- callbackRc =
- control->gpsm_dcm_callback_hw_pstate_mode(&fwPacket);
- }
-
- break;
-
- case GPSM_IC_WRITE:
- slaveRc = control->write_handler(control->buffer,
- control->buffer_size,
- control->write_arg);
- break;
- default:
- slaveRc = GPSM_DCM_PKT_INVALID_CMD_RCV;
- break;
- }
-
- if(fwPacket.command != GPSM_IC_WRITE) {
- protocolRc = gpsm_dcm_write((void*)(&slaveRc),
- sizeof(int),
- SSX_WAIT_FOREVER);
- }
- } while(0);
-
- control->protocol_rc = protocolRc;
- control->slave_rc = slaveRc;
- control->callback_rc = callbackRc;
-
- if (protocolRc == GPSM_DCM_RECV_PACKET_TIMEOUT) {
- rc = GPSM_DCM_SLAVE_TIMEOUT;
- } else if (protocolRc || slaveRc || callbackRc) {
- rc = GPSM_DCM_SLAVE_ERROR;
- } else {
- rc = 0;
- }
-
- TRACE_GPSM_B(TRACE_GPSM_DCM_SLAVE_COMPLETE, fwPacket.command);
-
- return rc;
-}
-
-
-/// Master an abstract transaction with a return code response from the slave
-///
-/// \param fwPacket A legal, initalized GpsmDcmPacket. This packet may be of
-/// any type other than GPSM_IC_DATA or GPSM_IC_WRITE. The GPSM_IC_WRITE does
-/// not get a response from the slave.
-///
-/// \param slaveRc The return code from running the protocol action on the
-/// slave. This includes any return code from a callback installed on the
-/// slave. If the return value of the function is non-0 then \a slaveRc is
-/// considered undefined.
-///
-/// This API send \a fwPacket to the slave and blocks waiting for the slave to
-/// respond with the \a slaveRc. The return value of the API indicates any
-/// problems with sending the packet or receiving the response.
-
-int
-gpsm_dcm_master(GpsmDcmPacket* fwPacket, int* slaveRc)
-{
- int rc;
- uint16_t size;
-
- do {
-
- rc = gpsm_dcm_send(fwPacket);
- if(rc) break;
-
- rc = gpsm_dcm_read((void*)slaveRc,
- sizeof(int),
- &size,
- SSX_WAIT_FOREVER);
- if(rc) break;
-
- //check if command_reply has correct size
- SSX_ERROR_IF_CHECK_API((size != sizeof(int)),
- GPSM_DCM_CMD_REPLY_NOT_INT);
-
- }while(0);
-
- return rc;
-}
diff --git a/src/lib/gpsm_dcm.h b/src/lib/gpsm_dcm.h
deleted file mode 100755
index 407ddbb..0000000
--- a/src/lib/gpsm_dcm.h
+++ /dev/null
@@ -1,192 +0,0 @@
-#ifndef __GPSM_DCM_H__
-#define __GPSM_DCM_H__
-
-// $Id: gpsm_dcm.h,v 1.2 2014/02/03 01:30:24 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpsm_dcm.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpsm_dcm.h
-/// \brief PgP Global PState Machine (Mechanism) in Dual Chip Model
-
-#include "pmc_dcm.h"
-
-/// GPSM-DCM Return Code
-#define GPSM_DCM_SUCCESS 0
-#define GPSM_DCM_ARG_INVALID_OBJ_SND 0x00326401 //ssx panic
-#define GPSM_DCM_ARG_INVALID_OBJ_RCV 0x00326402 //ssx panic
-#define GPSM_DCM_ARG_INVALID_OBJ_WRT 0x00326403 //ssx panic
-#define GPSM_DCM_ARG_INVALID_OBJ_RED 0x00326404 //ssx panic
-#define GPSM_DCM_PKT_INVALID_CMD_SND 0x00326405 //ssx panic
-#define GPSM_DCM_PKT_INVALID_CMD_RCV 0x00326406 //ssx panic
-#define GPSM_DCM_CMD_NOT_FROM_MASTER 0x00326407 //ssx panic
-#define GPSM_DCM_CMD_SHOULD_TO_SLAVE 0x00326408 //ssx panic
-#define GPSM_DCM_SEND_PACKET_TIMEOUT 0x00326409 //user handle
-#define GPSM_DCM_RECV_PACKET_TIMEOUT 0x0032640a //user handle
-#define GPSM_DCM_READ_RECV_NOT_WRITE 0x0032640b //ssx panic
-#define GPSM_DCM_READ_NOT_WRITE_DATA 0x0032640c //ssx panic
-#define GPSM_DCM_DAT_BIGGER_THAN_BUF 0x0032640d //user handle
-#define GPSM_DCM_CMD_REPLY_NOT_INT 0x0032640e //ssx panic
-#define GPSM_DCM_SLAVE_TIMEOUT 0x0032640f //user handle
-#define GPSM_DCM_SLAVE_ERROR 0x00326410 //user handle
-
-/// GPSM Interchip Command Code
-#define GPSM_IC_DATA 0 //0b0000
-#define GPSM_IC_WRITE 1 //0b0001
-#define GPSM_IC_ENABLE_PSTATES 2 //0b0010
-#define GPSM_IC_HW_PSTATE_MODE 3 //0b0011
-
-#define GPSM_DCM_NUMBER_OF_COMMANDS 4
-
-/// This is a special command return code returned by gpsm_dcm_slave() when it
-/// times out.
-#define GPSM_IC_NO_COMMAND GPSM_DCM_NUMBER_OF_COMMANDS
-
-
-/// Timeout Parameter
-#define GPSM_DCM_DEFAULT_TIMEOUT SSX_MICROSECONDS(15)
-
-#ifndef __ASSEMBLER__
-
-/// GPSM-DCM abstract packet
-
-typedef struct {
- /// Firmware command
- uint8_t command : 4;
- union {
- /// Used for Pstate-based protocols
- Pstate pstate[2];
- /// Generic byte data
- uint8_t u8[2];
- } payload;
-} GpsmDcmPacket;
-
-/// Data Structure for Fast Write/Read Handlers
-
-typedef struct {
- void* buffer_pointer;
- uint32_t remaining_size;
- SsxSemaphore fast_semaphore;
-} GpsmDcmFastData;
-
-/// Data Structure for Sync Mehotds
-
-
-/// Abstract type of gpsm_dcm_slave() callbacks
-///
-/// The callback receives the (first) master packet of the exchange. The
-/// return code is passed back to the master.
-
-typedef int (*GpsmDcmSlaveCallback)(GpsmDcmPacket* fwPacket);
-
-
-/// Control structure for gpsm_dcm_slave()
-
-typedef struct {
- /// Slave timeout when waiting for next packet to arrive in long commands.
- SsxInterval timeout;
-
- /// Callback called after "Enable Pstates" command
- GpsmDcmSlaveCallback gpsm_dcm_callback_enable_pstates;
-
- /// Callback called after "Enter HW Pstate Mode" command
- GpsmDcmSlaveCallback gpsm_dcm_callback_hw_pstate_mode;
-
- /// Callback for GPSM-DCM write command
- ///
- /// Will be called with the application-supplied buffer and the actual
- /// size of the data transmission.
- int (*write_handler)(void* buffer, uint16_t size, void* arg);
-
- /// Application-supplied buffer for GPSM-DCM write commands
- void* buffer;
-
- /// Size of the application-supplied write buffer
- uint16_t buffer_size;
-
- /// Application-supplied generic argument to the write handler
- void* write_arg;
-
- /// Callback when slave detects timeout from master
- GpsmDcmSlaveCallback timeout_handler;
-
- /// The last command recieved by the slave.
- int command;
-
- /// Return code from gpsm_dcm protocol actions
- int protocol_rc;
-
- /// Return code from slave action in response to master command
- int slave_rc;
-
- /// Return code from the application specific callback, if any.
- int callback_rc;
-
-} GpsmSlaveControl;
-
-////////////////////////////////////////////////////////////////////////////
-// High-level GPSM-DCM Interchip Communication Methods
-////////////////////////////////////////////////////////////////////////////
-
-int
-gpsm_dcm_send(GpsmDcmPacket* fwPacket);
-
-
-
-int
-gpsm_dcm_receive(GpsmDcmPacket* fwPacket,
- SsxInterval timeout_period);
-
-
-////////////////////////////////////////////////////////////////////////////
-// Generic Data Communication using GPSM-DCM 'write' command
-////////////////////////////////////////////////////////////////////////////
-
-int
-gpsm_dcm_write(void* buf,
- uint16_t size,
- SsxInterval timeout_period);
-
-
-int
-gpsm_dcm_read(void* buf,
- uint16_t buf_size,
- uint16_t* data_size,
- SsxInterval timeout_period);
-
-////////////////////////////////////////////////////////////////////////////
-// Fast Interrrupt Handlers for Data Transfer of GPSM-DCM 'write' command
-////////////////////////////////////////////////////////////////////////////
-
-SSX_IRQ_HANDLER(gpsm_dcm_fast_write);
-SSX_IRQ_HANDLER(gpsm_dcm_fast_read);
-
-////////////////////////////////////////////////////////////////////////////
-// Generic Synchronization Mechanism using GPSM-DCM 'write' command
-////////////////////////////////////////////////////////////////////////////
-
-int
-gpsm_dcm_sync(int state);
-
-////////////////////////////////////////////////////////////////////////////
-// The Control Method for Slave Thread
-////////////////////////////////////////////////////////////////////////////
-
-int
-gpsm_dcm_slave(GpsmSlaveControl *control,
- SsxInterval wait);
-
-
-////////////////////////////////////////////////////////////////////////////
-// The Command Method for Master Thread
-////////////////////////////////////////////////////////////////////////////
-
-int
-gpsm_dcm_master(GpsmDcmPacket* fwPacket, int* slaveRc);
-
-#endif /* __ASSEMBLER__ */
-
-#endif /* __GPSM_DCM_H__ */
diff --git a/src/lib/gpsm_dcm_fast_handler.S b/src/lib/gpsm_dcm_fast_handler.S
deleted file mode 100755
index 01cbb2d..0000000
--- a/src/lib/gpsm_dcm_fast_handler.S
+++ /dev/null
@@ -1,147 +0,0 @@
-// $Id: gpsm_dcm_fast_handler.S,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-
-/// \file gpsm_dcm_fast_handler.S
-/// \brief Assembler support for GPSM_DCM procedures
-/// \cond
- .nolist
-#include "ssx.h"
-#include "pmc_dcm.h"
-#include "gpsm_dcm.h"
- .list
-
-#define GPSM_IC_CONTINUOUS_DATA (PMC_IC_MSG_CC << 4 | GPSM_IC_DATA)
-
- // The gpsm_dcm_write fast handler.
-
- // Register use:
- //
- // R3 = Entry: void *arg; *arg -> GpsmDcmFast
- // R4 = Entry: SsxIrqId irq; irq : constant
- // R5 = Entry: int priority; priority -> data
- // R6 = data_pointer
- // R7 = remaining_size
- // CR = <condition>
- // LR = <return address>
- // No other registers can be used, other than SPRG
-
- .global_function gpsm_dcm_fast_write
-
-gpsm_dcm_fast_write:
-
- _ssx_irq_status_clear %r4, %r6, %r7 //clear status first
-
- lwz %r6, 0(%r3) //load data pointer
- lwz %r7, 4(%r3) //load remaining size
-
- cmpwi %r7, 0 //if size == 0
- beq exit_write_handler //exit fast write
- cmpwi %r7, 1 //if size == 1
- beq load_one_byte //load only one byte
-
- lhz %r5, 0(%r6) //otherwise load two bytes
- addi %r6, %r6, 2 //data pointer+2
- addi %r7, %r7,-2 //remaining size-2
- b form_and_send_packet //then form and send packet
-
-load_one_byte:
-
- lbz %r5, 0(%r6) //load one byte from buffer
- addi %r6, %r6, 1 //data pointer+1
- addi %r7, %r7,-1 //remaining size-1
-
-form_and_send_packet:
-
- stw %r6, 0(%r3) //store updated data pointer
- stw %r7, 4(%r3) //store updated remaining size
-
- lis %r6, GPSM_IC_CONTINUOUS_DATA //load cmd code to upper bits
- or %r5, %r5, %r6 //load data into lower bits
- slwi %r5, %r5, 8 //packet<<8 to give ecc field
- _stwi %r5, %r7, PMC_INTCHP_MSG_WDATA //send packet
- blr //return
-
-exit_write_handler:
-
- bl __ssx_irq_fast2full //convert fast to full irq handler
- _ssx_irq_disable %r4, %r6, %r7 //disable this irq
- addi %r3, %r3, 8 //argument pointer to semaphore
- bl ssx_semaphore_post //post to that semaphore
- b __ssx_irq_full_mode_exit //exit
-
- .epilogue gpsm_dcm_fast_write
-
-
-
- // The gpsm_dcm_read fast handler.
-
- // Register use:
- //
- // R3 = Entry: void *arg; *arg -> GpsmDcmFast(data,size,semaphore)
- // R4 = Entry: SsxIrqId irq; irq : constant
- // R5 = Entry: int priority; priority -> data
- // R6 = data_pointer
- // R7 = remaining_size
- // CR = <condition>
- // LR = <return address>
- // No other registers can be used, other than SPRG
-
- .global_function gpsm_dcm_fast_read
-
-gpsm_dcm_fast_read:
-
- _ssx_irq_status_clear %r4, %r6, %r7 //clear status first
-
- lwz %r7, 4(%r3) //load remaining size
- cmpwi %r7, 0 //if size == 0
- beq exit_read_handler //then exit fast read
-
- _lwzi %r6, %r7, PMC_INTCHP_MSG_RDATA //receive packet
-
- extrwi %r5, %r6, 16, 8 //extract data to r5
- extrwi %r6, %r6, 8, 0 //extract cmd code to r6
- li %r7, GPSM_IC_CONTINUOUS_DATA //designated cmd code to r7
-
- cmpw %r6, %r7 //compare and check cmd code
- bne panic_read_packet //panic on wrong cmd code
-
- lwz %r6, 0(%r3) //load data pointer
- lwz %r7, 4(%r3) //load remaining size
-
- cmpwi %r7, 1 //if only one byte left
- beq store_one_byte //then store only one byte
-
- sth %r5, 0(%r6) //otherwise store two bytes to buf
- addi %r6, %r6, 2 //data pointer+2
- addi %r7, %r7,-2 //remaining size-2
- b check_read_status //check read status
-
-store_one_byte:
-
- stb %r5, 0(%r6) //store one byte to buf
- addi %r6, %r6, 1 //data pointer+1
- addi %r7, %r7,-1 //remaining size-1
-
-check_read_status:
-
- stw %r6, 0(%r3) //store updated data pointer
- stw %r7, 4(%r3) //store updated remaining size
-
- cmpwi %r7, 0 //if size == 0
- beq exit_read_handler //then terminate fast read
- blr //return if still data left
-
-exit_read_handler:
-
- bl __ssx_irq_fast2full //convert fast to full irq handler
- _ssx_irq_disable %r4, %r6, %r7 //disable this irq
- addi %r3, %r3, 8 //argument pointer to semaphore
- bl ssx_semaphore_post //post to that semaphore
- b __ssx_irq_full_mode_exit //exit
-
-panic_read_packet:
-
- SSX_PANIC(GPSM_DCM_READ_NOT_WRITE_DATA) //PANIC if cmd code is wrong
-
- .epilogue gpsm_dcm_fast_read
-/// \endcond
-
diff --git a/src/lib/gpsm_init.c b/src/lib/gpsm_init.c
deleted file mode 100755
index ff0f68b..0000000
--- a/src/lib/gpsm_init.c
+++ /dev/null
@@ -1,1639 +0,0 @@
-// $Id: gpsm_init.c,v 1.10 2015/05/16 17:43:12 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpsm_init.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file gpsm_init.c
-/// \brief Global Pstate Machine procedures only required to initialize Pstate
-/// and Pstate modes.
-///
-/// In OCC product firmware this code is only needed immediately after IPL to
-/// set up Pstate tables and enable Pstates. This code could be run from an
-/// applet or otherwise removed once Pstates are initialized. Note that this
-/// file cointains code only; some global variables referenced here are
-/// defined in gpsm.c, along with the run-time APIs for GPSM.
-///
-/// The following sequence of procedures is required to initialize the GPSM
-/// mechanism, enable Pstate mode, and further enable Hardware Pstate Mode.
-///
-/// \code
-///
-/// PstateSuperStructure* pss;
-/// GlobalPstateTable *gpst;
-/// GpsmEnablePstatesMasterInfo info;
-/// Pstate voltage_pstate, frequency_pstate;
-///
-/// gpsm_initialize(pss, gpst);
-/// gpsm_enable_pstates_master(&info, &voltage_pstate, &frequency_pstate);
-/// gpsm_enable_pstates_slave(&info, voltage_pstate, frequency_pstate);
-/// gpsm_hw_mode();
-///
-/// \endcode
-///
-/// Executing these procedures enables Pstate control of voltage and
-/// frequency, and leaves the chip quiesced in Firmware Pstate mode. These
-/// procedures initializes both central (PMC) and remote (PCB Slave) Pstate
-/// hardware to fully enable Pstate control of voltage and frequency.
-/// Carefully note the procedure sequence preconditions and postconditions.
-///
-/// In the case of a DCM environment, the DCM master must execute the sequence
-/// as follows:
-///
-/// \code
-///
-/// PstateSuperStructure* pss;
-/// GlobalPstateTable *gpst;
-/// GpsmEnablePstatesMasterInfo info;
-/// Pstate voltage_pstate, frequency_pstate;
-///
-/// gpsm_initialize(pss, gpst);
-/// gpsm_enable_pstates_master(&info, &voltage_pstate, &frequency_pstate);
-///
-/// <em> Send voltage_pstate and frequency_pstate to the slave and wait for
-/// confirmation that the procedure has completed. </em>
-///
-/// gpsm_enable_pstates_slave(&info, voltage_pstate, frequency_pstate);
-/// gpsm_hw_mode();
-///
-/// <em> Send command to the slave to execute gpsm_hw_mode() </em>
-///
-/// \endcode
-///
-/// The DCM slave executes the following sequence
-/// \code
-/// PstateSuperStructure* pss;
-/// GlobalPstateTable *gpst;
-/// Pstate voltage_pstate, frequency_pstate;
-///
-/// gpsm_initialize(pss, gpst);
-///
-/// <em> Receive voltage_pstate and frequency_pstate from the masterand wait for
-/// confirmation that the procedure has completed. </em>
-///
-/// gpsm_enable_pstates_slave(0, voltage_pstate, frequency_pstate);
-///
-/// <em> Wait for a command from the master to execute gpsm_hw_mode(). </em>
-///
-/// \endcode
-///
-/// <b> Preconditions </b>
-///
-/// - This sequence must be called from a thread as it must be able to block
-/// for the completion of GPSM events.
-///
-/// - The fundamental precondition is the assumption that any snapshot of the
-/// voltage/frequency state of the system yields a legal state. As long as
-/// this is true, then this sequence should never take the system to an
-/// illegal V/F state.
-///
-/// - CPM-DPLL mode should be disabled, and all undervolting controls are
-/// assumed to be at their nominal values. Correctness can not guaranteed
-/// otherwise.
-///
-/// - iVRM mode should be disabled prior to calling this procedure.
-/// Correctness can not be guaranteed otherwise.
-///
-///
-/// <b> Standard/Benign Postconditions after executing
-/// gpsm_enable_pstates_slave() </b>
-///
-/// - The system will be in Firmware Pstate Mode, using the Local and Global
-/// Pstate tables installed by gpsm_initialize(). Pstate 0 will be mapped to
-/// the nominal frequency (modulo rounding down) of the
-/// 'nominal_frequency_khz' field of the Global Pstate table.
-///
-/// - All core chiplet frequencies will be under the control of the PMCR Local
-/// Pstate.
-///
-/// - The Global Actual Pstate immediately prior to the final entry of Pstate
-/// mode is the Pstate that most closely matches an arbitrary snapshot of the
-/// system voltage during the execution of this procedure.
-///
-/// - The PMCR and PMICR are not modified, therefore the Global Pstate
-/// subsequent to the release of Hardware Pstate mode is arbitrary.
-///
-/// - The PMC_RAIL_BOUNDS register is set to the maximum legal bounds allowed
-/// by Global Pstate Table
-///
-/// - IVRM is setup and enabled if Local Pstate Table is installed.
-///
-/// - Resonant Clock is setup and enabled if Resonant Clock is installed.
-///
-/// <b> Side-Effects </b>
-///
-/// - The dpll_fmax and dpll_fmin fields of the FREQ_CTRL_REG in each core are
-/// set to an arbitrary value. The dpll_fmax_bias is set to the value of the
-/// 'dpll_fmax_bias' field of the \a gpst.
-///
-/// - The core-level PCBS_POWER_MANAGEMENT_BOUNDS_REG registers are
-/// set to the maximum legal bounds. This is required due to Pstate table
-/// constraints.
-///
-/// \todo - How to handle redundant SPIVID interfaces? Here we get the
-/// current volatge from interface 0.
-///
-/// \bug Check to make sure that the PMC_CORE_DECONFIGURATION_REG matches
-/// multicast group 1.
-///
-/// \bug Code marked with ** VBU ** is necessary for VBU/EPO simulation, needs
-/// to be scrubbed once this is working in VBU.
-
-#include "ssx.h"
-#include "ssx_io.h"
-#include "gpsm.h"
-#include "vrm.h"
-#include "heartbeat.h"
-#include "special_wakeup.h"
-
-// Debugging support
-
-#if 0
-#define _BREAK \
- { \
- fprintf(stderr, "%s:%d: _BREAK trapped error rc = 0x%08x (-0x%08x)\n", \
- __FILE__, __LINE__, rc, -rc); \
- SSX_PANIC(GPSM_ERROR_BREAK); \
- }
-#else
-#define _BREAK break;
-#endif
-
-
-/// Flag set once gpsm_initialize() has been successfully completed.
-uint8_t G_gpsm_initialized = 0;
-
-
-/// Install a (new) Global Pstate Table
-///
-/// \param[out] o_gpst A pointer to a properly-aligned GlobalPstateTable
-///
-/// \param[in] i_source A pointer to an initialized source GlobalPstateTable
-/// that will be copied to \a gpst (if not in fact the same as \a gpst).
-///
-/// This procedure will likely only be called once, at initialization, and
-/// then only as part of the gpsm_initialize() procedure. The procedure:
-///
-/// - Copies the \a source to the \a gpst if required.
-///
-/// - Installs a pointer to the Global Pstate Table in the PMC hardware.
-///
-/// - Sets up the PMC Pstate clipping bounds.
-///
-/// - Sets up the Pstate stepping parameters from the GlobalPstateTable
-///
-/// - Clears the local undervolting register (via multicast) and sets the
-/// default undervolting bounds to the entire Local Pstate Table.
-///
-/// - Broadcasts the safe mode Pstate Psafe to the cores and clears the other
-/// fields of the PCBS_OCC_HEARTBEAT_REG, disabling the heartbeat timer.
-/// However the heartbeat timer must not have been active anyway.
-///
-/// \note This procedure does modify the rail bounds.
-///
-/// \note The caller is responsible for the mode-correctness of this
-/// procedure. This procedure must only be called when the PMC is in Firmware
-/// Pstate Mode.
-///
-/// \retval 0 Success
-///
-/// \retval -GPSM_INVALID_ARGUMENT_GPST_INSTALL The Global Pstate table argument
-/// was either NULL (0) or improperly aligned, or the \a source was NULL (0).
-///
-/// \retval -GPSM_ILLEGAL_MODE_GPST_INSTALL The PMC does not indicate that the
-// system is in Firmware Pstate Mode, or the heartbeat is enabled.
-
-int
-gpsm_gpst_install(GlobalPstateTable* o_gpst,
- const GlobalPstateTable* i_source)
-{
- pmc_occ_heartbeat_reg_t pohr;
- pmc_parameter_reg0_t ppr0;
- pmc_parameter_reg1_t ppr1;
- pmc_global_pstate_bounds_reg_t pgpbr;
- pmc_rail_bounds_register_t prbr;
- pmc_undervolting_reg_t pur;
- pcbs_occ_heartbeat_reg_t pcbsohr;
-
- int rc;
-
- TRACE_GPSM(TRACE_GPSM_GPST_INSTALL);
-
- do {
-
- // Optional bypass of the procedure
-
- if (i_source->options.options & PSTATE_NO_INSTALL_GPST) {
-
- rc = 0;
- break;
- }
-
- // Check presence and alignment of the Pstate table, and proper Pstate
- // and heartbeat modes.
-
- if ((o_gpst == 0) ||
- ((unsigned long)o_gpst % POW2_32(GLOBAL_PSTATE_TABLE_ALIGNMENT))) {
- rc = -GPSM_INVALID_ARGUMENT_GPST_INSTALL;
- _BREAK;
- }
-
- pohr.value = in32(PMC_OCC_HEARTBEAT_REG);
- rc = getscom(MC_ADDRESS(PCBS_OCC_HEARTBEAT_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(pcbsohr.value));
- if (rc) _BREAK;
-
- if (!gpsm_fw_mode_p() || pohr.fields.pmc_occ_heartbeat_en
- || pcbsohr.fields.occ_heartbeat_enable) {
- rc = -GPSM_ILLEGAL_MODE_GPST_INSTALL;
- _BREAK;
- }
-
-
- // Copy \a source to \a gpst if required, then install the Pstate
- // table, Pvsafe and Pstate stepping parameters, and set the clipping
- // bounds as well as the rail bounds
-
- if ((o_gpst != i_source) &&
- !(i_source->options.options & PSTATE_NO_COPY_GPST)) {
-
- memcpy(o_gpst, i_source, sizeof(*o_gpst));
- }
-
- ppr1.value = in32(PMC_PARAMETER_REG1);
- ppr1.fields.ba_sram_pstate_table =
- (unsigned long)o_gpst >> GLOBAL_PSTATE_TABLE_ALIGNMENT;
- ppr1.fields.pvsafe = i_source->pvsafe;
-
- // This fix is added per SW260911
- // Minimum Frequency in the system is given by MRW attribute
- // PState Datablock procedure will read the attribute then
- // convert it into pstate _pfloor_ and put it into
- // Global Pstate Table. GPSM here consumes the value
- // and set both lower bounds: pmin_rail(PMC) and pmin_clip(PCBS)
- // and two safe pstates: pvsafe(PMc) and psafe(PCBS) to be
- // _pfloor_ if _pfloor_ is higher than their default(gpst_pmin)
- // so that we should never run with frequency below the floor
- // even in safe mode
- if (ppr1.fields.pvsafe < i_source->pfloor && i_source->pfloor != 0)
- ppr1.fields.pvsafe = i_source->pfloor;
-
- out32(PMC_PARAMETER_REG1, ppr1.value);
-
- pgpbr.value = 0;
- pgpbr.fields.gpsi_min = gpst_pmin(i_source) - PSTATE_MIN;
- pgpbr.fields.gpst_number_of_entries_minus_one = i_source->entries - 1;
- out32(PMC_GLOBAL_PSTATE_BOUNDS_REG, pgpbr.value);
-
- ppr0.value = in32(PMC_PARAMETER_REG0);
- ppr0.fields.pstate_stepsize = i_source->pstate_stepsize;
- ppr0.fields.vrm_stepdelay_range = i_source->vrm_stepdelay_range;
- ppr0.fields.vrm_stepdelay_value = i_source->vrm_stepdelay_value;
- ppr0.fields.gpsa_timeout_value_sel = 1;
- out32(PMC_PARAMETER_REG0, ppr0.value);
-
- prbr.value = 0;
- prbr.fields.pmin_rail = gpst_pmin(i_source)+1;
- prbr.fields.pmax_rail = gpst_pmax(i_source);
-
- // This fix is added per SW260911
- // Minimum Frequency in the system is given by MRW attribute
- // PState Datablock procedure will read the attribute then
- // convert it into pstate _pfloor_ and put it into
- // Global Pstate Table. GPSM here consumes the value
- // and set both lower bounds: pmin_rail(PMC) and pmin_clip(PCBS)
- // and two safe pstates: pvsafe(PMc) and psafe(PCBS) to be
- // _pfloor_ if _pfloor_ is higher than their default(gpst_pmin)
- // so that we should never run with frequency below the floor
- // even in safe mode
- if (prbr.fields.pmin_rail < i_source->pfloor && i_source->pfloor != 0)
- prbr.fields.pmin_rail = i_source->pfloor;
-
- out32(PMC_RAIL_BOUNDS_REGISTER, prbr.value);
-
- // Clear the undervolting control, and set the undervolting range to
- // the entire Global Pstate Table range.
-
- pur.value = 0;
- pur.fields.puv_min = gpst_pmin(i_source);
- pur.fields.puv_max = gpst_pmax(i_source);
- pur.fields.kuv_request = 0;
- out32(PMC_UNDERVOLTING_REG, pur.value);
-
-
- // Broadcast the safe mode Pstate Psafe to the cores, disabling the
- // heartbeat (which must have been disabled anyway) and clearing any
- // other heartbeat setup.
-
- pcbsohr.value = 0;
- pcbsohr.fields.psafe = i_source->psafe;
-
- // This fix is added per SW260911
- // Minimum Frequency in the system is given by MRW attribute
- // PState Datablock procedure will read the attribute then
- // convert it into pstate _pfloor_ and put it into
- // Global Pstate Table. GPSM here consumes the value
- // and set both lower bounds: pmin_rail(PMC) and pmin_clip(PCBS)
- // and two safe pstates: pvsafe(PMc) and psafe(PCBS) to be
- // _pfloor_ if _pfloor_ is higher than their default(gpst_pmin)
- // so that we should never run with frequency below the floor
- // even in safe mode
- if (pcbsohr.fields.psafe < i_source->pfloor && i_source->pfloor != 0)
- pcbsohr.fields.psafe = i_source->pfloor;
-
- rc = putscom(MC_ADDRESS(PCBS_OCC_HEARTBEAT_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- pcbsohr.value);
- if (rc) _BREAK;
-
- rc = 0;
-
- } while(0);
-
- return rc;
-}
-
-
-/// Install a (new) Local Pstate Array
-///
-/// \param[in] i_lpsa A pointer to a LocalPstateArray to install in every
-/// configured core.
-///
-/// \param[in] i_options Options controlling the installation, or a NULL (0)
-/// pointer to indicate fully default behavior.
-///
-/// This procedure will likely only be called once, at initialization, and
-/// then only as part of the gpsm_initialize() procedure. The procedure:
-///
-/// - Power on PFET Voltage Reference Circuit
-///
-/// - Perform the binary search for IVRM Calibration
-///
-/// - Uploads the LocalPstateArray to every core using multicast.
-///
-/// - Sets up the Local Pstate table bounds in every core using multicast.
-///
-/// - Sets the step delay parameters for every core using multicast.
-///
-/// - Clears the local undervolting register (via multicast) and sets the
-/// default undervolting bounds to the entire Local Pstate Table.
-///
-/// - Setup IVRM delay parameters
-///
-/// - Enable IVRM
-///
-/// \note This procedure \e does \e not modify the rail bounds.
-///
-/// \note The caller is responsible for the mode-correctness of this
-/// procedure. This procedure must only be called when the iVRM are
-/// disabled, the DPLL is in "normal" (not CPM-DPLL) mode, and core heartbeats
-/// are disabled.
-///
-/// \retval 0 Success
-///
-/// \retval -GPSM_INVALID_ARGUMENT_LPST_INSTALL The Local Pstate array argument
-/// was NULL (0).
-///
-/// \retval -GPSM_ILLEGAL_MODE_LPST_INSTALL iVRM mode, CPM-DPLL mode, or the
-/// local heartbeat appears to be enabled in at least one core.
-///
-/// \retval -GPSM_IVRM_CALIBRATION_TIMEOUT, if IVRM Calibration does not
-/// complete in time.
-///
-/// \retval -GPSM_IVRM_GROSS_OR_FINE, if ivrm_gross_or_fine_err is set
-///
-/// \retval -GPSM_PSTATE_ENABLED, if pstate is enabled before enabling IVRM
-///
-/// \retval others This API may also return non-0 codes from
-/// getscom()/putscom()
-
-int
-gpsm_lpsa_install(const LocalPstateArray* i_lpsa,
- const PstateOptions* i_options)
-{
- pcbs_ivrm_control_status_reg_t picsr;
- pcbs_dpll_cpm_parm_reg_t pdcpr;
- pcbs_pstate_index_bound_reg_t ppibr;
- pcbs_ivrm_vid_control_reg0_t pivcr0;
- pcbs_ivrm_vid_control_reg1_t pivcr1;
- pcbs_undervolting_reg_t pur;
- pcbs_pmerr_reg_t ppr;
- pcbs_pcbspm_mode_reg_t ppmr;
- pmc_core_deconfiguration_reg_t pcdr;
- ChipConfigCores cores, wakedup;
- SsxTimebase timeout;
- int i, rc, timeout_rc = 0;
- uint32_t configured_cores;
- int flag, core;
-
- TRACE_GPSM(TRACE_GPSM_LPSA_INSTALL);
-
- do {
-
- // Optional bypass of this procedure
-
- if ((i_options != 0) &&
- (i_options->options & PSTATE_NO_INSTALL_LPSA)) {
-
- rc = 0;
- break;
- }
-
- // No LPST Install and IVRM Enable if there is no configued cores
-
- configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG);
- flag = 1;
- for (core = 0; core < PGP_NCORES; core++, configured_cores <<= 1) {
- if (!(configured_cores & 0x80000000)) continue;
- flag = 0;
- }
- if (flag == 1) {
- rc = 0;
- break;
- }
-
- // Check the array for existence. Do an OR-combining multicast read
- // to see if any of the cores have iVRM enabled, have the heartbeat
- // enabled, or any cores are running in CPM-DPLL mode.
-
- if (i_lpsa == 0) {
- rc = -GPSM_INVALID_ARGUMENT_LPST_INSTALL;
- _BREAK;
- }
- rc = getscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(picsr.value));
- if (rc) _BREAK;
- rc = getscom(MC_ADDRESS(PCBS_DPLL_CPM_PARM_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(pdcpr.value));
- if (rc) _BREAK;
-
- if (picsr.fields.ivrm_fsm_enable ||
- pdcpr.fields.cpm_filter_enable) {
- rc = -GPSM_ILLEGAL_MODE_LPST_INSTALL;
- _BREAK;
- }
-
- // In case cores are in deep winkle so that ivrm caliburation
- // will fail, insert special wakeup first
- pcdr.value = in32(PMC_CORE_DECONFIGURATION_REG);
- cores = ~pcdr.fields.core_chiplet_deconf_vector;
- rc = occ_special_wakeup(1, cores, 25, &wakedup);
- if (rc) _BREAK;
-
- // Power on PFET Voltage Reference Circuit
- picsr.fields.pvref_en = 1;
- rc = putscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- picsr.value);
- if (rc) _BREAK;
-
- // Wait 10us for circuit to power on
- timeout = ssx_timebase_get() + SSX_MICROSECONDS(10);
- while (ssx_timebase_get() < timeout) {;}
-
- // Perform the binary search
- picsr.fields.binsearch_cal_ena = 1;
- rc = putscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- picsr.value);
- if (rc) _BREAK;
-
- // Check IVRM Calibration is completed
- // Poll for up to 100us for done before erroring out
- timeout_rc = -GPSM_IVRM_CALIBRATION_TIMEOUT;
- timeout = ssx_timebase_get() + SSX_MICROSECONDS(100);
- while (ssx_timebase_get() < timeout) {
- rc = getscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_AND),
- &(picsr.value));
- if (rc) _BREAK;
- if (picsr.fields.binsearch_cal_done) {
- timeout_rc=0;
- break;
- }
- }
- if (timeout_rc||rc) _BREAK;
-
- // IVRM Calibration complete, Clear binary search enable
- picsr.fields.binsearch_cal_ena = 0;
- rc = putscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- picsr.value);
- if (rc) _BREAK;
-
- // Check if IVRM Gross or Fine Error is set after calibration!
- rc = getscom(MC_ADDRESS(PCBS_PMERR_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(ppr.value));
- if (rc) _BREAK;
- if (ppr.fields.pcbs_ivrm_gross_or_fine_err) {
- rc = -GPSM_IVRM_GROSS_OR_FINE;
- _BREAK;
- }
-
- // Deassert Special Wakeup
- rc = occ_special_wakeup(0, cores, 25, &wakedup);
- if (rc) _BREAK;
-
- // Upload the Local Pstate Array. The array is loaded via multicast,
- // using the built-in auto-increment mechanism. Then upload the
- // Pstate bounds register via multicast. Pstate clipping is not
- // modified.
-
- rc = putscom(MC_ADDRESS(PCBS_PSTATE_TABLE_CTRL_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- 0);
- if (rc) _BREAK;
-
- for (i = 0; i < LOCAL_PSTATE_ARRAY_ENTRIES+VDSVIN_ARRAY_ENTRIES; i++) {
-
- if (i < LOCAL_PSTATE_ARRAY_ENTRIES) {
- rc = putscom(MC_ADDRESS(PCBS_PSTATE_TABLE_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- i_lpsa->pstate[i].value);
- if (rc) _BREAK;
- } else {
- rc = putscom(MC_ADDRESS(PCBS_PSTATE_TABLE_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- i_lpsa->vdsvin[i-LOCAL_PSTATE_ARRAY_ENTRIES].value);
- if (rc) _BREAK;
- }
-
- }
-
- ppibr.value = 0;
- ppibr.fields.lpsi_min = lpst_pmin(i_lpsa) - PSTATE_MIN;
- ppibr.fields.lpsi_entries_minus_1 = i_lpsa->entries - 1;
- rc = putscom(MC_ADDRESS(PCBS_PSTATE_INDEX_BOUND_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- ppibr.value);
- if (rc) _BREAK;
-
-
- // Install the step delay parameters, then clear the undervolting
- // control (applicable to the entire range) via multicast.
-
- pivcr0.value = 0;
- if (i_lpsa->stepdelay_rising)
- pivcr0.fields.ivrm_req_pstate_stepdelay_rising =
- i_lpsa->stepdelay_rising;
- else
- pivcr0.fields.ivrm_req_pstate_stepdelay_rising = 0xFF;
- if (i_lpsa->stepdelay_lowering)
- pivcr0.fields.ivrm_req_pstate_stepdelay_lowering =
- i_lpsa->stepdelay_lowering;
- else
- pivcr0.fields.ivrm_req_pstate_stepdelay_lowering = 0XFF;
- rc = putscom(MC_ADDRESS(PCBS_IVRM_VID_CONTROL_REG0,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- pivcr0.value);
- if (rc) _BREAK;
-
- ///bug need to determine where these values come from
- pivcr1.value = 0;
- pivcr1.fields.ivrm_stabilize_delay_run = 0x40;
- pivcr1.fields.ivrm_stabilize_delay_idle = 0x40;
- pivcr1.fields.ivrm_pfstr_prop_delay = 0x1E;
- pivcr1.fields.ivrm_pfstrvalid_prop_delay = 0xFF;
- pivcr1.fields.ivrm_vpump_poweron_time = 0xFF;
- pivcr1.fields.ivrm_bypass_delay = 0x1E;
- pivcr1.fields.pfet_vpump_enable_delay = 0x4E;
- pivcr1.fields.ivrm_vid_vout_threshold = 0x00;
- rc = putscom(MC_ADDRESS(PCBS_IVRM_VID_CONTROL_REG1,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- pivcr1.value);
- if (rc) _BREAK;
-
- pur.value = 0;
- pur.fields.puv_min = lpst_pmin(i_lpsa);
- pur.fields.puv_max = lpst_pmax(i_lpsa);
- pur.fields.kuv = 0;
- rc = putscom(MC_ADDRESS(PCBS_UNDERVOLTING_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- pur.value);
- if (rc) _BREAK;
-
- // Set pre_vret_pstate to Non-Functional Pstate
- // \bug currently set to pmin, is it always same as psafe?
- rc = getscom(MC_ADDRESS(PCBS_DPLL_CPM_PARM_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(pdcpr.value));
- if (rc) _BREAK;
- pdcpr.fields.pre_vret_pstate = lpst_pmin(i_lpsa);
- rc = putscom(MC_ADDRESS(PCBS_DPLL_CPM_PARM_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- pdcpr.value);
- if (rc) _BREAK;
-
- // Checking that PStates are NOT enabled
- rc = getscom(MC_ADDRESS(PCBS_PCBSPM_MODE_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(ppmr.value));
- if (rc) _BREAK;
- if (ppmr.fields.enable_pstate_mode) {
- rc = -GPSM_PSTATE_ENABLED;
- _BREAK;
- }
-
- // Enable I-VRM FSM
- rc = getscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_OR),
- &(picsr.value));
- if (rc) _BREAK;
- picsr.fields.ivrm_fsm_enable = 1;
- rc = putscom(MC_ADDRESS(PCBS_IVRM_CONTROL_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- picsr.value);
- if (rc) _BREAK;
-
- } while (0);
-
- if (timeout_rc && !rc)
- return timeout_rc;
- else
- return rc;
-}
-
-
-/// Install (new) Resonant Clocking Setup
-///
-/// \param[in] i_resclk A pointer to a ResonantClockingSetup to install in
-/// every configured core.
-///
-/// \param[in] i_options Options controlling the installation, or a NULL (0)
-/// pointer to indicate fully default behavior.
-///
-/// This procedure will likely only be called once, at initialization, and
-/// then only as part of the gpsm_initialize() procedure. The procedure:
-///
-/// - Initializes the Pstate resonance range limits in the register
-/// PCBS_RESONANT_CLOCK_CONTROL_REG1 by multicast.
-///
-/// - Setup parameters in PCBS_RESONANT_CLOCK_CONTROL_REG0 and turn on
-/// Resonant Clock in Hardware Pstate Mode.
-///
-/// \note The caller is responsible for the mode-correctness of this
-/// procedure. This procedure must only be called when resonant clocking is
-/// disabled and the controls are set for manual mode. Because of the way the
-/// resonant clocking controls are designed we must enable resonant clocking
-/// to update the Pstate bounds! After the bounds are updated resonant
-/// clocking is disabled again.
-///
-/// \retval 0 Success
-///
-/// \retval -GPSM_INVALID_ARGUMENT_RCLK_INSTALL The ResonantClockingSetup
-/// argument was NULL (0).
-///
-/// \retval -GPSM_ILLEGAL_MODE_RCLK_INSTALL Resonant clocking appears to be
-/// enabled or not in manual mode in at least one configured core.
-///
-/// \retval others This API may also return non-0 codes from
-/// getscom()/putscom()
-
-int
-gpsm_resclk_install(const ResonantClockingSetup* i_resclk,
- const GlobalPstateTable* i_gpst,
- const PstateOptions* i_options)
-{
- ResonantClockingSetup d_resclk;
- pcbs_resonant_clock_control_reg0_t prccr0;
- pcbs_resonant_clock_control_reg1_t prccr1;
- int rc;
- uint32_t configured_cores;
- int flag, core;
-
- TRACE_GPSM(TRACE_GPSM_RESCLK_INSTALL);
-
- do {
-
- // Optional bypass of this procedure
-
- if ((i_options != 0) &&
- (i_options->options & PSTATE_NO_INSTALL_RESCLK)) {
-
- rc = 0;
- break;
- }
-
- // No Resonant Clock Install and Enable if there is no configued cores
-
- configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG);
- flag = 1;
- for (core = 0; core < PGP_NCORES; core++, configured_cores <<= 1) {
- if (!(configured_cores & 0x80000000)) continue;
- flag = 0;
- }
- if (flag == 1) {
- rc = 0;
- break;
- }
-
- // Check the setup for existence. Do an AND-combining multicast read
- // to see if any of the cores have resonant clocking enabled, or are
- // not in manual mode.
-
- if (i_resclk == 0) {
- rc = -GPSM_INVALID_ARGUMENT_RCLK_INSTALL;
- _BREAK;
- }
- rc = getscom(MC_ADDRESS(PCBS_RESONANT_CLOCK_CONTROL_REG0,
- MC_GROUP_EX, PCB_MULTICAST_AND),
- &(prccr0.value));
- if (rc) _BREAK;
-
- if (!prccr0.fields.resclk_dis || !prccr0.fields.resclk_control_mode) {
- rc = -GPSM_ILLEGAL_MODE_RCLK_INSTALL;
- _BREAK;
- }
-
-
- // Resonant clocking is specified such that it must be enabled (in a
- // benign manual mode) in order to be set up.
-
- // Enable resonant clocking in the GP3 register (AND), bit 22. Our
- // Simics environment does not model the GP3->PRCCR0 connection
- // currently, and does not enforce the register locks.
-
- if (!SIMICS_ENVIRONMENT) {
-
- rc = putscom(MC_ADDRESS(0x100f0013, MC_GROUP_EX,
- PCB_MULTICAST_WRITE),
- ~0x0000020000000000ull);
- if (rc) _BREAK;
- }
-
- // Write the PCBS_RESONANT_CLOCK_CONTROL_REG1 with the
- // Pstate setup, clearing all manual fields.
-
- // If at least one resonant clocking parm was 0 in PstateSuperStructure
- // write the register with default values
- // Low Band : 2 GHZ to 3.2 GHz
- // High Band : 3.2 GHZ - Up
-
- gpst_frequency2pstate(i_gpst, 0, &(d_resclk.full_csb_ps));
- gpst_frequency2pstate(i_gpst, 2000000, &(d_resclk.res_low_lower_ps));
- gpst_frequency2pstate(i_gpst, 3200000, &(d_resclk.res_low_upper_ps));
- gpst_frequency2pstate(i_gpst, 3200000, &(d_resclk.res_high_lower_ps));
- gpst_frequency2pstate(i_gpst, 9999999, &(d_resclk.res_high_upper_ps));
-
- prccr1.value = 0;
- if (!(i_resclk->full_csb_ps &&
- i_resclk->res_low_lower_ps &&
- i_resclk->res_low_upper_ps &&
- i_resclk->res_high_lower_ps &&
- i_resclk->res_high_upper_ps)) {
- prccr1.fields.full_csb_ps = d_resclk.full_csb_ps;
- prccr1.fields.res_low_lower_ps = d_resclk.res_low_lower_ps;
- prccr1.fields.res_low_upper_ps = d_resclk.res_low_upper_ps;
- prccr1.fields.res_high_lower_ps = d_resclk.res_high_lower_ps;
- prccr1.fields.res_high_upper_ps = d_resclk.res_high_upper_ps;
- } else {
- prccr1.fields.full_csb_ps = i_resclk->full_csb_ps;
- prccr1.fields.res_low_lower_ps = i_resclk->res_low_lower_ps;
- prccr1.fields.res_low_upper_ps = i_resclk->res_low_upper_ps;
- prccr1.fields.res_high_lower_ps = i_resclk->res_high_lower_ps;
- prccr1.fields.res_high_upper_ps = i_resclk->res_high_upper_ps;
- }
-
- ///bug need to determine where these values come from
- prccr1.fields.nonres_csb_value_ti = 0xC;
- prccr1.fields.full_csb_value_ti = 0xF;
-
- rc = putscom(MC_ADDRESS(PCBS_RESONANT_CLOCK_CONTROL_REG1,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- prccr1.value);
- if (rc) _BREAK;
-
-
- // Disable resonant clocking in the GP3 register (OR), bit 22.
-
- if (!SIMICS_ENVIRONMENT) {
-
- rc = putscom(MC_ADDRESS(0x100f0014, MC_GROUP_EX,
- PCB_MULTICAST_WRITE),
- 0x0000020000000000ull);
- if (rc) _BREAK;
- }
-
- // Enable resonant clock pstate hardware mode(control_mode = 0)
- // Sync Pulse Width maximum value : 0x7 of nest/4 cycles
- // Sync Delay maximum value : 0x7F of nest/4 cycles
- // Sector Buffer Strength Instruction . Low Band : 0xAAA
- // Sector Buffer Strength Instruction . High Band : 0xAAA
-
- prccr0.fields.resclk_control_mode = 0;
- prccr0.fields.resclk_sync_pw = 0x7;
- prccr0.fields.res_sync_delay_cnt = 0x7F;
- prccr0.fields.res_csb_str_instr_lo = 0xAAA;
- prccr0.fields.res_csb_str_instr_hi = 0x1FF;
-
- rc = putscom(MC_ADDRESS(PCBS_RESONANT_CLOCK_CONTROL_REG0,
- MC_GROUP_EX, PCB_MULTICAST_WRITE),
- prccr0.value);
- if (rc) break;
-
- // Enable resonant clocking in the GP3 register (AND), bit 22.
- if (!SIMICS_ENVIRONMENT) {
-
- rc = putscom(MC_ADDRESS(0x100f0013, MC_GROUP_EX,
- PCB_MULTICAST_WRITE),
- ~0x0000020000000000ull);
- if (rc) break;
- }
-
- } while (0);
-
- return rc;
-}
-
-
-/// Initialize the GPSM procedure mechanism
-///
-/// \param[in] i_pss A pointer to the PstateSuperStructure containing the
-/// Global and Local Pstate tables, plus resonant clocking setup and other
-/// options.
-///
-/// \param[out] o_gpst A pointer to a 1-KB aligned GlobalPstateTable which
-/// will be updated with a copy of the GlobalPstateTable from the
-/// PstateSuperStructure.
-///
-/// This API is designed to be called once at system initialization, to set up
-/// GPSM mechanisms, install the Global and Local Pstate tables, and set up
-/// resonant clocking from the PstateSuperStructure. At the entry of this
-/// procedure it is assumed that the system firmware has initialized the PMC
-/// mode register to either no mode, or to indicate Firmware Pstate Mode. It
-/// is further assumed that the core chiplets are in a state which will allow
-/// the Local Pstate tables and resonant clocking setup to be installed
-/// without affecting system stability. Such a state must be guaranteed at
-/// system initialization and after any OCC reset. If called from any other
-/// context the caller is responsible for ensuring that the system is in a
-/// state that will allow the procedure to run correctly.
-///
-/// This procedure does not enable Pstates or enter any Pstate mode, and does
-/// not alter any voltage or frequency settings. After the Pstate tables have
-/// been installed, Pstate mode is enabled by calls of
-/// gpsm_enable_pstates_master() and gpsm_enable_pstates_slave() as described
-/// in the commenst for gpsm_init.c.
-///
-/// The initialization of Pstates was split up into these three steps to best
-/// handle the initialization of the slave chip in a DCM. This procedure
-/// (gpsm_initialize()) can be called by the DCM slave whenever a
-/// PstateSuperStructure is available. By requirememt and convention this
-/// Pstate SuperStructure will be identical with the one installed by the DCM
-/// master.
-///
-/// The GPSM driver makes few assumptions about how the system firmware has
-/// set up the PMC, but does require some critical setup.
-///
-/// - It is assumed that for DCM configurations the system firmware will have
-/// set the PMC_MODE_REG.enable_interchip_interface (to indicate a DCM
-/// configuration), and set the PMC_MODE_REG.interchip_mode appropriately for
-/// the master and the slave.
-///
-/// - It is assumed that the PMC Core Deconfiguration register implies the
-/// same set of configured cores as the set included in the PCB multicast
-/// group covering all cores.
-///
-/// All GPSM procedures use the same semaphore, which is set by the interrupt
-/// handler for all GPSM interrupts. The GPSM driver claims the PMC protocol
-/// ongoing, voltage change ongoing, and PMC Sync interrupts.
-///
-/// Once the interrupts are set up, the GlobalPstateTable is copied from the
-/// PstateSuperStructure to its proper location and installed. Next, the
-/// Local Pstate tables and resonant clocking setup are installed into all
-/// cores by multicast SCOM.
-///
-/// \retval 0 Success
-///
-/// \retval -GPSM_INVALID_OBJECT Either the \a i_pss or \a o_gpst are NULL (0).
-///
-/// \retval -GPSM_INVALID_MAGIC The 'magic number' of the PstateSuperStructure
-/// is different from that expected.
-///
-/// \retval -GPSM_ILLEGAL_MODE_GPSM_INIT Either the PMC indicates a Pstate mode
-/// is active, one or more cores appear to have iVRM enabled, or one or more
-/// cores appear to have resonant clocking enabled.
-///
-/// \retval others This API may also return codes from gpsm_gpst_install(),
-/// gpsm_lpsa_install() and gpsm_resclk_install().
-
-int
-gpsm_initialize(const PstateSuperStructure* i_pss,
- GlobalPstateTable* o_gpst)
-{
- pmc_mode_reg_t pmr;
- int rc;
-
- TRACE_GPSM(TRACE_GPSM_INITIALIZE);
-
- do {
-
- // Check for a valid PstateSuperStructure and GlobalPstateTable
-
- if ((i_pss == 0) || (o_gpst == 0)) {
-
- rc = -GPSM_INVALID_OBJECT;
- _BREAK;
- }
-
- if (i_pss->magic != PSTATE_SUPERSTRUCTURE_GOOD1 &&
- i_pss->magic != PSTATE_SUPERSTRUCTURE_GOOD2 &&
- i_pss->magic != PSTATE_SUPERSTRUCTURE_GOOD3 &&
- i_pss->magic != PSTATE_SUPERSTRUCTURE_GOOD4) {
-
- rc = -GPSM_INVALID_MAGIC;
- _BREAK;
- }
-
-
- // Check/set up the PMC mode register
-
- pmr.value = in32(PMC_MODE_REG);
- if (pmr.fields.enable_hw_pstate_mode ||
- pmr.fields.enable_fw_auction_pstate_mode) {
- rc = -GPSM_ILLEGAL_MODE_GPSM_INIT;
- _BREAK;
- }
- if (!pmr.fields.enable_fw_pstate_mode) {
-
- pmr.fields.enable_fw_pstate_mode = 1;
- out32(PMC_MODE_REG, pmr.value);
- }
-
- // ** VBU **
- pmr.fields.halt_pstate_master_fsm = 0;
- out32(PMC_MODE_REG, pmr.value);
-
-
- // Initialize interrupt handling
-
- ssx_semaphore_create(&G_gpsm_protocol_semaphore, 0, 1);
-
- ssx_irq_disable(PGP_IRQ_PMC_PROTOCOL_ONGOING);
- ssx_irq_disable(PGP_IRQ_PMC_VOLTAGE_CHANGE_ONGOING);
- ssx_irq_disable(PGP_IRQ_PMC_SYNC);
-
- ssx_irq_setup(PGP_IRQ_PMC_PROTOCOL_ONGOING,
- SSX_IRQ_POLARITY_ACTIVE_LOW,
- SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
-
- ssx_irq_setup(PGP_IRQ_PMC_VOLTAGE_CHANGE_ONGOING,
- SSX_IRQ_POLARITY_ACTIVE_LOW,
- SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
-
- ssx_irq_setup(PGP_IRQ_PMC_SYNC,
- SSX_IRQ_POLARITY_ACTIVE_HIGH,
- SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
-
-
- ssx_irq_handler_set(PGP_IRQ_PMC_PROTOCOL_ONGOING,
- ssx_semaphore_post_handler,
- (void *)(&G_gpsm_protocol_semaphore),
- SSX_NONCRITICAL);
-
- ssx_irq_handler_set(PGP_IRQ_PMC_VOLTAGE_CHANGE_ONGOING,
- ssx_semaphore_post_handler,
- (void *)(&G_gpsm_protocol_semaphore),
- SSX_NONCRITICAL);
-
- ssx_irq_handler_set(PGP_IRQ_PMC_SYNC,
- ssx_semaphore_post_handler,
- (void *)(&G_gpsm_protocol_semaphore),
- SSX_NONCRITICAL);
-
- // Install the Global Pstate table, Local Pstate Array and resonant
- // clocking setup, using options contained in the PstateSuperStructure.
-
- rc = gpsm_gpst_install(o_gpst, &(i_pss->gpst));
- if (rc) _BREAK;
-
- rc = gpsm_lpsa_install(&i_pss->lpsa,
- &(i_pss->gpst.options));
- if (rc) _BREAK;
-
- rc = gpsm_resclk_install(&i_pss->resclk,
- &(i_pss->gpst),
- &(i_pss->gpst.options));
- if (rc) _BREAK;
-
- G_gpsm_initialized = 1;
-
- } while (0);
-
- return rc;
-}
-
-
-// Step voltage manually
-//
-// This API is only (?) used by gpsm_enable_pstates_master[slave](). It is
-// used to make a (hopefully) minor adjustment between the current voltage and
-// the target voltage associated with the initial Global Actual Pstate. In
-// cases where the current voltage is not represented in the new Pstate table,
-// this routine may take a long time as it will do many single-VID-code steps
-// as it gradually moves between the current and target voltages.
-//
-// Voltage change direction is determined by the difference in the Vdd VIDs,
-// and the alogorithm mimics the P7 PVID stepping protocol. If voltage is
-// going up, Vdd and Vcs slew together. If voltage is going down, Vdd slews
-// twice for every change in Vcs. Note that given a Vdd differential we can't
-// assume which way Vcs is moving.
-//
-// The use of Vcs offsets instead of straight-up VID codes in the hardware is
-// extremely confusing, especially since the offsets are defined in normal
-// order as opposed to VID codes which decrease as voltage increases.
-
-// Racall that the inputs are VID codes (lower VID --> higher voltage)
-
-static int
-_manual_step_voltage(const uint8_t i_currentVdd,
- const uint8_t i_currentVcs,
- const uint8_t i_targetVdd,
- const uint8_t i_targetVcs)
-{
- int rc, parity;
- pmc_global_actual_voltage_reg_t pgavr;
- uint8_t currentVdd, currentVcs;
-
- TRACE_GPSM(TRACE_MANUAL_STEP_VOLTAGE);
-
- do {
-
- rc = 0;
- currentVdd = i_currentVdd;
- currentVcs = i_currentVcs;
- parity = 1;
-
- while ((currentVdd != i_targetVdd) &&
- (currentVcs != i_targetVcs)) {
-
- if (currentVdd > i_targetVdd) {
-
- // Voltage going up, slew Vdd and Vcs together. Parity remains
- // 1.
-
- currentVdd--;
-
- } else if (currentVdd > i_targetVdd) {
-
- // Voltage going down, only slew Vcs every other time. Parity
- // is inverted.
-
- currentVdd++;
- parity = 1 - parity;
-
- } else {
-
- // Vdd not moving, set parity so Vcs will move every time.
-
- parity = 1;
- }
-
- if (parity) {
- if (currentVcs < i_targetVcs) {
- currentVcs++;
- } else if (currentVcs > i_targetVcs) {
- currentVcs--;
- }
- }
-
- rc = gpsm_quiesce();
- if (rc) _BREAK;
-
- pgavr.value = 0;
- pgavr.fields.evid_vdd = currentVdd;
- pgavr.fields.evid_vcs = -((int)currentVcs - (int)currentVdd);
- out32(PMC_GLOBAL_ACTUAL_VOLTAGE_REG, pgavr.value);
- }
- if (rc) _BREAK;
-
- rc = gpsm_quiesce();
- if (rc) _BREAK;
-
- } while (0);
-
- return rc;
-}
-
-
-// This is a 'prologue' sequence executed in each core chiplet during the
-// initialization of Pstates. The set of cores to operate on is taken from
-// the current value of the PMC_CORE_DECONFIGURATION_REG.
-//
-// At entry it assumed that iVRM and CPM-DPLL are disabled. It also clears
-// possible safe mode dails before enable pstate.
-//
-// At exit, the following will be true for all configured cores:
-//
-// - The core will be in DPLL frequency override mode with Fmin and Fmax set
-// to the frequency implied by the given Pstate in the given Pstate table with
-// 0 undervolting.
-//
-// - The Fmax bias of the core is set from the Pstate table.
-//
-// - The Fnom of the core is set from the Pstate table.
-//
-// - Pstate mode is enabled in the core and global requests are enabled.
-//
-// - The Local Actual Pstate is being controlled by the Pstate mechanism.
-//
-// - The PMCR will have been updated to the \a frequencyPstate (both global
-// and local) and the global bids (should be) consistent. Auto-override modes
-// in the PMCR are not modified.
-
-static int
-_enable_pstates_core_prologue(const GlobalPstateTable* i_gpst,
- const Pstate i_frequency_pstate,
- const gpst_entry_t i_entry)
-{
- int rc, core;
- unsigned int bogus;
- uint32_t configured_cores;
- DpllCode fNom, fPstate;
- pcbs_pmgp1_reg_t pmgp1;
- pcbs_freq_ctrl_reg_t pfcr;
- pcbs_pcbspm_mode_reg_t ppmr;
- pcbs_power_management_control_reg_t pmcr;
- pcbs_power_management_bounds_reg_t ppmbr;
- pcbs_pmc_vf_ctrl_reg_t ppvcr;
-
- TRACE_GPSM(TRACE_ENABLE_PSTATES_CORE_PROLOGUE);
-
- do {
-
- /* In the event of no configured cores, FW requested to not error out */
- //rc = -GPSM_CONFIGURATION_ERROR;
- rc = 0;
-
- // Do for each core chiplet...
- configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG);
-
- // Turn off possible safe mode so we can move pstate
- pcbs_hb_config(0, configured_cores, 0, 0, 0, &bogus);
- pmc_hb_config(0, 0, 0, &bogus);
-
- for (core = 0; core < PGP_NCORES; core++, configured_cores <<= 1) {
-
- if (!(configured_cores & 0x80000000)) continue;
-
- // The 'nominal' frequency code may be biased per core. This
- // should not under/over-flow.
-
- fNom = i_gpst->pstate0_frequency_code[core];
- rc = bias_frequency(fNom, i_frequency_pstate, &fPstate);
- if (rc) _BREAK;
-
-
- /// \bug HW Bug: Chicken-and-egg problem with frequency override
- /// mode. We need a different HW control structure here. This
- /// may glitch frequency.
-
- // Initial PMGP1_REG setup
- //
- // - Force OCC control of the PM SPRS. This may have to be
- // rethought if PHYP ever controls Pstates.
- //
- // - Enable DPLL frequency overrides
-
- pmgp1.value = 0;
- pmgp1.fields.pm_spr_override_en = 1;
- pmgp1.fields.dpll_freq_override_enable = 1;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMGP1_REG_OR, core),
- pmgp1.value);
- if (rc) _BREAK;
-
-
- // Update Fmin, Fmax, Fmax bias and Pstate0 frequency.
-
- pfcr.value = 0;
- pfcr.fields.dpll_fmin = fPstate;
- pfcr.fields.dpll_fmax = fPstate;
- pfcr.fields.dpll_fmax_bias = i_gpst->dpll_fmax_bias[core];
- pfcr.fields.frequ_at_pstate0 = fNom;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_FREQ_CTRL_REG, core),
- pfcr.value);
- if (rc) _BREAK;
-
-
- /// \bug HW BUG : PCBS_Power_Management_Bounds_reg hardware reset
- /// is whack, violating the Pstate constraints. (HW216565).
- /// Deferred to Venice. Not a problem for us, we always set up
- /// this register.
-
- // The PCBS clipping is initialized to the limits present in the
- // _global_ Pstate table. This is necessary for correctness of
- // the PCBS state machines. If fast-idle modes with retention are
- // enabled this is also necessary to protect against trying to
- // drop into non-functional Pstates required to be present in the
- // _local_ pstate table.
-
- // \bug Workaround, since pre_vret_pstate is set to pmin currently
- // until pstate super structure and pstate data block procedure
- // support an entry as non-functional pstate, need to set lower
- // clip bound to be the pstate one above pmin to make pmin
- // essentially a non-functional pstate for now
-
- ppmbr.value = 0;
- ppmbr.fields.pmin_clip = gpst_pmin(i_gpst)+1;
- ppmbr.fields.pmax_clip = gpst_pmax(i_gpst);
-
- // This fix is added per SW260911
- // Minimum Frequency in the system is given by MRW attribute
- // PState Datablock procedure will read the attribute then
- // convert it into pstate _pfloor_ and put it into
- // Global Pstate Table. GPSM here consumes the value
- // and set both lower bounds: pmin_rail(PMC) and pmin_clip(PCBS)
- // and two safe pstates: pvsafe(PMc) and psafe(PCBS) to be
- // _pfloor_ if _pfloor_ is higher than their default(gpst_pmin)
- // so that we should never run with frequency below the floor
- // even in safe mode
- if (ppmbr.fields.pmin_clip < i_gpst->pfloor && i_gpst->pfloor != 0)
- ppmbr.fields.pmin_clip = i_gpst->pfloor;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_POWER_MANAGEMENT_BOUNDS_REG,
- core),
- ppmbr.value);
- if (rc) _BREAK;
-
-
- // Now that we've locked the frequency and set valid clipping
- // bounds, disable the local Pstate override and allow Global Acks
- // and Pmax-Sync to propogate.
-
- rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_PMGP1_REG, core),
- &(pmgp1.value));
- if (rc) _BREAK;
-
- pmgp1.value = 0;
- pmgp1.fields.enable_occ_ctrl_for_local_pstate_eff_req = 1;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMGP1_REG_AND, core),
- ~pmgp1.value);
- if (rc) _BREAK;
-
-
- // Setup PCBS_PMC_VF_CTRL_REG before enable Pstate
-
- rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_PMC_VF_CTRL_REG, core),
- &(ppvcr.value));
- if (rc) _BREAK;
-
- ppvcr.fields.pglobal_actual = i_frequency_pstate;
- ppvcr.fields.maxregvcs = i_entry.fields.maxreg_vdd;
- ppvcr.fields.maxregvdd = i_entry.fields.maxreg_vcs;
- ppvcr.fields.evidvcs_eff = i_entry.fields.evid_vdd_eff;
- ppvcr.fields.evidvdd_eff = i_entry.fields.evid_vcs_eff;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMC_VF_CTRL_REG, core),
- ppvcr.value);
- if (rc) _BREAK;
-
-
- // Enable Pstate in PCB Slave
-
- rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_PCBSPM_MODE_REG, core),
- &(ppmr.value));
- if (rc) _BREAK;
-
- ppmr.fields.enable_pstate_mode = 1;
- ppmr.fields.enable_global_pstate_req = 1;
- ppmr.fields.enable_pmc_pmax_sync_notification = 1;
-
- // ** VBU **
- ppmr.fields.dpll_lock_replacement_timer_mode_en = 1;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PCBSPM_MODE_REG, core),
- ppmr.value);
- if (rc) _BREAK;
-
- // Update the PMCR to propagate the global bids
-
- rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_POWER_MANAGEMENT_CONTROL_REG,
- core),
- &(pmcr.value));
- if (rc) _BREAK;
-
- pmcr.fields.global_pstate_req = i_frequency_pstate;
- pmcr.fields.local_pstate_req = i_frequency_pstate;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_POWER_MANAGEMENT_CONTROL_REG,
- core),
- pmcr.value);
- if (rc) _BREAK;
- }
- if (rc) _BREAK;
-
- } while (0);
-
- return rc;
-}
-
-
-// This is an 'epilogue' sequence executed in each core chiplet during the
-// enablement of Pstate mode. When this code is executed, the core is in
-// frequency override mode at (or below) the frequency of the Global Pstate
-// Actual. This procedure releases frequency override mode and core-level
-// Pstate operations commence.
-//
-// retval -GPSM_BABYSTEPPER_SYNC_TIMEOUT, if baby stepper sync
-// local_pstate_actual times out
-//
-static int
-_enable_pstates_core_epilogue(void)
-{
- int rc = 0, timeout_rc = 0, core;
- uint32_t configured_cores;
- pcbs_pmgp1_reg_t pmgp1;
- pcbs_power_management_status_reg_t ppmsr;
- SsxTimebase timeout;
-
- TRACE_GPSM(TRACE_ENABLE_PSTATES_CORE_EPILOGUE);
-
- do {
-
- configured_cores = ~in32(PMC_CORE_DECONFIGURATION_REG);
- for (core = 0; core < PGP_NCORES; core++, configured_cores <<= 1) {
-
- if (!(configured_cores & 0x80000000)) continue;
-
- pmgp1.value = 0;
- pmgp1.fields.dpll_freq_override_enable = 1;
-
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMGP1_REG_AND, core),
- ~pmgp1.value);
- if (rc) _BREAK;
- }
- if (rc) _BREAK;
-
- // For Babystepper to catch up sync the local_pstate_actual
- // Poll for up to 300us for done before erroring out
-
- timeout_rc = -GPSM_BABYSTEPPER_SYNC_TIMEOUT;
- timeout = ssx_timebase_get() + SSX_MICROSECONDS(300);
- while (ssx_timebase_get() < timeout) {
- rc = getscom(MC_ADDRESS(PCBS_POWER_MANAGEMENT_STATUS_REG,
- MC_GROUP_EX, PCB_MULTICAST_AND),
- &(ppmsr.value));
- if (rc) _BREAK;
- if (ppmsr.fields.local_pstate_actual ==
- ppmsr.fields.global_pstate_actual) {
- timeout_rc = 0;
- break;
- }
- }
- if (timeout_rc||rc) _BREAK;
-
- } while(0);
-
- if (timeout_rc && !rc)
- return timeout_rc;
- else
- return rc;
-
-}
-
-
-/// Enable Pstates in Firmware Mode, initial Master-only phase
-///
-/// \param[out] o_info This structure is populated by this API for use
-/// by a DCM master in gpsm_enable_pstates_slave. The DCM slave does not
-/// require this information.
-///
-/// \param[out] o_voltage_pstate This parameter returns the Pstate
-/// corresponding to the current system voltage (or the closest safe
-/// approximation). This parameter must be communicated to the slave before
-/// the slave can call gpsm_enable_pstates_slave().
-///
-/// \param[out] o_frequency_pstate *DEPRECATED* This parameter returns the
-/// Pstate corresponding to the current system voltage (or the closest safe
-/// approximation). This parameter must be communicated to the slave before
-/// the slave can call gpsm_enable_pstates_slave().
-///
-/// \note This procedure is only called on an SCM or a DCM master. It will
-/// fail if called on a DCM slave.
-///
-/// \retval 0 Success
-///
-/// \returns All other return codes indicate an error.
-
-int
-gpsm_enable_pstates_master(GpsmEnablePstatesMasterInfo* o_info,
- Pstate* o_voltage_pstate,
- Pstate* o_frequency_pstate)
-{
- int rc, search_rc;
- GlobalPstateTable* gpst;
- gpst_entry_t voltage_entry;
-
- TRACE_GPSM(TRACE_GPSM_ENABLE_PSTATES_MASTER);
-
- do {
-
- if (gpsm_dcm_slave_p()) {
- rc = -GPSM_ILLEGAL_MODE_EPSM;
- _BREAK;
- }
-
- // Enter Firmware Pstate Mode. The gpsm_fw_mode() procedure
- // guarantees that the GPSM is quiesced at this point. Recover a
- // pointer to the Pstate table from PMC.
-
- rc = gpsm_fw_mode();
- if (rc) _BREAK;
-
- gpst = gpsm_gpst();
-
- // Map the current Vdd VID to a pstate in the new Pstate table.
- //
- // As an option (workaround, simulation hack), force the assumption
- // that the current voltage corresponds to PMIN. This will not move
- // the external voltage, however it will force the frequency down to
- // the PMIN frequency prior to starting Pstate operations. It is
- // always safe to change the Pstate from "PMIN", regardless of the
- // actual external voltage, since the PMIN frequency is safe at any
- // voltage.
-
- if (!(gpst->options.options & PSTATE_FORCE_INITIAL_PMIN)) {
-
- rc = vrm_voltage_read(SPIVRM_PORT(0),
- VRM_RD_VDD_RAIL,
- &(o_info->currentVdd));
- if (rc) _BREAK;
- rc = vrm_voltage_read(SPIVRM_PORT(0),
- VRM_RD_VCS_RAIL,
- &(o_info->currentVcs));
- if (rc) _BREAK;
-
- } else {
-
- rc = gpst_entry(gpst, gpst_pmin(gpst), 0, &voltage_entry);
- if (rc) {
- SSX_PANIC(GPSM_BUG); /* This can't happen */
- }
-
- o_info->currentVdd = voltage_entry.fields.evid_vdd;
- o_info->currentVcs = voltage_entry.fields.evid_vcs;
- }
-
- search_rc = gpst_vdd2pstate(gpst, o_info->currentVdd,
- o_voltage_pstate, &voltage_entry);
- if (search_rc &&
- (search_rc != -GPST_PSTATE_CLIPPED_LOW_GPST_V2P) &&
- (search_rc != -GPST_PSTATE_CLIPPED_HIGH_GPST_V2P)) {
- rc = search_rc;
- break;
- }
-
- o_info->targetVdd = voltage_entry.fields.evid_vdd;
- o_info->targetVcs = voltage_entry.fields.evid_vcs;
-
-
- // If the Pstate was 'clipped low', it indicates that the current
- // voltage is lower than the lowest new Pstate. Therefore we need to
- // manually step voltage up before locking in the Pmin frequency. If
- // the Pstate was 'clipped high' it means that the current voltage is
- // higher than the highest Pstate, and we need to lock frequency at
- // the Pmax frequency prior to stepping voltage down. The unclipped
- // case is lumped with the 'clipped low' case as this case might
- // entail a slight rise of voltage. V/F stepping must be split across
- // the calls of gpsm_enable_pstates_master[slave].
-
- if ((search_rc == 0)||(search_rc = -GPST_PSTATE_CLIPPED_LOW_GPST_V2P)) {
-
- rc = _manual_step_voltage(o_info->currentVdd, o_info->currentVcs,
- o_info->targetVdd, o_info->targetVcs);
- if (rc) _BREAK;
-
- o_info->move_voltage = 0;
-
- } else {
-
- o_info->move_voltage = 1;
-
- }
- } while (0);
-
- /// \todo The o_frequency_pstate parameter is no longer needed. It was
- /// originally needed when the Pstate table had an undervolting bias.
- *o_frequency_pstate = *o_voltage_pstate;
-
- return rc;
-}
-
-
-/// Enable Pstates in Firmware Pstate Mode, final Master/Slave phase
-///
-/// \param[in] i_info This structure is populated by
-/// gpsm_enable_pstates_master(), and only required in an SCM or DCM master.
-/// When this API is called on a DCM slave the parameter may be passed as NULL
-/// (0).
-///
-/// \param[in] i_voltage_pstate This parameter is computed by
-/// gpsm_enable_pstates_master(), and is required in every case.
-///
-/// \param[in] i_frequency_pstate This parameter is computed by
-/// gpsm_enable_pstates_master(), and is required in every case.
-///
-/// \note This procedure is called in all cases as the final step in enabling
-/// Pstate mode: SCM, DCM master, DCM slave.
-///
-/// \retval 0 Success
-///
-/// \returns All other return codes indicate an error.
-
-int
-gpsm_enable_pstates_slave(const GpsmEnablePstatesMasterInfo* i_info,
- const Pstate i_voltage_pstate,
- const Pstate i_frequency_pstate)
-{
- int rc;
- GlobalPstateTable* gpst;
- pmc_mode_reg_t pmr;
- gpst_entry_t voltage_entry;
-
- TRACE_GPSM(TRACE_GPSM_ENABLE_PSTATES_SLAVE);
-
- do {
-
- // Enter Firmware Pstate Mode. The gpsm_fw_mode() procedure
- // guarantees that the GPSM is quiesced at this point for the slave;
- // the master must already be quiesced. Recover a pointer to the
- // Pstate table from PMC.
-
- if (gpsm_dcm_slave_p()) {
-
- rc = gpsm_fw_mode();
- if (rc) _BREAK;
-
- } else {
-
- if (!i_info) {
- rc = -GPSM_INVALID_ARGUMENT_EPSS;
- _BREAK;
-
- } else if (!gpsm_fw_mode_p() || !gpsm_quiesced_p()) {
-
- rc = -GPSM_ILLEGAL_MODE_EPSS;
- _BREAK;
-
- }
- }
-
- gpst = gpsm_gpst();
- gpst_entry(gpst, i_voltage_pstate, 0, &voltage_entry);
-
- // Execute the core prologue. An SCM or DCM master may need to move
- // voltage after the frequency move. Since this is guaranteed to be a
- // safe downward move (otherwise we would have moved voltage already),
- // it is safe for the DCM slave to go ahead and finish its Pstate
- // setup before the master has moved the voltage.
-
- rc = _enable_pstates_core_prologue(gpst, i_frequency_pstate,
- voltage_entry);
- if (rc) _BREAK;
-
- if (!gpsm_dcm_slave_p()) {
-
- rc = _manual_step_voltage(i_info->currentVdd, i_info->currentVcs,
- i_info->targetVdd, i_info->targetVcs);
- if (rc) _BREAK;
- }
-
-
- // The Voltage and Frequency state is now consistent in the cores and
- // in PMC. Make sure that PMC modes are set correctly for Hardware
- // Pstate Mode.
-
- pmr.value = in32(PMC_MODE_REG);
- pmr.fields.enable_pstate_voltage_changes = 1;
- pmr.fields.enable_global_actual_pstate_forwarding = 1;
- //pmr.fields.enable_pstate_stepping = 1;
- out32(PMC_MODE_REG, pmr.value);
-
-
- // Since we're in Firmware Pstate mode and all cores are
- // frequency-locked, we can set the Global Actual without stepping -
- // under the assumption that the caller has disabled iVRM prior to the
- // call. The master has already computed the volatge_pstate. We
- // allow the GPSM to quiesce before unlocking the core frequencies.
-
- _gpsm_broadcast_global_actual(i_frequency_pstate, voltage_entry);
-
- rc = gpsm_quiesce();
- if (rc) _BREAK;
-
- rc = _enable_pstates_core_epilogue();
- if (rc) _BREAK;
-
- } while (0);
-
- return rc;
-}
-
diff --git a/src/lib/heartbeat.c b/src/lib/heartbeat.c
deleted file mode 100755
index 51be390..0000000
--- a/src/lib/heartbeat.c
+++ /dev/null
@@ -1,328 +0,0 @@
-// $Id: heartbeat.c,v 1.5 2014/07/16 18:07:35 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/heartbeat.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file heartbeat.c
-/// \brief PgP PMC/PCBS heartbeat configuration procedures
-
-#include "ssx.h"
-#include "heartbeat.h"
-
-/// Configure/Enable/Disable the pmc heartbeat register.
-///
-/// \param enable 1 = enable, 0 = disable, all other values will cause error.
-///
-/// \param req_time_us heartbeat interval time request (in microseconds).
-/// If the pmc does not detect a heartbeat within this time the pmc will
-/// set the corresponding fir bit and enter safe mode. This interval
-/// is the requested value. The return value will be the actual setting.
-/// The procedure well attempt to get as close to the requested time as possible
-/// without choosing a setting lower then requested.
-/// Legal values: 1-4194240 (us). Ignored if force = 1 or enable = 0
-///
-/// \param force 1 = force safe mode (debug), 0 = do not force, all other values
-/// will cause an error. enable = 0 and force = 1 will return an error
-///
-/// \param[out] o_time_us Actual configured time rounded down to the nearest us.
-/// This will be as close as the procedure could get to the requested time given
-/// the frequency and pulse time settings. Returns 0 if hearbeat was disabled or
-/// if safe mode was forced.
-///
-/// \retval 0 Success
-///
-/// \retval -HB_INVALID_ARGUMENT_PMC One of the arguments was invalid in
-/// some way
-
-int
-pmc_hb_config(unsigned int enable,
- unsigned int req_time_us,
- unsigned int force,
- unsigned int *o_time_us
- )
-
-{
- pmc_parameter_reg0_t ppr0;
- pmc_occ_heartbeat_reg_t pohr;
- tpc_hpr2_t l_hpr2;
- uint64_t divider, pulses, total_pulses, hp_freq;
- int rc = 0;
-
- // @dyd SW238882 fix
- // remove req_time_us overflow check since the upper boundary of
- // the req_time_us doesnt depand on certain static value but based on
- // the value set in hang_pulse_2_reg at runtime.
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((enable > 1) ||
- (force > 1) ||
- ((req_time_us < 1) && enable && (! force)) ||
- ((force == 1 && enable == 0)),
- HB_INVALID_ARGUMENT_PMC);
- }
-
- do {
-
- // in case firmware does not call ocb_timer_setup
- // before calling this procedure to setup g_ocb_timer_divider
- rc = getscom(TPC_HPR2, &l_hpr2.value);
- if(rc) break;
- g_ocb_timer_divider = 1 << l_hpr2.fields.hang_pulse_reg;
-
- // calculation based on pmc_occ_heartbeat_reg defination
- hp_freq = (__ssx_timebase_frequency_mhz/g_ocb_timer_divider);
- if(hp_freq < 1)
- hp_freq = 1;
- total_pulses = (req_time_us * hp_freq);
-
- // this may be an overkill for safety but no one should notice
- if ((req_time_us*__ssx_timebase_frequency_mhz) % g_ocb_timer_divider) {
- total_pulses++;
- }
-
- divider = 0;
- // determine values for predivider and number of pulses.
- if (force || (! enable)) { // predivider a don't care in this case
- pulses = 0;
- *o_time_us = 0;
- } else {
- // can count up to 2^16 pulses with no pre-divide, first determine
- // minimum pre-divider needed
- do {
- divider++;
- } while ((((divider << 16) - 1) / total_pulses) < 1);
-
- // @dyd SW238882 fix
- // underflow case
- // since pmc heartbeat counter counts with nest_nclk/4
- // instead of hang pulse when hangpulse_predivider==0,
- // this procedure doesnt allow predivider to be set to
- // zero as it is a special case which doesnt work with
- // occ heartbeat time value calculated by this procedure.
- // Given hangpulse_predivider = divider - 1,
- // set divider to 2 if it is 1, zero not possible.
- if (divider < 2) {
- divider = 2;
- //rc = HB_UNDERFLOW_DIVIDER_PMC;
- //break;
- }
- // overflow case
- // since hangpulse_predivider field is only 6 bit long,
- // check the overflow first, set to maximum if larger.
- if (divider > 64) {
- divider = 64;
- //rc = HB_OVERFLOW_DIVIDER_PMC;
- //break;
- }
-
- // divider is determined, now setup number of pulses
- pulses = total_pulses / divider;
- if (total_pulses % divider) {
- pulses++;
- }
-
- // @dyd SW238882 fix
- // there is no underflow case for pulses, because pulses=0 as
- // intended immediate timeout is allowed, plus no mathematical
- // substraction from pulses is done; however there is an overflow
- // case: the value of pulses doesnt fit into 16 bits HW field.
- // Here we set pulses to the maximum value that HW allows,
- // and use the o_time_us to feedback the caller this is done.
- if (pulses > 0xFFFF) {
- pulses = 0xFFFF;
- //rc = HB_OVERFLOW_PULSES_PMC;
- // break;
- }
-
- // calculating real timeout duration
- // that this procedure is going to set
- *o_time_us = (divider*pulses)/hp_freq;
-
- // @dyd SW238882 fix
- // in force == 0 && enable == 1 case
- // disable heartbeat first before reset hang pulse predivider
- // and new heartbeat time value to prevent immediate timeout.
- // if force == 1 then it is intended to be immediate timeout anyway
- // if enable == 0 then it is going to set this bit to zero anyway
- pohr.value = 0;
- pohr.fields.pmc_occ_heartbeat_en = 0;
- if (cfam_id() == CFAM_CHIP_ID_MURANO_10) {
- out32(PMC_OCC_HEARTBEAT_REG, pohr.value);
- }
- out32(PMC_OCC_HEARTBEAT_REG, pohr.value);
- }
-
- // Note through experiments, the divider=predivider+1 isnt always
- // in effect in hardware due to missing last pulse in tight timing,
- // some setup will end up with just divider=predivider; therefore,
- // in order to not result unexpected heartbeat timeout, always
- // set divider to predivider to be safe.
- if (enable && (! force)) {
- ppr0.value = in32(PMC_PARAMETER_REG0);
- ppr0.fields.hangpulse_predivider = divider;
- out32(PMC_PARAMETER_REG0, ppr0.value);
- }
-
- pohr.value = 0;
- pohr.fields.pmc_occ_heartbeat_en = enable;
- pohr.fields.pmc_occ_heartbeat_time = pulses;
- // Due to Issue HW219480, the heartbeat register needs to be written
- // Twice in order for the heartbeat count value to take correctly.
- // Technically it would not be harmful to just double-write in
- // every case, but this is currently written to only double-write
- // if a Murano dd1.0 part is detected
- if (cfam_id() == CFAM_CHIP_ID_MURANO_10) {
- out32(PMC_OCC_HEARTBEAT_REG, pohr.value);
- }
- out32(PMC_OCC_HEARTBEAT_REG, pohr.value);
-
- }while(0);
- return rc;
-
-}
-
-
-
-/// Configure/Enable/Disable the pcbs heartbeat registers.
-///
-/// \param enable 1 = enable, 0 = disable, all other values will cause error.
-///
-/// \param cores Use this mask to select which cores to update. This routine
-/// will cross reference the current pmc deconfig vector and only update
-/// those cores that are both selected here and configured.
-///
-/// \param hb_reg 32-bit unsigned address of register to setup as the
-/// PCBS heartbeat register. This must be a PCBS address.
-/// Ignored unless enable = 1
-///
-/// \param req_time_us heartbeat interval time request (in microseconds).
-/// If the pcbs does not detect a heartbeat within this time the pcbs will
-/// set the corresponding fir bit and enter safe mode. This interval
-/// is the requested value. The return value will be the actual setting and
-/// the procedure will attempt go get as close to possible to this without
-/// choosing a setting lower then requested.
-/// Legal values: 1 - 16320 (ignored unless enable = 1)
-///
-/// \param force 1 = force safe mode (debug), 0 = do not force, all other values
-/// will cause an error. In PCBS, the force safe mode is not related to
-/// the heartbeat so forcing safe mode while also enabling the heartbeat
-/// is allowed.
-///
-/// \param[out] o_time_us Actual configured time in us. This represents the
-/// actual setting rounded down to the nearest us. 0 if heartbeat was disabled.
-///
-/// \retval 0 Success
-
-/// \retval -HB_INVALID_ARGUMENT_PCBS One of the arguments was invalid in
-/// some way
-///
-/// \retval others This API may also return non-0 codes from
-/// getscom()/putscom()
-
-
-int
-pcbs_hb_config(unsigned int enable,
- ChipConfigCores cores,
- uint32_t hb_reg,
- unsigned int req_time_us,
- unsigned int force,
- unsigned int *o_time_us)
-{
- pcbs_occ_heartbeat_reg_t pohr;
- pcbs_pmgp1_reg_t pp1r;
- pmc_core_deconfiguration_reg_t pcdr;
- uint32_t reg_offset;
- uint32_t pp1r_addr;
- uint64_t pp1r_data;
- ChipConfigCores core_list;
- ChipConfigCores deconfig;
- int core;
- int rc = 0;
- unsigned int pulses;
-
- reg_offset = hb_reg - PCBS_PIB_BASE;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((enable > 1) ||
- ((reg_offset > 0xFF) && enable) ||
- ((req_time_us < 64) && enable) ||
- ((req_time_us > 16320) && enable) ||
- (force > 1),
- HB_INVALID_ARGUMENT_PCBS);
- }
-
-
- do {
-
- // calculation based on pcbs_occ_heartbeat_reg defination
- pulses = req_time_us/64;
- if (req_time_us % 64) {
- pulses++;
- }
-
- // @dyd SW238882 fix
- // overflow handling: HW only allows 8 bits in the field.
- // set pulses to maximum allowed value in HW if it overflows,
- // and o_time_us will feedback to caller this is done.
- if (pulses > 0xFF) {
- pulses = 0xFF;
- //rc = HB_PULSES_OVERFLOW_PCBS;
- //break;
- }
- // underflow case, pulses cannot be zero due to undefined HW behavior
- if (pulses < 1) {
- pulses = 1;
- //rc = HB_PULSES_UNDERFLOW_PCBS;
- //break;
- }
-
- pp1r.value = 0;
- pp1r.fields.force_safe_mode = 1;
- if (force) {
- pp1r_addr = PCBS_PMGP1_REG_OR;
- pp1r_data = pp1r.value;
- } else {
- pp1r_addr = PCBS_PMGP1_REG_AND;
- pp1r_data = ~(pp1r.value);
- }
-
- pcdr.value = in32(PMC_CORE_DECONFIGURATION_REG);
- deconfig = pcdr.fields.core_chiplet_deconf_vector;
-
- pohr.value = 0;
- pohr.fields.occ_heartbeat_enable = enable;
- pohr.fields.occ_heartbeat_time = pulses;
- pohr.fields.occ_heartbeat_reg_addr_offset = reg_offset;
-
- if (enable) {
- *o_time_us = pulses * 64;
- } else {
- *o_time_us = 0;
- }
-
- do {
- core_list = cores & (~deconfig);
- for (core = 0; core < PGP_NCORES; core++, core_list <<= 1) {
- if (core_list & 0x8000) {
- // read modify write to preserve psafe
- rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_OCC_HEARTBEAT_REG,
- core), &pohr.value);
- if (rc) break;
- pohr.fields.occ_heartbeat_enable = enable;
- pohr.fields.occ_heartbeat_time = pulses;
- pohr.fields.occ_heartbeat_reg_addr_offset = reg_offset;
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_OCC_HEARTBEAT_REG,
- core), pohr.value);
- if (rc) break;
- rc = putscom(CORE_CHIPLET_ADDRESS(pp1r_addr, core),
- pp1r_data);
- if (rc) break;
- }
- }
- } while (0);
-
- }while(0);
- return rc;
-}
diff --git a/src/lib/heartbeat.h b/src/lib/heartbeat.h
deleted file mode 100755
index 6c8616b..0000000
--- a/src/lib/heartbeat.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __HEARTBEAT_H__
-#define __HEARTBEAT_H__
-
-// $Id: heartbeat.h,v 1.3 2014/02/12 05:48:48 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/heartbeat.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file heartbeat.h
-/// \brief PgP PMC/PCBS heartbeat configuration procedures
-
-#ifndef __ASSEMBLER__
-
-#include <stdint.h>
-
-#define HB_INVALID_ARGUMENT_PMC 0x00482801
-#define HB_INVALID_ARGUMENT_PCBS 0x00482802
-#define HB_UNDERFLOW_DIVIDER_PMC 0x00482803
-#define HB_OVERFLOW_DIVIDER_PMC 0x00482804
-#define HB_OVERFLOW_PULSES_PMC 0x00482805
-#define HB_OVERFLOW_PULSES_PCBS 0x00482806
-#define HB_UNDERFLOW_PULSES_PCBS 0x00482807
-
-int
-pmc_hb_config(unsigned int enable,
- unsigned int req_time_us,
- unsigned int force,
- unsigned int *o_time_us);
-
-int
-pcbs_hb_config(unsigned int enable,
- ChipConfigCores cores,
- uint32_t hb_reg,
- unsigned int req_time_us,
- unsigned int force,
- unsigned int *o_time_us);
-
-
-
-#endif /* __ASEMBLER__ */
-
-
-#endif /* __HEARTBEAT_H__ */
diff --git a/src/lib/libfiles.mk b/src/lib/libfiles.mk
deleted file mode 100755
index 55773a4..0000000
--- a/src/lib/libfiles.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-# $Id: libfiles.mk,v 1.5 2014/06/26 12:51:16 cmolsen Exp $
-# $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/libfiles.mk,v $
-# @file libofiles.mk
-#
-# @brief mk for libssx.a object files
-#
-# @page ChangeLogs Change Logs
-# @section ofiles.mk
-# @verbatim
-#
-#
-# Change Log ******************************************************************
-# Flag Defect/Feature User Date Description
-# ------ -------------- ---------- ------------ -----------
-# @pb00E pbavari 03/11/2012 Makefile ODE support
-# @at007 alvinwan 05/25/2012 Use complex method for linking pore and PPC objects
-#
-# @endverbatim
-#
-##########################################################################
-# INCLUDES
-##########################################################################
-
-C-SOURCES = \
- assert.c \
- ctype.c \
- ctype_table.c \
- fgetc.c \
- gpe_pba.c \
- gpsm.c \
- gpsm_dcm.c \
- gpsm_init.c \
- heartbeat.c \
- memcpy.c \
- memset.c \
- pmc_dcm.c \
- polling.c \
- printf.c \
- pstates.c \
- puts.c \
- simics_stdio.c \
- special_wakeup.c \
- sprintf.c \
- ssx_dump.c \
- ssx_io.c \
- stdlib.c \
- strcasecmp.c \
- strdup.c \
- string.c \
- string_stream.c \
- strtox.c \
- time.c \
- vrm.c \
-
-S-SOURCES = gpsm_dcm_fast_handler.S
-
-LIBSSX_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/libgpefiles.mk b/src/lib/libgpefiles.mk
deleted file mode 100755
index 3f4efe1..0000000
--- a/src/lib/libgpefiles.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# $Id: libgpefiles.mk,v 1.3 2014/06/26 12:48:31 cmolsen Exp $
-# $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/libgpefiles.mk,v $
-# @file libgpefiles.mk
-#
-# @brief mk for libssx.a gpe object files
-#
-# @page ChangeLogs Change Logs
-# @section libgpefiles.mk
-# @verbatim
-#
-#
-# Change Log ******************************************************************
-# Flag Defect/Feature User Date Description
-# ------ -------------- ---------- ------------ -----------
-# @at007 alvinwan 05/25/2012 Use complex method for linking pore and PPC objects
-#
-# @endverbatim
-#
-##########################################################################
-# INCLUDES
-##########################################################################
-pS-SOURCES = \
- gpe_control.pS \
- gpe_data.pS \
- gpe_scom.pS \
- gpe_pba_pgas.pS
-
-LIB_PSOBJECTS = ${pS-SOURCES:.pS=.o}
-
-
diff --git a/src/lib/libssx.h b/src/lib/libssx.h
deleted file mode 100755
index 2bdffd4..0000000
--- a/src/lib/libssx.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __LIBSSX_H__
-#define __LIBSSX_H__
-
-// $Id: libssx.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/libssx.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file libssx.h
-/// \brief Header definitions with no other obvious home
-
-// Kernel panics
-
-#define ASSERTION_FAILURE 0x00542701
-#define ERROR_EXIT 0x00542702
-
-#endif // __LIBSSX_H__
diff --git a/src/lib/occlib/Makefile b/src/lib/occlib/Makefile
new file mode 100644
index 0000000..9f86413
--- /dev/null
+++ b/src/lib/occlib/Makefile
@@ -0,0 +1,57 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/occlib/Makefile $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# This Makefile currently builds a single archive, 'libocc.a', from
+# various library source files.
+#
+# part of the complete application build.
+#
+
+#all generated files from this makefile will end up in obj/$(IMAGE_NAME)/occ
+export SUB_OBJDIR = /occlib
+
+include img_defs.mk
+include liboccfiles.mk
+
+OBJS := $(addprefix $(OBJDIR)/, $(LIBOCC_OBJECTS))
+
+libocc.a: local
+ $(AR) crs $(OBJDIR)/libocc.a $(OBJDIR)/*.o
+
+.PHONY: clean
+
+local: $(OBJS)
+
+$(OBJS) $(OBJS:.o=.d): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+clean:
+ rm -fr $(OBJDIR)
+
+ifneq ($(MAKECMDGOALS),clean)
+include $(OBJS:.o=.d)
+endif
+
diff --git a/src/lib/occlib/README.txt b/src/lib/occlib/README.txt
new file mode 100644
index 0000000..2f3667f
--- /dev/null
+++ b/src/lib/occlib/README.txt
@@ -0,0 +1 @@
+This directory contains all code that is common for all processors in the OCC complex (405 + 4 GPE's)
diff --git a/src/lib/occlib/ipc_api.h b/src/lib/occlib/ipc_api.h
new file mode 100644
index 0000000..e4756f5
--- /dev/null
+++ b/src/lib/occlib/ipc_api.h
@@ -0,0 +1,519 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_api.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_API_H__
+#define __IPC_API_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_api.h
+/// \brief Common header for Interprocessor Communications API
+///
+#include "ipc_structs.h"
+
+#ifndef __ASSEMBLER__
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC command message
+///
+/// \param msg A pointer to the command message
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of a command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param resp_callback A user-defined function that should be called when
+/// the message is returned as a response to the command. This must be set
+/// to 0 if no callback function should be called.
+///
+/// \param callback_arg A pointer to user-defined data that will be passed in
+/// to the callback function when it is called. This should be set to 0 if
+/// no data needs to be passed.
+///
+/// This function (or \a ipc_init_msgq_msg) must be called on a message at
+/// least once before it is sent via the \a ipc_send_msg interface.
+///
+/// There are two types of function ID's. Function ID's that only work on a
+/// single processor are called \e single-target ID's. These function
+/// ID's have the target ID embedded as part of the ID. FUnction ID's
+/// that are supported on multiple processors are called \e multi-target ID's.
+/// Command messages associated with multi-target function ID's must go through
+/// the extra step of setting the target ID by calling the \a ipc_set_cmd_target
+/// interface on the command message.
+///
+/// If a callback function is provided, that callback function should cause
+/// (directly or indirectly) the \ipc_free_msg interface to be called once it
+/// is known that it is safe for the message to be reused (sent as a command
+/// again).
+///
+void ipc_init_msg(ipc_msg_t* msg,
+ uint32_t func_id,
+ ipc_msg_handler_t resp_callback,
+ void* callback_arg);
+
+//Use these to statically initialize an IPC message
+#define IPC_MSG_INIT(_func_id, _resp_callback, _callback_arg) \
+{\
+ {.node = KERN_DEQUE_ELEMENT_INIT()}, \
+ .func_id.word32 = _func_id, \
+ .ipc_rc = IPC_RC_SUCCESS, \
+ .resp_callback = _resp_callback, \
+ .callback_arg = _callback_arg \
+}
+
+#define IPC_MSG_CREATE(msg_name, _func_id, _resp_callback, _callback_arg) \
+ipc_msg_t msg_name = IPC_MSG_INIT(_func_id, _resp_callback, _callback_arg)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Free up a message to be reused.
+///
+/// \param msg a pointer to a message.
+///
+/// This interface should be called on a message when it is known that it is
+/// safe to reuse the message. Normally, this would be one of the last things
+/// performed in the response callback function for a command, but it may also
+/// be called when it is known that a peer has stopped functioning.
+///
+static inline void ipc_free_msg(ipc_msg_t* msg)
+{
+ msg->func_id.active_flag = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Set the target ID for a multi-target command message.
+///
+/// \param cmd A pointer to an initialized command message.
+///
+/// \param target_id The target ID of the processor the command is intended
+/// for.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The command's target ID was updated.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID associated with this
+/// command is not a valid mult-target function ID.
+///
+int ipc_set_cmd_target(ipc_msg_t* cmd, uint32_t target_id);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Send a message as a command
+///
+/// \param cmd A pointer to an initialized command message
+///
+/// It is expected that at some point prior to calling this function the
+/// message was initialized with a call to \a ipc_init_msg or
+/// \a ipc_init_msgq_msg.
+///
+/// Once a message has been sent it is not safe to send again until it has been
+/// sent back to the sender as a response.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The message was successfully placed on the target's
+/// receive buffer.
+///
+/// \retval IPC_RC_SELF_BLOCKED The call was made prior to calling
+/// \a ipc_enable.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The command was initialized with an invalid
+/// function ID.
+///
+/// \retval IPC_RC_MSG_ACTIVE The message is currently in use.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The message was initialized with an
+/// invalid target ID. This can happen if a multi-target command has not had
+/// its target set via the \a ipc_set_cmd_target function at least one time.
+///
+/// \retval IPC_RC_BUFFER_FULL The command could not be sent because the target's
+/// receive buffer is full.
+///
+/// \retval IPC_RC_TARGET_BLOCKED The command could not be sent because the
+/// target is blocking any new messages.
+///
+int ipc_send_cmd(ipc_msg_t* cmd);
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Send a command message back to the sender as a response message with status.
+///
+/// \param rsp A pointer to a message that was recieved as a command message.
+///
+/// \param ipc_rc This should be either \a IPC_RC_SUCCESS if the command was
+/// successful or \a IPC_RC_CMD_FAILED if the command failed. If
+/// command-specific return codes are needed, they should be returned as
+/// command-specific fields instead of returning them here so that there
+/// is no risk of overlapping return codes.
+///
+/// It is expected that at some point prior to calling this function the
+/// message was initialized with a call to \a ipc_init_msg or
+/// \a ipc_init_msgq_msg.
+///
+/// Once a message has been sent it is not safe to send again until it has been
+/// sent back to the sender as a response.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The message was successfully placed on the target's
+/// receive buffer.
+///
+/// \retval IPC_RC_MSG_NOT_ACTIVE The message is not from an active command.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The target id for the sender is invalid.
+/// This likely means that the message has been corrupted.
+///
+/// \retval IPC_RC_BUFFER_FULL The response could not be sent because the target's
+/// recieve buffer is full.
+///
+/// \retval IPC_RC_TARGET_BLOCKED The response could not be sent because the
+/// target is blocking any new messages.
+///
+int ipc_send_rsp(ipc_msg_t* rsp, uint32_t return_code);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieves the IPC return code embedded in the response message.
+///
+/// \param rsp A pointer to a response message.
+///
+/// The embedded IPC return code is how the remote processor communicates
+/// IPC internal failures to the local processor. It can also be used by
+/// non-IPC code on the remote processor to signal success or failure when it
+/// sends the response message via the \a ipc_send_rsp interface.
+///
+/// The IPC return code should always be checked to verify that a command
+/// message was processed successfully.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The message was successfully processed.
+///
+/// \retval IPC_RC_CMD_FAILED The command was processed on the remote end but
+/// did not complete successfully.
+///
+/// \retval IPC_RC_CMD_NOT_SUPPORTED The function ID for the command is valid
+/// but the remote end does not have support for that function ID.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID for the command is invalid.
+///
+static inline int ipc_get_rc(ipc_msg_t* rsp)
+{
+ return rsp->ipc_rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the IPC function ID for a message
+///
+/// \param msg A pointer to an IPC message
+///
+/// This interface should be used to extract the IPC function ID of a message.
+///
+/// The IPC function ID is returned.
+///
+static inline int ipc_get_funcid(ipc_msg_t* msg)
+{
+ int func_id = msg->func_id.word32;
+
+ //Multi-target function ID's always have the target ID set to
+ //so that if the caller doesn't set it to a proper target id it will
+ //flag an error.
+ if(func_id & IPC_FLAG_MT)
+ {
+ func_id |= IPC_TARGET_MASK;
+ }
+
+ //Clear the active and response flags in case they are set along
+ //with the sender ID.
+ func_id &= ~(IPC_FLAG_ACTIVE | IPC_FLAG_RESPONSE | IPC_SENDER_MASK);
+
+ return func_id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Determine if a message is a response or a command
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to determine if a message is a response or a
+/// command. The function will return a non-zero value if the message is a
+/// response and 0 otherwise.
+///
+static inline int ipc_is_a_response(ipc_msg_t* msg)
+{
+ return msg->func_id.response_flag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Determine if a message is free to be re-used
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to determine if a message is free to re-use.
+/// The function will return a non-zero value if the message is free and
+/// 0 otherwise.
+///
+static inline int ipc_is_free(ipc_msg_t* msg)
+{
+ return !msg->func_id.active_flag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the sender ID of a message.
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to retrieve the sender ID of a message. It
+/// returns the sender ID.
+///
+static inline int ipc_sender_id(ipc_msg_t* msg)
+{
+ return msg->func_id.sender_id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the target ID of a message.
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to retrieve the target ID of a message. It
+/// returns the target ID.
+///
+static inline int ipc_target_id(ipc_msg_t* msg)
+{
+ return msg->func_id.target_id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initializes IPC control structures.
+///
+/// Clears the IPC buffers for this processor and places them in a state
+/// where new messages are blocked. Also initializes the IPC handler table
+/// for this processor if STATIC_IPC_TABLES has not been defined.
+///
+/// This function always returns \a IPC_RC_SUCCESS
+///
+int ipc_init(void);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Enables IPC communications.
+///
+/// Unmasks the IPC interrupt for this processor and places the circular
+/// buffers in a state where they can recieve messages.
+///
+/// This function must be called before using the \a ipc_send_cmd function or
+/// it will return \a IPC_RC_SELF_BLOCKED.
+///
+/// The function always returns \a IPC_RC_SUCCESS.
+///
+int ipc_enable(void);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Disable recieving new IPC commands for a processor.
+///
+/// \param target_id The target ID of the processor to disable receiving new
+/// IPC commands on.
+///
+/// This interface should be used by a processor that knows it is about to go
+/// down or by a processor that knows that one of its peers has halted.
+///
+/// Calling this function on a processor will cause other processors to get
+/// a return code of \a IPC_RC_TARGET_BLOCKED with subsequent calls to
+/// \a ipc_send_cmd. Calling this function on one's self (using a target ID of
+/// OCCHW_INST_ID_SELF) will cause subsequent calls to \a ipc_send_cmd to
+/// return \a IPC_RC_SELF_BLOCKED.
+///
+/// Possible return codes for this function are:
+///
+/// \retval IPC_RC_SUCCESS The target processor was successfully disabled.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The target ID is invalid.
+///
+int ipc_disable(uint32_t target_id);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associates an IPC function ID with a handler function
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of a command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param handler A pointer to the function that handles command messages that
+/// have been initialized with \a func_id.
+///
+/// \param callback_arg A pointer to data that is passed as an argument to the
+/// handler function when it is called.
+///
+/// This function should be used to link an IPC function ID with a function.
+/// Once this has been done, if the local processor recieves a command message
+/// with an IPC function ID that matches \a func_id then it will call the
+/// handler function that was specified by \a handler.
+///
+/// NOTE: All handler functions will be called from an interrupt context.
+///
+/// Possible return codes are:
+///
+/// \retval IPC_RC_SUCCESS The operation completed successfully.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The function ID is a single-target
+/// function ID that does not target this processor.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID is not a valid IPC function
+/// ID.
+///
+/// \retval IPC_RC_INVALID_ARG The handler parameter must be a non-zero value.
+///
+int ipc_set_handler(uint32_t func_id,
+ ipc_msg_handler_t handler,
+ void* callback_arg);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message queue.
+///
+/// \param msgq A pointer to a message queue.
+///
+/// All message queues must be initialized one time prior to use with other
+/// interfaces.
+///
+void ipc_init_msgq(ipc_msgq_t* msgq);
+
+//Use this to statically initialize an IPC message queue
+#define IPC_MSGQ_CREATE(msgq) \
+ipc_msgq_t msgq = \
+{\
+ .msg_head = KERN_DEQUE_SENTINEL_INIT(&msgq.msg_head),\
+ .msg_sem = KERN_SEMAPHORE_INITIALIZATION(0, 0)\
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message and associate it with an IPC message queue
+///
+/// \param msg A pointer to an IPC message.
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of the command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param msgq A pointer to an initialized IPC message queue.
+///
+/// This interface should be used in place of \a ipc_init_msg when the caller
+/// wishes to have the command response placed on the specified IPC message
+/// queue. This allows a thread to block (via the \a ipc_msq_recv interface)
+/// on the message queue until a response to a command has arrived.
+///
+/// \note An IPC message queue can be associated with more than one IPC
+/// message.
+///
+/// See \a ipc_init_msg for more information.
+///
+void ipc_init_msgq_msg(ipc_msg_t* msg, uint32_t func_id, ipc_msgq_t* msgq);
+
+//Use this to statically create an initialized IPC message queue message
+#define IPC_MSGQ_MSG_CREATE(msg_name, func_id, msgq) \
+ IPC_MSG_CREATE(msg_name, func_id, ipc_msgq_handler, msgq)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Wait (with timeout) for an IPC message on an IPC message queue.
+///
+/// \param msg A pointer to an IPC message pointer.
+///
+/// \param msgq A pointer to an initialized IPC message queue.
+///
+/// \param timeout The time to wait for the next IPC message to arrive.
+///
+/// This interface can be used in a thread context to block while waiting for
+/// the next message (command or response) to arrive on an IPC message queue.
+///
+/// For an IPC command message to be placed on an IPC message queue, the
+/// function ID for the command must first be associated with the message queue
+/// by making a call to \a ipc_register_msgq.
+///
+/// For an IPC response message to be placed on an IPC message queue, the
+/// message must be initialized via the \a ipc_init_msgq_msg interface.
+///
+/// If \a ipc_msgq_recv returns a value of \a IPC_RC_SUCCESS then \a msg is
+/// guaranteed to point to a new message. Otherwise, an IPC message was not
+/// retrieved from the message queue and \a msg will be set to 0.
+///
+/// Possible return codes for this function are:
+///
+/// \retval IPC_RC_SUCCESS A new IPC message was received and \a msg has been
+/// set to point to the new message.
+///
+/// \retval IPC_RC_TIMEOUT No new messages were recieved within the timeout
+/// period and \msg was set to 0.
+///
+/// \retval IPC_RC_NO_MSG This should never happen, but if it does it indicates
+/// an internal failure occurred.
+///
+int ipc_msgq_recv(ipc_msg_t** msg, ipc_msgq_t* msgq, KERN_INTERVAL timeout);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associate an IPC message queue with an IPC function ID
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of a command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param msgq A pointer to an initialized IPC message queue.
+///
+/// This interface associates an IPC function ID with an IPC message queue so
+/// that when the calling processor recieves a command with the specified
+/// function ID the message will be place on the message queue and a thread
+/// that is blocked waiting for a message on the queue (using the
+/// \a ipc_msgq_recv interface) will be woken up and given the message.
+///
+/// This function should be called in place of the \a ipc_set_handler
+/// interface.
+///
+/// NOTE: Multiple function ID's can be associated with a single queue.
+///
+/// Possible return codes are:
+///
+/// \retval IPC_RC_SUCCESS The operation completed successfully.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The function ID is a single-target
+/// function ID that does not target this processor.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID is not a valid IPC function
+/// ID.
+///
+int ipc_register_msgq(uint32_t func_id, ipc_msgq_t* msgq);
+
+///////////////////////////////////////////////////////////////////////////////
+/// Internal function that places an IPC message on an IPC message queue
+///
+void ipc_msgq_handler(ipc_msg_t* msg, void* arg);
+
+///////////////////////////////////////////////////////////////////////////////
+/// The default IPC command handler simply sends a response with the IPC return
+/// code set to IPC_RC_CMD_NOT_SUPPORTED
+///
+void ipc_default_handler(ipc_msg_t* msg, void* arg);
+
+#endif /*__ASSEMBLER__*/
+#endif /* __IPC_API_H__ */
diff --git a/src/lib/occlib/ipc_async_cmd.h b/src/lib/occlib/ipc_async_cmd.h
new file mode 100644
index 0000000..db09e9e
--- /dev/null
+++ b/src/lib/occlib/ipc_async_cmd.h
@@ -0,0 +1,49 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_async_cmd.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_ASYNC_CMD_H__
+#define __IPC_ASYNC_CMD_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_async_cmd.h
+/// \brief This header is shared between the 405 and GPE's that need to
+/// support IPC command messages that are sent from the occhw_async_gpe.c
+/// code.
+///
+
+#include "ipc_api.h"
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+ ipc_msg_t cmd;
+ void* cmd_data;
+}ipc_async_cmd_t;
+
+#endif /*__ASSEMBLER__*/
+#endif /*__IPC_ASYNC_CMD_H__*/
diff --git a/src/lib/occlib/ipc_core.c b/src/lib/occlib/ipc_core.c
new file mode 100644
index 0000000..342f024
--- /dev/null
+++ b/src/lib/occlib/ipc_core.c
@@ -0,0 +1,484 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_core.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_core.c
+/// \brief Implementation of core IPC (InterProcessor Communication) routines
+
+#include "kernel.h"
+#include "ipc_api.h"
+#include "occhw_shared_data.h"
+
+/// If G_ipc_enabled is zero then calls to ipc_send_cmd() will return
+/// IPC_RC_SELF_BLOCKED.
+uint8_t G_ipc_enabled = 0;
+
+#ifndef STATIC_IPC_TABLES
+ipc_func_table_entry_t G_ipc_mt_handlers[IPC_MT_MAX_FUNCTIONS];
+ipc_func_table_entry_t G_ipc_st_handlers[IPC_ST_MAX_FUNCTIONS];
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/// Helper function used by ipc_send_cmd and ipc_send_rsp to send a message
+///
+int ipc_send_msg(ipc_msg_t* msg, uint32_t target_id)
+{
+ ipc_target_t* target_cbufs;
+ uint8_t* read_count;
+ uint8_t* write_count;
+ ipc_msg_t** msgs;
+ KERN_MACHINE_CONTEXT ctx;
+ int rc = IPC_RC_SUCCESS;
+ uint8_t num_entries;
+
+ do
+ {
+ // Check for invalid target ID
+ if(target_id > OCCHW_INST_ID_MAX)
+ {
+ rc = IPC_RC_INVALID_TARGET_ID;
+ break;
+ }
+
+ target_cbufs = &OSD_PTR->ipc_data.targets[target_id];
+ msgs = &target_cbufs->cbufs[OCCHW_INST_ID_SELF][0];
+ read_count = &target_cbufs->counts.reads.counts8[OCCHW_INST_ID_SELF];
+ write_count = &target_cbufs->counts.writes.counts8[OCCHW_INST_ID_SELF];
+
+ //Prevent other threads on this processor from updating the cbuf
+ KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
+
+ //Determine the number of entries in the buffer
+ num_entries = *write_count - *read_count;
+
+ //If the cbuf isn't full, then add the message and raise an interrupt
+ if(num_entries < IPC_CBUF_SIZE)
+ {
+ // Mark the message as being active
+ msg->func_id.active_flag = 1;
+
+ msgs[*write_count % IPC_CBUF_SIZE] = msg;
+ (*write_count)++;
+
+ //raise the IPC interrupt on the target
+ KERN_IRQ_STATUS_SET(IPC_GET_IRQ(target_id), 1);
+ }
+ else
+ {
+ //Check if cbuf is just full or is blocked
+ if(num_entries == IPC_CBUF_SIZE)
+ {
+ rc = IPC_RC_BUFFER_FULL;
+ }
+ else
+ {
+ rc = IPC_RC_TARGET_BLOCKED;
+ }
+ }
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+ }while(0);
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Send a message as a command
+///
+int ipc_send_cmd(ipc_msg_t* cmd)
+{
+ int rc;
+ do
+ {
+ //don't allow sending new commands if IPC is disabled
+ if(!G_ipc_enabled)
+ {
+ rc = IPC_RC_SELF_BLOCKED;
+ break;
+ }
+
+ //don't send a command if the valid flag is not set
+ if(!cmd->func_id.valid_flag)
+ {
+ rc = IPC_RC_INVALID_FUNC_ID;
+ break;
+ }
+
+ //don't send a command if the active flag is set
+ if(cmd->func_id.active_flag)
+ {
+ rc = IPC_RC_MSG_ACTIVE;
+ break;
+ }
+
+ cmd->func_id.response_flag = 0;
+
+ //Set the sender ID here. Remote side uses this for sending responses.
+ cmd->func_id.sender_id = OCCHW_INST_ID_SELF;
+
+ cmd->ipc_rc = 0;
+
+ //place the message on the target's circular buffer
+ rc = ipc_send_msg(cmd, cmd->func_id.target_id);
+
+ cmd->ipc_rc = rc;
+ }while(0);
+ return rc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Send a command message back to the sender as a response message with status.
+///
+int ipc_send_rsp(ipc_msg_t* rsp, uint32_t ipc_rc)
+{
+ int rc;
+ if(rsp->func_id.active_flag)
+ {
+ rsp->func_id.response_flag = 1;
+ rsp->ipc_rc = ipc_rc;
+ rc = ipc_send_msg(rsp, rsp->func_id.sender_id);
+ }
+ else
+ {
+ rc = IPC_RC_MSG_NOT_ACTIVE;
+ }
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Default IPC handler that is called when no IPC handler has been
+/// installed for the IPC function that is being requested.
+void ipc_default_handler(ipc_msg_t* msg, void* arg)
+{
+ //Return code is ignored. If failure occurs in sending
+ //the response then the sender of the command should eventually
+ //time out waiting for a response or the sender may be incapacitated.
+ ipc_send_rsp(msg, IPC_RC_CMD_NOT_SUPPORTED);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Set the target ID for a multi-target command message.
+///
+int ipc_set_cmd_target(ipc_msg_t* cmd, uint32_t target_id)
+{
+ int rc = IPC_RC_SUCCESS;
+ do
+ {
+ //verify that this is a muti-target function
+ if(!cmd->func_id.multi_target_flag)
+ {
+ rc = IPC_RC_INVALID_FUNC_ID;
+ break;
+ }
+ else
+ {
+ cmd->func_id.target_id = target_id;
+ }
+ }while(0);
+
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Processes an incoming message (response or command) after it has been
+/// removed from the circular buffer.
+/// This function is for internal use only!
+///
+void ipc_process_msg(ipc_msg_t* msg)
+{
+ uint32_t table_index;
+ uint32_t table_limit;
+ ipc_func_table_entry_t *func_table;
+
+ do
+ {
+ // If this is a response message, call the response callback function
+ if(msg->func_id.response_flag)
+ {
+ if(msg->resp_callback)
+ {
+ msg->resp_callback(msg, msg->callback_arg);
+ }
+ else
+ {
+ //normally, the resp_callback function would call this function
+ //to notify users of the message that it is free to be re-used.
+ //Since there is no callback for this message we call it here.
+ ipc_free_msg(msg);
+ }
+
+ break;
+ }
+
+ // extract the function table index
+ table_index = msg->func_id.table_index;
+
+ //setup for multi-target commands
+ if(msg->func_id.multi_target_flag)
+ {
+ table_limit = IPC_MT_NUM_FUNCIDS;
+ func_table = G_ipc_mt_handlers;
+ }
+ //setup for single-target commands
+ else
+ {
+ table_limit = IPC_ST_NUM_FUNCIDS;
+ func_table = G_ipc_st_handlers;
+ }
+
+ //Common command handling code
+ if(table_index < table_limit)
+ {
+ func_table[table_index].handler(msg, func_table[table_index].arg);
+ }
+ else
+ {
+ //drop errors if this fails. If target was waiting for a response
+ //it should eventually time out and log the message as FFDC.
+ ipc_send_rsp(msg, IPC_RC_INVALID_FUNC_ID);
+ }
+ }while(0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Removes messages from the circular buffer for the processor associated with
+/// sender_id and processes them one at a time.
+/// This function is for internal use only!
+///
+void ipc_process_cbuf(uint32_t sender_id)
+{
+ ipc_target_t *my_cbufs = &OSD_PTR->ipc_data.targets[OCCHW_INST_ID_SELF];
+ uint8_t *read_count = &my_cbufs->counts.reads.counts8[sender_id];
+ uint8_t *write_count = &my_cbufs->counts.writes.counts8[sender_id];
+ ipc_msg_t **msg_ptrs = &my_cbufs->cbufs[sender_id][0];
+ ipc_msg_t *cur_msg;
+
+
+ while(*read_count != *write_count)
+ {
+ // extract the message pointer
+ cur_msg = msg_ptrs[*read_count % IPC_CBUF_SIZE];
+
+ // increment the read count
+ (*read_count)++;
+
+ ipc_process_msg(cur_msg);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// The IPC interrupt handler. Finds which circular buffers have messages
+/// and processes them.
+///
+#ifdef __SSX__
+KERN_IRQ_HANDLER(ipc_irq_handler_full)
+#else
+KERN_IRQ_HANDLER(ipc_irq_handler)
+#endif
+{
+ ipc_counts_t xored_counts;
+ ipc_target_t *my_cbufs;
+ uint32_t sender_id;
+
+ // Processors could be sending us new packets while we're
+ // processing this interrupt. We need to mask all new
+ // IPI interrupts until we are done processing so that we don't
+ // end up processing an interrupt that was already handled.
+ KERN_IRQ_DISABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ // Clear the interrupt bit in the OISR before we check for
+ // status. Checking status and then clearing the OISR bit
+ // can lead to a race condition where we loose an interrupt.
+ KERN_IRQ_STATUS_CLEAR(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ my_cbufs = &OSD_PTR->ipc_data.targets[OCCHW_INST_ID_SELF];
+
+ // Make sure we get the most recent write counts from SRAM
+ // dcbf(&my_cbufs->counts.writes.counts64);
+
+ // Use XOR to find the buffers that aren't empty (read count != write count)
+ xored_counts.counts64 = my_cbufs->counts.reads.counts64 ^
+ my_cbufs->counts.writes.counts64;
+
+ while(1)
+ {
+ // Use cntlzw to find the first buffer that isn't empty
+ sender_id = cntlz64(xored_counts.counts64) / IPC_CBUF_COUNT_BITS;
+
+
+ // If all buffers are empty then we're done
+ if(sender_id > OCCHW_INST_ID_MAX)
+ {
+ break;
+ }
+
+ // Mark the buffer as empty in our local snapshot
+ xored_counts.counts8[sender_id] = 0;
+
+ // Process all new messages in the buffer
+ ipc_process_cbuf(sender_id);
+ }
+
+ // Unmask the irq before returning
+ KERN_IRQ_ENABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// This macro creates an assembly function named ipc_irq_handler which handles
+/// saving/restoring the context that is required for calling a C
+/// function.
+///
+/// NOTE: This is only needed for SSX. PK only supports full interrupts.
+///
+#ifdef __SSX__
+KERN_IRQ_FAST2FULL(ipc_irq_handler, ipc_irq_handler_full);
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize IPC control structures.
+///
+int ipc_init(void)
+{
+ //prevent new messages from coming in.
+ ipc_disable(OCCHW_INST_ID_SELF);
+
+#ifndef STATIC_IPC_TABLES
+ int i;
+ for(i = 0; i < IPC_MT_MAX_FUNCTIONS; i++)
+ {
+ G_ipc_mt_handlers[i].handler = ipc_default_handler;
+ G_ipc_mt_handlers[i].arg = 0;
+ }
+ for(i = 0; i < IPC_ST_MAX_FUNCTIONS; i++)
+ {
+ G_ipc_st_handlers[i].handler = ipc_default_handler;
+ G_ipc_st_handlers[i].arg = 0;
+ }
+#endif
+ return IPC_RC_SUCCESS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Enables IPC communications.
+///
+int ipc_enable(void)
+{
+ int rc;
+ ipc_target_t* my_cbufs;
+
+ do
+ {
+ // Install the IPI interrupt handler for this processor
+ rc = KERN_IRQ_HANDLER_SET(IPC_GET_IRQ(OCCHW_INST_ID_SELF),
+ ipc_irq_handler,
+ 0,
+ KERN_CRITICAL);
+
+ if(rc)
+ {
+ break;
+ }
+
+ my_cbufs = &OSD_PTR->ipc_data.targets[OCCHW_INST_ID_SELF];
+
+ //Any messages that were placed on the cbufs before this point
+ //are dropped. Clear any interrupts that might have been raised
+ //before this point.
+ KERN_IRQ_STATUS_CLEAR(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ // Clear and open up all receive buffers for this processor
+ // by setting the read counts equal to the write counts
+ my_cbufs->counts.reads.counts64 = my_cbufs->counts.writes.counts64;
+
+ // Unmask the IPI interrupt for this processor
+ KERN_IRQ_ENABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ //Allow us to send out new commands
+ G_ipc_enabled = 1;
+
+ }while(0);
+
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Disable recieving new IPC commands for a processor.
+///
+int ipc_disable(uint32_t target_id)
+{
+ int i;
+ int rc = IPC_RC_SUCCESS;
+ ipc_target_t* target_cbufs;
+ KERN_MACHINE_CONTEXT ctx;
+
+ do
+ {
+ // Check for invalid target ID
+ if(target_id > OCCHW_INST_ID_MAX)
+ {
+ rc = IPC_RC_INVALID_TARGET_ID;
+ break;
+ }
+
+ // Prevent us from sending out new commands
+ if(target_id == OCCHW_INST_ID_SELF)
+ {
+ G_ipc_enabled = 0;
+ }
+
+ //disable interrupts to prevent the IPC interrupt handler or other threads
+ //on this instance from interrupting us and changing the read count or
+ //interrupt mask bits under our feet.
+ KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
+
+ //mask off the IPC interrupt for the target (this is mostly for the case
+ //where we are diabling IPC for ourselves).
+ KERN_IRQ_DISABLE(IPC_GET_IRQ(target_id));
+
+ target_cbufs = &OSD_PTR->ipc_data.targets[target_id];
+
+ // Make each cbuf appear to be more than full. This signals to
+ // senders that the buffer is not just full, but blocked. When
+ // the sender sees this it knows not to place more messages on the cbuf.
+ // NOTE: we are updating the read register, which is allowed if the cbuf
+ // is owned by the instance this code is running on OR if the instance
+ // is known to be halted.
+ for(i = 0; i <= OCCHW_INST_ID_MAX; i++)
+ {
+ target_cbufs->counts.reads.counts8[i] =
+ target_cbufs->counts.writes.counts8[i] - (IPC_CBUF_SIZE * 2);
+ }
+
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ }while(0);
+ return rc;
+}
+
diff --git a/src/lib/occlib/ipc_init.c b/src/lib/occlib/ipc_init.c
new file mode 100644
index 0000000..4d732b7
--- /dev/null
+++ b/src/lib/occlib/ipc_init.c
@@ -0,0 +1,153 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_init.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_init.c
+/// \brief Implementation of IPC (InterProcessor Communication) routines for
+/// Setting up the IPC function tables, messages and message queues.
+///
+/// NOTE: The functions that these interfaces peform can all be done statically.
+/// This code will not be included in an image if none of the functions are
+/// referenced.
+
+#include "ipc_api.h"
+#include "ipc_ping.h"
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associate an IPC function ID with a handler function
+///
+int ipc_set_handler(uint32_t function_id,
+ ipc_msg_handler_t handler,
+ void* callback_arg)
+{
+ ipc_func_table_entry_t *func_table;
+ uint32_t table_limit;
+ int rc = IPC_RC_SUCCESS;
+ ipc_func_id_t func_id = {{0}};
+
+ do
+ {
+ func_id.word32 = function_id;
+
+ //setup for multi-target commands
+ if(func_id.multi_target_flag)
+ {
+ table_limit = IPC_MT_NUM_FUNCIDS;
+ func_table = G_ipc_mt_handlers;
+ }
+ //setup for single-target commands
+ else
+ {
+ //make sure the function id targets this processor
+ if(func_id.target_id != OCCHW_INST_ID_SELF)
+ {
+ rc = IPC_RC_INVALID_TARGET_ID;
+ break;
+ }
+ table_limit = IPC_ST_NUM_FUNCIDS;
+ func_table = G_ipc_st_handlers;
+ }
+
+ //make sure the function id is valid
+ if((func_id.table_index >= table_limit) || !func_id.valid_flag)
+ {
+ rc = IPC_RC_INVALID_FUNC_ID;
+ break;
+ }
+
+ if(!handler)
+ {
+ rc = IPC_RC_INVALID_ARG;
+ break;
+ }
+
+ func_table[func_id.table_index].handler = handler;
+ func_table[func_id.table_index].arg = callback_arg;
+ }while(0);
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC command message
+///
+void ipc_init_msg(ipc_msg_t* msg,
+ uint32_t func_id,
+ ipc_msg_handler_t resp_callback,
+ void* callback_arg)
+{
+ KERN_DEQUE_ELEMENT_CREATE(&msg->node);
+ msg->func_id.word32 = func_id;
+ msg->ipc_rc = IPC_RC_SUCCESS;
+ msg->resp_callback = resp_callback;
+ msg->callback_arg = callback_arg;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message queue.
+///
+void ipc_init_msgq(ipc_msgq_t* msgq)
+{
+ KERN_DEQUE_SENTINEL_CREATE(&msgq->msg_head);
+
+ //set the initial count to 0 with no max count
+ KERN_SEMAPHORE_CREATE(&msgq->msg_sem, 0, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message and associate it with an IPC message queue
+///
+void ipc_init_msgq_msg(ipc_msg_t* msg, uint32_t func_id, ipc_msgq_t* msgq)
+{
+ ipc_init_msg(msg, func_id, ipc_msgq_handler, msgq);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC ping command message
+///
+#ifdef IPC_ENABLE_PING
+int ipc_ping_cmd_init(ipc_ping_cmd_t* ping_cmd)
+{
+ int rc;
+
+ do
+ {
+ //initialize the message
+ ipc_init_msg(&ping_cmd->msg, IPC_MT_PING, ipc_ping_response, 0);
+
+ //initialize the semaphore count to 0 and set the max count to 1
+ rc = KERN_SEMAPHORE_CREATE(&ping_cmd->sem, 0, 1);
+ if(rc)
+ {
+ break;
+ }
+ }while(0);
+ return rc;
+}
+#endif /*IPC_ENABLE_PING*/
diff --git a/src/lib/occlib/ipc_macros.h b/src/lib/occlib/ipc_macros.h
new file mode 100644
index 0000000..c95bff6
--- /dev/null
+++ b/src/lib/occlib/ipc_macros.h
@@ -0,0 +1,197 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_macros.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_MACROS_H__
+#define __IPC_MACROS_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_macros.h
+/// \brief Contains macros related to the Interprocessor Communications (IPC)
+/// API.
+///
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieves the IRQ number for the specified OCC processor instance
+///
+#define IPC_GET_IRQ(instance_id) (OCCHW_IRQ_IPI0_HI_PRIORITY + instance_id)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the start of the IPC function ID table
+///
+#define IPC_FUNCIDS_TABLE_START \
+ typedef enum \
+{
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the end of the IPC function ID table
+///
+#define IPC_FUNCIDS_TABLE_END \
+} ipc_func_enum_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the start of the IPC multi-target function IDs within the IPC
+/// function ID table.
+///
+#define IPC_FUNCIDS_MT_START \
+ IPC_MT_START = (int)((IPC_TARGET_MASK | IPC_FLAG_MT | IPC_FLAG_VALID | (((uint32_t)((uint8_t)OCCHW_INST_ID_SELF)) << 16)) - 1),
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the end of the IPC multi-target function IDs within the IPC function
+/// ID table.
+///
+#define IPC_FUNCIDS_MT_END \
+ IPC_MT_END,
+
+#define IPC_CONCAT_INST(name, inst) name ## inst
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the start of the IPC single-target function IDs within the IPC
+/// ID table.
+///
+/// \param target_id The instance ID of the processor that the following
+/// function IDs will target.
+///
+/// Each processor has it's own set of single-target function IDs. Messages
+/// that are initialized with these function ID's can only be sent to the
+/// processor specified by \a target_id.
+///
+#define IPC_FUNCIDS_ST_START(target_id) \
+ IPC_CONCAT_INST(IPC_ST_START_, target_id) = \
+ (int)(((((uint32_t)target_id) << 24) | IPC_FLAG_VALID ) - 1),
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the end of the IPC single-target function IDs for the specified
+/// target ID, \a target_id.
+///
+#define IPC_FUNCIDS_ST_END(target_id) \
+ IPC_CONCAT_INST(IPC_ST_END_, target_id),
+
+///////////////////////////////////////////////////////////////////////////////
+/// Create an IPC function ID.
+///
+/// \param The name of the IPC function ID
+///
+/// This macro should only be used inside the IPC function ID table. Under
+/// the covers, an enum with a name of \a name is created.
+///
+#define IPC_FUNC_ID(name) \
+ name,
+
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_MT_NUM_FUNCIDS \
+ ((IPC_MT_END - IPC_MT_START) - 1)
+
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_ST_TARGET_NUM_FUNCIDS(target_id) \
+ ((IPC_CONCAT_INST(IPC_ST_END_, target_id) - IPC_CONCAT_INST(IPC_ST_START_, target_id)) - 1)
+
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_ST_NUM_FUNCIDS IPC_ST_TARGET_NUM_FUNCIDS(OCCHW_INST_ID_SELF)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Macros for statically initializing the IPC function tables
+#ifdef STATIC_IPC_TABLES
+
+#define IPC_MT_FUNC_TABLE_START \
+ ipc_func_table_entry_t G_ipc_mt_handlers[IPC_MT_MAX_FUNCTIONS] = \
+{
+
+#define IPC_ST_FUNC_TABLE_START \
+ ipc_func_table_entry_t G_ipc_st_handlers[IPC_ST_MAX_FUNCTIONS] = \
+{
+
+#define IPC_HANDLER(func, arg) \
+ {func, arg},
+
+#define IPC_HANDLER_DEFAULT \
+ {ipc_default_handler, 0},
+
+#define IPC_MSGQ_HANDLER(msgq_ptr) \
+ {ipc_msgq_handler, msgq_ptr},
+
+#define IPC_MT_FUNC_TABLE_END \
+};
+
+#define IPC_ST_FUNC_TABLE_END \
+};
+
+#else
+
+#define IPC_MT_FUNC_TABLE_START
+
+#define IPC_ST_FUNC_TABLE_START
+
+#define IPC_HANDLER(func, arg)
+
+#define IPC_HANDLER_DEFAULT
+
+#define IPC_MSGQ_HANDLER(msgq_ptr)
+
+#define IPC_MT_FUNC_TABLE_END
+
+#define IPC_ST_FUNC_TABLE_END
+
+#endif /*STATIC_IPC_TABLES*/
+
+///////////////////////////////////////////////////////////////////////////////
+/// Convenience macro for defering handling of a command or
+/// response in a noncritical interrupt context. This was
+/// specifically added for ipc functions that need to call
+/// ssx functions on the 405. (ssx functions can not be called
+/// inside a critical interrupt context).
+#ifdef __SSX__
+#define IPC_DEFER_TO_NONCRITICAL(ipc_msg) \
+{ \
+ ssx_deque_push_back(&G_ipc_deferred_queue, &ipc_msg->node); \
+ ssx_irq_status_set(OCCHW_IRQ_ASYNC_IPI, 1); \
+}
+
+#else
+#define IPC_DEFER_TO_NONCRITICAL(ipc_msg)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/// Determine if an IPC function ID is a multi-target ID
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_FUNCID_IS_MT(funcid) (IPC_FLAG_MT & (funcid))
+
+///////////////////////////////////////////////////////////////////////////////
+/// Set the target ID of a multi-target function ID
+/// Sets the target to be invalid if it's not a multi-target function id
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_SET_MT_TARGET(funcid, targetid) \
+(((funcid) & IPC_FLAG_MT)? \
+ (((targetid) << IPC_TARGET_SHIFT) | ((funcid) & ~(IPC_TARGET_MASK))): \
+ (IPC_TARGET_MASK | (funcid)))
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the target ID from an IPC function id
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_GET_TARGET_ID(funcid) (((uint32_t)(funcid)) >> IPC_TARGET_SHIFT)
+
+#endif /*__IPC_MACROS_H__*/
diff --git a/src/lib/occlib/ipc_msgq.c b/src/lib/occlib/ipc_msgq.c
new file mode 100644
index 0000000..8048b72
--- /dev/null
+++ b/src/lib/occlib/ipc_msgq.c
@@ -0,0 +1,108 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_msgq.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_msgq.c
+/// \brief Implementation of IPC (InterProcessor Communication) routines that
+/// involve using message queues (primarily in a thread context).
+
+#include "ipc_api.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Handles msgq messages (commands and responses) by placing them on a message
+// queue and then posting the message queue semaphore.
+// This function is for internal use only!
+void ipc_msgq_handler(ipc_msg_t* msg, void* arg)
+{
+ ipc_msgq_t *msgq = (ipc_msgq_t*)arg;
+
+ //NOTE: this is hard coded to 0 on PPE
+ if(KERN_CONTEXT_CRITICAL_INTERRUPT())
+ {
+ //NOTE: this is a no-op on PPE
+ IPC_DEFER_TO_NONCRITICAL(msg);
+ }
+ else
+ {
+ KERN_DEQUE_PUSH_BACK(&msgq->msg_head, &msg->node);
+ KERN_SEMAPHORE_POST(&msgq->msg_sem);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Wait (with timeout) for an IPC message on an IPC message queue.
+///
+int ipc_msgq_recv(ipc_msg_t** msg, ipc_msgq_t* msgq, KERN_INTERVAL timeout)
+{
+ int rc;
+ ipc_msg_t *popped_msg = 0;
+ KERN_MACHINE_CONTEXT ctx;
+
+ rc = KERN_SEMAPHORE_PEND(&msgq->msg_sem, timeout);
+ if(rc)
+ {
+ if(rc == -KERN_SEMAPHORE_PEND_TIMED_OUT ||
+ rc == -KERN_SEMAPHORE_PEND_NO_WAIT)
+ {
+ rc = IPC_RC_TIMEOUT;
+ }
+ }
+ else
+ {
+ //The queue is also modified in the IPC interrupt context so
+ //we need to make sure interrupts are disabled while we modify it.
+ KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
+ popped_msg = (ipc_msg_t*)KERN_DEQUE_POP_FRONT(&msgq->msg_head);
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ if(popped_msg)
+ {
+ rc = IPC_RC_SUCCESS;
+ }
+ else
+ {
+ rc = IPC_RC_NO_MSG;
+ }
+ }
+ *msg = popped_msg;
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associate a message queue with a function ID (commands recieved with the
+/// specified function id will be placed on the message queue).
+///
+int ipc_register_msgq(uint32_t func_id, ipc_msgq_t* msgq)
+{
+ return ipc_set_handler(func_id, ipc_msgq_handler, msgq);
+}
+
+
+
diff --git a/src/lib/occlib/ipc_ping.c b/src/lib/occlib/ipc_ping.c
new file mode 100644
index 0000000..f295c99
--- /dev/null
+++ b/src/lib/occlib/ipc_ping.c
@@ -0,0 +1,96 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_ping.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "ipc_ping.h"
+
+#ifdef IPC_ENABLE_PING
+//server side ping message handler
+void ipc_ping_handler(ipc_msg_t* cmd, void* arg)
+{
+ //NOTE: this will run in a critical interrupt when sent to the 405
+ //ignore return codes
+ ipc_send_rsp(cmd, IPC_RC_SUCCESS);
+}
+
+//Note: This runs in a critical interrupt on the 405 but SSX functions
+// can not be called from a critical interrupt. Instead, it must be
+// deferred to a non-critical handler.
+void ipc_ping_response(ipc_msg_t* rsp, void* arg)
+{
+ ipc_ping_cmd_t *ping_cmd = (ipc_ping_cmd_t*)rsp;
+
+ if(KERN_CONTEXT_CRITICAL_INTERRUPT())
+ {
+ //NOTE: this is a no-op on PPE
+ IPC_DEFER_TO_NONCRITICAL(rsp);
+ }
+ else
+ {
+ KERN_SEMAPHORE_POST(&ping_cmd->sem);
+ ipc_free_msg(&ping_cmd->msg);
+ }
+
+}
+
+
+//Command that can be run in a thread context to ping another target
+//The message is allocated on the stack
+int ipc_ping(ipc_ping_cmd_t* ping_cmd, uint32_t target_id)
+{
+ int rc;
+
+ do
+ {
+ //set the target (since this is a multi-target command)
+ rc = ipc_set_cmd_target(&ping_cmd->msg, target_id);
+ if(rc)
+ {
+ break;
+ }
+
+ //send the command
+ rc = ipc_send_cmd(&ping_cmd->msg);
+ if(rc)
+ {
+ break;
+ }
+
+ //assume that if we timed out then the target must have gone down.
+ rc = KERN_SEMAPHORE_PEND(&ping_cmd->sem, KERN_SECONDS(1));
+ if(rc)
+ {
+ if(rc == -KERN_SEMAPHORE_PEND_TIMED_OUT)
+ {
+ rc = IPC_RC_TIMEOUT;
+ }
+ break;
+ }
+
+ //response message was received. Now return the ipc_rc
+ rc = ipc_get_rc(&ping_cmd->msg);
+
+ }while(0);
+ return rc;
+}
+#endif /*IPC_ENABLE_PING*/
diff --git a/src/lib/occlib/ipc_ping.h b/src/lib/occlib/ipc_ping.h
new file mode 100644
index 0000000..0b315ee
--- /dev/null
+++ b/src/lib/occlib/ipc_ping.h
@@ -0,0 +1,53 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_ping.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "ipc_api.h"
+
+typedef struct
+{
+ ipc_msg_t msg;
+ KERN_SEMAPHORE sem;
+}ipc_ping_cmd_t;
+
+#ifdef IPC_ENABLE_PING
+//server side ping message handler
+void ipc_ping_handler(ipc_msg_t* cmd, void* arg);
+
+//Initialize a ping command.
+int ipc_ping_cmd_init(ipc_ping_cmd_t* ping_cmd);
+
+//function for handling the ping response on the local processor
+void ipc_ping_response(ipc_msg_t* rsp, void* arg);
+
+//Statically initialize a ping command
+#define IPC_PING_CMD_CREATE(name) \
+ipc_ping_cmd_t name = \
+{\
+ .msg = IPC_MSG_INIT(IPC_MT_PING, ipc_ping_response, 0), \
+ .sem = KERN_SEMAPHORE_INITIALIZATION(0, 1) \
+}
+
+//blocking command that can be run in a thread context to ping another target
+int ipc_ping(ipc_ping_cmd_t* ping_cmd, uint32_t target_id);
+#endif /*IPC_ENABLE_PING*/
diff --git a/src/lib/occlib/ipc_structs.h b/src/lib/occlib/ipc_structs.h
new file mode 100644
index 0000000..5f1c90b
--- /dev/null
+++ b/src/lib/occlib/ipc_structs.h
@@ -0,0 +1,226 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_structs.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_STRUCTS_H__
+#define __IPC_STRUCTS_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_structs.h
+/// \brief Common header for Interprocessor Communication structures in the
+/// OCC complex
+///
+#include "kernel.h" //kernel wrapper macros
+#include "occhw_common.h"
+#include "ipc_macros.h"
+
+
+#ifndef IPC_CBUF_SIZE
+#define IPC_CBUF_SIZE 8 //number of messages must be a power of 2
+#endif
+
+//the maximum number of multi-target functions (common functions)
+//This can be overriden in a global header that's included by all occ images
+//so that it is the same across all processors.
+#ifndef IPC_MT_MAX_FUNCTIONS
+#define IPC_MT_MAX_FUNCTIONS 8
+#endif
+
+//the maximum number of single-target functions (processor-specific functions)
+//This can be overridden in a local header file and does not need to be the
+//same across all processors.
+#ifndef IPC_ST_MAX_FUNCTIONS
+#define IPC_ST_MAX_FUNCTIONS 16
+#endif
+
+/// IPC return codes
+#define IPC_RC_SUCCESS 0
+#define IPC_RC_CMD_FAILED 0x00472000
+#define IPC_RC_BUFFER_FULL 0x00472001
+#define IPC_RC_SELF_BLOCKED 0x00472002
+#define IPC_RC_TARGET_BLOCKED 0x00472003
+#define IPC_RC_MSG_ACTIVE 0x00472004
+#define IPC_RC_INVALID_FUNC_ID 0x00472005
+#define IPC_RC_CMD_NOT_SUPPORTED 0x00472006
+#define IPC_RC_INVALID_TARGET_ID 0x00472007
+#define IPC_RC_INVALID_ARG 0x00472008
+#define IPC_RC_MSG_NOT_ACTIVE 0x00472009
+#define IPC_RC_NO_MSG 0x0047200a
+#define IPC_RC_TIMEOUT 0x0047200b
+
+/// IPC Message Flags
+#define IPC_FLAG_MT 0x00000100
+#define IPC_FLAG_RESPONSE 0x00000200
+#define IPC_FLAG_VALID 0x00000400
+#define IPC_FLAG_ACTIVE 0x00000800
+
+// Function ID field masks
+#define IPC_TARGET_MASK 0xff000000
+#define IPC_SENDER_MASK 0x00ff0000
+#define IPC_FLAGS_MASK 0x0000ff00
+#define IPC_INDEX_MASK 0x000000ff
+
+#define IPC_TARGET_SHIFT 24
+
+#define IPC_CBUF_COUNT_BYTES 1
+#define IPC_CBUF_COUNT_BITS 8
+
+#ifndef __ASSEMBLER__
+
+// If an occ application does not wish to use IPC then it should not
+// define the GLOBAL_CFG_USE_IPC macro. This allows IPC to compile
+// without errors.
+#ifdef GLOBAL_CFG_USE_IPC
+#include "ipc_func_ids.h"
+#else
+IPC_FUNCIDS_TABLE_START
+ IPC_FUNCIDS_MT_START
+ IPC_FUNCIDS_MT_END
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE0)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE0)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE1)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE1)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE2)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE2)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE3)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE3)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_PPC)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_PPC)
+IPC_FUNCIDS_TABLE_END
+#endif /*GLOBAL_CFG_USE_IPC*/
+
+//Statically check that the function tables are large enough
+KERN_STATIC_ASSERT(IPC_MT_NUM_FUNCIDS <= IPC_MT_MAX_FUNCTIONS);
+KERN_STATIC_ASSERT(IPC_ST_NUM_FUNCIDS <= IPC_ST_MAX_FUNCTIONS);
+
+#ifdef __SSX__
+extern KERN_DEQUE G_ipc_deferred_queue;
+#endif
+
+struct ipc_msg;
+typedef struct ipc_msg ipc_msg_t;
+
+typedef union
+{
+ uint64_t counts64;
+ uint8_t counts8[sizeof(uint64_t) / IPC_CBUF_COUNT_BYTES];
+} ipc_counts_t;
+
+/// Circular buffer read and write counts are grouped together by target_id
+/// so that an interrupt hander can quickly tell which buffer requires
+/// service. Each counter is 1 byte.
+///
+/// Note: index 0 (or most significant byte) is for GPE0
+typedef struct
+{
+ ipc_counts_t reads;
+ ipc_counts_t writes;
+}ipc_rwcounts_t;
+
+typedef struct
+{
+ ipc_rwcounts_t counts;
+ ipc_msg_t* cbufs[OCCHW_MAX_INSTANCES][IPC_CBUF_SIZE];
+ uint8_t pad[16];
+}ipc_target_t; //size is 6 x 32 = 192 bytes
+
+/// All of the shared data for IPC is contained in this structure
+typedef struct
+{
+ ipc_target_t targets[OCCHW_MAX_INSTANCES]; //880 bytes
+}ipc_shared_data_t;
+
+//prototype for ipc handlers and callback functions
+typedef void (*ipc_msg_handler_t)(ipc_msg_t*, void *);
+
+//function table entry
+typedef struct
+{
+ ipc_msg_handler_t handler;
+ void* arg;
+}ipc_func_table_entry_t;
+
+extern ipc_func_table_entry_t G_ipc_mt_handlers[IPC_MT_MAX_FUNCTIONS];
+
+extern ipc_func_table_entry_t G_ipc_st_handlers[IPC_ST_MAX_FUNCTIONS];
+
+typedef union
+{
+ struct
+ {
+ uint32_t target_id: 8;
+ uint32_t sender_id: 8;
+ uint32_t reserved: 4;
+ uint32_t active_flag: 1;
+ uint32_t valid_flag: 1;
+ uint32_t response_flag: 1;
+ uint32_t multi_target_flag: 1;
+ uint32_t table_index: 8;
+ };
+ uint32_t word32;
+}ipc_func_id_t;
+
+#define IPC_MSG_DEQUEUE_SZ 8 //expected size of a deque structure
+struct ipc_msg
+{
+ // but this file is shared by both, so use a void* type
+ // instead.
+ union
+ {
+ KERN_DEQUE node;
+ uint8_t pad[IPC_MSG_DEQUEUE_SZ];
+ };
+
+ //function ID of the function that the sender wants executed
+ volatile ipc_func_id_t func_id;
+
+ //The IPC return code
+ volatile uint32_t ipc_rc;
+
+ //function to call if this is a response message
+ ipc_msg_handler_t resp_callback;
+
+ //Argument passed into the callback function
+ void *callback_arg;
+};
+
+//Do a static check on the size of KERN_DEQUE. IPC_MSG_DEQUE_SZ must be <= sizeof(KERN_DEQUE).
+//If the compiler fails here then you probably need to update the value of IPC_MSG_DEQUEUE_SZ.
+//NOTE: this is needed because ipc_msg_t is used in both PK and SSX environments and there is
+// no guarantee that the size of a deque will be the same in both environments.
+KERN_STATIC_ASSERT(sizeof(KERN_DEQUE) <= IPC_MSG_DEQUEUE_SZ);
+
+//A message queue that threads can block on while they wait for new messages.
+typedef struct
+{
+ KERN_DEQUE msg_head;
+ KERN_SEMAPHORE msg_sem; //posted whenever a new message is queued
+}ipc_msgq_t;
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __IPC_STRUCTS_H__ */
diff --git a/src/lib/occlib/liboccfiles.mk b/src/lib/occlib/liboccfiles.mk
new file mode 100644
index 0000000..7b3c80a
--- /dev/null
+++ b/src/lib/occlib/liboccfiles.mk
@@ -0,0 +1,53 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/occlib/liboccfiles.mk $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# @file liboccfiles.mk
+#
+# @brief mk for libocc.a object files
+#
+# @page ChangeLogs Change Logs
+# @section liboccfiles.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+#
+# @endverbatim
+#
+##########################################################################
+# INCLUDES
+##########################################################################
+
+C-SOURCES = \
+ ipc_core.c \
+ ipc_init.c \
+ ipc_msgq.c \
+ ipc_ping.c \
+ occhw_xir_dump.c
+
+S-SOURCES =
+
+LIBOCC_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/occlib/occhw_scom_cmd.h b/src/lib/occlib/occhw_scom_cmd.h
new file mode 100644
index 0000000..c6051f5
--- /dev/null
+++ b/src/lib/occlib/occhw_scom_cmd.h
@@ -0,0 +1,93 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_scom_cmd.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __OCCHW_SCOM_CMD_H__
+#define __OCCHW_SCOM_CMD_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_scom_cmd.h
+/// \brief Defines the shared scom command control block
+///
+/// This file contains definitions that are used by both ppc405 and GPE
+/// instances inside the OCC.
+
+// The most significant bit of scom addresses is always 0, so we use this
+// bit to tell the SCOM proxy server (GPE) whether a getscom or putscom is
+// needed.
+#define OCCHW_SCOM_READ_MASK 0x80000000
+
+// This is a status value that the ppc405 will write to the status
+// word prior to starting a new request. This value can be used to
+// detect that the GPE has not yet written status for the request.
+// Note: The GPE simply copies it's MSR value to the status field
+// when it completes. This value is not a valid MSR value.
+#define OCCHW_SCOM_PENDING 0x0000EF00
+
+// Define the structure offsets for use in assembly code on the GPE
+#define OCCHW_SCOM_STATUS_OFFSET 0
+#define OCCHW_SCOM_ADDR_OFFSET 4
+#define OCCHW_SCOM_DATA_OFFSET 8
+
+#ifndef __ASSEMBLER__
+typedef union
+{
+ uint32_t status32;
+ struct
+ {
+ uint32_t rsvd0 : 1;
+ uint32_t mask : 7;
+ uint32_t is0 : 1;
+ uint32_t sibrc : 3;
+ uint32_t lp : 1;
+ uint32_t we : 1;
+ uint32_t is1 : 1;
+ uint32_t uie : 1;
+ uint32_t ee : 1;
+ uint32_t rsvd1 : 2;
+ uint32_t me : 1;
+ uint32_t rsvd2 : 3;
+ uint32_t ipe : 1;
+ uint32_t sibrca : 8;
+ };
+}occhw_scom_status_t;
+
+typedef struct
+{
+ //MSR is saved here
+ volatile occhw_scom_status_t scom_status;
+
+ //msg is used to communicate read/!write
+ volatile uint32_t scom_addr;
+
+ //data for putscom or from getscom
+ volatile uint64_t scom_data;
+} occhw_scom_cmd_t;
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __OCCHW_SCOM_CMD_H__ */
diff --git a/src/lib/occlib/occhw_shared_data.h b/src/lib/occlib/occhw_shared_data.h
new file mode 100644
index 0000000..643691a
--- /dev/null
+++ b/src/lib/occlib/occhw_shared_data.h
@@ -0,0 +1,93 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_shared_data.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __OCCHW_OSD_H__
+#define __OCCHW_OSD_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_osd.h
+/// \brief Common header for shared data within the OCC complex
+///
+
+#include "kernel.h"
+#include "ipc_structs.h"
+#include "occhw_scom_cmd.h"
+
+/// Hardcoded address for the location of the OCC shared data segment
+/// This is placed in the non-cacheable aliased region of SRAM space
+#ifndef OSD_ADDR
+#define OSD_ADDR 0xf7f00000
+#endif
+
+/// Total space of the OCC shared data segment
+#define OSD_TOTAL_SHARED_DATA_BYTES 4096
+
+/// Reserve space for IPC data in case it needs to grow
+#define OSD_IPC_RESERVED_BYTES 2048
+
+/// Reserve space for Debug
+#define OSD_DEBUG_RESERVED_BYTES 512
+
+#define OSD_GPE_SCOM_ADDR (OSD_ADDR + OSD_IPC_RESERVED_BYTES + OSD_DEBUG_RESERVED_BYTES)
+
+#define OSD_GPE_SCOM_RESERVED_BYTES 32
+
+#ifndef __ASSEMBLER__
+typedef union
+{
+ struct
+ {
+ union
+ {
+ ipc_shared_data_t ipc_data; //880 bytes
+ uint8_t ipc_reserved[OSD_IPC_RESERVED_BYTES];
+ };
+ union
+ {
+ //debug_shared_data_t debug_data;
+ uint8_t debug_reserved[OSD_DEBUG_RESERVED_BYTES];
+ };
+ union
+ {
+ occhw_scom_cmd_t scom_cmd;
+ uint8_t gpe_scom_reserved[OSD_GPE_SCOM_RESERVED_BYTES];
+ };
+
+ };
+ uint8_t total_reserved[OSD_TOTAL_SHARED_DATA_BYTES];
+} occhw_osd_t;
+
+// Fail to compile if ipc_shared_data exceeds the reserved space
+KERN_STATIC_ASSERT((sizeof(ipc_shared_data_t) <= OSD_IPC_RESERVED_BYTES));
+
+/// Hardcoded pointer for the location of the OCC shared data segment
+#define OSD_PTR ((occhw_osd_t*) OSD_ADDR)
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __OCCHW_OSD_H__ */
diff --git a/src/lib/occlib/occhw_xir_dump.c b/src/lib/occlib/occhw_xir_dump.c
new file mode 100644
index 0000000..7ff2e4e
--- /dev/null
+++ b/src/lib/occlib/occhw_xir_dump.c
@@ -0,0 +1,60 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_xir_dump.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_xir_dump.c
+/// \brief Implementation of the occhw_xir_dump function
+#include "kernel.h"
+#include "occhw_common.h"
+#include "occhw_xir_dump.h"
+
+int32_t occhw_xir_dump(uint32_t inst_id, occhw_xir_dump_t* xir_dump)
+{
+ int rc;
+ do
+ {
+ if(!xir_dump)
+ {
+ rc = OCCHW_XIR_INVALID_POINTER;
+ break;
+ }
+
+ if(inst_id > OCCHW_INST_ID_MAX_GPE)
+ {
+ rc = OCCHW_XIR_INVALID_GPE;
+ break;
+ }
+
+ //TODO: dump the XIR regs once the addresses are available
+ rc = 0;
+
+ }while(0);
+
+ return rc;
+}
diff --git a/src/lib/occlib/occhw_xir_dump.h b/src/lib/occlib/occhw_xir_dump.h
new file mode 100644
index 0000000..85e52ad
--- /dev/null
+++ b/src/lib/occlib/occhw_xir_dump.h
@@ -0,0 +1,70 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_xir_dump.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __OCCHW_XIR_DUMP_H__
+#define __OCCHW_XIR_DUMP_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_xir_dump.h
+/// \brief header for the occhw_xir_dump function
+///
+
+#ifndef __ASSEMBLER__
+#include "stdint.h"
+
+/// Structure for dumping XIR data for a GPE
+typedef struct
+{
+ uint32_t xsr;
+ uint32_t sprg0;
+ uint32_t edr;
+ uint32_t ir;
+ uint32_t iar;
+ uint32_t sib_upper;
+ uint32_t sib_lower;
+} occhw_xir_dump_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// Dump the XIR registers for a GPE engine
+///
+/// \param inst_id The instance ID of the target GPE.
+///
+/// \param xir_dump Pointer to a occhw_xir_dump_t structure.
+///
+/// Possible return codes are:
+///
+/// \retval 0 XIR registers were successfully dumped
+///
+/// \retval OCCHW_XIR_INVALID_GPE \a inst_id is not for a valid GPE instance.
+///
+/// \retval OCCHW_XIR_INVALID_POINTER \a xir_dump is NULL
+///
+int32_t occhw_xir_dump(uint32_t inst_id, occhw_xir_dump_t* xir_dump);
+
+#endif /*__ASSEMBLER__*/
+#endif /*__OCCHW_XIR_DUMP_H__*/
diff --git a/src/lib/pgas.h b/src/lib/pgas.h
deleted file mode 100755
index bdd3ba1..0000000
--- a/src/lib/pgas.h
+++ /dev/null
@@ -1,1153 +0,0 @@
-#ifndef __PGAS_H__
-#define __PGAS_H__
-
-#define __PGAS__
-
-// $Id: pgas.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pgas.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-// ** WARNING : This file is maintained as part of the OCC firmware. Do **
-// ** not edit this file in the PMX area, the hardware procedure area, **
-// ** or the PoreVe area as any changes will be lost. **
-
-/// \file pgas.h
-/// \brief Pore GAS
-///
-/// PGAS is documented in a seperate standalone document entitled <em> PGAS :
-/// PORE GAS (GNU Assembler) User's and Reference Manual </em>.
-///
-/// This file defines support macros for the GNU PORE assembler, and the PORE
-/// inline assembler and disassebler which follow the PGAS assembly syntax.
-/// If the compile swith PGAS_PPC is defined in the environment then pgas.h
-/// includes pgas_ppc.h which transforms a PowerPC assembler into an assembler
-/// for PORE.
-
-// These are the opcodes and mnemonics as defined by the PORE hardware
-// manual. Many of them will change names slightly in PGAS.
-
-#define PORE_OPCODE_NOP 0x0f
-#define PORE_OPCODE_WAIT 0x01
-#define PORE_OPCODE_TRAP 0x02
-#define PORE_OPCODE_HOOK 0x4f
-
-#define PORE_OPCODE_BRA 0x10
-#define PORE_OPCODE_BRAZ 0x12
-#define PORE_OPCODE_BRANZ 0x13
-#define PORE_OPCODE_BRAI 0x51
-#define PORE_OPCODE_BSR 0x14
-#define PORE_OPCODE_BRAD 0x1c
-#define PORE_OPCODE_BSRD 0x1d
-#define PORE_OPCODE_RET 0x15
-#define PORE_OPCODE_CMPBRA 0x56
-#define PORE_OPCODE_CMPNBRA 0x57
-#define PORE_OPCODE_CMPBSR 0x58
-#define PORE_OPCODE_LOOP 0x1f
-
-#define PORE_OPCODE_ANDI 0x60
-#define PORE_OPCODE_ORI 0x61
-#define PORE_OPCODE_XORI 0x62
-
-#define PORE_OPCODE_AND 0x25
-#define PORE_OPCODE_OR 0x26
-#define PORE_OPCODE_XOR 0x27
-
-#define PORE_OPCODE_ADD 0x23
-#define PORE_OPCODE_ADDI 0x24
-#define PORE_OPCODE_SUB 0x29
-#define PORE_OPCODE_SUBI 0x28
-#define PORE_OPCODE_NEG 0x2a
-
-#define PORE_OPCODE_COPY 0x2c
-#define PORE_OPCODE_ROL 0x2e
-
-#define PORE_OPCODE_LOAD20 0x30
-#define PORE_OPCODE_LOAD64 0x71
-#define PORE_OPCODE_SCR1RD 0x32
-#define PORE_OPCODE_SCR1RDA 0x73
-#define PORE_OPCODE_SCR2RD 0x36
-#define PORE_OPCODE_SCR2RDA 0x77
-#define PORE_OPCODE_WRI 0x78
-#define PORE_OPCODE_BS 0x74
-#define PORE_OPCODE_BC 0x75
-#define PORE_OPCODE_SCR1WR 0x39
-#define PORE_OPCODE_SCR2WR 0x3a
-#define PORE_OPCODE_SCAND 0x7c
-
-
-// These are the PGAS versions of the PORE opcodes used in the legacy PGAS_PPC
-// assembler and the current PORE inline assembler/disassembler.
-
-#define PGAS_OPCODE_NOP PORE_OPCODE_NOP
-#define PGAS_OPCODE_WAITS PORE_OPCODE_WAIT
-#define PGAS_OPCODE_TRAP PORE_OPCODE_TRAP
-#define PGAS_OPCODE_HOOKI PORE_OPCODE_HOOK
-
-#define PGAS_OPCODE_BRA PORE_OPCODE_BRA
-#define PGAS_OPCODE_BRAZ PORE_OPCODE_BRAZ
-#define PGAS_OPCODE_BRANZ PORE_OPCODE_BRANZ
-#define PGAS_OPCODE_BRAI PORE_OPCODE_BRAI
-#define PGAS_OPCODE_BSR PORE_OPCODE_BSR
-#define PGAS_OPCODE_BRAD PORE_OPCODE_BRAD
-#define PGAS_OPCODE_BSRD PORE_OPCODE_BSRD
-#define PGAS_OPCODE_RET PORE_OPCODE_RET
-#define PGAS_OPCODE_CMPIBRAEQ PORE_OPCODE_CMPBRA
-#define PGAS_OPCODE_CMPIBRANE PORE_OPCODE_CMPNBRA
-#define PGAS_OPCODE_CMPIBSREQ PORE_OPCODE_CMPBSR
-#define PGAS_OPCODE_LOOP PORE_OPCODE_LOOP
-
-#define PGAS_OPCODE_ANDI PORE_OPCODE_ANDI
-#define PGAS_OPCODE_ORI PORE_OPCODE_ORI
-#define PGAS_OPCODE_XORI PORE_OPCODE_XORI
-
-#define PGAS_OPCODE_AND PORE_OPCODE_AND
-#define PGAS_OPCODE_OR PORE_OPCODE_OR
-#define PGAS_OPCODE_XOR PORE_OPCODE_XOR
-
-#define PGAS_OPCODE_ADD PORE_OPCODE_ADD
-#define PGAS_OPCODE_ADDS PORE_OPCODE_ADDI
-#define PGAS_OPCODE_SUB PORE_OPCODE_SUB
-#define PGAS_OPCODE_SUBS PORE_OPCODE_SUBI
-#define PGAS_OPCODE_NEG PORE_OPCODE_NEG
-
-#define PGAS_OPCODE_MR PORE_OPCODE_COPY
-#define PGAS_OPCODE_ROLS PORE_OPCODE_ROL
-
-#define PGAS_OPCODE_LS PORE_OPCODE_LOAD20
-#define PGAS_OPCODE_LI PORE_OPCODE_LOAD64
-#define PGAS_OPCODE_LD0 PORE_OPCODE_SCR1RD /* Used by LD */
-#define PGAS_OPCODE_LD0ANDI PORE_OPCODE_SCR1RDA /* Used by LDANDI */
-#define PGAS_OPCODE_LD1 PORE_OPCODE_SCR2RD /* Used by LD */
-#define PGAS_OPCODE_LD1ANDI PORE_OPCODE_SCR2RDA /* Used by LDANDI */
-#define PGAS_OPCODE_STI PORE_OPCODE_WRI
-#define PGAS_OPCODE_STD0 PORE_OPCODE_SCR1WR /* Used by STD */
-#define PGAS_OPCODE_STD1 PORE_OPCODE_SCR2WR /* Used by STD */
-#define PGAS_OPCODE_SCAND PORE_OPCODE_SCAND
-
-#ifdef IGNORE_HW274735
-
-// BSI and BCI are normally redacted due to HW274735. See also pgas.h
-
-#define PGAS_OPCODE_BSI PORE_OPCODE_BS
-#define PGAS_OPCODE_BCI PORE_OPCODE_BC
-
-#endif // IGNORE_HW274735
-
-// These are the programmer-visible register names as defined by the PORE
-// hardware manual. All of these names (except the PC) appear differently in
-// the PGAS syntax, in some cases to reduce confusion, in other cases just to
-// have more traditional short mnemonics.
-
-#define PORE_REGISTER_PRV_BASE_ADDR0 0x0
-#define PORE_REGISTER_PRV_BASE_ADDR1 0x1
-#define PORE_REGISTER_OCI_BASE_ADDR0 0x2
-#define PORE_REGISTER_OCI_BASE_ADDR1 0x3
-#define PORE_REGISTER_SCRATCH0 0x4
-#define PORE_REGISTER_SCRATCH1 0x5
-#define PORE_REGISTER_SCRATCH2 0x6
-#define PORE_REGISTER_ERROR_MASK 0x7
-#define PORE_REGISTER_EXE_TRIGGER 0x9
-#define PORE_REGISTER_DATA0 0xa
-#define PORE_REGISTER_PC 0xe
-#define PORE_REGISTER_IBUF_ID 0xf
-
-
-// PgP IBUF_ID values
-
-#define PORE_ID_GPE0 0x00
-#define PORE_ID_GPE1 0x01
-#define PORE_ID_SLW 0x08
-#define PORE_ID_SBE 0x04
-
-
-// Condition Codes
-
-#define PORE_CC_UGT 0x8000
-#define PORE_CC_ULT 0x4000
-#define PORE_CC_SGT 0x2000
-#define PORE_CC_SLT 0x1000
-#define PORE_CC_C 0x0800
-#define PORE_CC_V 0x0400
-#define PORE_CC_N 0x0200
-#define PORE_CC_Z 0x0100
-
-
-// Memory Spaces
-
-#define PORE_SPACE_UNDEFINED 0xffff
-#define PORE_SPACE_OCI 0x8000
-#define PORE_SPACE_PNOR 0x800b
-#define PORE_SPACE_OTPROM 0x0001
-#define PORE_SPACE_SEEPROM 0x800c
-#define PORE_SPACE_PIBMEM 0x0008
-
-
-#ifdef __ASSEMBLER__
-
-////////////////////////////////////////////////////////////////////////////
-// PGAS Base Assembler Support
-////////////////////////////////////////////////////////////////////////////
-
-
- //////////////////////////////////////////////////////////////////////
- // Condition Codes
- //////////////////////////////////////////////////////////////////////
-
- .set CC_UGT, PORE_CC_UGT
- .set CC_ULT, PORE_CC_ULT
- .set CC_SGT, PORE_CC_SGT
- .set CC_SLT, PORE_CC_SLT
- .set CC_C, PORE_CC_C
- .set CC_V, PORE_CC_V
- .set CC_N, PORE_CC_N
- .set CC_Z, PORE_CC_Z
-
-
- //////////////////////////////////////////////////////////////////////
- // Utility Macros
- //////////////////////////////////////////////////////////////////////
-
- // 'Undefine' PowerPC mnemonics to trap programming errors
-
- .macro ..undefppc1, i
- .ifnc \i, ignore
- .macro \i, args:vararg
- .error "This is a PowerPC opcode - NOT a PGAS opcode or extended mnemonic"
- .endm
- .endif
- .endm
-
- .macro .undefppc, i0, i1=ignore, i2=ignore, i3=ignore
- ..undefppc1 \i0
- ..undefppc1 \i1
- ..undefppc1 \i2
- ..undefppc1 \i3
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // Argument Checking Macros
- //////////////////////////////////////////////////////////////////////
- //
- // These macros remain in the final pgas.h file because 1) they are
- // required for some PGAS pseudo-ops, and 2) to support robust
- // assembler macro definitions.
-
- // Check an unsigned immediate for size
-
- .macro ..checku, x:req, bits:req, err="Unsigned value too large"
-
- .if (((\bits) <= 0) || ((\bits) > 63))
- .error "The number of bits must be in the range 0 < bits < 64"
- .endif
-
- .iflt (\x)
- .error "An unsigned value is required here"
- .endif
-
- .ifgt ((\x) - (0xffffffffffffffff >> (64 - (\bits))))
- .error "\err"
- .endif
-
- .endm
-
- // Check unsigned 16/22-bit immediates for size
- //
- // In general, PGAS can check immediate values for size restrictions,
- // but unfortunately is not able to check address offset immediates for
- // range.
-
- .macro ..check_u16, u16
- ..checku (\u16), 16, "Unsigned immediate is larger than 16 bits"
- .endm
-
- .macro ..check_u24, u24
- ..checku (\u24), 24, "Unsigned immediate is larger than 24 bits"
- .endm
-
- // Check a 16/20/22-bit signed immediate for size
-
- .macro ..check_s16, s16
- .iflt \s16
- .iflt \s16 + 0x8000
- .error "Immediate value too small for a signed 16-bit field"
- .endif
- .else
- .ifgt \s16 - 0x7fff
- .error "Immediate value too large for a signed 16-bit field"
- .endif
- .endif
- .endm
-
- .macro ..check_s20, s20
- .iflt \s20
- .iflt \s20 + 0x80000
- .error "Immediate value too small for a signed 20-bit field"
- .endif
- .else
- .ifgt \s20 - 0x7ffff
- .error "Immediate value too large for a signed 20-bit field"
- .endif
- .endif
- .endm
-
- .macro ..check_s22, s22
- .iflt \s22
- .iflt \s22 + 0x200000
- .error "Immediate value too small for a signed 22-bit field"
- .endif
- .else
- .ifgt \s22 - 0x1fffff
- .error "Immediate value too large for a signed 22-bit field"
- .endif
- .endif
- .endm
-
- // Check a putative SCOM address for bits 0 and 8:11 == 0.
-
- .macro ..check_scom, address
- .if ((\address) & 0x80f00000)
- .error "Valid SCOM addresses must have bits 0 and 8:11 equal to 0."
- .endif
- .endm
-
- // A register required to be D0
-
- .macro ..d0, reg
- .if (\reg != D0)
- .error "Data register D0 is required here"
- .endif
- .endm
-
- // A register pair required to be D0, D1 in order
-
- .macro ..d0d1, reg1, reg2
- .if (((\reg1) != D0) && ((\reg2) != D1))
- .error "Register-Register ALU operations are only defined on the source pair D0, D1"
- .endif
- .endm
-
- // A register pair required to be D0, D1 in any order
- .macro ..dxdy, reg1, reg2, err="Expecting D0, D1 in either order"
- .if !((((\reg1) == D0) && ((\reg2) == D1)) || \
- (((\reg1) == D1) && ((\reg2) == D0)))
- .error "\err"
- .endif
- .endm
-
- // A register pair required to be A0, A1 in any order
- .macro ..axay, reg1, reg2, err="Expecting A0, A1 in either order"
- .if !((((\reg1) == A0) && ((\reg2) == A1)) || \
- (((\reg1) == A1) && ((\reg2) == A0)))
- .error "\err"
- .endif
- .endm
-
- // A register pair required to be the same register
-
- .macro ..same, dest, src
- .if ((\dest) != (\src))
- .error "PGAS requires the src and dest register of ADDS/SUBS to be explicit and identical"
- .endif
- .endm
-
- // A "Data" register
-
- .macro ..data, reg:req, err="Expecting a 'Data' register"
- .if (\reg != D0)
- .if (\reg != D1)
- .error "\err"
- .endif
- .endif
- .endm
-
- // An "Address" register
-
- .macro ..address, reg:req, err=:"Expecting an 'Address' register"
- .if (\reg != A0)
- .if (\reg != A1)
- .error "\err"
- .endif
- .endif
- .endm
-
- // A "Pervasive Chiplet ID" register
-
- .macro ..pervasive_chiplet_id, reg:req, err="Expecting a 'Pervasive Chiplet ID' register"
- .if (\reg != P0)
- .if (\reg != P1)
- .error "\err"
- .endif
- .endif
- .endm
-
- // A "Branch Compare Data" register
-
- .macro ..branch_compare_data, reg
- .if (\reg != D0)
- .if (\reg != D1)
- .if (\reg != CTR)
- .error "Expecting a 'Branch Compare Data' register"
- .endif
- .endif
- .endif
- .endm
-
- // An "LS Destination" register; Also the set for ADDS/SUBS
-
- .macro ..ls_destination, reg
- .if (\reg != D0)
- .if (\reg != D1)
- .if (\reg != A0)
- .if (\reg != A1)
- .if (\reg != P0)
- .if (\reg != P1)
- .if (\reg != CTR)
- .error "Expecting an 'LS Destination' register"
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endm
-
- // An "LI Destination" register
-
- .macro ..li_destination, reg
- .if (\reg != D0)
- .if (\reg != D1)
- .if (\reg != A0)
- .if (\reg != A1)
- .if (\reg != CTR)
- .error "Expecting an 'LI Destination' register"
- .endif
- .endif
- .endif
- .endif
- .endif
- .endm
-
- // An "LIA Destination" register
-
- .macro ..lia_destination, reg
- .if (\reg != D0)
- .if (\reg != D1)
- .if (\reg != A0)
- .if (\reg != A1)
- .if (\reg != TBAR)
- .error "Expecting an 'LIA Destination' register"
- .endif
- .endif
- .endif
- .endif
- .endif
- .endm
-
- // An "MR Source" register
-
- .macro ..mr_source, reg
- .if (\reg != D0)
- .if (\reg != D1)
- .if (\reg != A0)
- .if (\reg != A1)
- .if (\reg != P0)
- .if (\reg != P1)
- .if (\reg != CTR)
- .if (\reg != PC)
- .if (\reg != ETR)
- .if (\reg != SPRG0)
- .if (\reg != IFR)
- .if (\reg != EMR)
- .error "Expecting an 'MR Source' register"
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endm
-
- // An "MR Destination" register
-
- .macro ..mr_destination, reg
- .if (\reg != D0)
- .if (\reg != D1)
- .if (\reg != A0)
- .if (\reg != A1)
- .if (\reg != P0)
- .if (\reg != P1)
- .if (\reg != CTR)
- .if (\reg != PC)
- .if (\reg != ETR)
- .if (\reg != SPRG0)
- .if (\reg != EMR)
- .error "Expecting an 'MR Destination' register"
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // PORE address spaces
- //////////////////////////////////////////////////////////////////////
-
- // The ..set_address_space pseudo-op defines the default address
- // space. It must be defined in order to use BRAA, BRAIA, BSR and
- // CMPIBSR. Pseudo-ops are provided to set the default space of the
- // program. Note that code assembled for PNOR will also work in the
- // OCI space in the Sleep/Winkle engine.
-
- .macro ..set_default_space, s
- ..check_u16 (\s)
- .set _PGAS_DEFAULT_SPACE, (\s)
- .endm
-
- .macro ..check_default_space
- .if (_PGAS_DEFAULT_SPACE == PORE_SPACE_UNDEFINED)
- .error "The PGAS default address space has not been defined"
- .endif
- .endm
-
- ..set_default_space PORE_SPACE_UNDEFINED
-
- .macro .oci
- ..set_default_space PORE_SPACE_OCI
- .endm
-
- .macro .pnor
- ..set_default_space PORE_SPACE_PNOR
- .endm
-
- .macro .seeprom
- ..set_default_space PORE_SPACE_SEEPROM
- .endm
-
- .macro .otprom
- ..set_default_space PORE_SPACE_OTPROM
- .endm
-
- .macro .pibmem
- ..set_default_space PORE_SPACE_PIBMEM
-#ifndef PGAS_PPC
- .pibmem_port (PORE_SPACE_PIBMEM & 0xf)
-#else
- // NB: PGAS_PPC does not support relocatable PIBMEM addressing
-#endif
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // Address-Generation Pseudo Ops
- //////////////////////////////////////////////////////////////////////
-
- // .QUADA, .QUADIA
-
- .macro .quada, offset:req
- ..check_default_space
- .long _PGAS_DEFAULT_SPACE
- .long (\offset)
- .endm
-
- .macro .quadia, space:req, offset:req
- ..check_u16 (\space)
- .long (\space)
- .long (\offset)
- .endm
-
- //////////////////////////////////////////////////////////////////////
- // Bug workarounds
- //////////////////////////////////////////////////////////////////////
-
-#ifndef IGNORE_HW274735
-
- // HW274735 documents that BC and BS are broken for the PORE-GPE0/1
- // pair. This bug is unfixed in POWER8, and by default we require BSI
- // and BCI to be implemented as macros on all engines. For
- // compatability we continue to require that dx == D0.
-
- .macro bsi, dx:req, offset:req, base:req, imm:req
- ..d0 (\dx)
- ld D0, (\offset), (\base)
- ori D0, D0, (\imm)
- std D0, (\offset), (\base)
- .endm
-
- .macro bci, dx:req, offset:req, base:req, imm:req
- ..d0 (\dx)
- ldandi D0, (\offset), (\base), ~(\imm)
- std D0, (\offset), (\base)
- .endm
-
-#endif // IGNORE_HW274735
-
- //////////////////////////////////////////////////////////////////////
- // "A"- and "IA"-form Instructions
- //////////////////////////////////////////////////////////////////////
-
- // BRAA (Branch Address) is a 'long branch' to an address in the
- // default memory space.
-
- .macro braa, offset:req
- braia _PGAS_DEFAULT_SPACE, (\offset)
- .endm
-
- // LA (Load Address) loads the full address of an address in the
- // default memory space.
-
- .macro la, dest:req, offset:req
- lia (\dest), _PGAS_DEFAULT_SPACE, (\offset)
- .endm
-
- // STA (Store Address) stores the full address of an address in the
- // default memory space.
-
- .macro sta, mem_offset:req, base:req, addr_offset:req
- stia (\mem_offset), (\base), _PGAS_DEFAULT_SPACE, (\addr_offset)
- .endm
-
- // BSRIA is a subroutine branch into another memory space. This has to
- // be emulated by a local subroutine branch and a BRAIA.
-
- .macro bsria, space:req, offset:req
- bsr 27742f
- bra 27743f
-27742:
- braia (\space), (\offset)
-27743:
- .endm
-
-
-////////////////////////////////////////////////////////////////////////////
-// Extended Mnemonics, Macros and Special Cases
-////////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////
- // TFB<c> - Test flags and branch conditionally
- //////////////////////////////////////////////////////////////////////'
-
- .macro ..tfb, dest, target, flags
- ..data (\dest)
- mr (\dest), IFR
- andi (\dest), (\dest), (\flags)
- branz (\dest), (\target)
- .endm
-
- .macro ..tfbn dest, target, flags
- ..data (\dest)
- mr (\dest), IFR
- andi (\dest), (\dest), (\flags)
- braz (\dest), (\target)
- .endm
-
- .macro tfbcs, dest:req, target:req
- ..tfb (\dest), (\target), CC_C
- .endm
-
- .macro tfbcc, dest:req, target:req
- ..tfbn (\dest), (\target), CC_C
- .endm
-
- .macro tfbvs, dest:req, target:req
- ..tfb (\dest), (\target), CC_V
- .endm
-
- .macro tfbvc, dest:req, target:req
- ..tfbn (\dest), (\target), CC_V
- .endm
-
- .macro tfbns, dest:req, target:req
- ..tfb (\dest), (\target), CC_N
- .endm
-
- .macro tfbnc, dest:req, target:req
- ..tfbn (\dest), (\target), CC_N
- .endm
-
- .macro tfbeq, dest:req, target:req
- ..tfb (\dest), (\target), CC_Z
- .endm
-
- .macro tfbne, dest:req, target:req
- ..tfbn (\dest), (\target), CC_Z
- .endm
-
- .macro tfbult, dest:req, target:req
- ..tfb (\dest), (\target), CC_ULT
- .endm
-
- .macro tfbule, dest:req, target:req
- ..tfbn (\dest), (\target), CC_UGT
- .endm
-
- .macro tfbuge, dest:req, target:req
- ..tfbn (\dest), (\target), CC_ULT
- .endm
-
- .macro tfbugt, dest:req, target:req
- ..tfb (\dest), (\target), CC_UGT
- .endm
-
- .macro tfbslt, dest:req, target:req
- ..tfb (\dest), (\target), CC_SLT
- .endm
-
- .macro tfbsle, dest:req, target:req
- ..tfbn (\dest), (\target), CC_SGT
- .endm
-
- .macro tfbsge, dest:req, target:req
- ..tfbn (\dest), (\target), CC_SLT
- .endm
-
- .macro tfbsgt, dest:req, target:req
- ..tfb (\dest), (\target), CC_SGT
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // TEB[N]<eng> - Test Engine and branch if [not] engine.
- //////////////////////////////////////////////////////////////////////
- //
- // All but GPE0 use a 1-hot code.
-
- .macro tebgpe0, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), 0xf
- braz (\dest), (\target)
- .endm
-
- .macro tebgpe1, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), PORE_ID_GPE1
- branz (\dest), (\target)
- .endm
-
- .macro tebslw, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), PORE_ID_SLW
- branz (\dest), (\target)
- .endm
-
- .macro tebsbe, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), PORE_ID_SBE
- branz (\dest), (\target)
- .endm
-
-
- .macro tebngpe0, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), 0xf
- branz (\dest), (\target)
- .endm
-
- .macro tebngpe1, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), PORE_ID_GPE1
- braz (\dest), (\target)
- .endm
-
- .macro tebnslw, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), PORE_ID_SLW
- braz (\dest), (\target)
- .endm
-
- .macro tebnsbe, dest:req, target:req
- mr (\dest), IFR
- andi (\dest), (\dest), PORE_ID_SBE
- braz (\dest), (\target)
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // EXTRPRC - Extract and right-justify the PIB/PCB return code
- // TPRCB[N]Z - Test PIB return code and branch if [not] zero
- // TPRCBGT - Test PIB return code and branch if greater-than
- // TPRCBLE - Test PIB return code and branch if less-then or equal
- //////////////////////////////////////////////////////////////////////
- //
- // To support cases where PORE code expects or must explicitly handle
- // non-0 PIB return codes, the PIB return code and parity indication
- // are stored in bits 32 (parity) and 33-35 (return code) of the IFR.
- // These macros extract the four PIB/PCB status bits from the IFR and
- // right-justifies them into the data register provided. For EXTRPRC
- // that is the total function of the macro. The TPRCB[N]Z macros
- // provide a simple non-destructive test and branch for zero (success)
- // and non-zero (potential problem) codes after the extraction.
- //
- // In complex error handling scenarios one would typically compare the
- // PIB return code against an upper-bound, e.g., the offline response
- // (0x2), and then take further action. If the parity error bit is set
- // then this would produce an aggregate "return code" higher than any
- // that one would typically want to ignore. The TPRCBGT/TPRCBLE macros
- // provide this function; however the test destroys the extracted
- // return code so that if further analysis is required the code will
- // need to be a extracted again.
- //////////////////////////////////////////////////////////////////////
-
- .macro extrprc, dest:req
- ..data (\dest)
- mr (\dest), IFR
- extrdi (\dest), (\dest), 4, 32
- .endm
-
- .macro tprcbz, dest:req, target:req
- extrprc (\dest)
- braz (\dest), (\target)
- .endm
-
- .macro tprcbnz, dest:req, target:req
- extrprc (\dest)
- branz (\dest), (\target)
- .endm
-
- .macro tprcbgt, dest:req, target:req, bound:req
- extrprc (\dest)
- subs (\dest), (\dest), (\bound)
- tfbugt (\dest), (\target)
- .endm
-
- .macro tprcble, dest:req, target:req, bound:req
- extrprc (\dest)
- subs (\dest), (\dest), (\bound)
- tfbule (\dest), (\target)
- .endm
-
- //////////////////////////////////////////////////////////////////////
- // LPCS - Load Pervasive Chiplet from Scom address
- //////////////////////////////////////////////////////////////////////
-
- .macro lpcs, dest:req, scom:req
- ..pervasive_chiplet_id (\dest)
- ..check_scom (\scom)
- ls (\dest), (((\scom) >> 24) & 0x7f)
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // Shift/Mask extended mnemonics
- //////////////////////////////////////////////////////////////////////
-
- // All of the 'dot-dot' macros assume that error and identity
- // checking has been done on the arguments already.
-
- // The initial register-register rotate. If the incoming shift amount
- // is 0 then the instruction generated is a simple MR.
-
- .macro ..rotlrr, ra, rs, sh
-
- .if (\sh) >= 32
- rols (\ra), (\rs), 32
- ..rotlr (\ra), ((\sh) - 32)
- .elseif (\sh) >= 16
- rols (\ra), (\rs), 16
- ..rotlr (\ra), ((\sh) - 16)
- .elseif (\sh) >= 8
- rols (\ra), (\rs), 8
- ..rotlr (\ra), ((\sh) - 8)
- .elseif (\sh) >= 4
- rols (\ra), (\rs), 4
- ..rotlr (\ra), ((\sh) - 4)
- .elseif (\sh) >= 1
- rols (\ra), (\rs), 1
- ..rotlr (\ra), ((\sh) - 1)
- .else
- mr (\ra), (\rs)
- .endif
-
- .endm
-
-
- // Subsequent rotation of the same register. The SH should never be 0
- // here.
-
- .macro ..rotlr, ra, sh
-
- .if (\sh) >= 32
- rols (\ra), (\ra), 32
- ..rotlr (\ra), ((\sh) - 32)
- .elseif (\sh) >= 16
- rols (\ra), (\ra), 16
- ..rotlr (\ra), ((\sh) - 16)
- .elseif (\sh) >= 8
- rols (\ra), (\ra), 8
- ..rotlr (\ra), ((\sh) - 8)
- .elseif (\sh) >= 4
- rols (\ra), (\ra), 4
- ..rotlr (\ra), ((\sh) - 4)
- .elseif (\sh) >= 1
- rols (\ra), (\ra), 1
- ..rotlr (\ra), ((\sh) - 1)
-
- .endif
-
- .endm
-
-
- // RLDINM RA, RS, SH, MB, ME
- //
- // Defined as if there were an equivalent PowerPC instruction. The
- // 'word' forms of the PowerPC instructions and extended mnemonics are
- // undefined in order to catch programming typos.
-
- .undefppc rlwinm, extrwi, rotlwi, rotrwi
- .undefppc slwi, srwi
-
- .macro rldinm, ra:req, rs:req, sh:req, mb:req, me:req
-
- .if ((\sh) < 0) || ((\sh) > 63)
- .error "SH must be in the range 0..63"
- .endif
- .if ((\mb) < 0) || ((\mb) > 63)
- .error "MB must be in the range 0..63"
- .endif
- .if ((\me) < 0) || ((\me) > 63)
- .error "ME must be in the range 0..63"
- .endif
-
- .if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1)))
-
- // The mask is effectively 0..63, i.e., no mask. This is a
- // simple rotate.
-
- ..rotlrr (\ra), (\rs), (\sh)
-
- .else
-
- // We need a mask step. However if SH == 0 and RA == RS we can
- // bypass the rotate step.
-
- .if ((\sh) != 0) || ((\ra) != (\rs))
- ..rotlrr (\ra), (\rs), (\sh)
- .endif
- .if ((\mb) <= (\me))
-
- // This is a straightforward masking operation with a
- // single mask.
-
- andi (\ra), (\ra), ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me))))
- .else
-
- // This is a wrapped mask.
- // It is created as 2 masks OR-ed together - 0-ME and MB-63
-
- andi (\ra), (\ra), (((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63))))
- .endif
-
- .endif
-
- .endm
-
- // RLDINM Extended Mnemonics
- //
- // Defined as if they were equivalent to PowerPC 32-bit extended
- // mnemonics
-
- .macro extldi, ra:req, rs:req, n:req, b:req
- .if ((\n) < 0)
- .error "EXTLDI requires N > 0"
- .endif
- rldinm (\ra), (\rs), (\b), 0, ((\n) - 1)
- .endm
-
- .macro extrdi, ra:req, rs:req, n:req, b:req
- .if ((\n) < 0)
- .error "EXTRDI requires N > 0"
- .endif
- rldinm (\ra), (\rs), (((\b) + (\n)) % 64), (64 - (\n)), 63
- .endm
-
- .macro rotldi, ra:req, rs:req, n:req
- rldinm (\ra), (\rs), (\n), 0, 63
- .endm
-
-
- .macro rotrdi, ra:req, rs:req, n:req
- rldinm (\ra), (\rs), (64 - (\n)), 0, 63
- .endm
-
-
- .macro sldi, ra:req, rs:req, n:req
- rldinm (\ra), (\rs), (\n), 0, (63 - (\n))
- .endm
-
-
- .macro srdi, ra:req, rs:req, n:req
- rldinm (\ra), (\rs), (64 - (\n)), (\n), 63
- .endm
-
-
- // RLDIMI RA, RS, SH, MB, ME
- //
- // Defined as if there were an equivalent PowerPC instruction. The
- // 'word' forms of the PowerPC instructions and extended mnemonics are
- // undefined in order to catch programming typos.
- //
- // Note that unlike the PowerPC instructions, here RLDIMI must destroy
- // RS by masking and shifting it, and RA and RS may not be the same
- // register.
-
- .undefppc rlwimi, inslwi, insrwi
-
- .macro rldimi, ra:req, rs:req, sh:req, mb:req, me:req
-
- ..dxdy (\ra), (\rs)
-
- // SH error checks are done by rldinm
-
- .if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1)))
-
- // The mask is effectively 0..63, i.e., no mask. This is a
- // simple rotate of RS into RA
-
- rotldi (\ra), (\rs), (\sh)
-
- .else
-
- // Rotate RS and AND with mask
-
- rldinm (\rs), (\rs), (\sh), (\mb), (\me)
-
- // Mask out the significant bits of RS, clear that section of
- // RA, and logical OR RS into RA
-
- .if ((\mb) <= (\me))
-
- // This is a straightforward masking operation with a
- // single mask.
-
- andi (\ra), (\ra), \
- (~((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me)))))
- .else
-
- // This is a wrapped mask.
- // It is created as 2 masks OR-ed together - 0-ME and MB-63
-
- andi (\ra), (\ra), \
- (~(((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | \
- ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63)))))
- .endif
-
- or (\ra), D0, D1
-
- .endif
-
- .endm
-
- // RLDIMI Extended Mnemonics
- //
- // Defined as if they were equivalent to PowerPC 32-bit extended
- // mnemonics
-
- .macro insldi, ra:req, rs:req, n:req, b:req
- .if ((\n) < 0)
- .error "INSLDI requires N > 0"
- .endif
- rldimi (\ra), (\rs), (64 - (\b)), (\b), ((\b) + (\n) - 1)
- .endm
-
- .macro insrdi, ra:req, rs:req, n:req, b:req
- .if ((\n) < 0)
- .error "INSRDI requires N > 0"
- .endif
- rldimi (\ra), (\rs), (64 - (\b) - (\n)), (\b), ((\b) + (\n) - 1)
- .endm
-
-
- //////////////////////////////////////////////////////////////////////
- // .HOOK
- //////////////////////////////////////////////////////////////////////
-
- // The PoreVe (PORE Virtual Environment) is a PORE simulation
- // environment that allows the programmer to embed C/C++ code into the
- // PORE assembler source code, and arranges for the C/C++ code to be
- // executed in-line with the PORE assembly code. Instances of the
- // .hook macro are inserted into the assembler input by the
- // hook_extractor script, to mark the locations where hooks are
- // present. The hook reference is a string that combines the source
- // file name with an index number to uniquely identify the hook.
- //
- // .hook <file name>_<sequence number>
- //
- // The .hook macro marks the location of each hook in the relocatable
- // binaries with special symbols. The symbol name includes the hook
- // reference, which is used to locate the hook in the HookManager
- // symbol table. Because hooks can be defined in macros, a hook that
- // appears once in a source file may appear multiple times in the
- // final binary. For this reason each hook must also be tagged with a
- // unique index number to avoid symbol name collisions. The
- // complexity of the .hook macro is due to the necessity to decode a
- // dynamic symbol value (_PGAS_HOOK_INDEX) into its binary string form
- // to create the unique symbol name. The final hook symbol has the
- // form:
- //
- // __hook__<unique>_<reference>
- //
- // where <unique> is a binary string. It is then straightforward to
- // locate these symbols in the 'nm' output of the final link and
- // create a map of final addresses to the hook routine to call (the
- // <reference>) before executing the instruction at that address.
- //
- // Note: The maximum nesting depth of the recursive ..hook_helper
- // macro is log2(index), and the assembler supports nesting of at
- // least 32 which is much more than sufficient.
-
- .set _PGAS_HOOK_INDEX, 0
-
- .macro .hook, reference:req
- .set _PGAS_HOOK_INDEX, (_PGAS_HOOK_INDEX + 1)
- ..hook_helper _PGAS_HOOK_INDEX, "", \reference
- .endm
-
- .macro ..hook_helper, index, unique, reference
- .ifeq \index
- __hook__\unique\()_\reference\():
- .elseif (\index % 2)
- ..hook_helper (\index / 2), 1\unique, \reference
- .else
- ..hook_helper (\index / 2), 0\unique, \reference
- .endif
- .endm
-
-
-////////////////////////////////////////////////////////////////////////////
-// Help for Conversion from Old to New PGAS syntax
-////////////////////////////////////////////////////////////////////////////
-
- .macro loadp, arg:vararg
- .error "PGAS now implements 'lpcs' rather then 'loadp'"
- .endm
-
- .macro loadx, arg:vararg
- .error "PGAS now implements 'la' rather than 'loadx'"
- .endm
-
-#endif // __ASSEMBLER__
-
-#ifdef PGAS_PPC
-#include "pgas_ppc.h"
-#endif
-
-#endif // __PGAS_H__
diff --git a/src/lib/pgas_ppc.h b/src/lib/pgas_ppc.h
deleted file mode 100755
index 6771e4b..0000000
--- a/src/lib/pgas_ppc.h
+++ /dev/null
@@ -1,529 +0,0 @@
-#ifndef __PGAS_PPC_H__
-#define __PGAS_PPC_H__
-
-// $Id: pgas_ppc.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pgas_ppc.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-// ** WARNING : This file is maintained as part of the OCC firmware. Do **
-// ** not edit this file in the PMX area, the hardware procedure area, **
-// ** or the PoreVe area as any changes will be lost. **
-
-/// \file pgas_ppc.h
-/// \brief Legacy PGAS assembler implemented as PowerPC assembler macros.
-///
-/// PGAS is documented in a seperate standalone document entitled <em> PGAS :
-/// PORE GAS (GNU Assembler) User's and Reference Manual </em>.
-///
-/// This file contains the legacy PGAS assembler, which was first implemented
-/// as this set of assembler macros for the PowerPC assembler. This file is
-/// included into pgas.h if the compile switch PGAS_PPC is defined in the
-/// compile environment.
-
-#ifdef __ASSEMBLER__
-
-////////////////////////////////////////////////////////////////////////////
-// PGAS Base Assembler
-////////////////////////////////////////////////////////////////////////////
-
-
- //////////////////////////////////////////////////////////////////////
- // Symbolic Register Mnemonics
- //////////////////////////////////////////////////////////////////////
- //
- // PGAS uses gas symbols for register mnemonics so that they will
- // appear as-is in assembler listings, but we can still do arithmetic
- // on the mnemonics in the PGAS macros.
-
- .set P0, PORE_REGISTER_PRV_BASE_ADDR0
- .set P1, PORE_REGISTER_PRV_BASE_ADDR1
- .set A0, PORE_REGISTER_OCI_BASE_ADDR0
- .set A1, PORE_REGISTER_OCI_BASE_ADDR1
- .set CTR, PORE_REGISTER_SCRATCH0
- .set D0, PORE_REGISTER_SCRATCH1
- .set D1, PORE_REGISTER_SCRATCH2
- .set EMR, PORE_REGISTER_ERROR_MASK
- .set ETR, PORE_REGISTER_EXE_TRIGGER
- .set SPRG0, PORE_REGISTER_DATA0
- .set PC, PORE_REGISTER_PC
- .set IFR, PORE_REGISTER_IBUF_ID
-
-
- //////////////////////////////////////////////////////////////////////
- // Core Instruction Set
- //////////////////////////////////////////////////////////////////////
-
- // The final construction of an instruction word. The opcode is a
- // 7-bit value and the operand is always a 24-bit value. Note that the
- // parity bit is always 0.
-
- .macro ..instruction, opcode, operand
- .long (\opcode << 25) | (\operand)
- .endm
-
- // NOP, TRAP, RET
-
- .macro nop
- ..instruction PGAS_OPCODE_NOP, 0
- .endm
-
- .macro trap
- ..instruction PGAS_OPCODE_TRAP, 0
- .endm
-
- .macro ret
- ..instruction PGAS_OPCODE_RET, 0
- .endm
-
- // WAITS, HALT, HOOKI
-
- .macro waits, u24:req
- ..check_u24 (\u24)
- .if ((\u24) == 0)
- .error "PGAS does not allow WAITS 0; Use HALT if the intention is to halt"
- .endif
- ..instruction PGAS_OPCODE_WAITS, (\u24)
- .endm
-
- .macro halt
- ..instruction PGAS_OPCODE_WAITS, 0
- .endm
-
- .macro hooki, u24:req, imm:req
- ..check_u24 (\u24)
- ..instruction PGAS_OPCODE_HOOKI, (\u24)
- .quad (\imm)
- .endm
-
- .macro wait, args:vararg
- .error "PGAS implements the 'waits' mnemonic instead of PORE 'wait'"
- .endm
-
- .macro hook, args:vararg
- .error "PGAS implements the 'hooki' mnemonic instead of PORE 'hook'"
- .endm
-
- // BRA, LOOP
- //
- // Note that all branch offsets in PORE are WORD offsets, so the byte
- // offsets computed by the underlying assembler need to be divided by
- // 4. Unfortunately PGAS is not able to check whether the offsets fit
- // in the allowed space.
-
- .macro ..bra, opcode, target
- ..instruction \opcode, ((((\target) - $) / 4) & 0xffffff)
- .endm
-
- .macro bra, target:req
- ..bra PGAS_OPCODE_BRA, (\target)
- .endm
-
- .macro loop, target:req
- ..bra PGAS_OPCODE_LOOP, (\target)
- .endm
-
- // BRAZ, BRANZ
-
- .macro ..brac, opcode, src, target
- ..branch_compare_data (\src)
- ..instruction \opcode, ((\src << 20) | ((((\target) - $) / 4) & 0xfffff))
- .endm
-
- .macro braz, src:req, target:req
- ..brac PGAS_OPCODE_BRAZ, (\src), (\target)
- .endm
-
- .macro branz, src:req, target:req
- ..brac PGAS_OPCODE_BRANZ, (\src), (\target)
- .endm
-
- // CMPIBRAEQ, CMPIBRANE
-
- .macro ..cmpibra, opcode, src, target, imm
- ..d0 (\src)
- ..instruction \opcode, ((((\target) - $) / 4) & 0xffffff)
- .quad (\imm)
- .endm
-
- .macro cmpibraeq, src:req, target:req, imm:req
- ..cmpibra PGAS_OPCODE_CMPIBRAEQ, (\src), (\target), (\imm)
- .endm
-
- .macro cmpibrane, src:req, target:req, imm:req
- ..cmpibra PGAS_OPCODE_CMPIBRANE, (\src), (\target), (\imm)
- .endm
-
- .macro cmpbra, args:vararg
- .error "PGAS implements the 'cmpibraeq' mnemonic instead of PORE 'cmpbra'"
- .endm
-
- .macro cmpnbra, args:vararg
- .error "PGAS implements the 'cmpibrane' mnemonic instead of PORE 'cmpnbra'"
- .endm
-
- // BRAD, BSRD
-
- .macro ..brad, opcode, src
- ..data (\src)
- ..instruction \opcode, ((\src) << 20)
- .endm
-
- .macro brad, src:req
- ..brad PGAS_OPCODE_BRAD, (\src)
- .endm
-
- .macro bsrd, src:req
- ..brad PGAS_OPCODE_BSRD, (\src)
- .endm
-
- // ANDI, ORI, XORI
-
- .macro ..ilogic, opcode, dest, src, imm
- ..data (\dest)
- ..data (\src)
- ..instruction \opcode, (((\dest) << 20) | ((\src) << 16))
- .quad \imm
- .endm
-
- .macro andi, dest:req, src:req, imm:req
- ..ilogic PGAS_OPCODE_ANDI, (\dest), (\src), (\imm)
- .endm
-
- .macro ori, dest:req, src:req, imm:req
- ..ilogic PGAS_OPCODE_ORI, (\dest), (\src), (\imm)
- .endm
-
- .macro xori, dest:req, src:req, imm:req
- ..ilogic PGAS_OPCODE_XORI, (\dest), (\src), (\imm)
- .endm
-
- // AND, OR, XOR, ADD, SUB
-
- .macro ..alurr, opcode, dest, src1, src2
- ..data (\dest)
- ..d0d1 (\src1), (\src2)
- ..instruction \opcode, ((\dest) << 20)
- .endm
-
- .macro and, dest:req, src1:req, src2:req
- ..alurr PGAS_OPCODE_AND, (\dest), (\src1), (\src2)
- .endm
-
- .macro or, dest:req, src1:req, src2:req
- ..alurr PGAS_OPCODE_OR, (\dest), (\src1), (\src2)
- .endm
-
- .macro xor, dest:req, src1:req, src2:req
- ..alurr PGAS_OPCODE_XOR, (\dest), (\src1), (\src2)
- .endm
-
- .macro add, dest:req, src1:req, src2:req
- ..alurr PGAS_OPCODE_ADD, (\dest), (\src1), (\src2)
- .endm
-
- .macro sub, dest:req, src1:req, src2:req
- ..alurr PGAS_OPCODE_SUB, (\dest), (\src1), (\src2)
- .endm
-
- // ADDS, SUBS
-
- .macro ..inc, opcode, dest, src, short
- ..check_s16 (\short)
- ..ls_destination (\dest)
- ..same (\dest), (\src)
- ..instruction (\opcode), (((\dest) << 20) | ((\short) & 0xffff))
- .endm
-
- .macro adds, dest:req, src:req, short:req
- ..inc PGAS_OPCODE_ADDS, (\dest), (\src), (\short)
- .endm
-
- .macro subs, dest:req, src:req, short:req
- ..inc PGAS_OPCODE_SUBS, (\dest), (\src), (\short)
- .endm
-
- .macro addi, args:vararg
- .error "PGAS implements the 'adds' mnemonic instead of PORE 'addi'"
- .endm
-
- .macro subi, args:vararg
- .error "PGAS implements the 'subs' mnemonic instead of PORE 'subi'"
- .endm
-
- // NEG
-
- .macro neg, dest:req, src:req
- ..data (\dest)
- ..data (\src)
- ..instruction PGAS_OPCODE_NEG, (((\dest) << 20) | ((\src) << 16))
- .endm
-
- // MR
-
- .macro mr, dest:req, src:req
- ..mr_destination (\dest)
- ..mr_source (\src)
- ..instruction PGAS_OPCODE_MR, (((\dest) << 20) | ((\src) << 16))
- .endm
-
- .macro copy, args:vararg
- .error "PGAS implents the 'mr' mnemonic instead of PORE 'copy'"
- .endm
-
- // ROLS
-
- .macro rols, dest:req, src:req, short:req
- ..data (\dest)
- ..data (\src)
- .if ((\short) != 1)
- .if ((\short) != 4)
- .if ((\short) != 8)
- .if ((\short) != 16)
- .if ((\short) != 32)
- .error "The legal ROLS shift amounts are 1, 4, 8, 16 and 32"
- .endif
- .endif
- .endif
- .endif
- .endif
- ..instruction PGAS_OPCODE_ROLS, (((\dest) << 20) | ((\src) << 16) | (\short))
- .endm
-
- .macro rol, args:vararg
- .error "PGAS implements the 'rols' mnemonic instead of PORE 'rol'"
- .endm
-
- // LS
-
- .macro ls, dest:req, short:req
- ..ls_destination (\dest)
- ..check_s20 (\short)
- ..instruction PGAS_OPCODE_LS, (((\dest) << 20) | ((\short) & 0xfffff))
- .endm
-
- .macro load20, args:vararg
- .error "PGAS implements the 'ls' mnemonic instead of PORE 'load20'"
- .endm
-
- // LI, LIA
-
- .macro ..li, dest:req
- ..li_destination (\dest)
- ..instruction PGAS_OPCODE_LI, ((\dest) << 20)
- .endm
-
- .macro li, dest:req, imm:req
- ..li (\dest)
- .quad (\imm)
- .endm
-
- .macro lia, dest:req, space:req, offset:req
- ..lia_destination (\dest)
- ..li (\dest)
- .quadia (\space), (\offset)
- .endm
-
- .macro load64, args:vararg
- .error "PGAS implements the 'li' mnemonic instead of PORE 'load64'"
- .endm
-
- // LD, LDANDI, STD, STI, STIA, BSI, BCI
- //
- // For LD, LDANDI, and STD, PGAS does not expose the underlying
- // register-specific opcodes but only provides the general form.
- //
- // The base register is used to determine if this is a load/store from
- // the pervasive or memory address spaces. For memory space accesses
- // the offset is a 22-bit unsigned value, and the final ima24 is
- //
- // 1<reg 0/1><offset>
- //
- // PGAS will not assemble relocatable offsets, and checks that offsets
- // fit in 24 bits.
- //
- // For pervasive accesses, it is assumed that the offset provided is a
- // 32-bit SCOM address. Here the final ima24 is
- //
- // 0<reg 0/1>00<port><local_address>
- //
- // PGAS checks that the 32-bit SCOM address looks like a SCOM address
- // in that SCOM adresses are required to have bits 0 and 8:11 == 0.
- //
- // Note that memory and pervasive base registers use a 0/1 encoding
- // here, not the 4-bit encoding used elsewhere in the ISA. The bit
- // appearing in the instruction is the low-order bit of the register
- // encoding.
-
- .macro ..pervasive_ima24, opcode, offset, base
- ..check_scom (\offset)
- ..instruction (\opcode), ((((\base) % 2) << 22) | ((\offset) & 0x3fffff))
- .endm
-
- .macro ..memory_ima24, opcode, offset, base
- ..check_u24 (\offset)
- .if ((\offset) % 8)
- .error "The memory space offset is not a multiple of 8 - assumed alignment error"
- .endif
- ..instruction (\opcode), (0x800000 | (((\base) % 2) << 22) | ((\offset) & 0x3fffff))
- .endm
-
- .macro ..ima24, opcode, offset, base
- .if ((\base == P0) || ((\base == P1)))
- ..pervasive_ima24 (\opcode), (\offset), (\base)
- .elseif ((\base == A0) || ((\base == A1)))
- ..memory_ima24 (\opcode), (\offset), (\base)
- .else
- .error "Expecting either a 'Pervasive Chiplet ID' or an 'Address' register"
- .endif
- .endm
-
- .macro ..ima24_select, opcode0, opcode1, dest, offset, base
- ..data (\dest)
- .if ((\dest) == D0)
- ..ima24 (\opcode0), (\offset), (\base)
- .else
- ..ima24 (\opcode1), (\offset), (\base)
- .endif
- .endm
-
- .macro ld, dest:req, offset:req, base:req
- ..ima24_select PGAS_OPCODE_LD0, PGAS_OPCODE_LD1, (\dest), (\offset), (\base)
- .endm
-
- .macro ldandi, dest:req, offset:req, base:req, imm:req
- ..ima24_select PGAS_OPCODE_LD0ANDI, PGAS_OPCODE_LD1ANDI, (\dest), (\offset), (\base)
- .quad (\imm)
- .endm
-
- .macro std, dest:req, offset:req, base:req
- ..ima24_select PGAS_OPCODE_STD0, PGAS_OPCODE_STD1, (\dest), (\offset), (\base)
- .endm
-
- .macro sti, offset:req, base:req, imm:req
- ..ima24 PGAS_OPCODE_STI, (\offset), (\base)
- .quad (\imm)
- .endm
-
- .macro stia, offset:req, base:req, space:req, addr:req
- ..ima24 PGAS_OPCODE_STI, (\offset), (\base)
- .quadia (\space), (\addr)
- .endm
-
- .macro ..bsi, opcode, dest, offset, base, imm
- ..d0 (\dest)
- ..ima24 (\opcode), (\offset), (\base)
- .quad (\imm)
- .endm
-
-#ifdef IGNORE_HW274735
-
- // BSI and BCI are normally redacted due to HW274735. See also pgas.h
-
- .macro bsi, dest:req, offset:req, base:req, imm:req
- ..bsi PGAS_OPCODE_BSI, (\dest), (\offset), (\base), (\imm)
- .endm
-
- .macro bci, dest:req, offset:req, base:req, imm:req
- ..bsi PGAS_OPCODE_BCI, (\dest), (\offset), (\base), (\imm)
- .endm
-
-#endif // IGNORE_HW274735
-
- .macro scr1rd, args:vararg
- .error "PGAS implements the 'ld' mnemonic instead of the PORE 'scr1rd'"
- .endm
-
- .macro scr2rd, args:vararg
- .error "PGAS implements the 'ld' mnemonic instead of the PORE 'scr2rd'"
- .endm
-
- .macro scr1rda, args:vararg
- .error "PGAS implements the 'ldandi' mnemonic instead of the PORE 'scr1rda'"
- .endm
-
- .macro scr2rda, args:vararg
- .error "PGAS implements the 'ldandi' mnemonic instead of the PORE 'scr2rda'"
- .endm
-
- .macro scr1wr, args:vararg
- .error "PGAS implements the 'std' mnemonic instead of the PORE 'scr1wr'"
- .endm
-
- .macro scr2wr, args:vararg
- .error "PGAS implements the 'std' mnemonic instead of the PORE 'scr2wr'"
- .endm
-
- .macro wri, args:vararg
- .error "PGAS implements the 'sti' mnemonic instead of the PORE 'wri'"
- .endm
-
- .macro bs, args:vararg
- .error "PGAS implements the 'bsi' mnemonic instead of the PORE 'bs'"
- .endm
-
- .macro bc, args:vararg
- .error "PGAS implements the 'bci' mnemonic instead of the PORE 'bc'"
- .endm
-
- // SCAND
- //
- // The 24-bit operand here is
- //
- // <update><capture>000000<length>
-
- .macro scand, update:req, capture:req, length:req, select:req, offset:req
- .if (((\update) != 0) && ((\update) != 1))
- .error "SCAND requires a binary value for 'update'"
- .endif
- .if (((\capture) != 0) && ((\capture) != 1))
- .error "SCAND requires a binary value for 'capture'"
- .endif
- ..check_u16 (\length)
- ..instruction PGAS_OPCODE_SCAND, ((\update << 23) | (\capture << 22) | (\length))
- .long (\select)
- .long (\offset)
- .endm
-
- // BRAIA, BSR, CMPIBSREQ
- //
- // In order to support separate compilation in PGAS programs being
- // linked with the PowerPC linker it is necessary to implement BSR and
- // CMPIBSREQ in terms of BRAIA. These instructions require that the
- // default address space have been defined. The BSR instructions
- // first take a short local subroutine branch to create a stack frame,
- // then use BRAIA to branch to the (relocatable) target address. The
- // return from the subroutine then branches around the BRAIA to
- // complete the sequence.
-
- .macro braia, space:req, offset:req
- ..instruction PGAS_OPCODE_BRAI, 0
- .quadia (\space), (\offset)
- .endm
-
- .macro ..bsr, target
- ..bra PGAS_OPCODE_BSR, (\target)
- .endm
-
- .macro bsr, target:req
- ..check_default_space
- ..bsr (. + 8)
- bra (. + 16)
- braia _PGAS_DEFAULT_SPACE, (\target)
- .endm
-
- .macro cmpibsreq, src:req, target:req, imm:req
- ..d0 (\src)
- ..check_default_space
- cmpibrane (\src), (. + 32), (\imm)
- ..bsr (. + 8)
- bra (. + 16)
- braia _PGAS_DEFAULT_SPACE, (\target)
- .endm
-
-#endif // __ASSEMBLER__
-
-#endif // __PGAS_PPC_H__
diff --git a/src/lib/pgp_config.h b/src/lib/pgp_config.h
deleted file mode 100755
index f4041d4..0000000
--- a/src/lib/pgp_config.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef __PGP_CONFIG_H__
-#define __PGP_CONFIG_H__
-
-// $Id: pgp_config.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pgp_config.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file pgp_config.h
-/// \brief Chip configuration data structures for PgP OCC procedures
-
-#ifndef __ASSEMBLER__
-
-#include <stdint.h>
-
-/// A bitmask defining a chip configuration
-///
-/// Since we are using the conventional big-endian notation, any use of these
-/// bitmasks requires that the data being tested is of this type - otherwise
-/// the masks won't work.
-///
-/// Layout:
-///
-/// Bits 0:15 - Core chiplet 0..15 is configured
-/// Bits 16:23 - MCS 0..7 is configured
-/// Bits 24:31 - Centaur 0..7 is configured
-
-typedef uint64_t ChipConfig;
-typedef uint16_t ChipConfigCores;
-typedef uint8_t ChipConfigMcs;
-typedef uint8_t ChipConfigCentaur;
-
-
-/// Convert a ChipConfig into a mask suitable for use as the 32-bit chiplet
-/// mask argument of a PORE wakeup program.
-
-static inline uint32_t
-pore_exe_mask(ChipConfig config)
-{
- return (uint32_t)((config >> 32) & 0xffff0000);
-}
-
-/// Left justify and mask core chiplet configuration into a uint32_t
-
-static inline uint32_t
-left_justify_core_config(ChipConfig config)
-{
- return (uint32_t)((config >> 32) & 0xffff0000);
-}
-
-/// Left justify and mask MCS configuration into a uint32_t
-
-static inline uint32_t
-left_justify_mcs_config(ChipConfig config)
-{
- return (uint32_t)((config >> 16) & 0xff000000);
-}
-
-/// Left justify and mask Centaur configuration into a uint32_t
-
-static inline uint32_t
-left_justify_centaur_config(ChipConfig config)
-{
- return (uint32_t)((config >> 8) & 0xff000000);
-}
-
-#endif // __ASSEMBLER__
-
-
-#define CHIP_CONFIG_CORE_BASE 0
-#define CHIP_CONFIG_CORE(n) \
- ((0x8000000000000000ull >> CHIP_CONFIG_CORE_BASE) >> (n))
-
-#define CHIP_CONFIG_MCS_BASE 16
-#define CHIP_CONFIG_MCS(n) \
- ((0x8000000000000000ull >> CHIP_CONFIG_MCS_BASE) >> (n))
-
-#define CHIP_CONFIG_CENTAUR_BASE 24
-#define CHIP_CONFIG_CENTAUR(n) \
- ((0x8000000000000000ull >> CHIP_CONFIG_CENTAUR_BASE) >> (n))
-
-
-// PGAS macros to left justify configuration groups, allowing each member to
-// be tested in a loop that rotates the data (d) register left on each loop,
-// assuming standard big-endian bit assignments. The macros mask off all other
-// configuration bits so the destination register can also be tested for
-// 0/non-0 to determine if any of a configuration class are selected.
-
-#ifdef __PGAS__
-
- .macro left_justify_core_config, d
- extldi (\d), (\d), PGP_NCORES, CHIP_CONFIG_CORE_BASE
- .endm
-
- .macro left_justify_mcs_config, d
- extldi (\d), (\d), PGP_NMCS, CHIP_CONFIG_MCS_BASE
- .endm
-
- .macro left_justify_centaur_config, d
- extldi (\d), (\d), PGP_NCENTAUR, CHIP_CONFIG_CENTAUR_BASE
- .endm
-
-#endif /* __PGAS__ */
-
-#endif /* __PGP_CONFIG_H__ */
diff --git a/src/lib/pmc_dcm.c b/src/lib/pmc_dcm.c
deleted file mode 100755
index a0f7d82..0000000
--- a/src/lib/pmc_dcm.c
+++ /dev/null
@@ -1,425 +0,0 @@
-// $Id: pmc_dcm.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pmc_dcm.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file pmc_dcm.c
-/// \brief Genertic PMC Interhchip Communication Mechanism
-
-#include "ssx.h"
-#include "pmc_dcm.h"
-
-////////////////////////////////////////////////////////////////////////////
-// Low-level PMC-DCM Interfaces
-////////////////////////////////////////////////////////////////////////////
-
-/// Non-blocking transmission of a packet over the PMC-DCM interface
-///
-/// Note: Locking/synchronization of the PMC-DCM interface is the
-/// responsibility of the application.
-///
-/// \param hwPacket A PmcDcmPacket structure to be sent via PMC interchip link
-/// This argument is provided by the caller and passed in as reference.
-///
-/// \code
-/// hwPacket:
-///
-/// cmd_code | cmd_ext | payload 0 | payload 1 | ECC
-/// [0:3] | [4:7] | [8:15] | [16:23] | [24:31]
-///
-/// cmd_code:
-/// PMC_IC_GPA_CC | 1 | 0b0001 | Global PState Actual | Master to Slave
-/// PMC_IC_GPA_ACK_CC | 2 | 0b0010 | Global PState Ack | Slave to Master
-/// PMC_IC_GAR_CC | 3 | 0b0011 | Global Actual Request | Slave to Master
-/// PMC_IC_PING_CC | 4 | 0b0100 | Ping | Master to Slave
-/// PMC_IC_PING_ACK_CC | 6 | 0b0110 | Ping Acknowledge | Slave to Master
-/// PMC_IC_MSG_CC | 8 | 0b1000 | Message | Bidirectional
-/// PMC_IC_MSG_NACK_CC | 10 | 0b1010 | Message NACK | Bidirectional
-/// PMC_IC_MSG_ACK_CC | 11 | 0b1011 | Message ACK | Bidirectional
-/// PMC_IC_ERROR_CC | 12 | 0b1111 | Error | Slave to Master
-/// \endcode
-///
-/// This API sends command to another chip through the PMC interchip wire
-/// in DCM setup. The message will be sent out by writing the packet value
-/// to the regisiter: PMC_INTCHP_MSG_WDATA
-///
-/// It also checks the interchip_ga_ongoing and interchip_msg_send_ongoing
-/// bits of PMC_INTCHP_STATUS_REG to detect if the channel is free
-/// If the channel is busy, the function will exit with returning
-/// an error code \a PMC_DCM_OUTSTANDING_TRANSFER
-///
-/// Prerequisite: The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// Also, the hardware must be in DCM setup
-///
-/// Note: This API can be used to send any valid command over the link
-/// however, both command code and corresponding direction of transfer
-/// will be checked to ensure correctness of the protocol. Upon
-/// attempt to send an invalid command or an unexpected direction
-/// of transfering certain command will cause this API to abort
-/// which indicates a HW/FW bug
-///
-/// \retval PMC_DCM_SUCCESS
-///
-/// \retval PMC_DCM_ARG_NULL_OBJECT_SEND
-///
-/// \retval PMC_DCM_INTCHP_DISABLED_SEND
-///
-/// \retval PMC_DCM_OUTSTANDING_TRANSFER
-///
-/// \retval PMC_DCM_INVALID_COMMAND_CODE
-///
-
-int
-pmc_dcm_send(PmcDcmPacket* hwPacket)
-{
- int rc = PMC_DCM_SUCCESS;
-
- do {
-
- // check if reference packet is null
- SSX_ERROR_IF_CHECK_API(
- (hwPacket == 0),
- PMC_DCM_ARG_NULL_OBJECT_SEND);
-
- // check if interchip transfer is enabled on this chip
- SSX_ERROR_IF_CHECK_API(
- (pmc_dcm_if_interchip_interface_enabled() == 0),
- PMC_DCM_INTCHP_DISABLED_SEND);
-
- //check if command code is valid and direction of transfer is valid
- rc = pmc_dcm_check_ic_command((int)hwPacket->fields.cmd_code);
- if( rc ) break;
-
- // check if the interchip channel is busy
- if( pmc_dcm_if_channel_busy() ) {
- rc = PMC_DCM_OUTSTANDING_TRANSFER;
- break;
- }
-
- // send out the command
- _pmc_dcm_send(&hwPacket->value);
-
- } while (0);
-
- return rc;
-}
-
-/// Non-blocking reception of a packet from the PMC-DCM interface
-///
-/// Note: Locking/synchronization of the PMC-DCM interface is the
-/// responsibility of the application.
-///
-/// \param hwPacket A PmcDcmPacket structure passed by the caller
-/// as reference to receive the message sent from PMC interchip link
-///
-/// This API receives the message from the PMC interchip wire
-/// by reading the register: PMC_INTCHP_MSG_RDATA
-///
-/// It checks the interchip_msg_recv_detected bit of
-/// PMC_INTCHP_STATUS_REG to know if there is a new message
-/// If no new message is detected, the receive function will
-/// exit with returning an error code \a PMC_DCM_RECEIVE_NOT_DETECTRD
-///
-/// Prerequisite: The enable_interchip_interface bit of PMC_MODE_REG
-/// must be set to enable the PMC interchip transfer
-/// Also, the hardware must be in DCM setup
-///
-/// Note: only MSG type message or cmd code should be received
-/// otherwise function aborts and indicates a hardware bug
-///
-/// \retval PMC_DCM_SUCCESS
-///
-/// \retval PMC_DCM_ARG_NULL_OBJECT_RECV
-///
-/// \retval PMC_DCM_INTCHP_DISABLED_RECV
-///
-/// \retval PMC_DCM_RECEIVE_NOT_DETECTRD
-///
-/// \retval PMC_DCM_RECEIVE_NOT_MSG_TYPE
-///
-
-int
-pmc_dcm_receive(PmcDcmPacket* hwPacket)
-{
- int rc = PMC_DCM_SUCCESS;
-
- do {
-
- //check if reference packet is null
- SSX_ERROR_IF_CHECK_API(
- (hwPacket == 0),
- PMC_DCM_ARG_NULL_OBJECT_RECV);
-
- // check if interchip transfer is enabled on this chip
- SSX_ERROR_IF_CHECK_API(
- (!pmc_dcm_if_interchip_interface_enabled()),
- PMC_DCM_INTCHP_DISABLED_RECV);
-
- // check if there is a new incoming message
- if( !pmc_dcm_if_new_message() ) {
- rc = PMC_DCM_RECEIVE_NOT_DETECTED;
- break;
- }
-
- // receive the new message
- _pmc_dcm_receive(&hwPacket->value);
-
- // check if the command is MSG type
- SSX_ERROR_IF_CHECK_API(
- (hwPacket->fields.cmd_code != PMC_IC_MSG_CC),
- PMC_DCM_RECEIVE_NOT_MSG_TYPE);
-
- } while (0);
-
- return rc;
-}
-
-
-
-/// Internal API : Send data without error checking
-///
-/// \param value 32 bits data to be sent
-///
-/// This API send the interchip data by writing register:
-/// PMC_INTCHP_MSG_WDATA
-///
-/// \retval NONE
-///
-
-void
-_pmc_dcm_send(uint32_t *value)
-{
- out32(PMC_INTCHP_MSG_WDATA, *value);
-}
-
-
-/// Internal API : Receive data without error checking
-///
-/// \param value 32 bits data to be received
-///
-/// This API receive the interchip data by reading register:
-/// PMC_INTCHP_MSG_RDATA
-///
-/// \retval NONE
-///
-
-void
-_pmc_dcm_receive(uint32_t *value)
-{
- *value = in32(PMC_INTCHP_MSG_RDATA);
-}
-
-/// This API tells if the given command is a valid pmc interchip command
-/// and if the command is given by the designated source
-///
-/// \param cmd_code the command code
-///
-/// \param rc the return code back to caller
-///
-/// \code
-/// cmd_code:
-///
-/// PMC_IC_GPA_CC | 1 | 0b0001 | Global PState Actual | Master to Slave
-/// PMC_IC_GPA_ACK_CC | 2 | 0b0010 | Global PState Ack | Slave to Master
-/// PMC_IC_GAR_CC | 3 | 0b0011 | Global Actual Request | Slave to Master
-/// PMC_IC_PING_CC | 4 | 0b0100 | Ping | Master to Slave
-/// PMC_IC_PING_ACK_CC | 6 | 0b0110 | Ping Acknowledge | Slave to Master
-/// PMC_IC_MSG_CC | 8 | 0b1000 | Message | Bidirectional
-/// PMC_IC_MSG_NACK_CC | 10 | 0b1010 | Message NACK | Bidirectional
-/// PMC_IC_MSG_ACK_CC | 11 | 0b1011 | Message ACK | Bidirectional
-/// PMC_IC_ERROR_CC | 12 | 0b1111 | Error | Slave to Master
-/// \endcode
-///
-/// \retval PMC_DCM_INTCHP_CMD_ONLY_MTOS
-///
-/// \retval PMC_DCM_INTCHP_CMD_ONLY_STOM
-///
-/// \retval PMC_DCM_INVALID_COMMAND_CODE
-///
-
-int
-pmc_dcm_check_ic_command(int cmd_code)
-{
- //note:certain command can only be transferred from master to slave
- // or from slave to master or bidirectional.
- if( cmd_code == PMC_IC_GPA_CC ||
- cmd_code == PMC_IC_PING_CC ) {
- //those commands can only be sent from master to slave
- SSX_ERROR_IF_CHECK_API(
- (!pmc_dcm_if_dcm_master()),
- PMC_DCM_INTCHP_CMD_ONLY_MTOS);
- } else if( cmd_code == PMC_IC_GPA_ACK_CC ||
- cmd_code == PMC_IC_GAR_CC ||
- cmd_code == PMC_IC_PING_ACK_CC ||
- cmd_code == PMC_IC_ERROR_CC ) {
- //those commands can only be sent from slave to master
- SSX_ERROR_IF_CHECK_API(
- (pmc_dcm_if_dcm_master()),
- PMC_DCM_INTCHP_CMD_ONLY_STOM);
- } else if( !(cmd_code == PMC_IC_MSG_CC ||
- cmd_code == PMC_IC_MSG_NACK_CC ||
- cmd_code == PMC_IC_MSG_ACK_CC) ) {
- //those commands are bidirectional
- //none of above, invalid command
- SSX_ERROR_IF_CHECK_API(
- 0,
- PMC_DCM_INVALID_COMMAND_CODE);
- }
- return PMC_DCM_SUCCESS;
-}
-
-
-
-/// This API tells if the current chip is the DCM master or slave
-///
-/// \param NONE
-///
-/// The DCM master/slave is configured as the interchip_mode bit in register:
-/// PMC_MODE_REG
-///
-/// \retval 1 Master
-///
-/// \retval 0 Slave
-///
-
-int
-pmc_dcm_if_dcm_master()
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- return pmc_mode_reg.fields.enable_interchip_interface &&
- pmc_mode_reg.fields.interchip_mode;
-}
-
-/// This API sets the current chip to be the DCM master or slave
-///
-/// \param master if 1 then set to master otherwise slave
-///
-/// The DCM master/slave is configured as the interchip_mode bit in register:
-/// PMC_MODE_REG
-///
-/// \retval NONE
-///
-
-void
-pmc_dcm_set_interchip_mode(int master)
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- pmc_mode_reg.fields.enable_interchip_interface = 1;
- if( master == 0 )
- pmc_mode_reg.fields.interchip_mode = 0;
- else
- pmc_mode_reg.fields.interchip_mode = 1;
- out32(PMC_MODE_REG, pmc_mode_reg.value);
-}
-
-/// This API tells if the current chip is enabled with interchip interface
-///
-/// \param NONE
-///
-/// The DCM master/slave is configured as the enable_interchip_interface bit
-/// in register: PMC_MODE_REG
-///
-/// Note: set this bit is required for any interchip communication
-///
-/// \retval 1 Enabled
-///
-/// \retval 0 Disabled
-///
-
-int
-pmc_dcm_if_interchip_interface_enabled()
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- return pmc_mode_reg.fields.enable_interchip_interface;
-}
-
-/// This API sets the current chip to be enabled with interchip interface
-///
-/// \param enable if 1 then interface enabled otherwise disabled
-///
-/// The DCM master/slave is configured as the enable_interchip_interface bit
-/// in register: PMC_MODE_REG
-///
-/// \retval NONE
-///
-
-void
-pmc_dcm_set_interchip_interface(int enable)
-{
- pmc_mode_reg_t pmc_mode_reg;
- pmc_mode_reg.value = in32(PMC_MODE_REG);
- if( enable == 0 )
- pmc_mode_reg.fields.enable_interchip_interface = 0;
- else
- pmc_mode_reg.fields.enable_interchip_interface = 1;
- out32(PMC_MODE_REG, pmc_mode_reg.value);
-}
-
-
-/// This API tells if the interchip channel is busy for outgoing communication
-///
-/// \param NONE
-///
-/// depends on bits: interchip_ga_ongoing and interchip_msg_send_ongoing
-/// in register: PMC_INTCHP_STATUS_REG
-///
-/// \retval 1 Busy
-///
-/// \retval 0 Free
-///
-
-int
-pmc_dcm_if_channel_busy()
-{
- pmc_intchp_status_reg_t pmc_intchp_status_reg;
- pmc_intchp_status_reg.value = in32(PMC_INTCHP_STATUS_REG);
- return pmc_intchp_status_reg.fields.interchip_msg_send_ongoing;
- //return (pmc_intchp_status_reg.fields.interchip_ga_ongoing ||
- // pmc_intchp_status_reg.fields.interchip_msg_send_ongoing);
-}
-
-/// This API tells if there is a new message arrived from the interchip wire
-///
-/// \param NONE
-///
-/// if bit interchip_msg_recv_detected in register: PMC_INTCHP_STATUS_REG
-/// is set then new message otherwise none
-///
-/// \retval 1 New Message
-///
-/// \retval 0 NO New Message
-///
-
-int
-pmc_dcm_if_new_message()
-{
- pmc_intchp_status_reg_t pmc_intchp_status_reg;
- pmc_intchp_status_reg.value = in32(PMC_INTCHP_STATUS_REG);
- return pmc_intchp_status_reg.fields.interchip_msg_recv_detected;
-}
-
-/// This API initializes the DCM setup
-///
-/// \param master_or_slave configure the current chip to be master or slave
-///
-/// for current chip
-/// 1) enable interchip interface
-/// 2) configure to be DCM master or slave
-///
-/// Note: one chip has to be master and one chip has to be slave
-///
-/// \retval NONE
-///
-
-void
-pmc_dcm_init(int master_or_slave)
-{
- pmc_dcm_set_interchip_mode(master_or_slave);
-}
diff --git a/src/lib/pmc_dcm.h b/src/lib/pmc_dcm.h
deleted file mode 100755
index 3141aec..0000000
--- a/src/lib/pmc_dcm.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef __PMC_DCM_H__
-#define __PMC_DCM_H__
-
-// $Id: pmc_dcm.h,v 1.2 2014/02/03 01:30:25 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pmc_dcm.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file pmc_dcm.h
-/// \brief Generic PMC Interhchip Communication Mechanism
-
-
-/// PMC-DCM Return Code
-#define PMC_DCM_SUCCESS 0
-#define PMC_DCM_ARG_NULL_OBJECT_SEND 0x00326501 //ssx panic
-#define PMC_DCM_ARG_NULL_OBJECT_RECV 0x00326501 //ssx panic
-#define PMC_DCM_INTCHP_DISABLED_SEND 0x00326502 //ssx panic
-#define PMC_DCM_INTCHP_DISABLED_RECV 0x00326502 //ssx panic
-#define PMC_DCM_OUTSTANDING_TRANSFER 0x00326503 //user handle
-#define PMC_DCM_INTCHP_CMD_ONLY_MTOS 0x00326504 //ssx panic
-#define PMC_DCM_INTCHP_CMD_ONLY_STOM 0x00326504 //ssx panic
-#define PMC_DCM_INVALID_COMMAND_CODE 0x00326505 //ssx panic
-#define PMC_DCM_RECEIVE_NOT_DETECTED 0x00326506 //user handle
-#define PMC_DCM_RECEIVE_NOT_MSG_TYPE 0x00326507 //ssx panic
-
-/// PMC Interchip Command Code
-#define PMC_IC_GPA_CC 1 //0b0001
-#define PMC_IC_GPA_ACK_CC 2 //0b0010
-#define PMC_IC_GAR_CC 3 //0b0011
-#define PMC_IC_PING_CC 4 //0b0100
-#define PMC_IC_PING_ACK_CC 6 //0b0110
-#define PMC_IC_MSG_CC 8 //0b1000
-#define PMC_IC_MSG_NACK_CC 10 //0b1010
-#define PMC_IC_MSG_ACK_CC 11 //0b1011
-#define PMC_IC_ERROR_CC 15 //0b1111
-
-#ifndef __ASSEMBLER__
-
-/// PMC-DCM low-level (hardware) packet
-
-typedef union PmcInterchipPacket {
- uint32_t value;
- struct {
- /// Hardware command code
- uint8_t cmd_code : 4;
- /// Hardware command extension; GPSM-DCM command code
- uint8_t cmd_ext : 4;
- /// Payload. The plan of record is to use payload[2] as HW-generated ECC.
- uint8_t payload[3];
- } fields;
-} PmcDcmPacket;
-
-/// Macro to set and get payload field
-#define SET_PAYLOAD_FIELD(value) (value << 8) & 0xFFFF00
-#define GET_PAYLOAD_FIELD(value) (value & 0xFFFF00) >> 8
-
-
-/// low-level PMC-DCM interchip communication methods
-
-int
-pmc_dcm_send(PmcDcmPacket* hwPacket);
-
-int
-pmc_dcm_receive(PmcDcmPacket* hwPacket);
-
-void
-_pmc_dcm_send(uint32_t *value);
-
-void
-_pmc_dcm_receive(uint32_t *value);
-
-int
-pmc_dcm_check_ic_command(int cmd_code);
-
-int
-pmc_dcm_if_dcm_master();
-
-void
-pmc_dcm_set_interchip_mode(int master);
-
-int
-pmc_dcm_if_interchip_interface_enabled();
-
-void
-pmc_dcm_set_interchip_interface(int enable);
-
-int
-pmc_dcm_if_channel_busy();
-
-int
-pmc_dcm_if_new_message();
-
-void
-pmc_dcm_init(int master_or_slace);
-
-#endif /* __ASSEMBLER__ */
-
-#endif /* __PMC_DCM_H__ */
-
diff --git a/src/lib/polling.c b/src/lib/polling.c
deleted file mode 100644
index 42e9fef..0000000
--- a/src/lib/polling.c
+++ /dev/null
@@ -1,73 +0,0 @@
-// $Id: polling.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/polling.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file polling.c
-/// \brief Library APIs for polling
-
-#include "polling.h"
-
-int
-polling(int* o_rc,
- int (*i_condition)(void* io_arg, int* o_satisfied),
- void* io_arg,
- SsxInterval i_timeout,
- SsxInterval i_sleep)
-{
- SsxTimebase start;
- int rc, pollRc, timed_out, done;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((i_condition == 0), POLLING_ERROR);
- }
-
- start = ssx_timebase_get();
- timed_out = 0;
-
- do {
- pollRc = i_condition(io_arg, &done);
- if (pollRc) {
- rc = POLLING_CONDITION;
- break;
- }
- if (done) {
- rc = 0;
- break;
- }
- if (timed_out) {
- rc = POLLING_TIMEOUT;
- break;
- }
- if (i_sleep != 0) {
- rc = ssx_sleep(i_sleep);
- if (rc) {
- break;
- }
- }
- timed_out =
- ((i_timeout != SSX_WAIT_FOREVER) &&
- ((ssx_timebase_get() - start) >= i_timeout));
-
- } while (1);
-
- if (o_rc) {
- *o_rc = pollRc;
- }
-
- return rc;
-}
-
-
-void
-busy_wait(SsxInterval i_interval)
-{
- SsxTimebase start;
-
- start = ssx_timebase_get();
- while ((ssx_timebase_get() - start) < i_interval);
-}
-
diff --git a/src/lib/pore_hooks.h b/src/lib/pore_hooks.h
deleted file mode 100755
index f278acb..0000000
--- a/src/lib/pore_hooks.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef __PORE_HOOKS_H__
-#define __PORE_HOOKS_H__
-
-// $Id: pore_hooks.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pore_hooks.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file pore_hooks.h
-/// \brief Support for PORE hooks in Simics
-///
-/// Our Simics model of the PORE supports "hooks", that is, special forms of
-/// comments that include C++ code that is extracted and made available at
-/// simulation time in the Simics environment.
-///
-/// Besides hooks that do simple printf() type tracing, logging and tracing
-/// hooks are also provided that make use of the Simics log-level facility.
-/// This allows precise control over which PORE objects are logged/traced, and
-/// at which level.
-///
-/// In the Simics environment, hook routines have the following prototype:
-///
-/// void f(const PoreAddress& i_address,
-/// const HookType i_type,
-/// PoreSimics& io_pore);
-
-// Define the "1-liner" syntax
-
-#define HOOK_MARKER HOOK_INSERT_MARKER(#,#)
-#define HOOK_INSERT_MARKER(x,y) x##y##1@
-
-
-/// \defgroup standard_io_hooks Standard I/O Logging and Tracing Hooks
-///
-/// Standard I/O printing. The *TRACE* forms prefix the output with the file
-/// name and line number.
-///
-/// @{
-
-#define PORE_PRINTF(...) HOOK_MARKER printf(__VA_ARGS__);
-
-#define PORE_FPRINTF(stream, ...) HOOK_MARKER fprintf(stream, __VA_ARGS__);
-
-#define PORE_TRACEF(fmt, ...) \
- HOOK_MARKER printf("%s:d:" fmt, __FILE__, __LINE__, ##__VA_ARGS__);
-
-#define PORE_FTRACEF(stream, fmt, ...) \
- HOOK_MARKER printf(stream, "%s:d:" fmt, __FILE__, __LINE__, ##__VA_ARGS__);
-
-/// @}
-
-/// \defgroup quickie_debugging_prints Quickie Debugging Print Hooks
-///
-/// Quickie debugging prints. You provide a register name and string (w/o
-/// newline), the macro formats the data.
-///
-/// @{
-
-#define PORE_PRINT_REG(msg, reg, fmt, fn) \
- PORE_PRINTF(msg " : " #reg " = " FMT_##fmt "\n", fn)
-
-#define PORE_TRACE_REG(msg, reg, fmt, fn) \
- PORE_TRACEF(msg " : " #reg " = " FMT_##fmt "\n", fn)
-
-#define PORE_PRINT_D0(msg) PORE_PRINT_REG(msg, D0, DX, d0())
-#define PORE_PRINT_D1(msg) PORE_PRINT_REG(msg, D1, DX, d1())
-#define PORE_PRINT_A0(msg) PORE_PRINT_REG(msg, A0, AX, a0())
-#define PORE_PRINT_A1(msg) PORE_PRINT_REG(msg, A1, AX, a1())
-#define PORE_PRINT_P0(msg) PORE_PRINT_REG(msg, P0, PX, p0())
-#define PORE_PRINT_P1(msg) PORE_PRINT_REG(msg, P1, PX, p1())
-#define PORE_PRINT_CTR(msg) PORE_PRINT_REG(msg, CTR, CTR, ctr())
-#define PORE_PRINT_SPRG0(msg) PORE_PRINT_REG(msg, SPRG0, SPRG0, sprg0())
-#define PORE_PRINT_STATUS(msg) PORE_PRINT_REG(msg, STATUS, STATUS, status())
-#define PORE_PRINT_CONTROL(msg) PORE_PRINT_REG(msg, CONTROL, CONTROL, control())
-
-#define PORE_TRACE_D0(msg) PORE_TRACE_REG(msg, D0, DX, d0())
-#define PORE_TRACE_D1(msg) PORE_TRACE_REG(msg, D1, DX, d1())
-#define PORE_TRACE_A0(msg) PORE_TRACE_REG(msg, A0, AX, a0())
-#define PORE_TRACE_A1(msg) PORE_TRACE_REG(msg, A1, AX, a1())
-#define PORE_TRACE_P0(msg) PORE_TRACE_REG(msg, P0, PX, p0())
-#define PORE_TRACE_P1(msg) PORE_TRACE_REG(msg, P1, PX, p1())
-#define PORE_TRACE_CTR(msg) PORE_TRACE_REG(msg, CTR, CTR, ctr())
-#define PORE_TRACE_SPRG0(msg) PORE_TRACE_REG(msg, SPRG0, SPRG0, sprg0())
-#define PORE_TRACE_STATUS(msg) PORE_TRACE_REG(msg, STATUS, STATUS, status())
-#define PORE_TRACE_CONTROL(msg) PORE_TRACE_REG(msg, CONTROL, CONTROL, control())
-
-/// @}
-
-/// \defgroup simics_style_logging Simics-style Logging Hooks
-///
-/// Simics-style logging. All of these will produce a Simics prefix detailing
-/// the unit that failed. The *_TRACE_* forms add the file name and line number
-/// to the Simics info, print a newline and then format the trace message on
-/// the following line.
-///
-/// @{
-
-#define SIM_LOG_INFO(level, group, ...) HOOK_MARKER \
- SIM_log_info(level, io_pore.d_log, group, __VA_ARGS__);
-
-#define SIM_LOG_ERROR(group, ...) HOOK_MARKER \
- SIM_log_error(io_pore.d_log, group, __VA_ARGS__);
-
-#define SIM_TRACE_INFO(level, group, fmt, ...) HOOK_MARKER \
- SIM_log_info(level, io_pore.d_log, group, \
- "%s:%d\n" fmt, __FILE__, __LINE__,## __VA_ARGS__);
-
-#define SIM_TRACE_ERROR(group, fmt, ...) HOOK_MARKER \
- SIM_log_error(io_pore.d_log, group, \
- "%s:%d\n" fmt, __FILE__, __LINE__, ##__VA_ARGS__);
-
-/// @}
-
-/// \defgroup vcl_style_3_level_printing VCL-style 3-Level Logging Hooks
-///
-/// Define VCL-style 3-level logging and tracing, with programmable Simics
-/// log-level selection. All logs are controlled by (?) group 0. Note that
-/// setting the Simics log-level to 4 produces gobs of output from every part
-/// of the system, however here at the debug level of 3 we only get messages
-/// from hooks.
-///
-/// @{
-
-#ifndef SIMICS_LOG_LEVEL_OUTPUT
-#define SIMICS_LOG_LEVEL_OUTPUT 1
-#endif
-
-#ifndef SIMICS_LOG_LEVEL_INFO
-#define SIMICS_LOG_LEVEL_INFO 2
-#endif
-
-#ifndef SIMICS_LOG_LEVEL_DEBUG
-#define SIMICS_LOG_LEVEL_DEBUG 3
-#endif
-
-#define PORE_LOG_OUTPUT(...) SIM_LOG_INFO(SIMICS_LOG_LEVEL_OUTPUT, 0, __VA_ARGS__)
-#define PORE_LOG_INFO(...) SIM_LOG_INFO(SIMICS_LOG_LEVEL_INFO, 0, __VA_ARGS__)
-#define PORE_LOG_DEBUG(...) SIM_LOG_INFO(SIMICS_LOG_LEVEL_DEBUG, 0, __VA_ARGS__)
-
-#define PORE_LOG_ERROR(...) SIM_LOG_ERROR(0, __VA_ARGS__)
-
-#define PORE_TRACE_OUTPUT(...) SIM_TRACE_INFO(SIMICS_LOG_LEVEL_OUTPUT, 0, __VA_ARGS__)
-#define PORE_TRACE_INFO(...) SIM_TRACE_INFO(SIMICS_LOG_LEVEL_INFO, 0, __VA_ARGS__)
-#define PORE_TRACE_DEBUG(...) SIM_TRACE_INFO(SIMICS_LOG_LEVEL_DEBUG, 0, __VA_ARGS__)
-
-#define PORE_TRACE_ERROR(...) SIM_TRACE_ERROR(0, __VA_ARGS__)
-
-/// @}
-
-/// Break Simics simulation
-#define SIM_BREAK_SIMULATION(msg) \
- HOOK_MARKER SIM_break_simulation(msg); io_pore.dumpAll();
-
-
-/// A PORE Assertion
-#define PORE_ASSERT(assertion) \
- HOOK_MARKER \
- if (!(assertion)) { \
- SIM_log_error(io_pore.d_log, 0, \
- "Assertion below failed\n" #assertion); \
- SIM_break_simulation("Assertion failure"); \
- }
-
-
-/// Dump the PORE state
-#define PORE_DUMP(...) LOG_OUTPUT(__VA_ARGS__) io_pore.dumpAll();
-
-#endif // __PORE_HOOKS_H__
diff --git a/src/lib/ppc405lib/Makefile b/src/lib/ppc405lib/Makefile
new file mode 100644
index 0000000..37ef2ea
--- /dev/null
+++ b/src/lib/ppc405lib/Makefile
@@ -0,0 +1,57 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/ppc405lib/Makefile $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# This Makefile currently builds a single archive, 'libppc405.a', from
+# various library source files.
+#
+# part of the complete application build.
+#
+
+#all generated files from this makefile will end up in obj/$(IMAGE_NAME)/ppc405lib
+export SUB_OBJDIR = /ppc405lib
+
+include img_defs.mk
+include libppc405files.mk
+
+OBJS := $(addprefix $(OBJDIR)/, $(LIBPPC405_OBJECTS))
+
+libppc405.a: local
+ $(AR) crs $(OBJDIR)/libppc405.a $(OBJDIR)/*.o
+
+.PHONY: clean
+
+local: $(OBJS)
+
+$(OBJS) $(OBJS:.o=.d): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+clean:
+ rm -fr $(OBJDIR)
+
+ifneq ($(MAKECMDGOALS),clean)
+#include $(OBJS:.o=.d)
+endif
+
diff --git a/src/lib/ppc405lib/README.txt b/src/lib/ppc405lib/README.txt
new file mode 100644
index 0000000..cc0076f
--- /dev/null
+++ b/src/lib/ppc405lib/README.txt
@@ -0,0 +1,4 @@
+This directory contains all of the library code that only can run on the ppc405.
+For most of the files, the only reason it can not run on the ppe42 is because of
+it's dependence on SSX. Eventually, we would like to fix this so that most, if
+not all files can be made common.
diff --git a/src/lib/ppc405lib/assert.c b/src/lib/ppc405lib/assert.c
new file mode 100644
index 0000000..96143a4
--- /dev/null
+++ b/src/lib/ppc405lib/assert.c
@@ -0,0 +1,71 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/assert.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: assert.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/assert.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file assert.c
+/// \brief Implementation of library routines implied by <assert.h>
+
+#include "ssx.h"
+#include "ssx_io.h"
+#include "libssx.h"
+
+/// The __assert_fail() function is used to implement the assert() interface
+/// of ISO POSIX (2003). The __assert_fail() function prints the given \a
+/// file filename, \a line line number, \a function function name and a
+/// message on the standard error stream then causes a kernel panic. If there
+/// is no standard error stream then the error message is printed on the \a
+/// ssxout (printk()) stream.
+///
+/// If function is NULL, __assert_fail() omits information about the
+/// function. The aguments \a assertion, \a file, and \a line must be
+/// non-NULL.
+
+void
+__assert_fail(const char *assertion,
+ const char *file,
+ unsigned line,
+ const char *function)
+{
+ FILE *stream;
+
+ stream = stderr;
+ if (stream == 0) {
+ stream = ssxout;
+ }
+
+ fprintf(stream, "%s:%u:%s%s Assertion '%s' failed\n",
+ file, line,
+ function ? function : "", function ? ":" : "",
+ assertion);
+
+ SSX_PANIC(ASSERTION_FAILURE);
+}
+
diff --git a/src/lib/ppc405lib/byte_pool.c b/src/lib/ppc405lib/byte_pool.c
new file mode 100644
index 0000000..d382abc
--- /dev/null
+++ b/src/lib/ppc405lib/byte_pool.c
@@ -0,0 +1,1442 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/byte_pool.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file byte_pool.c
+/// \brief An implementation of a constant-time malloc() algorithm.
+///
+/// The 'byte-pool' API defined in this file is similar to ThreadX' byte-pool
+/// operations, with the major difference that here there is no concept of a
+/// thread blocking on memory allocation. This is a concept that is difficult
+/// to implement correctly and efficiently, and several semantic options
+/// exist for how allocation and freeing memory should work in the presence of
+/// blocked threads. The application is always free to implement a blocking
+/// API using these APIs and SSX synchronization primitives.
+///
+/// For convenience this implementation also provides malloc() and calloc()
+/// calls. These APIs depend on the application creating a byte pool and
+/// assigning it to the library variable \a _malloc_byte_pool.
+///
+/// \todo Consider separating the idea of creating a byte pool with a specific
+/// maximum-sized block, from the idea of adding memory to a byte pool. The
+/// idea is to allow pieces of memory required during initialization of the
+/// application to be added back to the pool at run time. We could also
+/// simply add an API to allow memory to be added to a previously created
+/// pool, with the special case that if the block were 'too big' that it would
+/// be split into smaller chunks.
+///
+/// \todo Consider
+/// adding an option to store a pointer to the originating byte pool in the
+/// block header. This would allow deallocation of any block with free()
+/// regardless of which pool it was allocated from, at a cost of 1 pointer per
+/// block. This would simplify some of our validation test cases. We could
+/// also accomplish this by having each pool register ranges of addresses that
+/// it allocates from, but that would require a search every time we freed a
+/// block.
+
+#include "ssx.h"
+#include "byte_pool.h"
+
+// This is an implementation of the TLSF (Two-Level Segregate Fit) algorithm
+// described by M. Masmano, I. Ripoll and A Crespol,
+// http:/rtportal.upv.es/rtmalloc. A couple of their papers and presentations
+// are archived in /lib/doc/tlsf. This is a 'clean-room' implementation of
+// their published ideas based solely on their papers and presentations. No
+// part of their GPL implementation was used to create the byte-pool facility
+// implemented here. The algorithm as implemented here should port without
+// problem to either 32-bit or 64-bit implementations.
+//
+// TLSF has the nice property that it is a constant-time algorithm, both for
+// allocation and freeing allocated blocks. This property is guaranteed by
+// always trading space for speed in the algorithm. This means that we can
+// (and do) run the allocation and freeing in a critical section. With all
+// error checking and statistics, a worst-case byte_bool_alloc() was
+// timed at 318 PowerPC instructions in the PgP OCC (PPC405) Simics
+// simulation. A worst-case byte_pool_free() was timed at 368 PowerPC
+// instructions. These times are expected to equate to ~3us in OCC, a
+// reasonable value for a critical section. [The above times include all
+// error checking].
+//
+// An allocation unit requires two pointers of overhead - a pointer to the
+// previous block and a pointer to the next block (both in terms of linear
+// addresses). The minimum block size also includes the requirement for two
+// extra pointers used to link free blocks into their free lists. The final
+// size of the block (including user data) is simply computed as (next - self)
+// in terms of linear addresses.
+//
+// An allocated block is marked by setting the low-order bit of the 'previous'
+// pointer, which bit is otherwise guaranteed to be 0 due to alignment
+// restrictions. Whenever a block is freed it is immediately merged with the
+// previous and next blocks, if possible. Several places in the block
+// splitting and merging code take advantage of this invariant, and assume
+// that if a block is not already merged with its 'next' partner, then the
+// 'next' partner must be allocated. Sentinel blocks are allocated at either
+// end of the managed area to avoid special checks for the first and last
+// memory blocks during merging.
+//
+// The 'Two-Level' in TLSF refers to the fact that there are multiple free
+// lists arranged in a 2-dimensional array. Each free lists contains blocks
+// that fall into a particular size range. The free list pointers and other
+// data structures described below are carved out of the initial free area
+// when a byte pool is initialized.
+//
+// The first dimension of the free list array is simply the floor(log2(size))
+// of the block. For the second dimension, a tuning parameter selects how many
+// columns each row in the table will contain. The number of columns must be
+// an even power-of-2. Each column represents a fixed power-of-2 size
+// increment of block sizes. Given a block size, it is easy to compute the
+// row and column indices of a free list containing blocks of that size with
+// shifting and masking operation.
+//
+// It is assumed that the C type 'unsigned long' is the same size as a
+// pointer. Therefore the number of rows in the table is less than or equal
+// to the number of bits in an unsigned long. The number of columns is also
+// restricted to being in the range (1, 2, 4, ... number of bits in unsigned
+// long).
+//
+// The above restrictions make it very fast (and constant time) to find a free
+// list that contains a block that will satisfy the allocation request. The
+// byte pool structure maintains a 'row status' word that indicates whether
+// there are any blocks free in any of the free lists of the row. Each row
+// also has an associated 'column status' word that indicates which free lists
+// have blocks free. A row status bit is set if and only if at least one bit
+// in the column status for that row is set.
+//
+// Note that although the 32-bit PowerPC implementation conceptually contains
+// a 32x32 array of free list pointers, only the free list pointers actually
+// required to hold the representable blocks are allocated.
+//
+// The algorithm uses the GCC __builtin_clzl() function to count leading zeros
+// in the status words to find rows/columns that contain free blocks. This
+// generates the 'cntlzw' instruction on 32-bit PowerPC and a similar
+// instruction on X86. So the algorithm is also portable across machines -
+// which simplifies testing.
+//
+// A couple of final facts: When the application requests memory, the block
+// header overhead is added to the request and we look for a free list
+// guaranteed to contain blocks of the requested size. That means that the
+// request size must be rounded up to the next free list size, to avoid having
+// to search a list that might not contain a block of the proper size. This
+// leads to cases where allocation will fail, even though the requested memory
+// is actually available. That's just the price we have to pay for a
+// constant-time guarantee.
+//
+// This memory allocator will never be used in mission-mode for hard-real-time
+// applications, so the statistics are always kept up-to-date. This adds some
+// overhead, but does not effect the constant-time behavior.
+//
+// Given the above description, hopefuly the brief comments with the
+// implementation will make sense.
+
+
+/// The byte pool for use by malloc() and calloc().
+///
+/// The application must define a byte pool and assign it to _malloc_byte_pool
+/// in order for malloc() and calloc() to work.
+
+BytePool *_malloc_byte_pool = 0;
+
+
+// The byte pool memory block header.
+//
+// Each memory block requires 2 pointers of overhead - the pointers to the
+// previous and next (in terms of linear addresses) blocks. The low-order bit
+// of the \a previous pointer is used as the \e allocated flag, and is set
+// when a block is allocated. The size of a block is computed simply as the
+// \a next - \a self. This header layout makes it very simple to merge blocks
+// when they are deallocated.
+
+typedef struct ByteBlock {
+
+ // Pointer to the previous (in terms of linear address) block.
+ //
+ // The low-order bit of the pointer is set to indicate a block that has
+ // been allocated.
+ struct ByteBlock *previous;
+
+ // Pointer to the next (in terms of linear address) block.
+ //
+ // The size of the block is computed simply as \a next - \a self.
+ struct ByteBlock *next;
+
+} ByteBlock;
+
+
+// A free byte-pool memory block
+//
+// Blocks stored in free lists require an additional 2 pointers of
+// overhead. The blocks are doubly-linked in the free lists to make deletion
+// a constant-time operation. Note that the previous pointer is a pointer to
+// a pointer to a ByteBlock - it may be pointing to the free list
+// header. Since all blocks must be freeable, this structure defines the
+// minimum block size.
+
+typedef struct FreeByteBlock {
+
+ // The base object
+ ByteBlock block;
+
+ // Pointer to the next block in the free list
+ struct FreeByteBlock *next;
+
+ // Pointer to the \a next pointer of the previous element in the free
+ // list, or a pointer to the free list header.
+ struct FreeByteBlock **previous;
+
+} FreeByteBlock;
+
+
+// All blocks will be aligned to this size, so this size also defines the
+// minimum quantum of memory allocation. The coice of 8 should give
+// good results for both 32-bit and 64-bit implementations.
+//
+// NB : This implmentation assumes that the ByteBlock and FreeByteBLock are
+// aligned to this alignment - if this constant is ever changed from 8 then
+// the ByteBlock and FreeByteBlock may need to be padded to meet the alignment
+// assumptions, and the \a minimum_block_size may need to be adjusted.
+
+#define ALIGNMENT 8
+
+
+// An unsigned long, big-endian bit mask
+
+#define UL_BE_MASK(i) \
+ ((unsigned long)1 << (BITS_PER_UNSIGNED_LONG - (i) - 1))
+
+
+// Align a value to the alignment. The direction is either positive or
+// negative to indicate alignment up or down.
+
+static inline unsigned long
+align(unsigned long x, int direction)
+{
+ if (x % ALIGNMENT) {
+ if (direction > 0) {
+ return x + (ALIGNMENT - (x % ALIGNMENT));
+ } else {
+ return x - (x % ALIGNMENT);
+ }
+ } else {
+ return x;
+ }
+}
+
+
+// Compute the floor(log2(x)) of x. This is used to compute the row indices
+// of blocks based on the block size.
+
+static inline int
+floor_log2(unsigned long x)
+{
+ return BITS_PER_UNSIGNED_LONG - 1 - __builtin_clzl(x);
+}
+
+
+// In theory the tuning parameters might vary based on the amount of memory
+// being managed, but for now we simply use constants.
+//
+// The minimum block size includes both the size of the header, as well as the
+// requirement that the number of columns be <= the mimumum block size to make
+// the addressing uniform. For example, on PPC405 the minimum block size is 16
+// bytes (4 pointers) -- unless the number of columns is 32, in which case it
+// has to grow to 32 bytes.
+//
+// Note that no matter what, we may allocate free list pointers in the
+// lower-numbered rows that will never be populated due to alignment
+// constraints.
+
+#ifndef BYTE_POOL_TLSF_COLUMNS
+#define BYTE_POOL_TLSF_COLUMNS 8 /* 1,2,4, ... BITS_PER_UNSIGNED_LONG */
+#endif
+
+static void
+compute_tuning(BytePool *pool, size_t size, int columns)
+{
+ int log2_min_size;
+
+ pool->columns = columns;
+ pool->log2_columns = floor_log2(pool->columns);
+ pool->column_mask = (1 << pool->log2_columns) - 1;
+
+ log2_min_size = MAX(pool->log2_columns, floor_log2(sizeof(FreeByteBlock)));
+ pool->minimum_block_size = align(1 << log2_min_size, 1);
+}
+
+
+// Compute the size of a block
+
+static inline size_t
+block_size(ByteBlock *block)
+{
+ return (unsigned long)(block->next) - (unsigned long)block;
+}
+
+
+/// Return implementation information for a block
+///
+/// \param memory The memory block to query. This pointer must have been
+/// returned by one of the byte_pool functions or derivitives, or may also be
+/// 0.
+///
+/// \param actual_address : Returned as the address of the block header.
+///
+/// \param actual_size Returned as the size of the complete block, including
+/// the header.
+///
+/// \param useful_size : Returned as the actual amount of space available from
+/// \a memory to the end of the block. The \a useful_size may be useful to
+/// applications that allocate big blocks then carve them up into smaller
+/// structures.
+///
+/// Note that any of \a actual_address, \a actual_size and \a useful_size may
+/// be passed in as 0 if the caller does not require the information.
+
+void
+byte_pool_block_info(void* memory,
+ void** actual_address, size_t* actual_size,
+ size_t* useful_size)
+{
+ ByteBlock* block;
+
+ if (memory == 0) {
+
+ if (actual_address) *actual_address = 0;
+ if (actual_size) *actual_size = 0;
+ if (useful_size) *useful_size = 0;
+
+ } else {
+
+ // This implementation uses the convention that if the \a next pointer
+ // of the putative ByteBlock == 1, then this is actually an aligned
+ // allocation and the actual ByteBlock is located at the address
+ // contained in the \a previous field of the dummy header.
+
+ block = (ByteBlock *)(((unsigned long)memory) - sizeof(ByteBlock));
+ if ((int)(block->next) == 1) {
+ block = block->previous;
+ }
+
+ if (actual_address) *actual_address = block;
+ if (actual_size) *actual_size = block_size(block);
+ if (useful_size)
+ *useful_size =
+ (unsigned long)(block->next) - (unsigned long)memory;
+ }
+}
+
+
+// Mark a block as allocated by setting the low-order bit of the \a previous
+// pointer.
+
+static inline ByteBlock *
+allocated(ByteBlock *p)
+{
+ return (ByteBlock *)((unsigned long)p | 1ul);
+}
+
+
+static void
+mark_allocated(BytePool *pool, ByteBlock *block)
+{
+ size_t bytes = block_size(block);
+
+ pool->bytes_allocated += bytes;
+ pool->bytes_free -= bytes;
+ pool->blocks_allocated += 1;
+ pool->blocks_free -= 1;
+
+ block->previous = allocated(block->previous);
+}
+
+
+// Mark a block as free by clearing the low-order bit of the \a previous
+// pointer.
+
+static inline ByteBlock *
+deallocated(ByteBlock *p)
+{
+ return (ByteBlock *)((unsigned long)p & ~1ul);
+}
+
+
+static void
+mark_free(BytePool *pool, ByteBlock *block)
+{
+ size_t bytes = block_size(block);
+
+ pool->bytes_allocated -= bytes;
+ pool->bytes_free += bytes;
+ pool->blocks_allocated -= 1;
+ pool->blocks_free += 1;
+
+ block->previous = deallocated(block->previous);
+}
+
+
+// Check for a block being free
+
+static inline int
+block_is_free(ByteBlock *block)
+{
+ return (((unsigned long)(block->previous)) & 1ul) == 0;
+}
+
+
+// Normalize a 'previous' pointer
+
+static inline ByteBlock *
+normalize_previous(ByteBlock *previous)
+{
+ return (ByteBlock *)((unsigned long)previous & ~1ul);
+}
+
+
+// Check for correct linkage. This is such a critical check for application
+// memory corruption that it is always done.
+
+static int
+check_linkage(ByteBlock *block)
+{
+ if (normalize_previous(block->next->previous) != block) {
+ printk("byte_pool: Forward linkage error\n"
+ " block : %p\n"
+ " block->next : %p\n"
+ " block->next->previous : %p\n",
+ block,
+ block->next,
+ block->next->previous);
+ SSX_ERROR(BYTE_POOL_REVERSE_LINKAGE);
+ } else if (normalize_previous(block->previous)->next != block) {
+ printk("byte_pool: linkage error\n"
+ " block->previous : %p\n"
+ " block->pevious->next : %p\n"
+ " block : %p\n",
+ block->previous,
+ block->previous->next,
+ block);
+ SSX_ERROR(BYTE_POOL_FORWARD_LINKAGE);
+ }
+ return 0;
+}
+
+
+// Mark a free list as empty
+
+static inline void
+mark_empty(BytePool *pool, int row, int column)
+{
+ pool->column_status[row] &= ~UL_BE_MASK(column);
+ if (pool->column_status[row] == 0) {
+ pool->row_status &= ~UL_BE_MASK(row);
+ }
+}
+
+
+// Mark a free list as non-empty
+
+static inline void
+mark_non_empty(BytePool *pool, int row, int column)
+{
+ pool->column_status[row] |= UL_BE_MASK(column);
+ pool->row_status |= UL_BE_MASK(row);
+}
+
+
+// Convert a size into row and column indices
+
+static inline void
+size2rc(BytePool *pool, size_t size, int *row, int *column)
+{
+ *row = floor_log2(size);
+ *column = (size >> (*row - pool->log2_columns)) & pool->column_mask;
+}
+
+
+// Given a block size, find the free list that contains blocks of that size
+// (or greater, up to the next free list). When called during block freeing,
+// the block size is known to be valid. When called during allocation, the
+// block size may be invalid (too big), in which case 0 is returned.
+
+static FreeByteBlock **
+find_free_list(BytePool *pool, size_t size, int *row, int *column)
+{
+ size2rc(pool, size, row, column);
+ if (*row > pool->last_row) {
+ return 0;
+ }
+ return &((pool->free[*row])[*column]);
+}
+
+
+// Remove an arbitrary block from its free list due to a merging operation.
+
+static void
+unlink_free_block(BytePool *pool, ByteBlock *block)
+{
+ FreeByteBlock **free_list;
+ FreeByteBlock *free_block;
+ int row, column;
+
+ free_list = find_free_list(pool, block_size(block), &row, &column);
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if (free_list == 0) {
+ SSX_PANIC(BYTE_POOL_NULL_FREE_LIST);
+ }
+ }
+
+ // Unlink the block from the free list
+
+ free_block = (FreeByteBlock *)block;
+ *(free_block->previous) = free_block->next;
+ if (free_block->next) {
+ free_block->next->previous = free_block->previous;
+ }
+
+ // If the free list is now 0, mark the free list as empty.
+
+ if (*free_list == 0) {
+ mark_empty(pool, row, column);
+ }
+}
+
+
+// Link a block into the head of its free list due to freeing memory
+
+static void
+link_free_block(BytePool *pool, ByteBlock *block)
+{
+ FreeByteBlock **free_list;
+ FreeByteBlock *free_block;
+ int row, column;
+
+ free_list = find_free_list(pool, block_size(block), &row, &column);
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if (free_list == 0) {
+ SSX_PANIC(BYTE_POOL_NULL_FREE_LIST);
+ }
+ }
+
+ // Link the block into the free list, and mark the free list as
+ // non-empty.
+
+ free_block = (FreeByteBlock *)block;
+
+ free_block->next = *free_list;
+ if (*free_list) {
+ (*free_list)->previous = &(free_block->next);
+ }
+ *free_list = free_block;
+ free_block->previous = free_list;
+
+ mark_non_empty(pool, row, column);
+}
+
+
+// Round up the block size (if required) to the next column. Note that the
+// block_size input here is aligned, and remains aligned even after rounding.
+
+static size_t
+round_up_size(BytePool *pool, size_t block_size)
+{
+ size_t residue, column_span, column_mask;
+ int row = floor_log2(block_size);
+
+ column_span = 1 << (row - pool->log2_columns);
+ column_mask = column_span - 1;
+ residue = block_size & column_mask;
+
+ if (residue == 0) {
+ return block_size;
+ } else {
+ return block_size + (column_span - residue);
+ }
+}
+
+
+// The implemenation of freeing a block of memory. When freed, a block is
+// immediately merged with its neighbors if possible, and the final merged
+// block is inserted into the proper free list.
+//
+// The linkage check is done here so that it can also protect internal uses of
+// this API (but only if SSX errors lead to panics, the expected default).
+
+static int
+byte_pool_free_block(BytePool *pool, ByteBlock *block)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ rc = check_linkage(block);
+ if (rc) return rc;
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ pool->free_calls++;
+
+ mark_free(pool, block);
+
+ if (block_is_free(block->next)) {
+
+ // Merge next block into current block
+
+ unlink_free_block(pool, block->next);
+
+ block->next = (ByteBlock *)((unsigned long)(block->next) +
+ block_size(block->next));
+ block->next->previous = allocated(block);
+
+ pool->blocks_free--;
+ }
+
+ if (block_is_free(block->previous)) {
+
+ // Merge current block into previous block
+
+ unlink_free_block(pool, block->previous);
+
+ block->previous->next =
+ (ByteBlock *)((unsigned long)(block->previous->next) +
+ block_size(block));
+ block = block->previous;
+ block->next->previous = allocated(block);
+
+ pool->blocks_free--;
+ }
+
+ // Finally, insert the block into the proper free list.
+
+ link_free_block(pool, block);
+
+ ssx_critical_section_exit(&ctx);
+
+ return 0;
+}
+
+
+/// Free a block of memory back to a byte pool
+///
+/// \param pool A pointer to the BytePool structure that allocated the memory.
+///
+/// \param memory A pointer to memory returned by byte_pool_alloc() or
+/// byte_pool_alloc_aligned() for the pool. This pointer may be NULL (0), in
+/// which case the byte_pool_free() request succeeds immediately.
+///
+/// The part of this API that manipulates the \a pool runs as an
+/// SSX_NONCRITICAL critical section. byte_pool_free() uses a constant-time
+/// algorithm.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Success
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool argument was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The block is not marked as being
+/// allocated, or does not appear to have been allocated from this byte_pool.
+///
+/// \retval -BYTE_POOL_LINKAGE_ERROR The block being freed is not linked
+/// correctly with the other blocks managed by the pool, most likely
+/// indicating that the memory being freed was not allocated by
+/// byte_pool_alloc(), or that memory corruption has occured.
+
+// This implementation uses the convention that if the \a next pointer of the
+// putative ByteBlock == 1, then this is actually an aligned allocation and
+// the actual ByteBlock is located at the address contained in the \a previous
+// field of the dummy header.
+
+int
+byte_pool_free(BytePool *pool, void *memory)
+{
+ ByteBlock *block;
+
+ if (memory == 0) {
+ return 0;
+ }
+
+ block = (ByteBlock *)(((unsigned long)memory) - sizeof(ByteBlock));
+ if ((int)(block->next) == 1) {
+ if (0) {
+ printk("byte_pool_free(%p, %p) [%p] : Aligned\n",
+ pool, memory, block);
+ }
+ block = block->previous;
+ }
+
+ if (0) {
+ printk("byte_pool_free(%p, %p) [%p] : %d %d %d\n",
+ pool, memory, block,
+ block_is_free(block),
+ block < pool->first_block,
+ block > pool->last_block);
+ }
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(pool == 0, BYTE_POOL_INVALID_OBJECT);
+ SSX_ERROR_IF(block_is_free(block) ||
+ (block < pool->first_block) ||
+ (block > pool->last_block),
+ BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ return byte_pool_free_block(pool, block);
+}
+
+
+/// Create a BytePool with explicit specification of tuning parameters
+///
+/// This routine is the real body of byte_pool_create(), however this
+/// underlying interface is provided for testing and experimentation and allows
+/// the specification of non-default tuning parameters.
+///
+/// There is actually only one tuning parameter for TLSF - the number of
+/// columns. The number of columns must be an even power of two no larger
+/// than the number of bits in an unsigned long.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool pointer was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT Either the \a memory pointer was NULL
+/// (0), the amount of memory was insufficient for the management overhead, or
+/// the parameterization was invalid.
+
+int
+byte_pool_create_tuned(BytePool *pool, void *memory, size_t size,
+ int columns)
+{
+ size_t overhead, free_list_overhead;
+ unsigned long memory_ul, aligned_memory;
+ int i;
+ FreeByteBlock **free;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(pool == 0, BYTE_POOL_INVALID_OBJECT);
+ SSX_ERROR_IF((memory == 0) ||
+ (columns < 1) ||
+ ((columns & (columns - 1)) != 0) ||
+ (floor_log2(columns) > floor_log2(BITS_PER_UNSIGNED_LONG)),
+ BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ // Compute tuning parameters
+
+ compute_tuning(pool, size, columns);
+
+ // Clear free list vector pointers and column status
+
+ for (i = 0; i < BITS_PER_UNSIGNED_LONG; i++) {
+ pool->free[i] = 0;
+ pool->column_status[i] = 0;
+ }
+
+ // Determine the first and last allocated rows.
+
+ pool->first_row = floor_log2(pool->minimum_block_size);
+ pool->last_row = floor_log2(size);
+
+ // The dynamic overhead consists of aligment overhead, 2 sentinel nodes,
+ // the vectors of pointers to free lists, plus 2 alignments. There must
+ // also be enough room for at least 1 block to allocate.
+
+ memory_ul = (unsigned long)memory;
+ aligned_memory = align(memory_ul, 1);
+
+ free_list_overhead =
+ (((pool->last_row - pool->first_row + 1) * pool->columns) *
+ sizeof(FreeByteBlock *));
+
+ overhead =
+ (aligned_memory - memory_ul) +
+ (2 * sizeof(ByteBlock)) +
+ free_list_overhead +
+ (2 * ALIGNMENT) +
+ pool->minimum_block_size;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(overhead >= size, BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ // Allocate the overhead items. The free list vectors and column status
+ // arrays are carved out and zeroed. For good measure we re-align after
+ // each of these operations. The sentinel blocks are carved off of either
+ // end of the remaining free space and marked allocated. The remaining
+ // initial "big block" is also initialized (as if it were allocated).
+
+ size = size - (aligned_memory - memory_ul);
+ size = align(size, -1);
+
+ pool->row_status = 0;
+
+ free = (FreeByteBlock **)aligned_memory;
+ memset((void *)free, 0, free_list_overhead);
+
+ aligned_memory += free_list_overhead;
+ size -= free_list_overhead;
+ aligned_memory = align(aligned_memory, 1);
+ size = align(size, -1);
+
+ for (i = pool->first_row; i <= pool->last_row; i++) {
+ pool->free[i] = free;
+ free += pool->columns;
+ }
+
+ pool->first_block = (ByteBlock *)aligned_memory;
+ aligned_memory += sizeof(ByteBlock);
+ size -= sizeof(ByteBlock);
+
+ pool->big_block = (ByteBlock *)aligned_memory;
+
+ pool->last_block =
+ (ByteBlock *)(aligned_memory + size - sizeof(ByteBlock));
+ size -= sizeof(ByteBlock);
+
+ pool->first_block->next = pool->big_block;
+ pool->first_block->previous = 0;
+ mark_allocated(pool, pool->first_block);
+
+ pool->last_block->next = 0;
+ pool->last_block->previous = pool->big_block;
+ mark_allocated(pool, pool->last_block);
+
+ pool->big_block->previous = pool->first_block;
+ pool->big_block->next = pool->last_block;
+
+ // Initialize statistics
+
+ pool->bytes_allocated = 0;
+ pool->bytes_free = block_size(pool->big_block);
+ pool->initial_allocation = pool->bytes_free;
+ pool->blocks_allocated = 0;
+ pool->blocks_free = 1;
+ pool->alloc_calls = 0;
+ pool->free_calls = 0;
+
+ // Free the big block and we're ready to go.
+
+ mark_allocated(pool, pool->big_block);
+ byte_pool_free_block(pool, pool->big_block);
+
+ return 0;
+}
+
+
+/// Create a BytePool
+///
+/// \param pool A pointer to an uninitialized BytePool structure
+///
+/// \param memory A pointer to the memory to be managed by the BytePool
+///
+/// \param size The size of the managed area in bytes
+///
+/// byte_pool_create() sets up the \a memory area to be used as a memory pool
+/// for malloc()-style allocation using byte_pool_alloc() and
+/// byte_pool_free(). Note that the actual memory area available for
+/// allocation will be smaller than \a size due to alignment, and reservation
+/// of a portion of the area for management overhead.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool pointer was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT Either the \a memory pointer was NULL
+/// (0), the amount of memory was insufficient for the management overhead, or
+/// the parameterization was invalid.
+
+int
+byte_pool_create(BytePool *pool, void *memory, size_t size)
+{
+ return byte_pool_create_tuned(pool, memory, size, BYTE_POOL_TLSF_COLUMNS);
+}
+
+
+/// Allocate memory from a byte pool
+///
+/// \param pool A pointer to an initialized BytePool
+///
+/// \param memory An address to recieve a pointer to the allocated memory.
+/// This address will be set to NULL (0) if the allocation request can not be
+/// satisfied (or the \a size is 0).
+///
+/// \param size The number of bytes to allocate.
+///
+/// The part of this API that manipulates the \a pool runs as an
+/// SSX_NONCRITICAL critical section. byte_pool_alloc() uses a constant-time
+/// algorithm.
+///
+/// Return values other than 0 are not necessarily errors; see \ref
+/// ssx_errors.
+///
+/// The following return codes are not considered errors:
+///
+/// \retval 0 Success
+///
+/// \retval -BYTE_POOL_NO_MEMORY The allocation request could not be
+/// satisfied. The memory pointer will also be NULL (0) in this case.
+///
+/// The following return codes are considered errors:
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool argument was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The \a memory argument is NULL (0).
+
+int
+byte_pool_alloc(BytePool *pool, void **memory, size_t size)
+{
+ SsxMachineContext ctx;
+ size_t request_size, actual_size;
+ int found, row, column;
+ unsigned long row_status, column_status;
+ FreeByteBlock **free_list;
+ FreeByteBlock *free_block;
+ ByteBlock *block;
+ ByteBlock *residue_block;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(pool == 0, BYTE_POOL_INVALID_OBJECT);
+ SSX_ERROR_IF(memory == 0, BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ // Quickly dispense with NULL requests
+
+ if (size == 0) {
+ *memory = 0;
+ return 0;
+ }
+
+ // Compute the requested block size (which includes the header). If the
+ // size went down we overflowed due to a huge request (which can't be
+ // filled). Otherwise if the request is small it is boosted up to the
+ // (aligned) minimum size. To guarantee fast search, the requested size
+ // must then be rounded up to a size that is represented in the 2-D array
+ // of free list pointers.
+
+ request_size = align(size + sizeof(ByteBlock), 1);
+ if (request_size < size) {
+ *memory = 0;
+ return -BYTE_POOL_NO_MEMORY;
+ }
+
+ if (request_size < pool->minimum_block_size) {
+ request_size = pool->minimum_block_size;
+ }
+
+ request_size = round_up_size(pool, request_size);
+
+ // Up to this point, all accesses of the memory pool object have been to
+ // read only constants. Now we get serious.
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ pool->alloc_calls++;
+
+ // See if a block of the correct or larger size exists in the row. The
+ // search is first via a single bit in the row_status. If that hits then
+ // we check for columns >= the target column.
+
+ found = 0;
+ size2rc(pool, request_size, &row, &column);
+
+ if (pool->row_status & UL_BE_MASK(row)) {
+
+ column_status = pool->column_status[row] &
+ ((UL_BE_MASK(column) << 1) - 1);
+
+ if (column_status != 0) {
+ column = __builtin_clzl(column_status);
+ found = 1;
+ }
+ }
+
+ // If the block was not found in the 'optimum' row, look in all rows of
+ // larger size and take the first block that fits.
+
+ if (!found) {
+
+ row_status = pool->row_status & (UL_BE_MASK(row) - 1);
+
+ if (row_status != 0) {
+ row = __builtin_clzl(row_status);
+ column = __builtin_clzl(pool->column_status[row]);
+ found = 1;
+ }
+ }
+
+ // Another out of memory case.
+
+ if (!found) {
+ ssx_critical_section_exit(&ctx);
+ *memory = 0;
+ return -BYTE_POOL_NO_MEMORY;
+ }
+
+ // Now we can get the pointer to the free list and take the block.
+
+ free_list = &((pool->free[row])[column]);
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if ((free_list == 0) || (*free_list == 0)) {
+ SSX_PANIC(BYTE_POOL_INVALID_FREE_LIST);
+ }
+ }
+
+ free_block = *free_list;
+ *free_list = free_block->next;
+ if (free_block->next) {
+ free_block->next->previous = free_list;
+ } else {
+ mark_empty(pool, row, column);
+ }
+
+ // Mark the block as allocated
+
+ block = (ByteBlock *)free_block;
+ mark_allocated(pool, block);
+
+ // If there is enough residue, split the excess memory off of the end of
+ // the block. This is a kind of dummy transaction for our statistical
+ // purposes.
+
+ actual_size = block_size(block);
+ if ((actual_size - request_size) >= pool->minimum_block_size) {
+
+ residue_block = (ByteBlock *)((unsigned long)block + request_size);
+
+ residue_block->next = block->next;
+ residue_block->previous = block;
+ residue_block->previous->next = residue_block;
+ residue_block->next->previous = allocated(residue_block);
+
+ pool->blocks_allocated++;
+ byte_pool_free_block(pool, residue_block);
+ pool->free_calls--;
+ }
+
+ // Set the memory pointer to the area to be used by the application and
+ // return.
+
+ *memory = (void *)((unsigned long)block + sizeof(ByteBlock));
+
+ ssx_critical_section_exit(&ctx);
+
+ if (0) {
+ ByteBlock* block =
+ (ByteBlock*)((unsigned long)*memory - sizeof(ByteBlock));
+
+ printk("byte_pool_alloc(%p, -> %p, %zu)\n"
+ " request_size = %u, Previous = %p, Next = %p\n",
+ pool, *memory, size,
+ request_size, block->previous, block->next);
+ }
+
+ return 0;
+}
+
+
+/// Allocate memory from a byte pool and clear
+///
+/// byte_pool_calloc() allocates memory using byte_pool_alloc() then clears
+/// the memory area using memset(). The arguments conform to the POSIX
+/// standard for calloc(). See byte_pool_alloc() for return codes and usage
+/// notes.
+
+int
+byte_pool_calloc(BytePool *pool, void **memory, size_t nmemb, size_t size)
+{
+ int rc;
+
+ rc = byte_pool_alloc(pool, memory, nmemb * size);
+ if (rc || (*memory == 0)) {
+ return rc;
+ }
+
+ memset(*memory, 0, nmemb * size);
+
+ return 0;
+}
+
+
+/// Allocate an aligned memory area
+///
+/// \param pool A pointer to an initialized BytePool
+///
+/// \param memory An address to recieve a pointer to the allocated memory.
+/// This address will be set to NULL (0) if the allocation request can not be
+/// satisfied (or the \a size is 0).
+///
+/// \param size The size of the memory area required (in bytes). This can be
+/// any size - it \e does \e not have to be a multiple of the aligned size (as
+/// is required by other common aligned memory allocators).
+///
+/// \param alignment The alignment constraint, specified as the base 2
+/// logarithm of the alignment. For example, to align on a 128-byte boundary
+/// the \a alignment would be specified as 7.
+///
+/// byte_pool_alloc_aligned() is a convenience interface for allocating memory
+/// with a guaranteed alignment. The BytePool APIs do not normally do aligned
+/// allocation. byte_pool_alloc_aligned() first uses byte_pool_alloc() to
+/// allocate a block of memory large enough to satisfy the request and
+/// guarantee that a subset of the memory allocation will satisfy the
+/// alignment constraint plus the overhead of a dummy block header. Note that
+/// it is space-inefficient to allocate many small aligned areas. If possble
+/// it would be better to allocate a single aligned area and then have the
+/// application partition the memory as required.
+///
+/// Memory areas allocated by byte_pool_alloc_aligned() can be freed with
+/// byte_pool_free(), just like any other dynamic memory allocation.
+///
+/// The part of this API that manipulates the \a pool runs as an
+/// SSX_NONCRITICAL critical section. The underlying call of byte_pool_alloc()
+/// uses a constant-time algorithm.
+///
+/// Return values other than 0 are not necessarily errors; see \ref
+/// ssx_errors.
+///
+/// The following return codes are not considered errors:
+///
+/// \retval 0 Success
+///
+/// \retval -BYTE_POOL_NO_MEMORY The allocation request could not be
+/// satisfied. The memory pointer will also be NULL (0) in this case.
+///
+/// The following return codes are considered errors:
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool argument was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The \a memory argument is NULL (0), or
+/// the \a alignment argument is invalid.
+
+// The allocation must be big enough for the size requested + the alignment
+// amount (to guarantee alignment) + room for a dummy ByteBlock. The dummy
+// ByteBlock is marked by setting the \a next pointer to 1 to indicate that
+// this is an aligned allocation. In this case the \a previous pointer of the
+// dummy ByteBlock points to the ByteBlock of the original allocation.
+
+int
+byte_pool_alloc_aligned(BytePool *pool, void **memory, size_t size,
+ int alignment)
+{
+ int rc;
+ unsigned long pow2_alignment, mask, aligned;
+ void *unaligned_memory;
+ ByteBlock *dummy_block, *unaligned_block;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((alignment < 1) || (alignment >= BITS_PER_UNSIGNED_LONG),
+ BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ pow2_alignment = (unsigned long)1 << (unsigned long)alignment;
+ mask = pow2_alignment - 1;
+
+ rc = byte_pool_alloc(pool, &unaligned_memory,
+ size + pow2_alignment + sizeof(ByteBlock));
+
+ if (rc || (unaligned_memory == 0)) {
+ *memory = 0;
+ return rc;
+ }
+ unaligned_block = (ByteBlock *)(((unsigned long)unaligned_memory) -
+ sizeof(ByteBlock));
+
+ aligned = (unsigned long)unaligned_memory + sizeof(ByteBlock);
+ if (aligned & mask) {
+ aligned += (pow2_alignment - (aligned & mask));
+ }
+ *memory = (void *)aligned;
+
+ dummy_block = (ByteBlock *)(aligned - sizeof(ByteBlock));
+ dummy_block->previous = unaligned_block;
+ dummy_block->next = (ByteBlock*)1;
+
+ if (0) {
+ printk("byte_pool_alloc_aligned(%p, -> %p, %zu, %d)\n",
+ pool, *memory, size, alignment);
+ }
+
+ return 0;
+}
+
+
+/// Allocate aligned memory from a byte pool and clear
+///
+/// byte_pool_calloc_alligned() allocates memory using
+/// byte_pool_alloc_aligned() then clears the memory area using memset(). The
+/// arguments conform to the POSIX standard for calloc(). See
+/// byte_pool_alloc_aligned() for return codes and usage notes. In particular
+/// note that this memory must be freed with byte_pool_free_aligned().
+
+int
+byte_pool_calloc_aligned(BytePool *pool, void **memory,
+ size_t nmemb, size_t size, int alignment)
+{
+ int rc;
+
+ rc = byte_pool_alloc_aligned(pool, memory, nmemb * size, alignment);
+ if (rc || (*memory == 0)) return rc;
+
+ memset(*memory, 0, nmemb * size);
+
+ return 0;
+}
+
+
+/// malloc() allocates \a size bytes and returns a pointer to the allocated
+/// memory. The memory is not cleared. The value returned is a pointer to the
+/// allocated memory, which is suitably aligned for any kind of variable, or
+/// NULL if the requested \a size is 0 or the request fails.
+///
+/// NB: The aplication must create and assign a BytePool object to the
+/// library variable _malloc_byte_pool in order for malloc() to work.
+
+void *
+malloc(size_t size)
+{
+ void *memory;
+
+ if (byte_pool_alloc(_malloc_byte_pool, &memory, size)) {
+ memory = 0;
+ }
+ return memory;
+}
+
+
+/// calloc() allocates memory for an array of \a nmemb elements of \a size
+/// bytes each and returns a pointer to the allocated memory. The memory is
+/// set to zero. The value returned is a pointer to the allocated and cleared
+/// memory, which is suitably aligned for any kind of variable, or NULL if the
+/// requested \a size is 0 or the request fails.
+///
+/// NB: The aplication must create and assign a BytePool object to the
+/// library variable _malloc_byte_pool in order for calloc() to work.
+
+void *
+calloc(size_t nmemb, size_t size)
+{
+ void *memory;
+
+ if (byte_pool_calloc(_malloc_byte_pool, &memory, nmemb, size)) {
+ return 0;
+ }
+ return memory;
+}
+
+
+/// free() frees the memory space pointed to by \a ptr, which must have been
+/// returned by a previous call to malloc(), posix_memalign, calloc() or
+/// realloc(). Otherwise, or if free(ptr) has already been called before,
+/// undefined behavior occurs. If \a ptr is NULL, no operation is performed.
+///
+/// NB: The aplication must create and assign a BytePool object to the
+/// library variable _malloc_byte_pool in order for free() to work.
+
+void
+free(void *ptr)
+{
+ byte_pool_free(_malloc_byte_pool, ptr);
+}
+
+
+/// realloc() changes the size of the memory block pointed to by \a ptr to \a
+/// size bytes. The contents will be unchanged to the minimum of the old and
+/// new sizes; newly allocated memory will be uninitialized. If \a ptr is
+/// NULL, the call is equivalent to malloc(size); if \a size is equal to zero,
+/// the call is equivalent to free(ptr). Unless \a ptr is NULL, it must have
+/// been returned by an earlier call to malloc(), calloc() or realloc(). If
+/// the area pointed to was moved, a free(ptr) is done.
+///
+/// realloc() returns a pointer to the newly allocated memory, which is
+/// suitably aligned for any kind of variable and may be different from \a
+/// ptr, or NULL if the request fails. If \a size was equal to 0, either NULL
+/// or a pointer suitable to be passed to free() is returned. If realloc()
+/// fails the original block is left untouched; it is not freed or moved.
+
+void*
+realloc(void *ptr, size_t size)
+{
+ void *memory;
+ size_t useful_size;
+
+ // Handle simple case
+
+ if (ptr == 0) {
+
+ memory = malloc(size);
+
+ } else if (size == 0) {
+
+ free(ptr);
+ memory = 0;
+
+ } else {
+
+ // Find out the useful size of the block. If we need more than this we
+ // need to allocate a new block and memcpy() the old data to the new
+ // block and free the old block. If we need less then this we also
+ // need to allocate a new block and move the head of the current
+ // data. If the new size is the same as the current size we do nothing.
+
+ byte_pool_block_info(ptr, 0, 0, &useful_size);
+
+ if (size == useful_size) {
+
+ memory = ptr;
+
+ } else {
+
+ memory = malloc(size);
+ if (memory != 0) {
+ memcpy(memory, ptr, (size > useful_size) ? useful_size : size);
+ free(ptr);
+ }
+ }
+ }
+ return memory;
+}
+
+
+/// The posix_memalign() function allocates \a size bytes aligned on a
+/// boundary specified by \a alignment, and returns a pointer to the allocated
+/// memory in \a memptr. The value of \a alignment shall be a multiple of
+/// sizeof(void*), that is also a power of two. Upon successful completion,
+/// the value pointed to by \a memptr will be a multiple of alignment.
+///
+/// Note that memory allocated with posix_memalign() can be freed with
+/// free().
+///
+/// In the event of errors, the contents of \a memptr will be returned as 0.
+///
+/// The following return codes are mandated by POSIX, and are always returned
+/// in the event of the specified condition.
+///
+/// \retval 0 Success
+///
+/// \retval -EINVAL The value of the \a alignment parameter is not a power of
+/// two multiple of sizeof(void*).
+///
+/// \retval -ENOMEM There is insufficient memory available with the requested
+/// alignment.
+///
+/// The following return codes are implementation-specific and may be
+/// configured to cause a kernel panic.
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a _malloc_byte_pool is NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The \a memptr argument is NULL (0).
+
+int
+posix_memalign(void** memptr, size_t alignment, size_t size)
+{
+ int rc;
+
+ if (((alignment & (alignment - 1)) != 0) ||
+ (alignment < sizeof(void*))) {
+ rc = -EINVAL;
+ } else {
+ rc = byte_pool_alloc_aligned(_malloc_byte_pool, memptr, size,
+ floor_log2(alignment));
+ if (!rc && (*memptr == 0)) {
+ rc = -ENOMEM;
+ }
+ }
+ if (rc && memptr) {
+ *memptr = 0;
+ }
+ return rc;
+}
+
+
+/// Print a dump of a byte pool, including the header and allocation report
+///
+/// \param stream The stream to receive the dump
+///
+/// \param pool The BytePool object to dump
+///
+/// \bug This routine is not thread safe.
+
+void
+byte_pool_report(FILE* stream, BytePool* pool)
+{
+ ByteBlock* block;
+ uint8_t* p8;
+ uint32_t* p32;
+ int i;
+
+ fprintf(stream, ">>> Byte Pool Report for Pool %p <<<\n", pool);
+
+ fprintf(stream, ">>> BytePool Object Dump <<<\n");
+
+#define DUMPIT(x, fmt) \
+ fprintf(stream, "%20s : " #fmt "\n", #x, pool->x)
+
+ DUMPIT(first_row, %d);
+ DUMPIT(last_row, %d);
+ DUMPIT(columns, %d);
+ DUMPIT(log2_columns, %d);
+ DUMPIT(column_mask, 0x%08x);
+ DUMPIT(minimum_block_size, %d);
+ DUMPIT(free, %p);
+ DUMPIT(column_status, %p);
+ DUMPIT(row_status, %lu);
+ DUMPIT(first_block, %p);
+ DUMPIT(big_block, %p);
+ DUMPIT(last_block, %p);
+ DUMPIT(initial_allocation, %d);
+ DUMPIT(bytes_allocated, %d);
+ DUMPIT(bytes_free, %d);
+ DUMPIT(blocks_allocated, %d);
+ DUMPIT(blocks_free, %d);
+ DUMPIT(alloc_calls, %d);
+ DUMPIT(free_calls, %d);
+
+ fprintf(stream, ">>> Byte Pool Allocation Report <<<\n");
+ fprintf(stream,
+ ">>> status : address : size : binary[0:7] : ASCII[0:7] <<<\n");
+
+ for (block = pool->first_block->next;
+ block != pool->last_block;
+ block = block->next) {
+
+ fprintf(stream, " %c : %p : %6zu : ",
+ (block_is_free(block) ? 'F' : 'A'),
+ block, block_size(block));
+
+ p8 = (uint8_t*)((unsigned long)block + sizeof(ByteBlock));
+ p32 = (uint32_t*)p8;
+
+ fprintf(stream, "0x%08x 0x%08x : ", p32[0], p32[1]);
+ for (i = 0; i < 8; i++) {
+ if (isprint(p8[i])) {
+ fputc(p8[i], stream);
+ } else {
+ fputc('.', stream);
+ }
+ }
+ fputc('\n', stream);
+ }
+
+ fprintf(stream, ">>> End Report <<<\n");
+}
diff --git a/src/lib/ppc405lib/byte_pool.h b/src/lib/ppc405lib/byte_pool.h
new file mode 100644
index 0000000..8766745
--- /dev/null
+++ b/src/lib/ppc405lib/byte_pool.h
@@ -0,0 +1,166 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/byte_pool.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __BYTE_POOL_H__
+#define __BYTE_POOL_H__
+
+// $Id$
+
+#ifndef __ASSEMBLER__
+
+#include "ssx_io.h"
+
+struct ByteBlock;
+struct FreeByteBlock;
+
+// A handy constant
+
+#define BITS_PER_UNSIGNED_LONG (8 * sizeof(unsigned long))
+
+
+/// A control structure for a byte pool. The application will never modify the
+/// structure fields directly, but some applications may be interested in
+/// reading the statistics.
+
+typedef struct {
+
+ // The index of the first allocated row of free list pointers
+ int first_row;
+
+ // The index of the last allocated row of free list pointers
+ int last_row;
+
+ // The number of columns in each row of free list pointers
+ int columns;
+
+ // The log2 of the number of columns in each row of free list pointers
+ int log2_columns;
+
+ // The shifted block size is ANDed with this mask to extract the column
+ // number.
+ size_t column_mask;
+
+ // The minimum block size.
+ int minimum_block_size;
+
+ // The vectors of free list pointers
+ struct FreeByteBlock **free[BITS_PER_UNSIGNED_LONG];
+
+ // The array of column status bit masks
+ unsigned long column_status[BITS_PER_UNSIGNED_LONG];
+
+ // The row status bit mask
+ unsigned long row_status;
+
+ // A sentinel node - the first allocated block. Kept for error checking
+ // purposes.
+ struct ByteBlock *first_block;
+
+ // The initial memory allocation. Kept here only for debugging purposes.
+ struct ByteBlock *big_block;
+
+ // A sentinel node - the last allocated block. Kept here for error
+ // checking purposes.
+ struct ByteBlock *last_block;
+
+ // The initial allocation. Kept here for debugging and statistics.
+ size_t initial_allocation;
+
+ // The total number of bytes currently allocated (excludes overhead)
+ size_t bytes_allocated;
+
+ // The total number of bytes currently free in the pool
+ size_t bytes_free;
+
+ // The total number of blocks allocated from the pool
+ size_t blocks_allocated;
+
+ // The total number of blocks free in the pool
+ size_t blocks_free;
+
+ // The number of calls to allocate memory
+ size_t alloc_calls;
+
+ // The number of calls to free memory
+ size_t free_calls;
+
+} BytePool;
+
+extern BytePool *_malloc_byte_pool;
+
+int
+byte_pool_create(BytePool *pool, void *memory, size_t size);
+
+int
+byte_pool_create_tuned(BytePool *pool, void *memory, size_t size,
+ int columns);
+
+int
+byte_pool_alloc(BytePool *pool, void **memory, size_t size);
+
+int
+byte_pool_calloc(BytePool *pool, void **memory, size_t nmemb, size_t size);
+
+int
+byte_pool_free(BytePool *pool, void *memory);
+
+void
+byte_pool_block_info(void* memory,
+ void** actual_address, size_t* actual_size,
+ size_t* useful_size);
+
+int
+byte_pool_alloc_aligned(BytePool *pool, void **memory, size_t size,
+ int alignment);
+
+void *
+malloc(size_t size);
+
+void *
+calloc(size_t nmemb, size_t size);
+
+void
+free(void *ptr);
+
+int
+posix_memalign(void** memptr, size_t alignment, size_t size);
+
+void
+byte_pool_report(FILE* stream, BytePool* pool);
+
+#endif /* __ASSEMBLER__ */
+
+
+// Error/panic codes
+
+#define BYTE_POOL_INVALID_OBJECT 0x00b98e01
+#define BYTE_POOL_INVALID_ARGUMENT 0x00b98e02
+#define BYTE_POOL_REVERSE_LINKAGE 0x00b98e03
+#define BYTE_POOL_FORWARD_LINKAGE 0x00b98e04
+#define BYTE_POOL_NO_MEMORY 0x00b98e05
+
+#define BYTE_POOL_NULL_FREE_LIST 0x00b98e10
+#define BYTE_POOL_INVALID_FREE_LIST 0x00b98e11
+
+#endif /* __BYTE_POOL_H__ */
diff --git a/src/lib/ppc405lib/chip_config.h b/src/lib/ppc405lib/chip_config.h
new file mode 100644
index 0000000..cc772e2
--- /dev/null
+++ b/src/lib/ppc405lib/chip_config.h
@@ -0,0 +1,109 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/chip_config.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __CHIP_CONFIG_H__
+#define __CHIP_CONFIG_H__
+
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2014
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file chip_config.h
+/// \brief Chip configuration data structures for OCC procedures
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/// A bitmask defining a chip configuration
+///
+/// Since we are using the conventional big-endian notation, any use of these
+/// bitmasks requires that the data being tested is of this type - otherwise
+/// the masks won't work.
+///
+/// Layout:
+///
+/// Bits 0:15 - Core chiplet 0..15 is configured
+/// Bits 16:23 - MCS 0..7 is configured
+/// Bits 24:31 - Centaur 0..7 is configured
+
+typedef uint64_t ChipConfig;
+typedef uint16_t ChipConfigCores;
+typedef uint8_t ChipConfigMcs;
+typedef uint8_t ChipConfigCentaur;
+
+
+/// Convert a ChipConfig into a mask suitable for use as the 32-bit chiplet
+/// mask argument of a PORE wakeup program.
+#if 0
+static inline uint32_t
+pore_exe_mask(ChipConfig config)
+{
+ return (uint32_t)((config >> 32) & 0xffff0000);
+}
+#endif
+
+/// Left justify and mask core chiplet configuration into a uint32_t
+
+static inline uint32_t
+left_justify_core_config(ChipConfig config)
+{
+ return (uint32_t)((config >> 32) & 0xffff0000);
+}
+
+/// Left justify and mask MCS configuration into a uint32_t
+
+static inline uint32_t
+left_justify_mcs_config(ChipConfig config)
+{
+ return (uint32_t)((config >> 16) & 0xff000000);
+}
+
+/// Left justify and mask Centaur configuration into a uint32_t
+
+static inline uint32_t
+left_justify_centaur_config(ChipConfig config)
+{
+ return (uint32_t)((config >> 8) & 0xff000000);
+}
+
+#endif // __ASSEMBLER__
+
+
+#define CHIP_CONFIG_CORE_BASE 0
+#define CHIP_CONFIG_CORE(n) \
+ ((0x8000000000000000ull >> CHIP_CONFIG_CORE_BASE) >> (n))
+
+#define CHIP_CONFIG_MCS_BASE 16
+#define CHIP_CONFIG_MCS(n) \
+ ((0x8000000000000000ull >> CHIP_CONFIG_MCS_BASE) >> (n))
+
+#define CHIP_CONFIG_CENTAUR_BASE 24
+#define CHIP_CONFIG_CENTAUR(n) \
+ ((0x8000000000000000ull >> CHIP_CONFIG_CENTAUR_BASE) >> (n))
+
+
+#endif /* __CHIP_CONFIG_H__ */
diff --git a/src/lib/ppc405lib/ctype.c b/src/lib/ppc405lib/ctype.c
new file mode 100644
index 0000000..5069590
--- /dev/null
+++ b/src/lib/ppc405lib/ctype.c
@@ -0,0 +1,46 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ctype.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: ctype.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ctype.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ctype.c
+/// \brief Replacement for <ctype.h> functions
+///
+/// This file contains entry point equivalents for the "ctype.h" macros.
+/// These would only ever be used by assembler programs, therefore it's likely
+/// that the object file will never be linked into an image.
+
+#define __CTYPE_C__
+#include "ctype.h"
+#undef __CTYPE_C__
+
+
+
+
diff --git a/src/lib/ctype.h b/src/lib/ppc405lib/ctype.h
index 9072c41..9e41e45 100755..100644
--- a/src/lib/ctype.h
+++ b/src/lib/ppc405lib/ctype.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ctype.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __CTYPE_H__
#define __CTYPE_H__
diff --git a/src/lib/ctype_table.c b/src/lib/ppc405lib/ctype_table.c
index 6f3e576..01dd08a 100644
--- a/src/lib/ctype_table.c
+++ b/src/lib/ppc405lib/ctype_table.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ctype_table.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: ctype_table.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ctype_table.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ppc405lib/errno.h b/src/lib/ppc405lib/errno.h
new file mode 100644
index 0000000..e5ac6a9
--- /dev/null
+++ b/src/lib/ppc405lib/errno.h
@@ -0,0 +1,49 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/errno.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __ERRNO_H__
+#define __ERRNO_H__
+
+// $Id: errno.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/errno.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file errno.h
+/// \brief Replacement for <errno.h>
+///
+/// SSX does not support a per-thread or global 'errno'. The standard Unix
+/// errno values returned by library functions are defined here. The prefix
+/// code is the 'telephone code' for "errn".
+
+#define EINVAL 0x00377601
+#define EBADF 0x00377602
+#define EAGAIN 0x00377603
+#define ENXIO 0x00377604
+#define ENOMEM 0x00377605
+
+#endif /* __ERRNO_H__ */
diff --git a/src/lib/fgetc.c b/src/lib/ppc405lib/fgetc.c
index e4e4a49..6e6a1f9 100755..100644
--- a/src/lib/fgetc.c
+++ b/src/lib/ppc405lib/fgetc.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/fgetc.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: fgetc.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/fgetc.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ppc405lib/initcall.c b/src/lib/ppc405lib/initcall.c
new file mode 100644
index 0000000..664fb6e
--- /dev/null
+++ b/src/lib/ppc405lib/initcall.c
@@ -0,0 +1,70 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/initcall.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file initcall.c
+/// \brief An anonymous early initialization facility for SSX applications
+
+#include "ssx.h"
+#include "initcall.h"
+
+// These linker symbols must be defined if the initcall facility is used. The
+// special ELF section .data.initcall contains an array of Initcall structures
+// for all declared initcalls.
+
+extern InitCall _INITCALL_SECTION_BASE[];
+extern SsxLinkerSymbol _INITCALL_SECTION_SIZE;
+
+void
+_initcall_run(InitCall* initcall)
+{
+ void (*f)(void* arg);
+
+ f = initcall->initcall;
+ if (f) {
+ initcall->initcall = 0;
+ f(initcall->arg);
+ }
+}
+
+
+void
+initcall_run_all()
+{
+ InitCall* initcall;
+ size_t nCalls;
+
+ initcall = _INITCALL_SECTION_BASE;
+ nCalls = (size_t)(&_INITCALL_SECTION_SIZE) / sizeof(InitCall);
+
+ for (; nCalls--; initcall++) {
+ _initcall_run(initcall);
+ }
+}
+
+
+
+
+
diff --git a/src/lib/ppc405lib/initcall.h b/src/lib/ppc405lib/initcall.h
new file mode 100644
index 0000000..af8b53c
--- /dev/null
+++ b/src/lib/ppc405lib/initcall.h
@@ -0,0 +1,116 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/initcall.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __INITCALL_H__
+#define __INITCALL_H__
+
+// $Id$
+
+/// \file initcall.h
+/// \brief An early initialization facility for SSX applications
+///
+/// The C language standard does not define a generic load-time initialization
+/// method, unlike C++ which supports load-time initialization of static
+/// objects. The \e initcall facility implements a simple method for SSX
+/// applications to declare early initialization functions that are executed
+/// prior to or during the invocation of main().
+///
+/// An \e initcall can be any function with the prototype
+///
+/// \code
+///
+/// void (*initcall)(void* arg)
+///
+/// \endcode
+///
+/// Initcalls are declared with the INITCALL() macro. An initcall is
+/// represented by a named structure, and typically an initcall will be
+/// declared static to the compilation unit that implements the initcall:
+///
+/// \code
+///
+/// void (*init_fn)(void* arg);
+/// void* init_data = ...;
+/// static INITCALL(init_var, init_fn, init_data);
+///
+/// \endcode
+///
+/// All INITCALLS loaded in the executable image are executed by the
+/// initcall_run_all() API. An SSX application will typically call
+/// initcall_run_all() in the function declared as the \a ssx_main_hook, or in
+/// the main() routine itself.
+///
+/// Initcalls are run in an arbitrary order. However if initcall \a b is
+/// dependent on initcall \a a, then initcall \a b can execute
+/// initcall_run(&a) to guarantee that initcall \a a runs before \a b.
+/// Regardless, every initcall is run exectly once by the initcall facility,
+/// even if initcall_run() or initcall_run_all() were to be used multiple
+/// times.
+///
+/// Behind the scenes, initcalls are implemented by a special ELF section,
+/// .data.initcall, that records all declared initcalls. The
+/// initcall_run_all() API simply runs all initcalls declared in
+/// .data.initcall.
+
+/// The structure representing an initcall
+
+typedef struct {
+
+ /// The initialization function
+ ///
+ /// Prior to running the initcall, this field is zeroed. This guarantess
+ /// that each initcall is run at most 1 time.
+ void (*initcall)(void* arg);
+
+ /// The argument to the initialization function
+ void* arg;
+
+} InitCall;
+
+
+/// Declare an initcall
+///
+/// This macro generates C code and global data so must be placed at file
+/// scope in a C file, not in a header file or inside a C function
+/// body. Unless the initcall needs to be referenced by another initcall (to
+/// guarantee ordering), this declaration will normally be prepended with
+/// 'static'.
+#define INITCALL(_var, _initcall, _arg) \
+ InitCall _var __attribute__ ((used, section (".data.initcall"))) = \
+ {.initcall = _initcall, .arg = _arg};
+
+
+/// Run the initcall represented by an InitCall structure, assuming it has not
+/// already run.
+///
+/// \param[in] i_initcall The address of the initcall structure to run
+void
+initcall_run(InitCall* i_initcall);
+
+
+/// Run all initcalls
+void
+initcall_run_all();
+
+#endif // __INITCALL_H__
diff --git a/src/lib/ppc405lib/lfsr.c b/src/lib/ppc405lib/lfsr.c
new file mode 100644
index 0000000..21ddb93
--- /dev/null
+++ b/src/lib/ppc405lib/lfsr.c
@@ -0,0 +1,50 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/lfsr.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file lfsr.c
+/// \brief
+
+#include <stdint.h>
+#include "lfsr.h"
+
+// Parity for 4-bit numbers
+static uint8_t S_parity4[16] = {
+ 0, 1, 1, 0,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 0, 1, 1, 0
+};
+
+// 64, 63, 61, 60 LFSR. The routine is coded with the uint8_t casting to help
+// the compiler generate more efficient code.
+
+void
+_lfsr64(uint64_t* io_seed)
+{
+ *io_seed = (*io_seed << 1) |
+ S_parity4[(uint8_t)((*io_seed >> 59) & 0x3) |
+ (uint8_t)((*io_seed >> 60) & 0xc)];
+}
diff --git a/src/lib/ppc405lib/lfsr.h b/src/lib/ppc405lib/lfsr.h
new file mode 100644
index 0000000..951ec45
--- /dev/null
+++ b/src/lib/ppc405lib/lfsr.h
@@ -0,0 +1,46 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/lfsr.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __LFSR_H__
+#define __LFSR_H__
+
+/// \file lfsr.h
+/// \brief Linear-Feedback Shift Register Implementations
+///
+/// The 32- and 64-bit pseudo-random number generators in this library are of
+/// the linear-conguential type. These maximal-length LFSR pseudo-random
+/// sequence generators are also provided.
+
+/// 64-bit LFSR
+///
+/// \param[in,out] io_seed The input seed is converted in one step to the
+/// output seed.
+///
+/// This 64-bit LFSR uses taps 64, 63, 61, and 60. In big-endian numbering
+/// these are bits 0, 1, 3 and 4. This LFSR is also implemented for the PORE
+/// engines in the file pore_rand.pS.
+void
+_lfsr64(uint64_t* io_seed);
+
+#endif // __LFSR_H__
diff --git a/src/lib/ppc405lib/libppc405files.mk b/src/lib/ppc405lib/libppc405files.mk
new file mode 100644
index 0000000..59aa7a0
--- /dev/null
+++ b/src/lib/ppc405lib/libppc405files.mk
@@ -0,0 +1,74 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/ppc405lib/libppc405files.mk $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# @file libppc405files.mk
+#
+# @brief mk for libppc405.a object files
+#
+# @page ChangeLogs Change Logs
+# @section libppc405files.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+#
+# @endverbatim
+#
+##########################################################################
+# INCLUDES
+##########################################################################
+
+C-SOURCES = \
+ assert.c \
+ byte_pool.c \
+ ctype.c \
+ ctype_table.c \
+ fgetc.c \
+ initcall.c \
+ lfsr.c \
+ mutex.c \
+ periodic_semaphore.c \
+ polling.c \
+ printf.c \
+ progress.c \
+ puts.c \
+ rtx_stdio.c \
+ simics_stdio.c \
+ sprintf.c \
+ ssx_dump.c \
+ ssx_io.c \
+ stdlib.c \
+ strcasecmp.c \
+ strdup.c \
+ string.c \
+ string_stream.c \
+ strtox.c \
+ sxlock.c \
+ time.c
+
+S-SOURCES =
+
+LIBPPC405_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/ppc405lib/libssx.h b/src/lib/ppc405lib/libssx.h
new file mode 100644
index 0000000..601eb00
--- /dev/null
+++ b/src/lib/ppc405lib/libssx.h
@@ -0,0 +1,44 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/libssx.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __LIBSSX_H__
+#define __LIBSSX_H__
+
+// $Id: libssx.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/libssx.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file libssx.h
+/// \brief Header definitions with no other obvious home
+
+// Kernel panics
+
+#define ASSERTION_FAILURE 0x00542701
+#define ERROR_EXIT 0x00542702
+
+#endif // __LIBSSX_H__
diff --git a/src/lib/ppc405lib/mutex.c b/src/lib/ppc405lib/mutex.c
new file mode 100644
index 0000000..db57f54
--- /dev/null
+++ b/src/lib/ppc405lib/mutex.c
@@ -0,0 +1,129 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/mutex.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file mutex.c
+/// \brief A ThreadX-style mutual exclusion object
+
+#include "mutex.h"
+
+int
+mutex_create(Mutex* i_mutex)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(i_mutex == 0, SSX_INVALID_OBJECT);
+ }
+
+ rc = ssx_semaphore_create(&(i_mutex->sem), 1, 1);
+ i_mutex->thread = 0;
+ i_mutex->count = 0;
+
+ return rc;
+}
+
+
+// If the current thread owns the Mutex we simply increment the count,
+// otherwise pend for the semaphore.
+//
+// Note: It's possible this doesn't need to be done in a critical section. The
+// fact that ssx_semaphore_pend() is atomic may be sufficient since it locks
+// the Mutex.
+
+int
+mutex_pend(Mutex* i_mutex, SsxInterval i_timeout)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(i_mutex == 0, SSX_INVALID_OBJECT);
+ SSX_ERROR_UNLESS_THREAD_CONTEXT();
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (i_mutex->thread == ssx_current()) {
+
+ i_mutex->count++;
+ if (i_mutex->count == 0) {
+ rc = MUTEX_OVERFLOW;
+ } else {
+ rc = 0;
+ }
+
+ } else {
+
+ rc = ssx_semaphore_pend(&(i_mutex->sem), i_timeout);
+ if (rc == 0) {
+ i_mutex->thread = ssx_current();
+ i_mutex->count = 1;
+ }
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+// If the current thread owns the Mutex we decrement the count and free the
+// object when the count goes to 0.
+//
+// Note: It's possible this doesn't need to be done in a critical section. The
+// fact that ssx_semaphore_pend() is atomic may be sufficient since it locks
+// the Mutex.
+
+int
+mutex_post(Mutex* i_mutex)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(i_mutex == 0, SSX_INVALID_OBJECT);
+ SSX_ERROR_UNLESS_THREAD_CONTEXT();
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ SSX_ERROR_IF(i_mutex->thread != ssx_current(), MUTEX_NOT_OWNED);
+
+ if (--i_mutex->count == 0) {
+ i_mutex->thread = 0;
+ rc = ssx_semaphore_post(&(i_mutex->sem));
+ } else {
+ rc = 0;
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+
+
diff --git a/src/lib/ppc405lib/mutex.h b/src/lib/ppc405lib/mutex.h
new file mode 100644
index 0000000..6d3a352
--- /dev/null
+++ b/src/lib/ppc405lib/mutex.h
@@ -0,0 +1,164 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/mutex.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __MUTEX_H__
+#define __MUTEX_H__
+
+// $Id$
+
+/// \file mutex.h
+/// \brief A ThreadX-style mutual exclusion object
+///
+/// A Mutex is a binary semaphore with the concept of thread ownership. A
+/// thread first obtains the Mutex using the mutex_pend() API, which may block
+/// if the Mutex is currently owned by another thread. Once a thread owns a
+/// Mutex, subsequent calls of mutex_pend() by the same thread simply
+/// increment an internal counter, but do not block. Once a thread has
+/// executed a matching mutex_post() call for every mutex_pend() call, the
+/// Mutex is free for another thread.
+///
+/// This type of mutual exclusion object is useful for example to control
+/// access to data structures that are manipulated by APIs with several common
+/// entry points. Each call of an API in the chain will 'lock' the data
+/// structure using mutex_pend()/mutex_post(). The Mutex semantics allows
+/// multiple "locks" by the same thread, but requires a corresponding "unlock"
+/// for every "lock".
+///
+/// The Mutex usage counter is a 32-bit unsigned integer. If a thread makes
+/// 2^32 calls to mutex_pend() without an intervening call of mutex_post(), an
+/// overflow is signalled. This error should be considered unrecoverable to
+/// the application.
+///
+/// Like the SSX semaphore, no record is kept in the thread of which Mutex
+/// objects are currently owned by the thread. If a thread terminates or is
+/// deleted while holding a Mutex it is likely that the application will
+/// hang. Unlike the SSX semaphore, it is absolutely illegal to call
+/// mutex_pend() and mutex_post() from interrupt contexts. It is also illegal
+/// for a thread to call mutex_post() for a mutex it does not own.
+///
+/// Mutex objects are easily created with the static initialization macro
+/// MUTEX_INITIALIZATION as in the following example.
+///
+/// \code
+///
+/// Mutex G_mutex = MUTEX_INITIALIZATION;
+///
+/// \endcode
+///
+/// The API mutex_create() is also provided for run-time initialization.
+
+#include "ssx.h"
+
+
+// Mutex error/panic codes
+
+#define MUTEX_OVERFLOW 0x00688901
+#define MUTEX_NOT_OWNED 0x00688902
+
+
+#ifndef __ASSEMBLER__
+
+/// Static initialization of a Mutex
+///
+/// For a full description of the Mutex please see the documentation fof the
+/// file mutex.h.
+#define MUTEX_INITIALIZATION {SSX_SEMAPHORE_INITIALIZATION(1, 1), 0, 0}
+
+
+/// The Mutex object
+
+typedef struct {
+
+ /// The binary semaphore
+ SsxSemaphore sem;
+
+ /// A pointer to the owning thread, or NULL (0)
+ SsxThread* thread;
+
+ /// The count of unmatched mutex_pend() calls made by the owning thread.
+ uint32_t count;
+
+} Mutex;
+
+
+/// Create (initialize) a Mutex
+///
+/// \param[in] i_mutex A pointer to the Mutex object to initialize.
+///
+/// For a full description of the Mutex please see the documentation for the
+/// file mutex.h.
+///
+/// \retval 0 Success
+///
+/// \retval 0 -SSX_INVALID_OBJECT The \a i_mutex is NULL (0).
+int
+mutex_create(Mutex* i_mutex);
+
+
+/// Pend on a Mutex with optional timeout
+///
+/// \param[in] i_mutex A pointer to the Mutex
+///
+/// \param[in] i_timeout Either the constant SSX_WAIT_FOREVER, or a timeout
+/// interval specification.
+///
+/// For a full description of the Mutex please see the documentation for the
+/// file mutex.h.
+///
+/// \retval 0 Success
+///
+/// \retval -SSX_INVALID_OBJECT The \a i_mutex is NULL (0).
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The call was not made from a thread context.
+///
+/// \retval -SSX_SEMEPHORE_PEND_TIMED_OUT The thread was not able to obtain
+/// the Mutex before the timeout.
+///
+/// \retval -MUTEX_OVERFLOW The owning thread has made 2^32 unmatched calls of
+/// mutex_pend().
+int
+mutex_pend(Mutex* i_mutex, SsxInterval i_timeout);
+
+
+/// Post to a Mutex
+///
+/// \param[in] i_mutex A pointer to the Mutex
+///
+/// For a full description of the Mutex please see the documentation for the
+/// file mutex.h.
+///
+/// \retval 0 Success
+///
+/// \retval -SSX_INVALID_OBJECT The \a i_mutex is NULL (0).
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The call was not made from a thread context.
+///
+/// \retval -MUTEX_NOT_OWNED The thread calling mutex_post() does not own the
+/// Mutex.
+int
+mutex_post(Mutex* i_mutex);
+
+#endif // __ASSEMBLER__
+
+#endif // __MUTEX_H__
diff --git a/src/lib/ppc405lib/periodic_semaphore.c b/src/lib/ppc405lib/periodic_semaphore.c
new file mode 100644
index 0000000..dec9ea2
--- /dev/null
+++ b/src/lib/ppc405lib/periodic_semaphore.c
@@ -0,0 +1,114 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/periodic_semaphore.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file perodic_semaphore.h
+/// \brief Periodic semphores
+
+#include "ssx.h"
+#include "periodic_semaphore.h"
+
+// The timer callback is created nonpreemptible, so noncritical interrupts are
+// disabled at entry.
+
+static void
+_periodic_semaphore_timeout(void* arg)
+{
+ PeriodicSemaphore* ps;
+
+ ps = (PeriodicSemaphore*)arg;
+
+ if (ps->sem.count != 1) {
+ ssx_semaphore_post(&(ps->sem));
+ }
+}
+
+
+int
+periodic_semaphore_create(PeriodicSemaphore* sem, SsxInterval period)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sem == 0, SSX_INVALID_OBJECT);
+ }
+
+ do {
+ rc = ssx_semaphore_create(&(sem->sem), 0, 1);
+ if (rc) break;
+
+ rc = ssx_timer_create_nonpreemptible(&(sem->timer),
+ _periodic_semaphore_timeout,
+ sem);
+ if (rc) break;
+
+ rc = ssx_timer_schedule(&(sem->timer),
+ period,
+ period);
+ if (rc) break;
+
+ } while (0);
+
+ return rc;
+}
+
+
+int
+periodic_semaphore_pend(PeriodicSemaphore* sem)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sem == 0, SSX_INVALID_OBJECT);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (sem->sem.count == 0) {
+
+ rc = ssx_semaphore_pend(&(sem->sem), SSX_WAIT_FOREVER);
+
+ } else {
+
+ sem->sem.count = 0;
+ rc = -PERIODIC_SEMAPHORE_OVERRUN;
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+int
+periodic_semaphore_cancel(PeriodicSemaphore* sem)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sem == 0, SSX_INVALID_OBJECT);
+ }
+
+ return ssx_timer_cancel(&(sem->timer));
+}
diff --git a/src/lib/ppc405lib/periodic_semaphore.h b/src/lib/ppc405lib/periodic_semaphore.h
new file mode 100644
index 0000000..c3c2e53
--- /dev/null
+++ b/src/lib/ppc405lib/periodic_semaphore.h
@@ -0,0 +1,152 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/periodic_semaphore.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PERIODIC_SEMAPHORE_H__
+#define __PERIODIC_SEMAPHORE_H__
+
+// $Id$
+
+/// \file perodic_semaphore.h
+/// \brief Periodic semphores
+///
+/// The PeriodicSemphore is a simple abstraction introduced to simplify coding
+/// peridic threads. A periodic thread creates the PeriodicSemaphore after
+/// thread initialization, but prior to the entry to the periodic infinite
+/// loop. This creates the periodicSemaphore with a count of 0. Once thread
+/// processing is finished, the thread pends on the PeriodicSemaphore. A
+/// periodic timer posts to the PeriodicSemaphore on a fixed, absolute period
+/// to reschedule the thread.
+///
+/// If the thread pends on the PeriodicSemaphore and the timer has already
+/// posted to the semaphore, the call of periodic_semaphore_pend() clears the
+/// semaphore and terminates immediately with the return code
+/// -PERIODIC_SEMAPHORE_OVERRUN, indicating that the thread has overrun its
+/// period. The thread can choose the appropriate action upon obtaining this
+/// return code.
+///
+/// The PeriodicSemaphore can also be cancelled, which simply cancels the
+/// periodic timer posting to the semaphore. If the thread needs to
+/// re-initialize the PeriodicSemaphore for any reason (e.g, to resynchronize
+/// after an overrun) it must be cancelled first.
+
+// Error/Panic codes
+
+#define PERIODIC_SEMAPHORE_OVERRUN 0x0077e601
+
+
+/// A periodic semaphore
+
+typedef struct {
+
+ /// The semaphore
+ SsxSemaphore sem;
+
+ /// The timer
+ SsxTimer timer;
+
+} PeriodicSemaphore;
+
+
+/// Create (initialize) a PeriodicSemaphore
+///
+/// \param sem A pointer to an uninitialized or inactive
+/// PeriodicSemaphore.
+///
+/// \param period The semaphore period
+///
+/// This API creates the embedded semaphore as a binary semaphore with an
+/// initial value of 0, and schedules a periodic timer to post to the
+/// semaphore.
+///
+/// \retval 0 Success
+///
+/// \retval -SSX_INVALID_OBJECT The \a sem was NULL (0) or otherwise invalid.
+///
+/// Other return codes are possible from the embedded calls of SSX APIs.
+int
+periodic_semaphore_create(PeriodicSemaphore* sem, SsxInterval period);
+
+
+/// Pend on a PeriodicSemaphore
+///
+/// \param sem A pointer to an initialized PeriodicSemaphore
+///
+/// Pend on a PeriodicSemaphore. It is considered a non-fatal error if the
+/// semaphore has a non-0 count as this may indicate that a periodic thread
+/// has missed a deadline.
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Success. In particular, the semaphore count was 0 at entry.
+///
+/// \retval -PERIODIC_SEMAPHORE_OVERRUN This return code indicates that the
+/// semaphore count was 1 at entry. This code is always returned (never causes
+/// a panic).
+///
+/// The following return codes are error codes:
+///
+/// \retval -SSX_IVALID_OBJECT The \a sem was NULL () or otherwise invalid at
+/// entry.
+///
+/// Other error return codes are possible from embedded calls of SSX APIs.
+int
+periodic_semaphore_pend(PeriodicSemaphore* sem);
+
+
+/// Cancel a periodic semaphore
+///
+/// \param sem A pointer to an initialized PeriodicSemaphore
+///
+/// Cancel the PeriodicSemaphore timeout. This is a required step if the
+/// PeriodicSemaphore is to be reinitialized. This is also required if the
+/// PeriodicSemaphore is created on the thread stack and the thread
+/// terminates. PeriodicSemaphore can be canceled at any time. It is never
+/// an error to call periodic_semaphore_cancel() on a PeriodicSemaphore object
+/// after it is created.
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_TIMER_NOT_ACTIVE The embedded timer is not currently
+/// scheduled, meaning that the PeriodicSemaphore was previosly
+/// cancelled.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SSX_IVALID_OBJECT The \a sem was NULL () or otherwise invalid at
+/// entry.
+///
+/// Other error return codes are possible from embedded calls of SSX APIs.
+int
+periodic_semaphore_cancel(PeriodicSemaphore* sem);
+
+
+#endif // __PERIODIC_SEMAPHORE_H__
diff --git a/src/lib/ppc405lib/polling.c b/src/lib/ppc405lib/polling.c
new file mode 100644
index 0000000..a013202
--- /dev/null
+++ b/src/lib/ppc405lib/polling.c
@@ -0,0 +1,97 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/polling.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: polling.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/polling.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file polling.c
+/// \brief Library APIs for polling
+
+#include "polling.h"
+
+int
+polling(int* o_rc,
+ int (*i_condition)(void* io_arg, int* o_satisfied),
+ void* io_arg,
+ SsxInterval i_timeout,
+ SsxInterval i_sleep)
+{
+ SsxTimebase start;
+ int rc, pollRc, timed_out, done;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((i_condition == 0), POLLING_ERROR);
+ }
+
+ start = ssx_timebase_get();
+ timed_out = 0;
+
+ do {
+ pollRc = i_condition(io_arg, &done);
+ if (pollRc) {
+ rc = POLLING_CONDITION;
+ break;
+ }
+ if (done) {
+ rc = 0;
+ break;
+ }
+ if (timed_out) {
+ rc = POLLING_TIMEOUT;
+ break;
+ }
+ if (i_sleep != 0) {
+ rc = ssx_sleep(i_sleep);
+ if (rc) {
+ break;
+ }
+ }
+ timed_out =
+ ((i_timeout != SSX_WAIT_FOREVER) &&
+ ((ssx_timebase_get() - start) >= i_timeout));
+
+ } while (1);
+
+ if (o_rc) {
+ *o_rc = pollRc;
+ }
+
+ return rc;
+}
+
+
+void
+busy_wait(SsxInterval i_interval)
+{
+ SsxTimebase start;
+
+ start = ssx_timebase_get();
+ while ((ssx_timebase_get() - start) < i_interval);
+}
+
diff --git a/src/lib/polling.h b/src/lib/ppc405lib/polling.h
index b719ac6..99afbe7 100644
--- a/src/lib/polling.h
+++ b/src/lib/ppc405lib/polling.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/polling.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __POLLING_H__
#define __POLLING_H__
diff --git a/src/lib/printf.c b/src/lib/ppc405lib/printf.c
index 96f08f3..d75cdf3 100755..100644
--- a/src/lib/printf.c
+++ b/src/lib/ppc405lib/printf.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/printf.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: printf.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/printf.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ppc405lib/progress.c b/src/lib/ppc405lib/progress.c
new file mode 100644
index 0000000..8d2cd30
--- /dev/null
+++ b/src/lib/ppc405lib/progress.c
@@ -0,0 +1,743 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/progress.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id
+
+/// \file progress.c
+/// \brief Programmable progress (hang) checking
+///
+/// This is a simple implementation of a progress (hang) checking
+/// facility. The application provides an array of \e pass \e counts that are
+/// expected to update/count over time. For simplicity and generality all
+/// pass counts are defined to be \c uint64_t types. The
+/// progress_checker_create() API initializes the checker, and as a
+/// convenience clears the pass counts.
+///
+/// The checker can be created with an optional \a callback function, which
+/// has the prototype
+///
+/// \code
+/// typedef int (*ProgressCheckerCallback)(struct ProgressChecker *checker,
+/// void* arg,
+/// size_t failed)
+/// \endcode
+///
+/// The checker callback is called \e every time a check is made by
+/// progress_checker_check(). In addition to a private void* argument, the
+/// parameter list of the callback includes a count of the number of counters
+/// that failed to make progress - this count will be 0 if the check was
+/// successful. The return value of the callback is passed back as the return
+/// value of progress_checker_check(). If the callback is specified as NULL
+/// (0), then a successful check returns 0, and any failure causes a return
+/// code of -PROGRESS_CHECKER_FAILED.
+///
+/// The application can dynamically mark counters as either \e exempt or \e
+/// required. By default all counts are required to have increased
+/// each time a check is made for progress. Counters marked \e exempt when a
+/// progress check is made are not checked for progress.
+///
+/// The application can also use the progress_checker_schedule() API to
+/// schedule either one-shot or periodic checks. The
+/// progress_checker_cancel() API can be used to cancel any scheduled
+/// checks. It is never an error to call this API, even if no checks are
+/// currently scheduled. Note that each call of progress_checker_schedule()
+/// also cancels any outstanding scheduled requests before (re-) scheduling
+/// the checker. If using the built-in timer mechanism, any calls of
+/// progress_checker_check that return a non-0 value will cause a kernel panic.
+///
+/// If failures are detected and caught, the ProgressChecker provides a
+/// primitive iteration facility for the callback or the applicaton to
+/// determine which counters have failed to update. Calling
+/// progress_checker_next_failure() returns either the index of the next
+/// failing counter, or -1 to indicate no more failures. This iteration
+/// facility is reset every time a check is made by progress_checker_check()
+/// (including those made implcitly by the timer-based mechanism). There is no
+/// API to reset the iteration.
+///
+/// The implemetation provides 2 standard callback functions:
+/// progess_checker_printk() and progress_checker_printk_dump(). The former
+/// callback uses printk() to print a simple report of failed counters, and if
+/// there were any failures it then returns its argument as a return code. If
+/// the return code is non-zero then the lack of progress will cause a kernel
+/// panic (test failure). The later callback first calls
+/// progress_checker_printk(). If progress_checker_printk() returns a non-0
+/// value then progress_checker_printk_dump() enters an SSX_CRITICAL crictal
+/// section and prints a full kernel state dump that may be useful to help
+/// diagnose the hang.
+///
+/// \note We do not make the kernel dump the default or only behavior because
+/// it could take 1ms or more to produce the large quantity of formatted
+/// output required, which could be a significant amount of wall time in a
+/// logic simulation environment.
+///
+/// The progress_checker_create() API could be used in a couple of ways as
+/// illustrated below:
+///
+/// \code
+///
+/// ProgressChecker progress;
+/// uint64_t counter;
+///
+/// progress_checker_create(&progress, "progress", counter, 1,
+/// progress_checker_printk,
+/// (void*)-PROGRESS_CHECKER_FAILED);
+///
+/// OR
+///
+/// progress_checker_create(&progress, "progress", counter, 1,
+/// progress_checker_printk, 0);
+///
+/// \endcode
+///
+/// The first usage prints a report and panics the test if lack of progress is
+/// detected. The second form simply prints a report in the event of a lack
+/// or progress. The second form may be useful to report on counters that
+/// only have a statistical probability of making progress, however be aware
+/// that the report is generated in an interrupt context and all thread
+/// activity will be blocked until the formatted I/O is complete.
+///
+/// Notes:
+///
+/// This implementation requires the \c byte_pool facility and malloc() to be
+/// set up as the ProgressChecker allocates dynamic storage during
+/// initialization to store the previous pass counts.
+///
+/// It is probably not a good idea to use a single ProgressChecker for both
+/// manual and timer-based checking, since there is no protection in the
+/// implementation for mutiple accesses to the ProgressChecker.
+
+#include "progress.h"
+#include "ssx_dump.h"
+
+// The built-in timer callback
+
+static void
+progress_callback(void *arg)
+{
+ ProgressChecker *checker = (ProgressChecker *)arg;
+
+ if (progress_checker_check(checker)){
+ if (0) {
+ progress_checker_dump(checker);
+ }
+ SSX_PANIC(PROGRESS_CHECKER_FAILED);
+ }
+}
+
+
+// Bit-vector operations manage the array of bits using little-endian
+// protocols
+
+static inline void
+bit_vector_set(uint8_t *vector, size_t bit)
+{
+ vector[bit / 8] |= (1 << (bit % 8));
+}
+
+
+static inline void
+bit_vector_clear(uint8_t *vector, size_t bit)
+{
+ vector[bit / 8] &= ~(1 << (bit % 8));
+}
+
+
+static inline int
+bit_vector_is_set(uint8_t *vector, size_t bit)
+{
+ return ((vector[bit / 8] & (1 << (bit % 8))) != 0);
+}
+
+
+// NB: We don't have a bit-vector object with a size included. For this
+// application we can only call this API if we know that there is at least 1
+// bit set in the vector.
+
+static size_t
+bit_vector_find_first_set(uint8_t *vector)
+{
+ size_t byte = 0;
+
+ while (vector[byte] == 0) {
+ byte++;
+ }
+
+ return (8 * byte) + __builtin_ffs(vector[byte]) - 1;
+}
+
+
+/// Create a progress checker
+///
+/// \param checker A pointer to an uninitialized or idle ProgressChecker
+///
+/// \param name An optional character string associated with the checker
+///
+/// \param pass_counts An array of pass counters - the array will be cleared
+/// by this API.
+///
+/// \param counters The number of counters in the array
+///
+/// \param callback This function is called \e every time a check is
+/// completed.
+///
+/// \param arg The private argument of the callback function
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT A null (0) pointer was provided
+/// as the \a pass_counts argument, or the number of \a counters can not be
+/// represented as a signed integer.
+///
+/// \retval -PROGRESS_CHECKER_ALLOCATION_FAILED Memory allocation of dynamic
+/// memory failed. This is treated as a fatal error here.
+///
+/// This API may also return or signal other errors from its implementation
+/// APIs.
+
+int
+progress_checker_create(ProgressChecker *checker,
+ const char* name,
+ uint64_t *pass_counts,
+ size_t counters,
+ ProgressCheckerCallback callback,
+ void *arg)
+{
+ int rc, bytes;
+ void *memory;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((checker == 0),
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ SSX_ERROR_IF((pass_counts == 0) ||
+ (counters != (int)counters),
+ PROGRESS_CHECKER_INVALID_ARGUMENT);
+ }
+
+ // Install and clear the counters
+
+ checker->pass_counts = pass_counts;
+ memset((void *)pass_counts, 0, counters * sizeof(uint64_t));
+ checker->counters = counters;
+
+ // Allocate and clear dynamic memory
+
+ memory = calloc(counters, sizeof(uint64_t));
+ checker->saved_counts = (uint64_t *)memory;
+
+ bytes = (counters / 8) + (counters % 8 ? 1 : 0);
+ checker->bit_vector_bytes = bytes;
+
+ memory = calloc(bytes, 1);
+ checker->exempt = (uint8_t *)memory;
+
+ memory = calloc(bytes, 1);
+ checker->failure = (uint8_t *)memory;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((counters != 0) &&
+ ((checker->saved_counts == 0) ||
+ (checker->exempt == 0) ||
+ (checker->failure == 0)),
+ PROGRESS_CHECKER_ALLOCATION_FAILED);
+ }
+
+ // Initialize other fields
+
+ checker->name = name;
+ checker->callback = callback;
+ checker->arg = arg;
+ checker->failed = 0;
+ checker->checks = 0;
+
+ // Initialize the timer structure.
+
+ rc = ssx_timer_create(&(checker->timer),
+ progress_callback,
+ (void *)checker);
+ if (rc) return rc;
+
+ return 0;
+}
+
+
+/// Exempt a pass count from progress checking
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter The index of the counter to exempt
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT The \a counter argument is not
+/// valid.
+
+int
+progress_checker_exempt(ProgressChecker *checker,
+ size_t counter)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ SSX_ERROR_IF(counter >= checker->counters,
+ PROGRESS_CHECKER_INVALID_ARGUMENT);
+ }
+
+ bit_vector_set(checker->exempt, counter);
+
+ return 0;
+}
+
+
+/// Exempt all pass counts from progress checking
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// This API is provided to support applications where pass-count-updating
+/// processes are added dynamically. This API coule typically be called
+/// immediately after progress_checker_create(). Them, as each process was
+/// created it would call progress_checker_require() for the pass count.
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+int
+progress_checker_exempt_all(ProgressChecker *checker)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ memset(checker->exempt, -1, checker->bit_vector_bytes);
+
+ return 0;
+}
+
+
+/// Require a pass count to update for progress checking
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter The index of the counter to require
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT The \a counter argument is not
+/// valid.
+
+int
+progress_checker_require(ProgressChecker *checker,
+ size_t counter)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ SSX_ERROR_IF(counter >= checker->counters,
+ PROGRESS_CHECKER_INVALID_ARGUMENT);
+ }
+
+ bit_vector_clear(checker->exempt, counter);
+
+ return 0;
+}
+
+
+/// Require a pass count to update for progress checking avoiding races
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter The index of the counter to require
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// If a pass counter is marked "exempt" but then later marked "required",
+/// there is a potential race between the update of the pass counter and the
+/// next check, particularly when the checker is scheduled periodically. This
+/// form of the progress_checker_require() marks the progress checker such
+/// that \e all checks are deferred on the next call of
+/// progress_checker_check() targeting the object in order to avoid the race.
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT The \a counter argument is not
+/// valid.
+int
+progress_checker_require_defer(ProgressChecker *checker,
+ size_t counter)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ ssx_critical_section_enter(SSX_CRITICAL, &ctx);
+
+ rc = progress_checker_require(checker, counter);
+ checker->defer = 1;
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Check for progress in every required pass counter.
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// \retval various Except for the error listed below,
+/// progress_checker_check() returns the code returned by the callback
+/// function. If no callback was provided when the checker was created, then 0
+/// is returned for success and -PROGRESS_CHECKER_FAILED is returned in the
+/// event of a lack of progress.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+
+int
+progress_checker_check(ProgressChecker *checker)
+{
+ size_t i;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ // Avoid doing this step unless necessary
+
+ if (checker->failed != 0) {
+ checker->failed = 0;
+ memset((void *)checker->failure, 0, checker->bit_vector_bytes);
+ }
+
+ // Check, unless checking has been deferred for 1 time by
+ // progress_checker_require_defer().
+
+ if (checker->defer) {
+
+ checker->defer = 0;
+
+ } else {
+
+ SSX_ATOMIC(SSX_CRITICAL, checker->start_check = ssx_timebase_get());
+
+ for (i = 0; i < checker->counters; i++) {
+
+ if ((checker->pass_counts[i] <= checker->saved_counts[i]) &&
+ !(bit_vector_is_set(checker->exempt, i))) {
+
+ checker->failed++;
+ bit_vector_set(checker->failure, i);
+ }
+ checker->saved_counts[i] = checker->pass_counts[i];
+ }
+
+ SSX_ATOMIC(SSX_CRITICAL, checker->end_check = ssx_timebase_get());
+ }
+
+ checker->checks++;
+
+ if (checker->callback) {
+ return checker->callback(checker, checker->arg, checker->failed);
+ } else if (checker->failed != 0) {
+ return -PROGRESS_CHECKER_FAILED;
+ } else {
+ return 0;
+ }
+}
+
+
+/// Schedule progress checks (periodically) in the future.
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param interval The relative time of the (first) check
+///
+/// \param period If non-zero, checks will be made periodically with this
+/// period.
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c. See the SSX documentation for a discussion of
+/// timer scheduling in SSX.
+///
+/// Return values other than 0 errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// This API may also return or signal other errors from its implementation
+/// APIs.
+
+
+int
+progress_checker_schedule(ProgressChecker *checker,
+ SsxInterval interval,
+ SsxInterval period)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ rc = ssx_timer_cancel(&(checker->timer));
+ if (rc != -SSX_TIMER_NOT_ACTIVE) return rc;
+
+ rc = ssx_timer_schedule(&(checker->timer), interval, period);
+ if (rc) return rc;
+
+ return 0;
+}
+
+
+/// Cancel all future (periodic) progress checks
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c. See the SSX documentation for a discussion of
+/// timer scheduling in SSX.
+///
+/// Return values other than 0 errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// This API may also return or signal other errors from its implementation
+/// APIs.
+
+int
+progress_checker_cancel(ProgressChecker *checker)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ rc = ssx_timer_cancel(&(checker->timer));
+ if (rc) return rc;
+
+ return 0;
+}
+
+
+/// Iterate over progress check failures
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter Will return the index of the next failing counter, or -1 to
+/// indicate no more failing counters.
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c.
+///
+/// Return values other than 0 errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+
+int
+progress_checker_next_failure(ProgressChecker *checker, int *counter)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ if (checker->failed == 0) {
+ *counter = -1;
+ return 0;
+ }
+
+ *counter = bit_vector_find_first_set(checker->failure);
+ bit_vector_clear(checker->failure, *counter);
+ checker->failed--;
+
+ return 0;
+}
+
+
+/// A standard way to print the results of a progress check failure, suitable
+/// for use as a ProgressChecker callback.
+///
+/// \param checker The checker - which may or may not have failed. If the
+/// checker did fail, then a failure report is printed using printk().
+///
+/// \param arg The value to return in case of failure. In case of
+/// success, 0 is returned.
+///
+/// \param failed - The number of failed checks
+
+int
+progress_checker_printk(ProgressChecker *checker,
+ void *arg,
+ size_t failed)
+{
+ int counter;
+
+ if (!failed) {
+ return 0;
+ }
+
+ printk("---------------------------------------------------------------\n");
+ printk("-- Progress check failed for \"%s\" (%p).\n",
+ checker->name, checker);
+ printk("-- Check %zu over interval 0x%016llx - 0x%016llx\n",
+ checker->checks, checker->start_check, checker->end_check);
+ printk("-- %zu failed counter%s listed below\n",
+ failed, failed > 1 ? "s are" : " is");
+ printk("---------------------------------------------------------------\n");
+
+ do {
+ progress_checker_next_failure(checker, &counter);
+ if (counter < 0) {
+ break;
+ }
+ printk("%4d. 0x%016llx\n", counter, checker->pass_counts[counter]);
+ } while (1);
+
+ printk("---------------------------------------------------------------\n");
+
+ return (int)arg;
+}
+
+
+/// Call progress_checker_printk(), then create a kernel dump on failure
+///
+/// \param checker The checker - which may or may not have failed. If the
+/// checker did fail, then a failure report is printed using
+/// progress_checker_printk().
+///
+/// \param arg The value to return in case of failure. In case of
+/// success, 0 is returned.
+///
+/// \param failed - The number of failed checks
+///
+/// If progress_checker_printk() fails with a non-0 return code then this API
+/// prints a full SSX kernel dump after the progress_checker_printk() report.
+int
+progress_checker_printk_dump(ProgressChecker *checker,
+ void *arg,
+ size_t failed)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ rc = progress_checker_printk(checker, arg, failed);
+ if (rc != 0) {
+ ssx_critical_section_enter(SSX_CRITICAL, &ctx);
+ ssx_dump(ssxout, 0);
+ ssx_critical_section_exit(&ctx);
+ }
+
+ return rc;
+}
+
+
+/// Dump a progress checker structure using printk()
+
+void
+progress_checker_dump(ProgressChecker *checker)
+{
+ size_t i;
+
+ printk("Dump of progress checker \"%s\" (%p)\n"
+ " Counters = %zu\n"
+ " Checks = %zu\n"
+ " Failed = %zu\n"
+ " Callback = %p(%p)\n",
+ checker->name, checker, checker->counters, checker->checks,
+ checker->failed, checker->callback, checker->arg);
+
+ printk(" Pass Counts (%p) :\n", checker->pass_counts);
+ for (i = 0; i < checker->counters; i++) {
+ printk(" %9d%c 0x%016llx\n",
+ i,
+ bit_vector_is_set(checker->exempt, i) ? '*' : ' ',
+ checker->pass_counts[i]);
+ }
+ printk(" Saved Counts (%p) :\n", checker->saved_counts);
+ for (i = 0; i < checker->counters; i++) {
+ printk(" %9d 0x%016llx\n",
+ i, checker->saved_counts[i]);
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/src/lib/ppc405lib/progress.h b/src/lib/ppc405lib/progress.h
new file mode 100644
index 0000000..3454a0f
--- /dev/null
+++ b/src/lib/ppc405lib/progress.h
@@ -0,0 +1,177 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/progress.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PROGRESS_H__
+#define __PROGRESS_H__
+
+// $Id$
+
+/// \file progress.h
+/// \brief Programmable progress (hang) checking
+
+#include <time.h>
+#include "ssx.h"
+#include "byte_pool.h"
+#include "ssx_io.h"
+
+#ifndef __ASSEMBLER__
+
+struct ProgressChecker;
+
+/// ProgressChecker callback type
+///
+/// \param checker The checker that has just been checked
+///
+/// \param arg The private argument provided when the checker was created
+///
+/// \param failed The number of failed pass counts - 0 indicates no failures
+
+typedef int (*ProgressCheckerCallback)(struct ProgressChecker* checker,
+ void* arg,
+ size_t failed);
+
+
+/// A simple progress (hang) checker. For API details see file progress.c
+
+typedef struct ProgressChecker {
+
+ /// The application provided pass-count array
+ uint64_t *pass_counts;
+
+ /// The number of pass-count counters in the array.
+ size_t counters;
+
+ /// The (optional) name of the checker for reporting purposes.
+ const char *name;
+
+ /// The (optional) checker callback.
+ ProgressCheckerCallback callback;
+
+ /// The checker callback private argument
+ void *arg;
+
+ /// The dynamically-allocated saved pass counts.
+ uint64_t *saved_counts;
+
+ /// The dynamically-allocated exemption bit-vector
+ ///
+ /// \todo Get or implement a generic unlimited-precision bit vector
+ uint8_t *exempt;
+
+ /// The dynamically-allocated failure bit-vector
+ uint8_t *failure;
+
+ /// The number of bytes in the bit vector
+ size_t bit_vector_bytes;
+
+ /// Defer all checking the next time progress_checker_check() is called.
+ ///
+ /// See progress_checker_require_defer()
+ int defer;
+
+ /// The number of failures present in the *failure vector
+ size_t failed;
+
+ /// A timer object to support time-based checking.
+ SsxTimer timer;
+
+ /// The number of times progress_checker_check() has been called on the
+ /// object.
+ size_t checks;
+
+ /// The time the last check started
+ SsxTimebase start_check;
+
+ /// The time the last check ended
+ SsxTimebase end_check;
+
+} ProgressChecker;
+
+
+int
+progress_checker_create(ProgressChecker *checker,
+ const char *name,
+ uint64_t *pass_counts,
+ size_t counters,
+ ProgressCheckerCallback callback,
+ void *arg);
+
+int
+progress_checker_exempt(ProgressChecker *checker,
+ size_t counter);
+
+int
+progress_checker_exempt_all(ProgressChecker *checker);
+
+int
+progress_checker_require(ProgressChecker *checker,
+ size_t counter);
+
+int
+progress_checker_require_defer(ProgressChecker *checker,
+ size_t counter);
+
+int
+progress_checker_check(ProgressChecker *checker);
+
+int
+progress_checker_schedule(ProgressChecker *checker,
+ SsxInterval interval,
+ SsxInterval period);
+
+int
+progress_checker_cancel(ProgressChecker *checker);
+
+int
+progress_checker_next_failure(ProgressChecker *checker, int *counter);
+
+int
+progress_checker_delete(ProgressChecker *checker);
+
+int
+progress_checker_printk(ProgressChecker *checker,
+ void *arg,
+ size_t failed);
+
+int
+progress_checker_printk_dump(ProgressChecker *checker,
+ void *arg,
+ size_t failed);
+
+void
+progress_checker_dump(ProgressChecker *checker);
+
+
+#endif /* __ASSEMBLER__ */
+
+// Error/Panic codes
+
+#define PROGRESS_CHECKER_INVALID_OBJECT 0x00776001
+#define PROGRESS_CHECKER_INVALID_ARGUMENT 0x00776002
+#define PROGRESS_CHECKER_FAILED 0x00776003
+#define PROGRESS_CHECKER_CALLBACK_PANIC 0x00776004
+#define PROGRESS_CHECKER_INVARIANT 0x00776005
+#define PROGRESS_CHECKER_ALLOCATION_FAILED 0x00776006
+
+#endif /* __PROGRESS_H__ */
diff --git a/src/lib/puts.c b/src/lib/ppc405lib/puts.c
index ab24d6b..446671a 100755..100644
--- a/src/lib/puts.c
+++ b/src/lib/ppc405lib/puts.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/puts.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: puts.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/puts.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ppc405lib/rtx_stdio.c b/src/lib/ppc405lib/rtx_stdio.c
new file mode 100644
index 0000000..4bb1a18
--- /dev/null
+++ b/src/lib/ppc405lib/rtx_stdio.c
@@ -0,0 +1,149 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/rtx_stdio.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file rtx_stdio.c
+/// \brief SSX I/O drivers for RTX stdio streams
+///
+/// The RTX \a stdout and \a stderr components accept 1, 2 and 4-byte
+/// transactions on a 32-bit OCI address and write the data to the RTX
+/// job's \a stdout or \a stderr respectively. The \a stdin device is not yet
+/// implemented.
+
+#include "ssx.h"
+#include "rtx_stdio.h"
+
+RtxStdio rtx_stdin;
+RtxStdio rtx_stdout;
+RtxStdio rtx_stderr;
+
+int
+rtx_stdio_sread(FILE *stream, void *buf, size_t count, size_t *read)
+{
+ SSX_PANIC(ENXIO);
+ return -ENXIO;
+}
+
+
+int
+rtx_stdio_swrite(FILE *stream, const void *buf,
+ size_t count, size_t *written)
+{
+ RtxStdio *rtx = (RtxStdio *)stream;
+ size_t n;
+
+ n = count;
+ while (n) {
+ if (n >= 4) {
+ out32(rtx->address, *((uint32_t *)buf));
+ buf += 4;
+ n -= 4;
+ } else if (n >= 2) {
+ out16(rtx->address, *((uint16_t *)buf));
+ buf += 2;
+ n -= 2;
+ } else {
+ out8(rtx->address, *((uint8_t *)buf));
+ buf++;
+ n--;
+ }
+ }
+
+ if (written != 0) {
+ *written = count;
+ }
+
+ return 0;
+}
+
+
+ssize_t
+rtx_stdio_fflush(FILE *stream)
+{
+ RtxStdio *rtx = (RtxStdio *)stream;
+
+ out8(rtx->flush_address, 0);
+ return 0;
+}
+
+
+int
+rtx_stdin_create(RtxStdio *stream)
+{
+ FILE *base = (FILE *)stream;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, EBADF);
+ }
+
+ memset((void *)stream, 0, sizeof(RtxStdio));
+ base->sread = rtx_stdio_sread;
+
+ stream->address = RTX_STDIN;
+
+ return 0;
+}
+
+
+int
+rtx_stdout_create(RtxStdio *stream)
+{
+ FILE *base = (FILE *)stream;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, EBADF);
+ }
+
+ memset((void *)stream, 0, sizeof(RtxStdio));
+ base->swrite = rtx_stdio_swrite;
+ base->fflush = rtx_stdio_fflush;
+
+ stream->address = RTX_STDOUT;
+ stream->flush_address = RTX_STDOUT_FLUSH;
+
+ return 0;
+}
+
+
+int
+rtx_stderr_create(RtxStdio *stream)
+{
+ FILE *base = (FILE *)stream;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, ENXIO);
+ }
+
+ memset((void *)stream, 0, sizeof(RtxStdio));
+ base->swrite = rtx_stdio_swrite;
+ base->fflush = rtx_stdio_fflush;
+
+ stream->address = RTX_STDERR;
+ stream->flush_address = RTX_STDERR_FLUSH;
+
+ return 0;
+}
+
+
diff --git a/src/lib/ppc405lib/rtx_stdio.h b/src/lib/ppc405lib/rtx_stdio.h
new file mode 100644
index 0000000..cd2a439
--- /dev/null
+++ b/src/lib/ppc405lib/rtx_stdio.h
@@ -0,0 +1,74 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/rtx_stdio.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __RTX_STDIO_H__
+#define __RTX_STDIO_H__
+
+// $Id$
+
+/// \file rtx_stdio.h
+/// \brief SSX I/O implementations for RTX stdio streams
+
+#include "ssx_io.h"
+#include "rtx_stdio_addresses.h"
+
+/// A FILE structure for a RTX fake stdio stream
+
+typedef struct {
+
+ /// The base class
+ FILE stream;
+
+ /// The MMIO address of the RTX device for the stream
+ SsxAddress address;
+
+ /// The MMIO address of the RTX device for flushing the stream;
+ SsxAddress flush_address;
+
+} RtxStdio;
+
+extern RtxStdio rtx_stdin;
+extern RtxStdio rtx_stdout;
+extern RtxStdio rtx_stderr;
+
+int
+rtx_stdin_create(RtxStdio *stream);
+
+int
+rtx_stdout_create(RtxStdio *stream);
+
+int
+rtx_stderr_create(RtxStdio *stream);
+
+int
+rtx_stdio_sread(FILE *stream, void *buf, size_t count, size_t *read);
+
+int
+rtx_stdio_swrite(FILE *stream, const void *buf,
+ size_t count, size_t *written);
+
+int
+rtx_stdio_sflush(FILE *stream);
+
+#endif /* __RTX_STDIO_H__ */
diff --git a/src/lib/ppc405lib/rtx_stdio_addresses.h b/src/lib/ppc405lib/rtx_stdio_addresses.h
new file mode 100644
index 0000000..5359f7f
--- /dev/null
+++ b/src/lib/ppc405lib/rtx_stdio_addresses.h
@@ -0,0 +1,55 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/rtx_stdio_addresses.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __RTX_STDIO_ADDRESSES_H__
+#define __RTX_STDIO_ADDRESSES_H__
+
+// $Id$
+
+/// \file rtx_stdio_addresses.h
+/// \brief MMIO addresses and offsets of the rtx fake stdio model
+///
+/// The RTX stdio module appears as OCI device #7? Reading 1 byte from the
+/// stdin offset returns that byte from stdin. Writing 1, 2 or 4 bytes to the
+/// stdout or stderr offsets causes output on that stream. Writing any single
+/// byte to the 'flush' offsets flush the stdout or stderr streams.
+///
+/// -*- This header is maintained as part of the PMX RTX model. -*-
+/// -*- Do not edit in the SSX library as your edits will be lost. -*-
+
+#define RTX_STDIO_BASE 0x40060000
+
+#define RTX_STDIN_OFFSET 0x00
+#define RTX_STDOUT_OFFSET 0x04
+#define RTX_STDOUT_FLUSH_OFFSET 0x08
+#define RTX_STDERR_OFFSET 0x0c
+#define RTX_STDERR_FLUSH_OFFSET 0x10
+
+#define RTX_STDIN (RTX_STDIO_BASE + RTX_STDIN_OFFSET)
+#define RTX_STDOUT (RTX_STDIO_BASE + RTX_STDOUT_OFFSET)
+#define RTX_STDOUT_FLUSH (RTX_STDIO_BASE + RTX_STDOUT_FLUSH_OFFSET)
+#define RTX_STDERR (RTX_STDIO_BASE + RTX_STDERR_OFFSET)
+#define RTX_STDERR_FLUSH (RTX_STDIO_BASE + RTX_STDERR_FLUSH_OFFSET)
+
+#endif /* __RTX_STDIO_ADDRESSES_H__ */
diff --git a/src/lib/simics_stdio.c b/src/lib/ppc405lib/simics_stdio.c
index 5c276a2..6ff1fa9 100755..100644
--- a/src/lib/simics_stdio.c
+++ b/src/lib/ppc405lib/simics_stdio.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/simics_stdio.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: simics_stdio.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/simics_stdio.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/simics_stdio.h b/src/lib/ppc405lib/simics_stdio.h
index abbfe26..b9ebfcf 100755..100644
--- a/src/lib/simics_stdio.h
+++ b/src/lib/ppc405lib/simics_stdio.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/simics_stdio.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __SIMICS_STDIO_H__
#define __SIMICS_STDIO_H__
diff --git a/src/lib/simics_stdio_addresses.h b/src/lib/ppc405lib/simics_stdio_addresses.h
index 9f7d886..4554bbf 100755..100644
--- a/src/lib/simics_stdio_addresses.h
+++ b/src/lib/ppc405lib/simics_stdio_addresses.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/simics_stdio_addresses.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __SIMICS_STDIO_ADDRESSES_H__
#define __SIMICS_STDIO_ADDRESSES_H__
diff --git a/src/lib/sprintf.c b/src/lib/ppc405lib/sprintf.c
index 458cd39..0a95416 100755..100644
--- a/src/lib/sprintf.c
+++ b/src/lib/ppc405lib/sprintf.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/sprintf.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: sprintf.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/sprintf.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ssx_dump.c b/src/lib/ppc405lib/ssx_dump.c
index 93ce1ea..52334ab 100644
--- a/src/lib/ssx_dump.c
+++ b/src/lib/ppc405lib/ssx_dump.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_dump.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: ssx_dump.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ssx_dump.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ssx_dump.h b/src/lib/ppc405lib/ssx_dump.h
index 17455c0..a413214 100644
--- a/src/lib/ssx_dump.h
+++ b/src/lib/ppc405lib/ssx_dump.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_dump.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __SSX_DUMP_H__
#define __SSX_DUMP_H__
diff --git a/src/lib/ssx_io.c b/src/lib/ppc405lib/ssx_io.c
index e69dcbe..b517aeb 100755..100644
--- a/src/lib/ssx_io.c
+++ b/src/lib/ppc405lib/ssx_io.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_io.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: ssx_io.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ssx_io.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ssx_io.h b/src/lib/ppc405lib/ssx_io.h
index 794fe5d..b30b32f 100755..100644
--- a/src/lib/ssx_io.h
+++ b/src/lib/ppc405lib/ssx_io.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_io.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __SSX_IO_H__
#define __SSX_IO_H__
diff --git a/src/lib/stdlib.c b/src/lib/ppc405lib/stdlib.c
index 2dcc009..a15308d 100755..100644
--- a/src/lib/stdlib.c
+++ b/src/lib/ppc405lib/stdlib.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/stdlib.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: stdlib.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/stdlib.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/strcasecmp.c b/src/lib/ppc405lib/strcasecmp.c
index 361a387..fc7585c 100644
--- a/src/lib/strcasecmp.c
+++ b/src/lib/ppc405lib/strcasecmp.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strcasecmp.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: strcasecmp.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strcasecmp.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/ppc405lib/strdup.c b/src/lib/ppc405lib/strdup.c
new file mode 100644
index 0000000..6d205c7
--- /dev/null
+++ b/src/lib/ppc405lib/strdup.c
@@ -0,0 +1,63 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strdup.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: strdup.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strdup.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file strdup.c
+/// \brief Functions from <string.h> that require malloc()
+///
+/// These APIs are split from string.c for the benefit of applications like
+/// OCC FW that don't use malloc().
+
+#include <stdlib.h>
+#include <string.h>
+
+/// Duplicate a string
+///
+/// \param s The string to duplicate
+///
+/// The strdup() function returns a pointer to a new string which is a
+/// duplicate of the input string \a s. Memory for the new string is obtained
+/// with malloc(), and can be freed with free().
+///
+/// \returns The strdup() function returns a pointer to the duplicated string,
+/// or NULL (0) if insufficient memory was available.
+
+char *
+strdup(const char* s)
+{
+ char* dup;
+
+ dup = (char*)malloc(strlen(s) + 1);
+ if (dup != 0) {
+ strcpy(dup, s);
+ }
+ return dup;
+}
diff --git a/src/lib/string_stream.c b/src/lib/ppc405lib/string_stream.c
index f3b1889..1dfc439 100755..100644
--- a/src/lib/string_stream.c
+++ b/src/lib/ppc405lib/string_stream.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/string_stream.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: string_stream.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string_stream.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/string_stream.h b/src/lib/ppc405lib/string_stream.h
index 939489c..07891f5 100755..100644
--- a/src/lib/string_stream.h
+++ b/src/lib/ppc405lib/string_stream.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/string_stream.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __STRING_STREAM_H__
#define __STRING_STREAM_H__
diff --git a/src/lib/strtox.c b/src/lib/ppc405lib/strtox.c
index d901158..56493fa 100755..100644
--- a/src/lib/strtox.c
+++ b/src/lib/ppc405lib/strtox.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strtox.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: strtox.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strtox.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/strtox.h b/src/lib/ppc405lib/strtox.h
index b005ca9..db2cef2 100755..100644
--- a/src/lib/strtox.h
+++ b/src/lib/ppc405lib/strtox.h
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strtox.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
#ifndef __STRTOX_H__
#define __STRTOX_H__
diff --git a/src/lib/ppc405lib/sxlock.c b/src/lib/ppc405lib/sxlock.c
new file mode 100644
index 0000000..35f9698
--- /dev/null
+++ b/src/lib/ppc405lib/sxlock.c
@@ -0,0 +1,494 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/sxlock.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file sxlock.c
+/// \brief API for the SharedExclusiveLock
+///
+/// The APIs in this file implement a shared-exclusive lock for SSX
+/// applications. This type of lock is also called a readers-writer lock. The
+/// lock is implemented in terms of SSX semaphores, so its use is limited to
+/// threads willing to block for access to a resource.
+///
+/// The SharedExclusiveLock allows multiple threads shared access to a
+/// resource, while limiting exclusive access to a single thread. There are
+/// several ways that this type of lock might be specified. The specification
+/// implemented here is an "exclusive-biasing" lock. As long as the lock is
+/// held or requested in exclusive mode, all new shared-mode requests will
+/// block, and only exclusive accesses will be allowed. If multiple threads
+/// are blocked exclusive the requests are honored in priority order (as
+/// the underlying implementation is an SSX semaphore). Once the exclusive
+/// lock is cleared, any/all threads blocked for shared access are released
+/// simultaneously (using an SSX semaphore as a thread barrier).
+///
+/// The lock is created (initialized) by sxlock_create(), which allows
+/// specification of an initial value of the number of shared or exclusive
+/// accesses outstanding. The lock/unlock APIs are as follows:
+///
+/// - sxlock_lock_shared(SharedExclusiveLock* sxlock, SsxInterval timeout)
+/// - sxlock_unlock_shared(SharedExclusiveLock* sxlock)
+/// - sxlock_lock_exclusive(SharedExclusiveLock* sxlock, SsxInterval timeout)
+/// - sxlock_unlock_exclusive(SharedExclusiveLock* sxlock)
+///
+/// Threads must always issue *_lock() and *_unlock() requests in matched
+/// pairs in order to avoid errors and deadlock. The *_lock() APIs allow
+/// specification of a timeout, which may be SSX_WAIT_FOREVER to indicate no
+/// timeout. The *_lock() APIs will return the code -SXLOCK_TIMED_OUT if the
+/// timeout occurs before the thread acquires the resource. If called from an
+/// interrupt context then the only legal timeout specification is
+/// SSX_NO_WAIT (0).
+///
+/// If a *_lock() request times out then the thread \e has \e not acquired the
+/// resource and \e must \e not call *_unlock(). As with semaphores there is
+/// no record that a thread holds a lock, so if a thread completes or is
+/// deleted while holding a lock it is likely that the application will
+/// deadlock.
+
+#include "ssx.h"
+#include "sxlock.h"
+
+/// Create (initialize) a SharedExclusiveLock
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to
+/// initialize
+///
+/// \param shared The initial numbers of shared accesses
+///
+/// \param exclusive The initial numbers of exclusive accesses
+///
+/// Create (initialize) a SharedExclusiveLock and optionally specify an
+/// initial state. The initial number of shared or exclusive accesses can be
+/// specified, however at most one of \a nshared and \a exclusive can be
+/// non-0. If \a shared or \a exclusive are non-0 then eventually a
+/// thread(s) will need to issue unmatched *_unlock() call(s) to allow
+/// progress for other threads requiring the resource.
+///
+/// \retval 0 Success
+///
+/// \retval SXLOCK_INVALID_OBJECT The \a sxlock parameter is NULL (0) or
+/// otherwise invalid.
+///
+/// \retval SXLOCK_INVALID_ARGUMENT Both of the \a shared and \a exclusive
+/// parameters are non-0.
+///
+/// \retval others sxlock_create() may also return codes from
+/// ssx_semaphore_create(), which would indicate a serious bug.
+
+int
+sxlock_create(SharedExclusiveLock* sxlock,
+ SsxSemaphoreCount shared,
+ SsxSemaphoreCount exclusive)
+{
+ int rc;
+
+ rc = 0;
+ do {
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sxlock == 0,
+ SXLOCK_INVALID_OBJECT);
+ SSX_ERROR_IF((shared != 0) && (exclusive != 0),
+ SXLOCK_INVALID_ARGUMENT);
+ }
+
+ rc = ssx_semaphore_create(&(sxlock->shared_sem), 0, 0);
+ if (rc) break;
+
+ rc = ssx_semaphore_create(&(sxlock->exclusive_sem), 0, 0);
+ if (rc) break;
+
+ sxlock->running_shared = shared;
+ sxlock->running_exclusive = exclusive;
+
+ } while (0);
+
+ return rc;
+}
+
+
+/// Lock a SharedExclusiveLock for shared access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to lock
+///
+/// \param timeout The maximum amount of time to wait for access, or the
+/// constant SSX_WAIT_FOREVER to wait forever.
+///
+/// Acquire a SharedExclusiveLock for shared access, potentially blocking
+/// forever or until a specified timeout if access is not immediately
+/// granted. Access will be blocked as long as one or more threads request or
+/// control exclusive acesss to the resource. Once the access is granted, the
+/// thread maintains shared access to the resource until a subsequent call of
+/// sxlock_unlock_shared().
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SXLOCK_TIMED_OUT Shared access was not acquired before the
+/// timeout expired.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_SEMAPHORE_PEND_WOULD_BLOCK The call was made from an
+/// interrupt context (or before threads have been started), shared access was
+/// not immediately available and a non-zero timeout was specified.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which should be considered as non-recoverable errors.
+
+
+int
+sxlock_lock_shared(SharedExclusiveLock* sxlock, SsxInterval timeout)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ rc = 0;
+ do {
+
+ // NB: This is the only way to correctly compute the number of threads
+ // pending exclusive, given that threads could be removed from the
+ // exclusive_sem by timeout.
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if ((sxlock->running_exclusive == 0) && (pending_exclusive == 0)) {
+
+ // If no other thread has or is requesting exclusive access, the
+ // current thread gets immediate access.
+
+ sxlock->running_shared++;
+
+ } else {
+
+ // If threads are running or pending exclusive, this thread must
+ // pend shared. The thread will be unblocked by an exclusive
+ // unlock, which is responsible for adjusting
+ // sxlock->running_shared in this case.
+
+ rc = ssx_semaphore_pend(&(sxlock->shared_sem), timeout);
+ if (rc == -SSX_SEMAPHORE_PEND_TIMED_OUT) {
+ rc = -SXLOCK_TIMED_OUT;
+ }
+ }
+
+ } while (0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Relase a SharedExclusiveLock from shared access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to unlock
+///
+/// Release a SharedExclusiveLock from shared access, signalling that the
+/// thread no longer requires or expects shared access to the resource. It is
+/// an error for a thread to use this API if it has not previously locked
+/// shared access by a call of sxlock_pend_shared() (or the thread is
+/// unlocking a lock initialized in the shared-locked state).
+///
+/// Return values other than SSX_OK (0) are errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SXLOCK_SHARED_UNDERFLOW There was apparently no matched call of
+/// sxlock_lock_shared() prior to this call.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which should be considered as non-recoverable errors.
+
+int
+sxlock_unlock_shared(SharedExclusiveLock* sxlock)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ SSX_ERROR_IF(sxlock->running_shared == 0, SXLOCK_SHARED_UNDERFLOW);
+ }
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ SSX_PANIC_IF(sxlock->running_exclusive != 0,
+ SXLOCK_SHARED_EXCLUSIVE_INVARIANT);
+ }
+
+ rc = 0;
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ do {
+
+ // If this is the last shared thread running, and a thread wants
+ // exclusive access, grant it. Note that there may be shared requests
+ // pending on the shared_sem but we always give preference to
+ // exclusive requests.
+
+ sxlock->running_shared--;
+ if (sxlock->running_shared == 0) {
+
+ // Wake any single thread pending exclusive
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if (pending_exclusive != 0) {
+
+ sxlock->running_exclusive = 1;
+ rc = ssx_semaphore_post(&(sxlock->exclusive_sem));
+ if (rc) break;
+ }
+ }
+
+ } while(0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Lock a SharedExclusiveLock for exclusive access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to lock
+///
+/// \param timeout The maximum amount of time to wait for access, or the
+/// constant SSX_WAIT_FOREVER to wait forever.
+///
+/// Acquire a SharedExclusiveLock for exclusive access, potentially blocking
+/// forever or until a specified timeout if access is not immediately
+/// granted. Access will be blocked as long as one or more threads control
+/// shared acesss to the resource, however once the thread requests exclusive
+/// access all new shared access requests will block. Once the access is
+/// granted, the thread maintains exclusive access to the resource until a
+/// subsequent call of sxlock_unlock_exclusive().
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SXLOCK_TIMED_OUT Exclusive access was not acquired before the
+/// timeout expired.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_SEMAPHORE_PEND_WOULD_BLOCK The call was made from an
+/// interrupt context (or before threads have been started), exclusive access
+/// was not immediately available and a non-zero timeout was specified.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which shoudl be considered as non-recoverable errors.
+
+
+int
+sxlock_lock_exclusive(SharedExclusiveLock* sxlock, SsxInterval timeout)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive, pending_shared;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ rc = 0;
+ do {
+
+ if ((sxlock->running_shared == 0) &&
+ (sxlock->running_exclusive == 0)) {
+
+ // If no other thread has acquired the lock, this thread gets
+ // immediate access.
+
+ sxlock->running_exclusive = 1;
+
+ } else {
+
+ // Some other thread has acquired the lock. This thread must pend
+ // exclusive. In this case the sxlock->running_exclusive must be
+ // set by the *_unlock() operation that unblocks the thread.
+
+ rc = ssx_semaphore_pend(&(sxlock->exclusive_sem), timeout);
+ if (rc == -SSX_SEMAPHORE_PEND_TIMED_OUT) {
+
+ // This exclusive request timed out. Since the request may
+ // have blocked shared requests, then if this is the only
+ // exclusive request or thread we need to unblock any pending
+ // shared requests.
+
+ if (sxlock->running_exclusive == 0) {
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if (pending_exclusive == 0) {
+
+ rc = ssx_semaphore_info_get(&(sxlock->shared_sem),
+ 0, &pending_shared);
+ if (rc) break;
+
+ if (pending_shared != 0) {
+
+ sxlock->running_shared += pending_shared;
+ rc = ssx_semaphore_release_all(&(sxlock->shared_sem));
+ if (rc) break;
+ }
+ }
+ }
+
+ rc = -SXLOCK_TIMED_OUT;
+ }
+ }
+
+ } while (0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Release a SharedExclusiveLock from exclusive access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to unlock
+///
+/// Release a SharedExclusiveLock from exclusive access, signalling that the
+/// thread no longer requires or expects exclusive access to the resource. It
+/// is an error for a thread to use this API if it has not previously locked
+/// exclusive access by a call of sxlock_lock_exclusive() (or the thread is
+/// unlocking a lock initialized in the exclusive-locked state).
+///
+/// Return values other than SSX_OK (0) are errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SXLOCK_EXCLUSIVE_UNDERFLOW There was apparently no matched call of
+/// sxlock_lock_exclusive() prior to this call.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which should be considered as non-recoverable errors.
+
+int
+sxlock_unlock_exclusive(SharedExclusiveLock* sxlock)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive, pending_shared;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ SSX_ERROR_IF(sxlock->running_exclusive != 1, SXLOCK_SHARED_UNDERFLOW);
+ }
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ SSX_PANIC_IF(sxlock->running_shared != 0,
+ SXLOCK_SHARED_EXCLUSIVE_INVARIANT);
+ }
+
+ rc = 0;
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ do {
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if (pending_exclusive != 0) {
+
+ // If there are other threads pending exclusive, make the
+ // highest-priority one of them
+ // runnable. sxlock->running_exclusive remains equal to 1.
+
+ rc = ssx_semaphore_post(&(sxlock->exclusive_sem));
+ if (rc) break;
+
+ } else {
+
+ // Otherwise unblock any/all threads pending shared
+
+ sxlock->running_exclusive = 0;
+
+ rc = ssx_semaphore_info_get(&(sxlock->shared_sem),
+ 0, &pending_shared);
+ if (rc) break;
+
+ if (pending_shared != 0) {
+
+ sxlock->running_shared = pending_shared;
+ rc = ssx_semaphore_release_all(&(sxlock->shared_sem));
+ if (rc) break;
+ }
+ }
+ } while (0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
diff --git a/src/lib/ppc405lib/sxlock.h b/src/lib/ppc405lib/sxlock.h
new file mode 100644
index 0000000..e0fa196
--- /dev/null
+++ b/src/lib/ppc405lib/sxlock.h
@@ -0,0 +1,108 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/sxlock.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SXLOCK_H__
+#define __SXLOCK_H__
+
+// $Id$
+
+/// \file sxlock.h
+/// \brief The implementation of a SharedExclusiveLock
+///
+/// The SharedExclusiveLock is documented in the comments for the file
+/// sxlock.c
+
+// Error/panic codes
+
+#define SXLOCK_INVALID_OBJECT 0x00795501
+#define SXLOCK_INVALID_ARGUMENT 0x00795502
+#define SXLOCK_TIMED_OUT 0x00795503
+#define SXLOCK_SHARED_UNDERFLOW 0x00795504
+#define SXLOCK_EXCLUSIVE_UNDERFLOW 0x00795505
+#define SXLOCK_SHARED_EXCLUSIVE_INVARIANT 0x00795506
+
+/// A shared-exclusive lock object (also called a readers-write lock)
+///
+/// This facility is documented in the file sxlock.c
+
+typedef struct {
+
+ /// A semaphore for threads requesting shared access
+ SsxSemaphore shared_sem;
+
+ /// A semaphore for threads requesting exclusive access
+ SsxSemaphore exclusive_sem;
+
+ /// The number of threads running shared
+ SsxSemaphoreCount running_shared;
+
+ /// The number of threads running exclusive
+ SsxSemaphoreCount running_exclusive;
+
+} SharedExclusiveLock;
+
+
+/// Static initialization of a shared-exclusive lock object
+///
+/// \param[in] shared The number of threads running shared at static
+/// initialization
+///
+/// \param[in] exclusive The number of threads running exclusive at static
+/// initialization.
+///
+/// Note that it is an error to specify both \a shared and \a exclusive as
+/// non-0.
+
+#define SXLOCK_INITIALIZATION(shared, exclusive) \
+ { \
+ SSX_SEMAPHORE_INITIALIZATION(0, 0), \
+ SSX_SEMAPHORE_INITIALIZATION(0, 0), \
+ (shared), (exclusive) \
+ }
+
+/// Declare and initialize a shared-exclusive lock
+
+#define SXLOCK(sxlock, shared, exclusive) \
+ SharedExclusiveLock sxlock = SXLOCK_INITIALIZATION(shared, exclusive)
+
+
+
+int
+sxlock_create(SharedExclusiveLock* sxlock,
+ SsxSemaphoreCount shared,
+ SsxSemaphoreCount exclusive);
+
+int
+sxlock_lock_shared(SharedExclusiveLock* sxlock, SsxInterval timeout);
+
+int
+sxlock_unlock_shared(SharedExclusiveLock* sxlock);
+
+int
+sxlock_lock_exclusive(SharedExclusiveLock* sxlock, SsxInterval timeout);
+
+int
+sxlock_unlock_exclusive(SharedExclusiveLock* sxlock);
+
+#endif // __SXLOCK_H__
diff --git a/src/lib/time.c b/src/lib/ppc405lib/time.c
index bc1f2e7..39d005c 100755..100644
--- a/src/lib/time.c
+++ b/src/lib/ppc405lib/time.c
@@ -1,3 +1,27 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/time.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// $Id: time.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/time.c,v $
//-----------------------------------------------------------------------------
diff --git a/src/lib/pstates.c b/src/lib/pstates.c
deleted file mode 100755
index 958b9e1..0000000
--- a/src/lib/pstates.c
+++ /dev/null
@@ -1,410 +0,0 @@
-// $Id: pstates.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pstates.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file pstates.c
-/// \brief Pstate routines required by OCC product firmware
-
-#include "ssx.h"
-#include "pgp_common.h"
-#include "pstates.h"
-
-/// Validate a VRM11 VID code
-///
-/// \param vid A VRM11 VID
-///
-/// \retval 0 The VID is valid
-///
-/// \retval -VID11_UNDERFLOW_VID11_VALIDATE The Vid code is a low 'power off'
-/// VID (0 or 1)
-///
-/// \retval -VID11_OVERFLOW_VID11_VALIDATE The Vid code is a high 'power off'
-/// VID (0xfe or 0xff)
-
-int
-vid11_validate(Vid11 vid)
-{
- int rc;
-
- if (vid < VID11_MIN) {
-
- rc = -VID11_UNDERFLOW_VID11_VALIDATE;
-
- } else if (vid > VID11_MAX) {
-
- rc = -VID11_OVERFLOW_VID11_VALIDATE;
-
- } else {
-
- rc = 0;
-
- }
-
- return rc;
-}
-
-
-/// Bias a Pstate with saturation
-///
-/// \param pstate The initial Pstate to bias
-///
-/// \param bias The signed bias amount
-///
-/// \param biased_pstate The final biased Pstate
-///
-/// This API adds a signed bias to the \a pstate and returns the saturated sum
-/// as \a biased_pstate. Any application that biases Pstates should use this
-/// API rather than simple addition/subtraction.
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -PSTATE_OVERFLOW_BIAS_PS The biased Pstate saturated at PSTATE_MAX.
-///
-/// \retval -PSTATE_UNDERFLOW_BIAS_PS The biased Pstate saturated at PSTATE_MIN.
-
-int
-bias_pstate(Pstate pstate, int bias, Pstate* biased_pstate)
-{
- int rc, int_pstate;
-
- int_pstate = (int)pstate + bias;
- if (int_pstate != (Pstate)int_pstate) {
- if (bias < 0) {
- *biased_pstate = PSTATE_MIN;
- rc = -PSTATE_UNDERFLOW_BIAS_PS;
- } else {
- *biased_pstate = PSTATE_MAX;
- rc = -PSTATE_OVERFLOW_BIAS_PS;
- }
- } else {
- *biased_pstate = int_pstate;
- rc = 0;
- }
-
- return rc;
-}
-
-
-/// Bias a DPLL frequency code with saturation and bounds checking
-///
-/// \param fcode The initial frequency code to bias
-///
-/// \param bias The signed bias amount
-///
-/// \param biased_fcode The final biased frequency code
-///
-/// This API adds a signed bias to the \a fcode and returns the saturated and
-/// bounded sum as \a biased_fcode. Any application that biases frequency
-/// codes should use this API rather than simple addition/subtraction.
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -DPLL_OVERFLOW The biased frequency code saturated at DPLL_MAX.
-///
-/// \retval -DPLL_UNDERFLOW1 The biased frequency code saturated at DPLL_MIN.
-///
-/// \retval -DPLL_UNDERFLOW2 The biased frequency code saturated at DPLL_MIN.
-
-int
-bias_frequency(DpllCode fcode, int bias, DpllCode* biased_fcode)
-{
- int rc;
- unsigned uint_fcode;
-
- uint_fcode = (unsigned)fcode + bias;
- if (uint_fcode != (DpllCode)uint_fcode) {
- if (bias < 0) {
- *biased_fcode = DPLL_MIN;
- rc = -DPLL_UNDERFLOW1;
- } else {
- *biased_fcode = DPLL_MAX;
- rc = -DPLL_OVERFLOW;
- }
- } else if (uint_fcode < DPLL_MIN) {
- *biased_fcode = DPLL_MIN;
- rc = -DPLL_UNDERFLOW2;
- } else {
- *biased_fcode = uint_fcode;
- rc = 0;
- }
-
- return rc;
-}
-
-
-/// Bias a VRM11 VID code with saturation and bounds checking
-///
-/// \param vid The initial vid code to bias
-///
-/// \param bias The signed bias amount
-///
-/// \param biased_vid The final biased VID code
-///
-/// This API adds a signed bias to the \a vid and returns the saturated and
-/// bounded sum as \a biased_vid. Any application that biases VID codes
-/// should use this API rather than simple addition/subtraction.
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -VID11_OVERFLOW_BIAS_VID11 The biased VID code saturated
-/// at VID11_MAX.
-///
-/// \retval -VID11_UNDERFLOW_BIAS_VID11 The biased VID code saturated
-/// at VID11_MIN.
-
-int
-bias_vid11(Vid11 vid, int bias, Vid11* biased_vid)
-{
- int rc;
- unsigned uint_vid;
-
- uint_vid = (unsigned)vid + bias;
- if (uint_vid != (DpllCode)uint_vid) {
- if (bias < 0) {
- *biased_vid = VID11_MIN;
- rc = -VID11_UNDERFLOW_BIAS_VID11;
- } else {
- *biased_vid = VID11_MAX;
- rc = -VID11_OVERFLOW_BIAS_VID11;
- }
- } else {
-
- rc = vid11_validate(uint_vid);
- *biased_vid = uint_vid;
-
- }
-
- return rc;
-}
-
-
-/// Retrieve an entry from the Global Pstate Table abstraction
-///
-/// \param gpst An initialized GlobalPstateTable structure.
-///
-/// \param pstate The Pstate index of the entry to fetch
-///
-/// \param bias This is a signed bias. The entry searched is the \a pstate +
-/// \a bias entry.
-///
-/// \param entry A pointer to a gpst_entry_t to hold the returned data.
-///
-/// This routine functions similar to PMC harwdare. When a Pstate is
-/// requested the index is first biased (under/over-volted) and clipped to the
-/// defined bounds, then the Pstate entry is returned.
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -GPST_PSTATE_CLIPPED_HIGH_GPST_ENTRY The requested Pstate does not
-/// exist in the table. The maximum Pstate entry in the table has been returned.
-///
-/// \retval -GPST_PSTATE_CLIPPED_LOW_GPST_ENTRY The requested Pstate does not
-/// exist in the table. The minimum Pstate entry in the table has been returned.
-///
-/// The following return codes are considered errors:
-///
-/// \retval -GPST_INVALID_OBJECT_GPST_ENTRY The Global Pstate Table is
-/// either null (0) or otherwise invalid.
-
-int
-gpst_entry(const GlobalPstateTable *gpst,
- const Pstate pstate,
- int bias,
- gpst_entry_t *entry)
-{
- int rc, index;
- Pstate biased_pstate;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF(gpst == 0, GPST_INVALID_OBJECT_GPST_ENTRY);
- }
-
- rc = bias_pstate(pstate, bias, &biased_pstate);
-
- if ((rc == -PSTATE_UNDERFLOW_BIAS_PS) || (pstate < gpst_pmin(gpst))) {
-
- rc = -GPST_PSTATE_CLIPPED_LOW_GPST_ENTRY;
- index = 0;
-
- } else if ((rc == -PSTATE_OVERFLOW_BIAS_PS) || (pstate > gpst_pmax(gpst))) {
-
- rc = -GPST_PSTATE_CLIPPED_HIGH_GPST_ENTRY;
- index = gpst->entries - 1;
-
- } else {
-
- rc = 0;
- index = pstate - gpst_pmin(gpst);
-
- }
-
- *entry = gpst->pstate[index];
-
- return rc;
-}
-
-
-/// Translate a Vdd VID code to the closest Pstate in a Global Pstate table.
-///
-/// \param gpst The GlobalPstateTable to search
-///
-/// \param vdd A VID code representing an external VDD voltage
-///
-/// \param pstate The Pstate most closely matching the \a vid.
-///
-/// \param entry The GlobalPstateTable entry of the returned \a pstate.
-///
-/// This routine assumes that Pstate voltages increase monotonically from
-/// lower to higher Pstates. The algorithm operates from lowest to highest
-/// voltage, scanning until the Pstate voltage is >= the VID voltage. Thus
-/// the algorithm effectively rounds up voltage (unless clipped at the highest
-/// Pstate).
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -GPST_PSTATE_CLIPPED_HIGH_GPST_V2P The requested voltage does not
-/// exist in the table. The highest legal Pstate is returned.
-///
-/// \retval -GPST_PSTATE_CLIPPED_LOW_GPST_V2P The requested voltage does not
-/// exist in the table. The lowest legal Pstate in the table is returned.
-///
-/// The following return codes are considered errors:
-///
-/// \retval -VRM_INVALID_VOLTAGE The \a vid is invalid.
-///
-/// \retval -GPST_INVALID_OBJECT_GPST_V2P The \a gpst argument is NULL (0).
-
-// Recall that VID codes _decrease_ as voltage _increases_
-
-int
-gpst_vdd2pstate(const GlobalPstateTable* gpst,
- const Vid11 vdd,
- Pstate* pstate,
- gpst_entry_t* entry)
-{
- size_t i;
- int rc;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF(gpst == 0, GPST_INVALID_OBJECT_GPST_V2P);
- }
-
- do {
- rc =vid11_validate(vdd);
- if (rc) break;
-
- // Search for the Pstate that contains (close to) the requested
- // voltage, then handle special cases.
-
- for (i = 0; i < gpst->entries; i++) {
- if (gpst->pstate[i].fields.evid_vdd <= vdd) {
- break;
- }
- }
-
- if (i == gpst->entries) {
-
- *pstate = gpst_pmax(gpst);
- *entry = gpst->pstate[i - 1];
- rc = -GPST_PSTATE_CLIPPED_HIGH_GPST_V2P;
-
- } else if ((i == 0) && (gpst->pstate[i].fields.evid_vdd < vdd)) {
-
- *pstate = gpst_pmin(gpst);
- *entry = gpst->pstate[0];
- rc = -GPST_PSTATE_CLIPPED_LOW_GPST_V2P;
-
- } else {
-
- rc = bias_pstate(gpst_pmin(gpst), i, pstate);
- if (rc) break;
-
- *entry = gpst->pstate[i];
- }
- } while (0);
- return rc;
-}
-
-
-/// Translate a frequency in KHz to the closest Pstate in a Global Pstate
-/// table.
-///
-/// \param gpst The GlobalPstateTable to search
-///
-/// \param frequency_khz The frequency in KHz
-///
-/// \param pstate The Pstate most closely matching the frequency, rounded down
-/// (towards lower Pstates).
-///
-///
-/// Note that the Pstate returned may or may not be represented in the Pstate
-/// table. This means that it may be higher that the highest legal frequency
-/// or lower than the lowest frequency represented in the Pstate table.
-///
-/// The following return codes are not considered errors:
-///
-/// \retval 0 Success
-///
-/// \retval -PSTATE_OVERFLOW_GPST_F2P The requested frequency translates to an
-/// unrepresentable Pstate. PSTATE_MAX (127) is returned.
-///
-/// \retval -PSTATE_UNDERFLOW_GPST_F2P The requested frequency translates to an
-/// unrepresentable Pstate. PSTATE_MIN (-128) is returned.
-int
-gpst_frequency2pstate(const GlobalPstateTable* gpst,
- const uint32_t frequency_khz,
- Pstate* pstate)
-{
- int rc;
- int32_t intPstate;
-
- // Compute the Pstate and round down
-
- intPstate =
- (int32_t)(frequency_khz - gpst->pstate0_frequency_khz) /
- (int32_t)gpst->frequency_step_khz;
-
- if (intPstate < 0) {
-
- if (((int32_t)(frequency_khz - gpst->pstate0_frequency_khz) %
- (int32_t)gpst->frequency_step_khz) != 0) {
-
- intPstate--;
- }
- }
-
-
- // Clip to legal Pstate type values
-
- if (intPstate < PSTATE_MIN) {
-
- *pstate = PSTATE_MIN;
- rc = -PSTATE_UNDERFLOW_GPST_F2P;
-
- } else if (intPstate > PSTATE_MAX) {
-
- *pstate = PSTATE_MAX;
- rc = -PSTATE_OVERFLOW_GPST_F2P;
-
- } else {
-
- *pstate = intPstate;
- rc = 0;
- }
-
- return rc;
-}
diff --git a/src/lib/pstates.h b/src/lib/pstates.h
deleted file mode 100755
index 2aeb52c..0000000
--- a/src/lib/pstates.h
+++ /dev/null
@@ -1,835 +0,0 @@
-#ifndef __PSTATES_H__
-#define __PSTATES_H__
-
-// $Id: pstates.h,v 1.5 2015/05/18 15:56:07 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pstates.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file pstates.h
-/// \brief Pstate structures and support routines for OCC product firmware
-
-#include "pgp_common.h"
-
-////////////////////////////////////////////////////////////////////////////
-// Global and Local Pstate Tables
-////////////////////////////////////////////////////////////////////////////
-
-/// The Global Pstate Table must be 1KB-aligned in SRAM. The alignment is
-/// specified in the traditional log2 form.
-#define GLOBAL_PSTATE_TABLE_ALIGNMENT 10
-
-/// The Global Pstate table has 128 * 8-byte entries
-#define GLOBAL_PSTATE_TABLE_ENTRIES 128
-
-/// The Local Pstate table has 32 x 64-bit entries
-#define LOCAL_PSTATE_ARRAY_ENTRIES 32
-
-/// The VDS/VIN table has 32 x 64-bit entries
-#define VDSVIN_ARRAY_ENTRIES 64
-
-/// The VRM-11 VID base voltage in micro-Volts
-#define VRM11_BASE_UV 1612500
-
-/// The VRM-11 VID step as an unsigned number (micro-Volts)
-#define VRM11_STEP_UV 6250
-
-/// The iVID base voltage in micro-Volts
-#define IVID_BASE_UV 600000
-
-/// The iVID step as an unsigned number (micro-Volts)
-#define IVID_STEP_UV 6250
-
-/// CPM Inflection Points
-#define CPM_RANGES 8
-
-/// VPD #V Operating Points
-#define VPD_PV_POINTS 4
-#define VPD_PV_ORDER_STR {"PowerSave", "Nominal ", "Turbo ", "UltraTurbo"}
-#define POWERSAVE 0
-#define NOMINAL 1
-#define TURBO 2
-#define ULTRA 3
-
-/// IDDQ readings
-#define CORE_IDDQ_MEASUREMENTS 6
-#define CHIP_IDDQ_MEASUREMENTS 1
-
-#define CORE_IDDQ_ARRAY_VOLTAGES {0.80, 0.90, 1.00, 1.10, 1.20, 1.25}
-#define CHIP_IDDQ_ARRAY_VOLTAGES {1.10}
-
-/// Iddq LRPx and CRPx elements
-#define LRP_IDDQ_RECORDS CORE_IDDQ_MEASUREMENTS
-#define CRP_IDDQ_RECORDS CHIP_IDDQ_MEASUREMENTS
-#define IDDQ_READINGS_PER_IQ 2
-
-/// LRPx mapping to Core measurements 1 2 3 4 5 6
-/// Index 0 1 2 3 4 5
-#define CORE_IDDQ_MEASUREMENTS_ORDER { 1, 2, 3, 4, 5, 0}
-#define CORE_IDDQ_MEASUREMENT_VOLTAGES {"0.90", "1.00", "1.10", "1.20", "1.25", "0.80"}
-#define CORE_IDDQ_VALIDITY_CHECK { 1, 1, 1, 1, 1, 0}
-#define CORE_IDDQ_VALID_SECOND { 1, 1, 1, 1, 1, 0}
-
-// CRPx mapping to Chip measurements 0
-#define CHIP_IDDQ_MEASUREMENTS_ORDER { 0 }
-#define CHIP_IDDQ_MEASUREMENT_VOLTAGES {"1.10"}
-#define CHIP_IDDQ_VALID_SECOND { 0 }
-
-/// WOF Items
-#define NUM_ACTIVE_CORES 12
-#define MAX_UT_PSTATES 64 // Oversized
-
-// Error/Panic codes for support routines
-
-#define VRM11_INVALID_VOLTAGE 0x00876101
-
-#define PSTATE_OVERFLOW_BIAS_PS 0x00778a01
-#define PSTATE_UNDERFLOW_BIAS_PS 0x00778a02
-#define PSTATE_OVERFLOW_GPST_F2P 0x00778a03
-#define PSTATE_UNDERFLOW_GPST_F2P 0x00778a04
-
-#define PSTATE_LT_PSTATE_MIN 0x00778a05
-#define PSTATE_GT_PSTATE_MAX 0x00778a06
-
-#define DPLL_OVERFLOW 0x00d75501
-#define DPLL_UNDERFLOW1 0x00d75502
-#define DPLL_UNDERFLOW2 0x00d75503
-
-#define VID11_OVERFLOW_VID11_VALIDATE 0x00843101
-#define VID11_OVERFLOW_BIAS_VID11 0x00843102
-#define VID11_UNDERFLOW_VID11_VALIDATE 0x00843103
-#define VID11_UNDERFLOW_BIAS_VID11 0x00843104
-
-#define GPST_INVALID_OBJECT_GPST_ENTRY 0x00477801
-#define GPST_INVALID_OBJECT_GPST_V2P 0x00477802
-#define GPST_INVALID_ARGUMENT 0x00477803
-#define GPST_INVALID_ENTRY 0x00477804
-#define GPST_PSTATE_CLIPPED_HIGH_GPSM_BGA 0x00477805
-#define GPST_PSTATE_CLIPPED_LOW_GPSM_BGA 0x00477806
-#define GPST_PSTATE_CLIPPED_HIGH_GPST_ENTRY 0x00477807
-#define GPST_PSTATE_CLIPPED_LOW_GPST_ENTRY 0x00477808
-#define GPST_PSTATE_CLIPPED_HIGH_GPST_V2P 0x00477809
-#define GPST_PSTATE_CLIPPED_LOW_GPST_V2P 0x0047780a
-#define GPST_BUG 0x0047780b
-#define GPST_PSTATE_GT_GPST_PMAX 0x0047780c
-
-#define LPST_INVALID_OBJECT 0x00477901
-#define LPST_GPST_WARNING 0x00477902
-#define LPST_INCR_CLIP_ERROR 0x00477903
-
-/// PstateSuperStructure Magic Number
-///
-/// This magic number identifies a particular version of the
-/// PstateSuperStructure and its substructures. The version number should be
-/// kept up to date as changes are made to the layout or contents of the
-/// structure.
-
-#define PSTATE_SUPERSTRUCTURE_MAGIC 0x5053544154453034ull /* PSTATE04 */
-#define PSTATE_SUPERSTRUCTURE_GOOD1 0x5053544154453031ull /* PSTATE01 */
-#define PSTATE_SUPERSTRUCTURE_GOOD2 0x5053544154453032ull /* PSTATE02 */
-#define PSTATE_SUPERSTRUCTURE_GOOD3 0x5053544154453033ull /* PSTATE03 */
-#define PSTATE_SUPERSTRUCTURE_GOOD4 0x5053544154453034ull /* PSTATE03 */
-
-
-/// \defgroup pstate_options Pstate Options
-///
-/// These are flag bits for the \a options field of the PstateOptions
-/// structure.
-///
-/// @{
-
-/// gpsm_gpst_install() - Bypass copying the Pstate table from the
-/// PstateSuperStructure into the aligned global location.
-#define PSTATE_NO_COPY_GPST 0x01
-
-/// gpsm_gpst_install() - Bypass Global Pstate Table installation and setup.
-#define PSTATE_NO_INSTALL_GPST 0x02
-
-/// gpsm_lpsa_install() - Bylass Local Pstate Array installation and setup
-#define PSTATE_NO_INSTALL_LPSA 0x04
-
-/// gpsm_resclk_install - Bypass resonant clocking Pstate limit setup
-#define PSTATE_NO_INSTALL_RESCLK 0x08
-
-/// gpsm_enable_pstates() - Force the system to the minimum Pstate at
-/// initialization
-///
-/// This mode is added as a workaround for the case that the SPIVID interface
-/// is not working correctly during initial bringup. This forces Pstate mode
-/// to come up at a low frequency.
-#define PSTATE_FORCE_INITIAL_PMIN 0x10
-
-/// Flag to indicated that the 0.8V readings in the IDDQ Table are valid
-#define PSTATE_IDDQ_0P80V_VALID 0x20
-#define PSTATE_IDDQ_0P80V_INVALID ~PSTATE_IDDQ_0P80V_VALID
-
-/// @}
-
-#ifndef __ASSEMBLER__
-
-#include <stdint.h>
-
-/// A Global Pstate Table Entry, in the form of a packed 'firmware register'
-///
-/// Global Pstate table entries are referenced by OCC firmware, for example
-/// in procedures that do 'manual' Pstate manipulation.
-
-typedef union gpst_entry {
-
- uint64_t value;
- struct {
-#ifdef _BIG_ENDIAN
- uint32_t high_order;
- uint32_t low_order;
-#else
- uint32_t low_order;
- uint32_t high_order;
-#endif // _BIG_ENDIAN
- } words;
- struct {
-#ifdef _BIG_ENDIAN
- uint64_t evid_vdd : 8;
- uint64_t evid_vcs : 8;
- uint64_t reserved16 : 1;
- uint64_t evid_vdd_eff : 7;
- uint64_t reserved24 : 1;
- uint64_t evid_vcs_eff : 7;
- uint64_t reserved32 : 1;
- uint64_t maxreg_vdd : 7;
- uint64_t reserved40 : 1;
- uint64_t maxreg_vcs : 7;
- uint64_t reserved48 : 8;
- uint64_t ecc : 8;
-#else
- uint64_t ecc : 8;
- uint64_t reserved48 : 8;
- uint64_t maxreg_vcs : 7;
- uint64_t reserved40 : 1;
- uint64_t maxreg_vdd : 7;
- uint64_t reserved32 : 1;
- uint64_t evid_vcs_eff : 7;
- uint64_t reserved24 : 1;
- uint64_t evid_vdd_eff : 7;
- uint64_t reserved16 : 1;
- uint64_t evid_vcs : 8;
- uint64_t evid_vdd : 8;
-#endif // _BIG_ENDIAN
- } fields;
-
-} gpst_entry_t;
-
-
-/// A Local Pstate Table Entry, in the form of a packed 'firmware register'
-///
-/// This structure is provided for reference only; Currently the OCC firmware
-/// does not manupulate Local Pstate table entries, however it is possible
-/// that future lab applications will require this.
-
-typedef union lpst_entry {
-
- uint64_t value;
- struct {
-#ifdef _BIG_ENDIAN
- uint32_t high_order;
- uint32_t low_order;
-#else
- uint32_t low_order;
- uint32_t high_order;
-#endif // _BIG_ENDIAN
- } words;
- struct {
-#ifdef _BIG_ENDIAN
- uint64_t ivid_vdd : 7;
- uint64_t ivid_vcs : 7;
- uint64_t vdd_core_pwrratio : 6;
- uint64_t vcs_core_pwrratio : 6;
- uint64_t vdd_eco_pwrratio : 6;
- uint64_t vcs_eco_pwrratio : 6;
- uint64_t ps1_vid_incr : 3;
- uint64_t ps2_vid_incr : 3;
- uint64_t ps3_vid_incr : 3;
- uint64_t reserved47 : 7;
- uint64_t inc_step : 3;
- uint64_t dec_step : 3;
- uint64_t reserved60 : 4;
-#else
- uint64_t reserved60 : 4;
- uint64_t dec_step : 3;
- uint64_t inc_step : 3;
- uint64_t reserved47 : 7;
- uint64_t ps3_vid_incr : 3;
- uint64_t ps2_vid_incr : 3;
- uint64_t ps1_vid_incr : 3;
- uint64_t vcs_eco_pwrratio : 6;
- uint64_t vdd_eco_pwrratio : 6;
- uint64_t vcs_core_pwrratio : 6;
- uint64_t vdd_core_pwrratio : 6;
- uint64_t ivid_vcs : 7;
- uint64_t ivid_vdd : 7;
-#endif // _BIG_ENDIAN
- } fields;
-
-} lpst_entry_t;
-
-
-/// A VDS/VIN table Entry
-
-typedef union vdsvin_entry {
- uint64_t value;
- struct {
-#ifdef _BIG_ENDIAN
- uint32_t high_order;
- uint32_t low_order;
-#else
- uint32_t low_order;
- uint32_t high_order;
-#endif // _BIG_ENDIAN
- } words;
- struct {
-#ifdef _BIG_ENDIAN
- uint64_t ivid0 : 7;
- uint64_t ivid1 : 7;
- uint64_t reserved14 : 2;
- uint64_t pfet0 : 5;
- uint64_t pfet1 : 5;
- uint64_t pfet2 : 5;
- uint64_t pfet3 : 5;
- uint64_t pfet4 : 5;
- uint64_t pfet5 : 5;
- uint64_t pfet6 : 5;
- uint64_t pfet7 : 5;
- uint64_t reserved_56 : 8;
-#else
- uint64_t reserved_56 : 8;
- uint64_t pfet7 : 5;
- uint64_t pfet6 : 5;
- uint64_t pfet5 : 5;
- uint64_t pfet4 : 5;
- uint64_t pfet3 : 5;
- uint64_t pfet2 : 5;
- uint64_t pfet1 : 5;
- uint64_t pfet0 : 5;
- uint64_t reserved14 : 2;
- uint64_t ivid1 : 7;
- uint64_t ivid0 : 7;
-#endif // _BIG_ENDIAN
- } fields;
-} vdsvin_entry_t;
-
-/// Standard options controlling Pstate setup and GPSM procedures
-
-typedef struct {
-
- /// Option flags; See \ref pstate_options
- uint32_t options;
-
- /// Pad structure to 8 bytes. Could also be used for other options later.
- uint32_t pad;
-
-} PstateOptions;
-
-
-/// An abstract Global Pstate table
-///
-/// The GlobalPstateTable is an abstraction of a set of voltage/frequency
-/// operating points along with hardware limits. Besides the hardware global
-/// Pstate table, the abstract table contains enough extra information to make
-/// it the self-contained source for setting up and managing voltage and
-/// frequency in either Hardware or Firmware Pstate mode.
-///
-/// When installed in PMC, Global Pstate table indices are adjusted such that
-/// the defined Pstates begin with table entry 0. The table need not be full -
-/// the \a pmin and \a entries fields define the minimum and maximum Pstates
-/// represented in the table. However at least 1 entry must be defined to
-/// create a legal table.
-///
-/// Note that Global Pstate table structures to be mapped into PMC hardware
-/// must be 1KB-aligned. This requirement is fullfilled by ensuring that
-/// instances of this structure are 1KB-aligned.
-
-typedef struct {
-
- /// The Pstate table
- gpst_entry_t pstate[GLOBAL_PSTATE_TABLE_ENTRIES];
-
- /// Pstate options
- ///
- /// The options are included as part of the GlobalPstateTable so that they
- /// are available to all procedures after gpsm_initialize().
- PstateOptions options;
-
- /// The frequency associated with Pstate[0] in KHz
- uint32_t pstate0_frequency_khz;
-
- /// The frequency step in KHz
- uint32_t frequency_step_khz;
-
- /// The DPLL frequency code corresponding to Pstate 0
- ///
- /// This frequency code is installed in the PCB Slave as the DPLL Fnom
- /// when the Pstate table is activated. Normally this frequency code is
- /// computed as
- ///
- /// pstate0_frequency_khz / frequency_step_khz
- ///
- /// however it may be replaced by any other code as a way to
- /// transparently bias frequency on a per-core basis.
- DpllCode pstate0_frequency_code[PGP_NCORES];
-
- /// The DPLL Fmax bias
- ///
- /// This bias value (default 0, range -8 to +7 frequency ticks) is
- /// installed when the Pstate table is installed. The value is allowed to
- /// vary per core. This bias value will usually be set to a small
- /// positive number to provide a small amount of frequency headroom for
- /// the CPM-DPLL voltage control algorithm.
- ///
- /// \bug Hardware currently specifies this field as unsigned for the
- /// computation of frequency stability in
- /// dpll_freqout_mode_en. (HW217404). This issue will be fixed in
- /// Venice. Since we never plan to use this mode no workaround or
- /// mitigation is provided by GPSM procedures.
-
- int8_t dpll_fmax_bias[PGP_NCORES];
-
- /// The number of entries defined in the table.
- uint8_t entries;
-
- /// The minimum Pstate in the table
- ///
- /// Note that gpsi_min = pmin - PSTATE_MIN, gpsi_max = pmin + entries - 1.
- Pstate pmin;
-
- /// The "Safe" Global Pstate
- ///
- /// This Pstate is installed in the PMC and represents the safe-mode
- /// voltage.
- Pstate pvsafe;
-
- /// The "Safe" Local Pstate
- ///
- /// This Pstate is installed in the PCB Slaves and represents the
- /// safe-mode frequency.
- Pstate psafe;
-
- /// Step size of Global Pstate steps
- uint8_t pstate_stepsize;
-
- /// The exponent of the exponential encoding of Pstate stepping delay
- uint8_t vrm_stepdelay_range;
-
- /// The significand of the exponential encoding of Pstate stepping delay
- uint8_t vrm_stepdelay_value;
-
- /// The Pstate for minimum core frequency in the system, defined by MRW
- uint8_t pfloor;
-
- /// The Pstate representing the Turbo VPD point
- Pstate turbo_ps;
-
- /// The Pstate representing the Nominal VPD point
- Pstate nominal_ps;
-
- /// The Pstate representing the PowerSave VPD point
- Pstate powersave_ps;
-
- /// The Pstate within the GPST which is the maximum for which iVRMs are
- /// defined. This allows WOF Pstate and iVRM Pstates to be non-overlapping
- /// to simplify characterization.
- Pstate ivrm_max_ps;
-
- /// The number of entries over which iVRM enablement is possible. The
- /// starting entry is PMin.
- uint8_t ivrm_entries;
-
-} GlobalPstateTable;
-
-
-/// This macro creates a properly-aligned Global Pstate table structure as a
-/// static initialization.
-
-#define GLOBAL_PSTATE_TABLE(x) \
- GlobalPstateTable x \
- ALIGNED_ATTRIBUTE(POW2_32(GLOBAL_PSTATE_TABLE_ALIGNMENT)) \
- SECTION_ATTRIBUTE(".noncacheable") \
- = {.entries = 0}
-
-
-/// An opaque Local Pstate Array
-///
-/// An array local to each core contains the Local Pstate Table, Vds table and
-/// Vin table. The array contents are presented to OCC firmware as an opaque
-/// set of 96 x 64-bit entries which are simply installed verbatim into each
-/// core. Every core stores the same table.
-///
-/// When installed in the core, Local Pstate table indices are adjusted such
-/// that the defined Pstates begin with table entry 0. The table need not be
-/// full - the \a pmin and \a entries fields define the minimum and maximum
-/// Pstates represented in the table. However at least 1 entry must be
-/// defined to create a legal table.
-
-typedef struct {
-
- /// The vdsvin table contents
- vdsvin_entry_t vdsvin[VDSVIN_ARRAY_ENTRIES];
-
- /// The local pstate table contents
- lpst_entry_t pstate[LOCAL_PSTATE_ARRAY_ENTRIES];
-
- /// The number of entries defined in the Local Pstate Table
- uint8_t entries;
-
- /// The minimum Pstate in the Local Pstate table
- ///
- /// Note that lpsi_min = pmin - PSTATE_MIN, lpsi_max = pmin + entries - 1.
- Pstate pmin;
-
- /// Pstate step delay for rising iVRM voltages
- uint8_t stepdelay_rising;
-
- /// Pstate step delay for falling iVRM voltages
- uint8_t stepdelay_lowering;
-
- /// Pad structure to 8-byte alignment
- uint8_t pad[4];
-
-} LocalPstateArray;
-
-
-/// Resonant Clocking setup parameters
-///
-/// All Pstate parameters are specified in terms of Pstates as defined in the
-/// current PstateSuperStructure.
-
-typedef struct {
-
- /// Full Clock Sector Buffer Pstate
- Pstate full_csb_ps;
-
- /// Low-Frequency Resonant Lower Pstate
- Pstate res_low_lower_ps;
-
- /// Low-Frequency Resonant Upper Pstate
- Pstate res_low_upper_ps;
-
- /// High-Frequency Resonant Lower Pstate
- Pstate res_high_lower_ps;
-
- /// High-Frequency Resonant Upper Pstate
- Pstate res_high_upper_ps;
-
- /// Pad structure to 8-byte alignment
- uint8_t pad[3];
-
-} ResonantClockingSetup;
-
-/// CPM Pstate ranges per mode
-///
-/// These Pstate range specifications apply to all chiplets operating in the
-/// same mode.
-
-typedef union {
-
- /// Forces alignment
- uint64_t quad[2];
-
- struct {
-
- /// Lower limit of each CPM calibration range
- ///
- /// The entries in this table are Pstates representing the
- /// lowest-numbered (lowest-voltage) Pstate of each range. This is the
- /// inflection point between range N and range N+1.
- Pstate inflectionPoint[CPM_RANGES];
-
- /// The number of ranges valid in the \a inflectionPoint table
- ///
- /// Validity here is defined by the original characterization
- /// data. Whether or not OCC will use any particular range is managed
- /// by OCC.
- uint8_t validRanges;
-
- /// The Pstate corresponding to the upper limit of range 0.
- ///
- /// This is the "CPmax" for the mode. The "CPmin" for this
- /// mode is the value of inflectionPoint[valid_ranges - 1].
- Pstate pMax;
-
- uint8_t pad[6];
- };
-
-} CpmPstateModeRanges;
-
-
-/// A VPD operating point
-///
-/// VPD operating points are stored without load-line correction. Frequencies
-/// are in MHz, voltages are specified in units of 5mV, and characterization
-/// currents are specified in units of 500mA.
-///
-/// \bug The assumption is that the 'maxreg' points for the iVRM will also be
-/// supplied in the VPD in units of 5mv. If they are supplied in some other
-/// form then chip_characterization_create() will need to be modified.
-
-typedef struct {
-
- uint32_t vdd_5mv;
- uint32_t vcs_5mv;
- uint32_t vdd_maxreg_5mv;
- uint32_t vcs_maxreg_5mv;
- uint32_t idd_500ma;
- uint32_t ics_500ma;
- uint32_t frequency_mhz;
-
-} VpdOperatingPoint;
-
-/// System Power Distribution Paramenters
-///
-/// Parameters set by system design that influence the power distribution
-/// for a rail to the processor module. This values are typically set in the
-/// system machine readable workbook and are used in the generation of the
-/// Global Pstate Table. This values are carried in the Pstate SuperStructure
-/// for use and/or reference by OCC firmware (eg the WOF algorithm)
-
-typedef struct {
-
- /// Loadline
- /// Impedance (binary microOhms) of the load line from a processor VDD VRM
- /// to the Processor Module pins.
- uint32_t loadline_uohm;
-
- /// Distribution Loss
- /// Impedance (binary in microOhms) of the VDD distribution loss sense point
- /// to the circuit.
- uint32_t distloss_uohm;
-
- /// Distribution Offset
- /// Offset voltage (binary in microvolts) to apply to the rail VRM
- /// distribution to the processor module.
- uint32_t distoffset_uv;
-
-} SysPowerDistParms;
-
-
-
-/// IDDQ Reading Type
-/// Each entry is 2 bytes. The values are in 10mA units; this allow for a
-/// maximum value of 655.36A represented.
-///
-typedef uint16_t iddq_entry_t;
-
-/// IDDQ Reading
-///
-/// Structure with "raw" and "temperature corrected" values. See VPD
-/// documentation for the correction function that is applied to the raw
-/// value to load the corrected value.
-///
-typedef union {
- uint32_t value;
- struct {
-#ifdef _BIG_ENDIAN
- iddq_entry_t iddq_raw_value;
- iddq_entry_t iddq_corrected_value;
-#else
- iddq_entry_t iddq_corrected_value;
- iddq_entry_t iddq_raw_value;
-#endif // _BIG_ENDIAN
- } fields;
-
-} IddqReading;
-
-/// Iddq Table
-///
-/// A set of arrays of leakage values (Iddq) collected at various voltage
-/// conditions during manufacturing test that will feed into the Workload
-/// Optimized Frequency algorithms on the OCC. These values are not installed
-/// in any hardware facilities.
-///
-typedef struct {
-
- /// IDDQ version
- uint8_t iddq_version;
-
- /// VDD IDDQ readings
- IddqReading iddq_vdd[CORE_IDDQ_MEASUREMENTS];
-
- /// VCS IDDQ readings
- IddqReading iddq_vcs[CORE_IDDQ_MEASUREMENTS];
-
- /// VIO IDDQ readings
- IddqReading iddq_vio[CHIP_IDDQ_MEASUREMENTS];
-
-} IddqTable;
-
-
-
-/// UltraTurbo Segment VIDs by Core Count
-typedef struct {
-
- /// Number of Segment Pstates
- uint8_t ut_segment_pstates;
-
- /// Maximum number of core possibly active
- uint8_t ut_max_cores;
-
- /// VDD VID modification
- /// 1 core active = offset 0
- /// 2 cores active = offset 1
- /// ...
- /// 12 cores active = offset 11
- uint8_t ut_segment_vdd_vid[MAX_UT_PSTATES][NUM_ACTIVE_CORES];
-
- /// VCS VID modification
- /// 1 core active = offset 0
- /// 2 cores active = offset 1
- /// ...
- /// 12 cores active = offset 11
- uint8_t ut_segment_vcs_vid[MAX_UT_PSTATES][NUM_ACTIVE_CORES];
-
-} VIDModificationTable;
-
-/// Workload Optimized Frequency (WOF) Elements
-///
-/// Structure defining various control elements needed by the WOF algorithm
-/// firmware running on the OCC.
-///
-typedef struct {
-
- /// WOF Enablement
- uint8_t wof_enabled;
-
- /// Operating points
- ///
- /// VPD operating points are stored without load-line correction. Frequencies
- /// are in MHz, voltages are specified in units of 5mV, and currents are
- /// in units of 500mA.
- VpdOperatingPoint operating_points[VPD_PV_POINTS];
-
- /// Loadlines and Distribution values for the VDD rail
- SysPowerDistParms vdd_sysparm;
-
- /// Loadlines and Distribution values for the VCS rail
- SysPowerDistParms vcs_sysparm;
-
- /// TDP<>RDP Current Factor
- /// Value read from ??? VPD
- /// Defines the scaling factor that converts current (amperage) value from
- /// the Thermal Design Point to the Regulator Design Point (RDP) as input
- /// to the Workload Optimization Frequency (WOF) OCC algorithm.
- ///
- /// This is a ratio value and has a granularity of 0.01 decimal. Data
- /// is held in hexidecimal (eg 1.22 is represented as 122 and then converted
- /// to hex 0x7A).
- uint32_t tdp_rdp_factor;
-
- /// UltraTurbo Segment VIDs by Core Count
- VIDModificationTable ut_vid_mod;
-
- uint8_t pad[4];
-
-} WOFElements;
-
-
-/// The layout of the data created by the Pstate table creation firmware
-///
-/// This structure is only used for passing Pstate data from the FSP into OCC,
-/// therefore there is no alignment requirement. The \gpst member is copied
-/// to an aligned location, and the \a lpsa and \a resclk members are directly
-/// installed in hardware.
-///
-/// Both the master and slave OCCs (in DCM-mode) install their Pstate tables
-/// independently via the API gpsm_initialize(). At that point the
-/// PstateSuperStructure can be discarded.
-
-typedef struct {
-
- /// Magic Number
- uint64_t magic;
-
- /// Global Pstate Table
- GlobalPstateTable gpst;
-
- /// Local Pstate Array
- LocalPstateArray lpsa;
-
- /// Resonant Clocking Setup
- ResonantClockingSetup resclk;
-
- /// CPM Pstate ranges
- CpmPstateModeRanges cpmranges;
-
- /// Iddq Table
- IddqTable iddq;
-
- /// WOF Controls
- WOFElements wof;
-
-} PstateSuperStructure;
-
-
-int
-vid11_validate(Vid11 vid);
-
-int
-bias_pstate(Pstate pstate, int bias, Pstate* biased_pstate);
-
-int
-bias_frequency(DpllCode fcode, int bias, DpllCode* biased_fcode);
-
-int
-bias_vid11(Vid11 vid, int bias, Vid11* biased_fcode);
-
-int
-gpst_entry(const GlobalPstateTable* gpst,
- const Pstate pstate,
- const int bias,
- gpst_entry_t* entry);
-
-int
-gpst_frequency2pstate(const GlobalPstateTable* gpst,
- const uint32_t frequency_khz,
- Pstate* pstate);
-
-int
-gpst_vdd2pstate(const GlobalPstateTable* gpst,
- const uint8_t vdd,
- Pstate* pstate,
- gpst_entry_t* entry);
-
-
-/// Return the Pmin value associated with a GlobalPstateTable
-static inline Pstate
-gpst_pmin(const GlobalPstateTable* gpst)
-{
- return gpst->pmin;
-}
-
-
-/// Return the Pmax value associated with a GlobalPstateTable
-static inline Pstate
-gpst_pmax(const GlobalPstateTable* gpst)
-{
- return (int)(gpst->pmin) + (int)(gpst->entries) - 1;
-}
-
-/// Return the Pmin value associated with a LocalPstateTable
-static inline Pstate
-lpst_pmin(const LocalPstateArray* lpsa)
-{
- return lpsa->pmin;
-}
-
-
-/// Return the Pmax value associated with a GlobalPstateTable
-static inline Pstate
-lpst_pmax(const LocalPstateArray* lpsa)
-{
- return (int)(lpsa->pmin) + (int)(lpsa->entries) - 1;
-}
-
-#endif /* __ASSEMBLER__ */
-
-#endif /* __PSTATES_H__ */
diff --git a/src/lib/special_wakeup.c b/src/lib/special_wakeup.c
deleted file mode 100644
index 59e3274..0000000
--- a/src/lib/special_wakeup.c
+++ /dev/null
@@ -1,149 +0,0 @@
-// $Id: special_wakeup.c,v 1.4 2014/02/03 01:30:25 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/special_wakeup.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file special_wakeup.c
-/// \brief Container for special wakeup related procedures
-
-#include "special_wakeup.h"
-
-uint32_t G_special_wakeup_count[PGP_NCORES] = {0};
-
-/// Enter or clear special wakeup for a core
-///
-/// \param set 1 = set, 0 = clear, all other values will cause an error.
-///
-/// \param cores = mask of cores to set/clear special wakeup.
-///
-/// \param[out] o_timeouts. Mask of cores that timed out before special wakeup
-/// complete was observed.
-///
-/// \retval 0 Success
-///
-/// \retval -SPWU_INVALID_ARGUMENT One of the arguments was invalid in some way
-///
-/// \retval others This API may also return non-0 codes from
-/// getscom()/putscom()
-///
-/// If getscom/putscom rc = 0, the state of the global special_wakeup counts
-/// may no longer be valid.
-///
-
-int
-occ_special_wakeup(int set,
- ChipConfigCores cores,
- int timeout_ms,
- ChipConfigCores *o_timeouts)
-
-{
-
- pmc_core_deconfiguration_reg_t pcdr;
- pcbs_pmgp0_reg_t pmgp0;
- pcbs_pmspcwkupocc_reg_t ppr;
- ChipConfigCores core_list;
- ChipConfigCores awake_list = 0;
- ChipConfigCores success_list = 0;
- ChipConfigCores poll_list = 0;
- ChipConfigCores timeout_list = 0;
- int rc, poll_count, core;
- int time = 0;
- int bad_clear;
-
- // get pmc deconfig vector
- pcdr.value = in32(PMC_CORE_DECONFIGURATION_REG);
-
- core_list = cores;
- bad_clear = 0;
- if (! set) {
- for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
- if (core_list & (0x1 << (PGP_NCORES - 1))) {
- if (G_special_wakeup_count[core] == 0) {
- bad_clear = 1;
- }
- }
- }
- }
-
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF( (set < 0) ||
- (set > 1) ||
- (bad_clear) ||
- (pcdr.fields.core_chiplet_deconf_vector & cores),
- SPWU_INVALID_ARGUMENT);
- }
-
- do {
- ppr.value = 0;
- if (set) {
- // If count is currently zero, set the bit and increment count.
- // Otherwise, just increment count
- core_list = cores;
- for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
- if (core_list & (0x1 << (PGP_NCORES - 1))) {
- if (! G_special_wakeup_count[core]) {
- ppr.fields.occ_special_wakeup = 1;
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMSPCWKUPOCC_REG, core), ppr.value);
- poll_list |= (0x1 << (PGP_NCORES - 1 - core));
- }
- if (rc) break; // break for loop
- ++G_special_wakeup_count[core];
- success_list |= (0x1 << (PGP_NCORES - 1 - core));
- }
- }
- if (rc) break;
-
- // poll special_wkup_done bit.
- poll_count = 0;
- while ((poll_list != awake_list) && (time < timeout_ms)) {
- if (! poll_count) {
- ssx_sleep(SSX_MICROSECONDS(2));
- ++poll_count;
- } else {
- ssx_sleep(SSX_MILLISECONDS(5));
- time += 5;
- }
- core_list = poll_list & (~awake_list);
- for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
- if (core_list & (0x1 << (PGP_NCORES - 1))) {
- rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_PMGP0_REG, core), &pmgp0.value);
- if (rc) break;
- if (pmgp0.fields.special_wkup_done) {
- awake_list |= (0x1 << (PGP_NCORES - 1 - core));
- } else {
- if (time >= timeout_ms) {
- timeout_list |= (0x1<<(PGP_NCORES-1-core));
- }
- }
- }
- }
- }
- } else { // clear special wakeup
- core_list = cores;
- for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
- if (core_list & (0x1 << (PGP_NCORES - 1))) {
- if (G_special_wakeup_count[core] == 1) {
- ppr.fields.occ_special_wakeup = 0;
- rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMSPCWKUPOCC_REG, core), ppr.value);
- }
- if (rc) break;
- --G_special_wakeup_count[core];
- success_list |= (0x1 << (PGP_NCORES - 1 - core));
- }
- }
- if (rc) break;
- }
- } while (0);
-
- // bad rc recovery (recovery of counts, etc?)
-
- *o_timeouts = timeout_list;
- return rc;
-
-}
-
-
diff --git a/src/lib/special_wakeup.h b/src/lib/special_wakeup.h
deleted file mode 100644
index 88b8ec0..0000000
--- a/src/lib/special_wakeup.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __SPECIAL_WAKEUP_H__
-#define __SPECIAL_WAKEUP_H__
-
-// $Id: special_wakeup.h,v 1.2 2014/02/03 01:30:25 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/special_wakeup.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file special_wakeup.h
-/// \brief Container for special wakeup related procedures
-
-#ifndef __ASSEMBLER__
-
-#include <stdint.h>
-#include "pgp_config.h"
-#include "ssx.h"
-
-#define SPWU_INVALID_ARGUMENT 0x00779801
-
-extern uint32_t G_special_wakeup_count[PGP_NCORES];
-
-int
-occ_special_wakeup(int set,
- ChipConfigCores cores,
- int timeout_ms,
- ChipConfigCores *o_timeouts);
-
-#endif /* __ASEMBLER__ */
-#endif /* __SPECIAL_WAKEUP_H__ */
diff --git a/src/lib/strdup.c b/src/lib/strdup.c
deleted file mode 100755
index c6ac04c..0000000
--- a/src/lib/strdup.c
+++ /dev/null
@@ -1,39 +0,0 @@
-// $Id: strdup.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strdup.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file strdup.c
-/// \brief Functions from <string.h> that require malloc()
-///
-/// These APIs are split from string.c for the benefit of applications like
-/// OCC FW that don't use malloc().
-
-#include <stdlib.h>
-#include <string.h>
-
-/// Duplicate a string
-///
-/// \param s The string to duplicate
-///
-/// The strdup() function returns a pointer to a new string which is a
-/// duplicate of the input string \a s. Memory for the new string is obtained
-/// with malloc(), and can be freed with free().
-///
-/// \returns The strdup() function returns a pointer to the duplicated string,
-/// or NULL (0) if insufficient memory was available.
-
-char *
-strdup(const char* s)
-{
- char* dup;
-
- dup = (char*)malloc(strlen(s) + 1);
- if (dup != 0) {
- strcpy(dup, s);
- }
- return dup;
-}
diff --git a/src/lib/string.h b/src/lib/string.h
deleted file mode 100755
index 2376463..0000000
--- a/src/lib/string.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __STRING_H__
-#define __STRING_H__
-
-// $Id: string.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file string.h
-/// \brief Replacement for <string.h>
-///
-/// The SSX library does not implement the entire <string.h> function.
-/// However the real reason for this header was the finding that under certain
-/// optimization modes, we were geting errors from the default <string.h>
-/// supplied with the MPC environment. So we created this replacement that
-/// only calls out what is implemented, exactly as it is implemented for SSX.
-
-#ifndef __ASSEMBLER__
-
-#include <stddef.h>
-
-// APIs inmplemented by string.c
-
-size_t
-strlen(const char *s);
-
-int
-strcmp(const char* s1, const char* s2);
-
-int
-strncmp(const char* s1, const char* s2, size_t n);
-
-int
-strcasecmp(const char* s1, const char* s2);
-
-int
-strncasecmp(const char* s1, const char* s2, size_t n);
-
-char *
-strcpy(char *dest, const char *src);
-
-char *
-strncpy(char *dest, const char *src, size_t n);
-
-void *
-memcpy(void *dest, const void *src, size_t n);
-
-void *
-memset(void *s, int c, size_t n);
-
-int
-memcmp(const void* s1, const void* s2, size_t n);
-
-// APIs implemented by strdup.c
-
-char *
-strdup(const char* s);
-
-#endif /* __ASSEMBLER__ */
-
-#endif /* __STRING_H__ */
diff --git a/src/lib/vrm.c b/src/lib/vrm.c
deleted file mode 100755
index 57f19fa..0000000
--- a/src/lib/vrm.c
+++ /dev/null
@@ -1,394 +0,0 @@
-// $Id: vrm.c,v 1.2 2014/02/03 01:30:26 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/vrm.c,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file vrm.c
-/// \brief PgP SPIVRM procedures
-
-#include "vrm.h"
-
-// The semaphore used to block threads waiting for o2s operations to complete
-
-static SsxSemaphore o2s_protocol_semaphore;
-
-
-/// o2s_initialize follows the steps for setting up the o2s bridge as outlined
-/// In the Energy Management spec (PMC section)
-int
-o2s_initialize()
-{
- pmc_o2s_ctrl_reg0a_t pocr0a;
- pmc_o2s_ctrl_reg0b_t pocr0b;
- pmc_o2s_ctrl_reg1_t pocr1;
-
-
- ssx_semaphore_create(&o2s_protocol_semaphore, 0, 1);
-
- ssx_irq_disable(PGP_IRQ_OCI2SPIVID_ONGOING);
-
- ssx_irq_setup(PGP_IRQ_OCI2SPIVID_ONGOING,
- SSX_IRQ_POLARITY_ACTIVE_LOW,
- SSX_IRQ_TRIGGER_LEVEL_SENSITIVE);
-
- ssx_irq_handler_set(PGP_IRQ_OCI2SPIVID_ONGOING,
- ssx_semaphore_post_handler,
- (void *)(&o2s_protocol_semaphore),
- SSX_NONCRITICAL);
-
- pocr0a.value = in32(PMC_O2S_CTRL_REG0A);
- pocr0a.fields.o2s_frame_size = 32;
- pocr0a.fields.o2s_out_count1 = 32;
- pocr0a.fields.o2s_in_delay1 = 0x3F;
- pocr0a.fields.o2s_in_count1 = 0;
- out32(PMC_O2S_CTRL_REG0A, pocr0a.value);
-
- pocr0b.value = in32(PMC_O2S_CTRL_REG0B);
- pocr0b.fields.o2s_out_count2 = 0;
- pocr0b.fields.o2s_in_delay2 = 0;
- pocr0b.fields.o2s_in_count2 = 32;
- out32(PMC_O2S_CTRL_REG0B, pocr0b.value);
-
- pocr1.value = in32(PMC_O2S_CTRL_REG1);
- pocr1.fields.o2s_bridge_enable = 1;
- pocr1.fields.o2s_cpol = 0;
- pocr1.fields.o2s_cpha = 0;
- pocr1.fields.o2s_clock_divider = 29; // 10 MHz(?)
- pocr1.fields.o2s_nr_of_frames = 1; // 2 frames
- out32(PMC_O2S_CTRL_REG1, pocr1.value);
-
- return 0;
-
-}
-
-/// similar to o2s_intialize, but for the automated spivid fsm
-/// \param vrm_select A 3-bit vector of VRM selected for the operation.
-///
-/// NOTE: The spivid is normally initialized by Host Boot
-///
-/// \retval 0 Success
-int
-spivid_initialize(int vrm_select)
-{
- pmc_spiv_ctrl_reg0a_t pocr0a;
- pmc_spiv_ctrl_reg0b_t pocr0b;
- pmc_spiv_ctrl_reg1_t pocr1;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((vrm_select <= 0) ||
- (vrm_select > 0x7),
- VRM_INVALID_ARGUMENT_INIT);
- }
-
-
- pocr0a.value = in32(PMC_SPIV_CTRL_REG0A);
- pocr0a.fields.spivid_frame_size = 32;
- pocr0a.fields.spivid_out_count1 = 32;
- pocr0a.fields.spivid_in_delay1 = 0x3F;
- pocr0a.fields.spivid_in_count1 = 0;
- out32(PMC_SPIV_CTRL_REG0A, pocr0a.value);
-
- pocr0b.value = in32(PMC_SPIV_CTRL_REG0B);
- pocr0b.fields.spivid_out_count2 = 0;
- pocr0b.fields.spivid_in_delay2 = 0;
- pocr0b.fields.spivid_in_count2 = 32;
- out32(PMC_SPIV_CTRL_REG0B, pocr0b.value);
-
- pocr1.value = in32(PMC_SPIV_CTRL_REG1);
- pocr1.fields.spivid_fsm_enable = 1;
- pocr1.fields.spivid_cpol = 0;
- pocr1.fields.spivid_cpha = 0;
- pocr1.fields.spivid_clock_divider = 29; // 10 MHz(?)
- pocr1.fields.spivid_port_enable = vrm_select;
- out32(PMC_SPIV_CTRL_REG1, pocr1.value);
-
- return 0;
-
-}
-
-
-// Start an O2S transaction and poll for completion. Optionally return the
-// input data.
-
-static void
-o2s_start_poll(uint64_t out, uint64_t *in)
-{
-
- out32(PMC_O2S_WDATA_REG, out >> 32);
-
- if (!ssx_irq_status_get(PGP_IRQ_OCI2SPIVID_ONGOING)) {
- ssx_irq_enable(PGP_IRQ_OCI2SPIVID_ONGOING);
- ssx_semaphore_pend(&o2s_protocol_semaphore, SSX_WAIT_FOREVER);
- }
-
-
- if (in != 0) {
- *in = in32(PMC_O2S_RDATA_REG);
- }
-}
-
-
-/// Write a voltage using the O2S bridge
-///
-/// \param vrm_select A 3-bit vector of VRM selected for the operation.
-///
-/// \param vdd_vid The VRM-11 VID code for Vdd.
-///
-/// \param vcs_offset The signed offset (Vdiff) equal to Vcs - Vdd expressed
-/// in VRM-11 VID units.
-///
-/// \param phases The number of phases enabled.
-///
-/// This is a polling CPU procedure that writes a new voltage to a set of one
-/// or more VRM then does a status read to make sure it succeeded.
-///
-/// \retval 0 Success
-///
-/// \retval -VRM_INVALID_ARGUMENT_VWRITE One of the arguments was invalid in
-/// some way.
-///
-/// \retval -O2S_BUSY_VRM_VOLTAGE_WRITE The O2S bridge is currently busy
-///
-/// \retval -O2S_READ_NOT_READY A 'read not ready' condition occurred on the
-/// status read.
-///
-/// \retval -O2S_WRITE_NOT_VALID The voltage write was invalid
-///
-/// \retval -O2S_ECC_ERROR An ECC error occurred
-///
-/// \todo We need to understand what the firmware is expected to do when the
-/// 'read not ready' or other error responses come back. Here they will
-/// likely panic.
-
-int
-vrm_voltage_write(int vrm_select,
- uint8_t vdd_vid,
- int8_t vcs_offset,
- int phases)
-{
- int i, port;
- uint64_t result;
- pmc_o2s_ctrl_reg1_t pocr;
- pmc_o2s_status_reg_t posr;
- vrm_write_transaction_t vwt;
- vrm_write_resp_t vwr;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((vrm_select <= 0) ||
- (vrm_select > 0x7) ||
- (phases < 0) ||
- (phases > 0xf),
- VRM_INVALID_ARGUMENT_VWRITE);
- }
-
- // Check for O2S busy
-
- posr.value = in32(PMC_O2S_STATUS_REG);
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF(posr.fields.o2s_ongoing, O2S_BUSY_VRM_VOLTAGE_WRITE);
- }
-
- // Use O2S to set voltage and read status, one port at a time.
-
- for (i = 0; i < SPIVRM_NPORTS; i++) {
-
- port = vrm_select & SPIVRM_PORT(i);
- if (port != 0) {
-
- // Set the (singular) O2S port
-
- pocr.value = in32(PMC_O2S_CTRL_REG1);
- pocr.fields.o2s_port_enable = port;
- out32(PMC_O2S_CTRL_REG1, pocr.value);
-
- // Create and initiate a voltage write command
-
- vwt.value = 0;
- vwt.fields.command = VRM_WRITE_VOLTAGE;
- vwt.fields.vdd_vid = vdd_vid;
- vwt.fields.vcs_offset = vcs_offset;
- vwt.fields.phase_enable = phases;
-
-
- o2s_start_poll(vwt.value, &result);
- // Check the status
- vwr.value = result << 32;
-
- // results are duplicated 3x, using first byte for checking
-
- SSX_ERROR_IF(vwr.fields.write_status0 == 0x00, O2S_READ_NOT_READY);
- SSX_ERROR_IF(vwr.fields.write_status0 == 0x55, O2S_WRITE_ECC_ERROR);
- SSX_ERROR_IF(vwr.fields.write_status0 != 0xAA, O2S_WRITE_NOT_VALID);
- }
- }
- return 0;
-}
-
-/// Read VRM state using the O2S bridge
-///
-/// \param vrm_select A 3-bit vector of VRM selected for the operation.
-/// This procedure only allows 1 VRM to be selected.
-///
-/// \param vrail A 4-bit value for selecting a voltage rail
-///
-/// \param[out] o_vid The resulting 8-bit VRM-11 encoded voltage ID
-///
-///
-/// \retval 0 Success
-///
-/// \retval -VRM_INVALID_ARGUMENT_SREAD One of the arguments was invalid in some
-/// way.
-///
-/// \retval -O2S_BUSY_VRM_READ_STATE The O2S bridge is currently busy
-///
-
-int
-vrm_read_state(int vrm_select,
- int *mnp1,
- int *mn,
- int *vfan,
- int *vovertmp)
-{
- int i, port;
- uint64_t result;
- pmc_o2s_status_reg_t posr;
- pmc_o2s_ctrl_reg1_t pocr;
- vrm_read_state_t vrs;
- vrm_read_state_resp_t vrsr;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((!((vrm_select == SPIVRM_PORT(0)) ||
- (vrm_select == SPIVRM_PORT(1)) ||
- (vrm_select == SPIVRM_PORT(2)))),
- VRM_INVALID_ARGUMENT_SREAD);
- }
-
-
- // Check for O2S busy
-
- posr.value = in32(PMC_O2S_STATUS_REG);
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF(posr.fields.o2s_ongoing, O2S_BUSY_VRM_READ_STATE);
- }
-
- // Use O2S to read voltage for selected rail.
-
- for (i = 0; i < SPIVRM_NPORTS; i++) {
-
- port = vrm_select & SPIVRM_PORT(i);
- if (port != 0) {
-
- // Set the (singular) O2S port
-
- pocr.value = in32(PMC_O2S_CTRL_REG1);
- pocr.fields.o2s_port_enable = port;
- out32(PMC_O2S_CTRL_REG1, pocr.value);
-
- // Create and initiate a voltage read command
-
- vrs.value = 0;
- vrs.fields.command = VRM_READ_STATE;
-
-
- o2s_start_poll(vrs.value, &result);
- // Check the status
- vrsr.value = result << 32;
-
- // results are duplicated 3x, returning first byte
- *mnp1 = vrsr.fields.minus_nplus1_0;
- *mn = vrsr.fields.minus_n0;
- *vfan = vrsr.fields.vrm_fan0;
- *vovertmp = vrsr.fields.vrm_overtemp0;
-
- }
- }
- return 0;
-}
-
-
-/// Read a voltage using the O2S bridge
-///
-/// \param vrm_select A 3-bit vector of VRM selected for the operation.
-/// This procedure only allows 1 VRM to be selected.
-///
-/// \param vrail A 4-bit value for selecting a voltage rail
-///
-/// \param[out] o_vid The resulting 8-bit VRM-11 encoded voltage ID
-///
-///
-/// \retval 0 Success
-///
-/// \retval -VRM_INVALID_ARGUMENT_VREAD One of the arguments was invalid in some
-/// way.
-///
-/// \retval -O2S_BUSY_VRM_VOLTAGE_READ The O2S bridge is currently busy
-///
-
-int
-vrm_voltage_read(int vrm_select,
- uint8_t vrail,
- uint8_t *o_vid)
-{
- int i, port;
- uint64_t result;
- pmc_o2s_status_reg_t posr;
- pmc_o2s_ctrl_reg1_t pocr;
- vrm_read_voltage_t vrv;
- vrm_read_voltage_resp_t vrvr;
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF((!((vrm_select == SPIVRM_PORT(0)) ||
- (vrm_select == SPIVRM_PORT(1)) ||
- (vrm_select == SPIVRM_PORT(2)))) ||
- (vrail > (SPIVRM_NRAILS - 1)),
- VRM_INVALID_ARGUMENT_VREAD);
- }
-
-
- // Check for O2S busy
-
- posr.value = in32(PMC_O2S_STATUS_REG);
-
- if (SSX_ERROR_CHECK_API) {
- SSX_ERROR_IF(posr.fields.o2s_ongoing, O2S_BUSY_VRM_VOLTAGE_READ);
- }
-
- // Use O2S to read voltage for selected rail.
-
- for (i = 0; i < SPIVRM_NPORTS; i++) {
-
- port = vrm_select & SPIVRM_PORT(i);
- if (port != 0) {
-
- // Set the (singular) O2S port
-
- pocr.value = in32(PMC_O2S_CTRL_REG1);
- pocr.fields.o2s_port_enable = port;
- out32(PMC_O2S_CTRL_REG1, pocr.value);
-
- // Create and initiate a voltage read command
-
- vrv.value = 0;
- vrv.fields.command = VRM_READ_VOLTAGE;
- vrv.fields.rail = vrail;
-
-
- o2s_start_poll(vrv.value, &result);
- // Check the status
- vrvr.value = result << 32;
-
- // results are duplicated 3x, returning first byte
- *o_vid = vrvr.fields.vid0;
- }
- }
- return 0;
-}
-
-
-
-
diff --git a/src/lib/vrm.h b/src/lib/vrm.h
deleted file mode 100755
index 2efea4d..0000000
--- a/src/lib/vrm.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef __VRM_H__
-#define __VRM_H__
-
-// $Id: vrm.h,v 1.2 2014/02/03 01:30:26 daviddu Exp $
-// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/vrm.h,v $
-//-----------------------------------------------------------------------------
-// *! (C) Copyright International Business Machines Corp. 2013
-// *! All Rights Reserved -- Property of IBM
-// *! *** IBM Confidential ***
-//-----------------------------------------------------------------------------
-
-/// \file vrm.h
-/// \brief PgP SPIVRM procedures
-
-#include "ssx.h"
-
-#ifndef __ASSEMBLER__
-
-int
-o2s_initialize();
-
-int
-spivid_initialize();
-
-
-int
-vrm_voltage_write(int vrm_select,
- uint8_t vdd_vid,
- int8_t vcs_offset,
- int phases);
-
-int
-vrm_read_state(int vrm_select,
- int *mnp1,
- int *mn,
- int *vfan,
- int *vovertmp);
-
-int
-vrm_voltage_read(int vrm_select,
- uint8_t vrail,
- uint8_t *o_vid);
-
-#endif /* __ASEMBLER__ */
-
-// Error/panic codes
-
-#define O2S_BUSY_VRM_VOLTAGE_READ 0x00627001
-#define O2S_BUSY_VRM_VOLTAGE_WRITE 0x00627002
-#define O2S_BUSY_VRM_READ_STATE 0x00627003
-#define O2S_READ_NOT_READY 0x00627004
-#define O2S_WRITE_NOT_VALID 0x00627005
-#define O2S_WRITE_ECC_ERROR 0x00627006
-#define VRM_INVALID_ARGUMENT_VREAD 0x00627007
-#define VRM_INVALID_ARGUMENT_VWRITE 0x00627008
-#define VRM_INVALID_ARGUMENT_SREAD 0x00627009
-#define VRM_INVALID_ARGUMENT_INIT 0x0062700a
-
-#endif /* __VRM_H__ */
OpenPOWER on IntegriCloud