summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/build/citest/etc/workarounds.presimsetup7
-rwxr-xr-xsrc/build/simics/post_model_hook.simics3
-rw-r--r--src/build/tocgen/pnortoc.xml12
-rw-r--r--src/include/kernel/intmsghandler.H99
-rw-r--r--src/include/sys/interrupt.h39
-rw-r--r--src/include/sys/misc.h6
-rw-r--r--src/include/sys/mmio.h1
-rw-r--r--src/include/sys/msg.h20
-rw-r--r--src/include/usr/hbotcompid.H8
-rw-r--r--src/include/usr/initservice/initsvcreasoncodes.H1
-rw-r--r--src/include/usr/intr/interrupt.H79
-rw-r--r--src/include/usr/intr/intr_reasoncodes.H45
-rw-r--r--src/kernel/exception.C13
-rw-r--r--src/kernel/intmsghandler.C125
-rw-r--r--src/kernel/makefile2
-rw-r--r--src/kernel/start.S2
-rw-r--r--src/kernel/syscall.C43
-rw-r--r--src/lib/syscall_misc.C22
-rw-r--r--src/lib/syscall_msg.C25
-rw-r--r--src/lib/syscall_task.C3
-rw-r--r--src/makefile6
-rw-r--r--src/usr/initservice/extinitsvc/extinitsvctasks.H13
-rw-r--r--src/usr/intr/intrrp.C600
-rw-r--r--src/usr/intr/intrrp.H191
-rw-r--r--src/usr/intr/makefile30
-rw-r--r--src/usr/intr/test/intrtest.H221
-rw-r--r--src/usr/intr/test/makefile29
-rw-r--r--src/usr/makefile3
-rw-r--r--src/usr/pnor/pnorrp.C2
-rw-r--r--src/usr/pnor/test/pnorrptest.H6
30 files changed, 1625 insertions, 31 deletions
diff --git a/src/build/citest/etc/workarounds.presimsetup b/src/build/citest/etc/workarounds.presimsetup
index 738b83211..726629fe8 100755
--- a/src/build/citest/etc/workarounds.presimsetup
+++ b/src/build/citest/etc/workarounds.presimsetup
@@ -56,3 +56,10 @@ echo "INTERNALREGS # List all scom registers" >> $sb/simu/data/cec-chi
echo " 0xFF00000F, 64 # Simics workaround" >> $sb/simu/data/cec-chip/centaur.chip
echo "END" >> $sb/simu/data/cec-chip/centaur.chip
echo "DONE" >> $sb/simu/data/cec-chip/centaur.chip
+
+echo "+++ Update to new phyp and mambo level."
+mkdir -p $sb/simu/data
+cp --update $BACKING_BUILD/src/simu/data/simicsInfo $sb/simu/data/simicsInfo
+sed -i -e's/^WSALIAS HOSTBOOT_LEVEL MAMBOLEVEL.*/WSALIAS HOSTBOOT_LEVEL MAMBOLEVEL env\/mamboa\/2011_11_10__4.2/' $sb/simu/data/simicsInfo
+sed -i -e's/^WSALIAS HOSTBOOT_LEVEL PHYPLEVEL.*/WSALIAS HOSTBOOT_LEVEL PHYPLEVEL env\/phypa\/simics-4.2.0\/simics-4.2.82\/ph111111a700.42/' $sb/simu/data/simicsInfo
+sed -i -e's/^WSALIAS HOSTBOOT_LEVEL PHYP_PATCH_LEVEL.*/WSALIAS HOSTBOOT_LEVEL PHYP_PATCH_LEVEL env\/phypa\/simics-4.2.0\/simics-4.2.82\/patches\/ph111111a700.42/' $sb/simu/data/simicsInfo
diff --git a/src/build/simics/post_model_hook.simics b/src/build/simics/post_model_hook.simics
index 85dc001ec..292a7a9ac 100755
--- a/src/build/simics/post_model_hook.simics
+++ b/src/build/simics/post_model_hook.simics
@@ -29,6 +29,7 @@
################################################################################
+#setup traces
run-python-file simics-debug-framework.py
run-python-file hb-simdebug.py
@@ -36,5 +37,5 @@ run-python-file hb-simdebug.py
#This will be merged into once the proper tools are written.
phys_mem.load-file ../img/hbicore_extended.bin 0x500690
phys_mem.load-file ../img/pnor.toc 0x500000
-phys_mem.load-file ../img/targeting.bin 0x57E690
+phys_mem.load-file ../img/targeting.bin 0x5B0690
diff --git a/src/build/tocgen/pnortoc.xml b/src/build/tocgen/pnortoc.xml
index 89e268c0a..df2d889c2 100644
--- a/src/build/tocgen/pnortoc.xml
+++ b/src/build/tocgen/pnortoc.xml
@@ -74,11 +74,11 @@
<length>8</length>
<format>number</format>
</field>
- <field type="logical_size">0x7D000
+ <field type="logical_size">0xAF000
<length>8</length>
<format>number</format>
</field>
- <field type="physical_size">0x7D000
+ <field type="physical_size">0xAF000
<length>8</length>
<format>number</format>
</field>
@@ -97,11 +97,11 @@
<length>8</length>
<format>string</format>
</field>
- <field type="logical_offset">0x7D690
+ <field type="logical_offset">0xAF690
<length>8</length>
<format>number</format>
</field>
- <field type="physical_offset">0x7D690
+ <field type="physical_offset">0xAF690
<length>8</length>
<format>number</format>
</field>
@@ -128,11 +128,11 @@
<length>8</length>
<format>string</format>
</field>
- <field type="logical_offset">0x7E690
+ <field type="logical_offset">0xB0690
<length>8</length>
<format>number</format>
</field>
- <field type="physical_offset">0x7E690
+ <field type="physical_offset">0xB0690
<length>8</length>
<format>number</format>
</field>
diff --git a/src/include/kernel/intmsghandler.H b/src/include/kernel/intmsghandler.H
new file mode 100644
index 000000000..52eadde27
--- /dev/null
+++ b/src/include/kernel/intmsghandler.H
@@ -0,0 +1,99 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/include/kernel/intmsghandler.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef __KERNEL_INTERRUPTMSGHDLR_H
+#define __KERNEL_INTERRUPTMSGHDLR_H
+
+#include <stdint.h>
+#include <kernel/types.h>
+#include <kernel/msghandler.H>
+#include <kernel/msg.H>
+
+/**
+ * @class InterruptMsgHdlr
+ * @brief Class to handle sending a message to user space for
+ * an External Interrupt.
+ *
+ * This class extends from the base MessageHandler so the base send/receive
+ * message functions can be utilized. It overrides how to handle the message
+ * responses
+ */
+class InterruptMsgHdlr : public MessageHandler
+{
+ public:
+
+ // Notes:
+ // All external interrupts are routed to one cpu core
+ // External Interrupts are only processed one at a time
+ // So we don't need a spinlock
+ /**
+ * Constructor
+ */
+ InterruptMsgHdlr(MessageQueue * i_msgQ)
+ : MessageHandler(NULL,i_msgQ) {} // TODO need splinlock?
+
+ /**
+ * Destructor.
+ */
+ virtual ~InterruptMsgHdlr() {};
+
+ /**
+ * Handle response to 'send message'
+ *
+ * @param[in] i_type - The message type previously sent.
+ * @param[in] i_key - The key value for the received message.
+ * @param[in] i_task - The deferred task.
+ * @param[in] i_rc - The response rc from userspace.
+ *
+ * @return HandleResult - The desired behavior on the 'recv message'
+ * interface for this <key, task> pair.
+ */
+ virtual HandleResult handleResponse(msg_sys_types_t i_type,void* i_key,
+ task_t* i_task,int i_rc);
+
+
+ /**
+ * Create the InterruptMsgHdlr to handle external interrupts
+ * @param[in] i_msgQ The message queue
+ */
+ static void create(MessageQueue * i_msgQ);
+
+ /**
+ * Handle an external interrupt from HW
+ */
+ static void handleInterrupt();
+
+ /**
+ * Add cpu core - set up the external interrupt registers
+ * @param[in] i_pir The cpu id of the core to to set-up
+ * @note should be called when ever a new core becomes active
+ */
+ static void addCpuCore(uint64_t i_pir);
+
+ private:
+
+ static InterruptMsgHdlr * cv_instance;
+};
+
+
+#endif
+
diff --git a/src/include/sys/interrupt.h b/src/include/sys/interrupt.h
new file mode 100644
index 000000000..59a1a17e3
--- /dev/null
+++ b/src/include/sys/interrupt.h
@@ -0,0 +1,39 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/include/sys/interrupt.h $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef __INTERRUPT_H
+#define __INTERRUPT_H
+
+
+extern const char* INTR_MSGQ;
+
+/**
+ * INTR constants
+ */
+enum
+{
+ ICPBAR_SCOM_ADDR = 0x020109c9, //!< for P8, P7 = 0x02011C09
+ // This BAR value agrees with simics (for now)
+ ICPBAR_VAL = 0x03FBFF90, //!< ICPBAR value bits[0:29]>>34
+};
+
+#endif
diff --git a/src/include/sys/misc.h b/src/include/sys/misc.h
index f30a408ca..59b6c10bd 100644
--- a/src/include/sys/misc.h
+++ b/src/include/sys/misc.h
@@ -86,6 +86,12 @@ ProcessorCoreType cpu_core_type();
*/
uint8_t cpu_dd_level();
+/** @fn cpu_thread_count()
+ * @breif Get the number of threads per cpu for this proctype
+ * @return # of threads per cpu
+ */
+size_t cpu_thread_count();
+
#ifdef __cplusplus
}
#endif
diff --git a/src/include/sys/mmio.h b/src/include/sys/mmio.h
index 740b080c2..aca9286a5 100644
--- a/src/include/sys/mmio.h
+++ b/src/include/sys/mmio.h
@@ -38,6 +38,7 @@ extern "C"
*/
enum SEG_DATA_SIZES
{
+ THIRTYTWO_MB = (32*MEGABYTE),
THIRTYTWO_GB = (32*GIGABYTE),
};
diff --git a/src/include/sys/msg.h b/src/include/sys/msg.h
index be7ba397a..f58e3c8f1 100644
--- a/src/include/sys/msg.h
+++ b/src/include/sys/msg.h
@@ -57,6 +57,19 @@ enum msg_sys_types_t
MSG_MM_RP_READ,
MSG_MM_RP_WRITE,
MSG_MM_RP_PERM,
+
+ MSG_INTR_EXTERN, //!< Msg sent from kernel to user space on ext intr
+ MSG_INTR_ADD_CPU, //!< Add cpu core, data[0] = cpuid (PIR)
+};
+
+// System-defined root queue types
+/** @enum msg_root_queue_types_t
+ * @brief Message queue types that the kernel tracks
+ */
+enum msg_root_queue_types_t
+{
+ MSGQ_ROOT_VFS,
+ MSGQ_ROOT_INTR,
};
/** @var msg_sys_types_t::MSG_MM_RP_READ
@@ -229,9 +242,10 @@ msg_t* msg_wait(msg_q_t q);
*
* @return true if asynchronous message
*/
-ALWAYS_INLINE
- inline uint32_t msg_is_async(msg_t* msg)
- { return 0 == msg->__reserved__async; }
+ ALWAYS_INLINE
+inline uint32_t msg_is_async(msg_t* msg)
+{ return 0 == msg->__reserved__async; }
+
#ifdef __cplusplus
}
diff --git a/src/include/usr/hbotcompid.H b/src/include/usr/hbotcompid.H
index 48d6c71c5..a4102001c 100644
--- a/src/include/usr/hbotcompid.H
+++ b/src/include/usr/hbotcompid.H
@@ -172,6 +172,14 @@ const compId_t EEPROM_COMP_ID = 0x0E00;
const char EEPROM_COMP_NAME[] = "eeprom";
//@}
+/** @name INTR
+ * Interrupt presenter component
+ */
+//@{
+const compId_t INTR_COMP_ID = 0x0F00;
+const char INTR_COMP_NAME[] = "intr";
+//@}
+
// ----------------------------------------------------------
// CXXTEST Unit Test, reserve compid near the end...
/** @name CXXTEST
diff --git a/src/include/usr/initservice/initsvcreasoncodes.H b/src/include/usr/initservice/initsvcreasoncodes.H
index 1ed76efdd..6cbaa81c7 100644
--- a/src/include/usr/initservice/initsvcreasoncodes.H
+++ b/src/include/usr/initservice/initsvcreasoncodes.H
@@ -63,6 +63,7 @@ enum InitServiceModuleID
START_FSISCOM_ERRL_ID = 0x17,
START_TARGETING_ERRL_ID = 0x18,
START_I2C_ERRL_ID = 0x19,
+ START_INTR_ERRL_ID = 0x1A,
// Internal InitService codes
diff --git a/src/include/usr/intr/interrupt.H b/src/include/usr/intr/interrupt.H
new file mode 100644
index 000000000..142917df2
--- /dev/null
+++ b/src/include/usr/intr/interrupt.H
@@ -0,0 +1,79 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/include/usr/intr/interrupt.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef INTERRUPT_H
+#define INTERRUPT_H
+
+#include <sys/msg.h>
+#include <errl/errltypes.H>
+#include <sys/interrupt.h>
+
+namespace INTR
+{
+
+
+ /**
+ * External Interrupt Types (XISR)
+ */
+ enum ext_intr_t
+ {
+ NO_INTERRUPT = 0, //!< no interrupt present
+ INTERPROC = 2, //!< Inter processor interrupt
+ FSP_MAILBOX = 0x25, //!< TODO find this value
+ ATTENTION = 0x26, //!< TODO find this value
+ };
+
+ /**
+ * Msg types for intrRp from usr space
+ */
+ enum msg_intr_types_t
+ {
+ MSG_INTR_ADD_CPU_USR = 1, //!< Add cpu core, data[0] = cpuid (PIR)
+ MSG_INTR_REGISTER_MSGQ, //!< Register a msgQ
+ MSG_INTR_ENABLE, //!< Enable external Interrupts
+ MSG_INTR_DISABLE, //!< Disable external interrupts
+ };
+
+
+ /**
+ * Register a message queue to recieve external interrupts
+ * @param[in] i_msgQ The message queue
+ * @param[in] i_type The type of interrupt (XISR value)
+ * @return errlHndl_t on error.
+ */
+ errlHndl_t registerMsgQ(msg_q_t i_msgQ, ext_intr_t i_type);
+
+ /**
+ * Enable hardware to report external interrupts
+ * @return errlHndl_t on error.
+ */
+ errlHndl_t enableExternalInterrupts();
+
+ /**
+ * Disable hardware from reporting external interrupts
+ * @return errlHndl_t on error.
+ */
+ errlHndl_t disableExternalInterrupts();
+
+};
+
+#endif
diff --git a/src/include/usr/intr/intr_reasoncodes.H b/src/include/usr/intr/intr_reasoncodes.H
new file mode 100644
index 000000000..98070196b
--- /dev/null
+++ b/src/include/usr/intr/intr_reasoncodes.H
@@ -0,0 +1,45 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/include/usr/intr/intr_reasoncodes.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef INTR_REASONCODES_H
+#define INTR_REASONCODES_H
+
+#include <hbotcompid.H>
+
+namespace INTR
+{
+ enum IntrModuleID
+ {
+ UNDEFINED_MODULE_ERRL_ID = 0,
+ INTR_MODULE_ID,
+ };
+
+ enum IntrReasonCode
+ {
+ INTR_ALREADY_REGISTERED = INTR_COMP_ID | 0x01,
+ INTR_REGISTRY_NOT_READY = INTR_COMP_ID | 0x02,
+ INTR_RP_NOT_INITIALIZED = INTR_COMP_ID | 0x03,
+ INTR_BAD_VIRTUAL_IO_ADDRESS = INTR_COMP_ID | 0x04,
+ };
+};
+
+#endif
diff --git a/src/kernel/exception.C b/src/kernel/exception.C
index 863743f06..6ce01bc96 100644
--- a/src/kernel/exception.C
+++ b/src/kernel/exception.C
@@ -28,6 +28,7 @@
#include <arch/ppc.H>
#include <kernel/vmmmgr.H>
#include <kernel/cpuid.H>
+#include <kernel/intmsghandler.H>
namespace ExceptionHandles
{
@@ -221,6 +222,16 @@ void kernel_execute_machine_check()
"\tSRR0 = %lx, SRR1 = %lx\n"
"\tDSISR = %lx, DAR = %lx\n",
t->tid, getPIR(),
- getSRR0(), getSRR0(), getDSISR(), getDAR());
+ getSRR0(), getSRR1(), getDSISR(), getDAR());
kassert(false);
}
+
+extern "C"
+void kernel_execute_external()
+{
+ // SRR0 set to the effective addr the thread
+ // would have attempted to execute next
+ // SRR1 [33:36,42:47] set to zero
+ // all others copied from MSR
+ InterruptMsgHdlr::handleInterrupt();
+}
diff --git a/src/kernel/intmsghandler.C b/src/kernel/intmsghandler.C
new file mode 100644
index 000000000..b7b86c2f5
--- /dev/null
+++ b/src/kernel/intmsghandler.C
@@ -0,0 +1,125 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/kernel/intmsghandler.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#include <kernel/intmsghandler.H>
+#include <sys/msg.h>
+#include <util/singleton.H>
+#include <kernel/console.H>
+#include <sys/interrupt.h>
+#include <util/lockfree/atomic_construct.H>
+
+const char* INTR_MSGQ = "/msg/interrupt";
+
+InterruptMsgHdlr * InterruptMsgHdlr::cv_instance = NULL;
+
+
+void InterruptMsgHdlr::create(MessageQueue * i_msgQ)
+{
+ if(cv_instance)
+ {
+ // TODO should this be considered an unrecoverable error?
+ // i_msgQ has already been changed by the syscall, so we either have to
+ // make a new InterrupMsgHdlr object to match the new queue or we halt
+ // the system.
+ printk("WARNING replacing existing Interrupt handler!\n");
+
+ InterruptMsgHdlr* instance = cv_instance;
+ while(instance != NULL)
+ {
+ if(__sync_bool_compare_and_swap(&cv_instance, instance, NULL))
+ {
+ delete instance;
+ }
+ instance = cv_instance;
+ }
+ }
+
+ // Atomically construct.
+ if (__sync_bool_compare_and_swap(&cv_instance, NULL, NULL))
+ {
+ InterruptMsgHdlr* instance = new InterruptMsgHdlr(i_msgQ);
+ if (!__sync_bool_compare_and_swap(&cv_instance, NULL, instance))
+ {
+ delete instance;
+ }
+ }
+}
+
+
+void InterruptMsgHdlr::handleInterrupt()
+{
+
+ // TODO will this always be processor 0 core 0 thread 0?
+ // Need a way to pass this addr down from user code?
+ uint64_t xirrAddress = (static_cast<uint64_t>(ICPBAR_VAL) << 20) + 4;
+
+ // Ignore HRMOR setting
+ xirrAddress |= 0x8000000000000000ul;
+
+ uint32_t xirr = 0;
+ printkd ("XirrAddr %lx\n",xirrAddress);
+
+ // Reading this register acknowledges the interrupt and deactivates the
+ // external interrupt signal to the processor. The XIRR is now locked
+ // and can't be pre-empted by a "more favored" interrupt.
+ // This is a cache-inhibited load from hypervisor state.
+ // lwzcix BOP1,Ref_G0,BOP2
+ asm volatile("lwzcix %0, 0, %1"
+ : "=r" (xirr) // output, %0
+ : "r" (xirrAddress) // input, %1
+ : ); // no impacts
+
+ if(cv_instance)
+ {
+ cv_instance->sendMessage(MSG_INTR_EXTERN,
+ (void *)xirr,
+ NULL,
+ NULL);
+ }
+
+ // else we got an external interrupt before we got things set up.
+ // TODO Is there anything that can be done other than
+ // leave the interrupt presenter locked.
+ // Does the code that sets up the IP registers need to check to see if
+ // there is an interrupt sitting there and send an EOI?
+}
+
+
+void InterruptMsgHdlr::addCpuCore(uint64_t i_pir)
+{
+ if(cv_instance)
+ {
+ cv_instance->sendMessage(MSG_INTR_ADD_CPU,(void *)i_pir,NULL,NULL);
+ }
+}
+
+MessageHandler::HandleResult InterruptMsgHdlr::handleResponse
+(
+ msg_sys_types_t i_type,
+ void* i_key,
+ task_t* i_task,
+ int i_rc
+ )
+{
+ return UNHANDLED_RC;
+}
+
diff --git a/src/kernel/makefile b/src/kernel/makefile
index 05c15115a..06c7536be 100644
--- a/src/kernel/makefile
+++ b/src/kernel/makefile
@@ -26,7 +26,7 @@ OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o
OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o
OBJS += futexmgr.o ptmgr.o segmentmgr.o devicesegment.o basesegment.o
OBJS += block.o cpuid.o misc.o msghandler.o blockmsghdlr.o stacksegment.o
-OBJS += softpatch_p7.o barrier.o idebug.o
+OBJS += softpatch_p7.o barrier.o idebug.o intmsghandler.o
include ${ROOTPATH}/config.mk
diff --git a/src/kernel/start.S b/src/kernel/start.S
index 71f3b6db9..bcb770a58 100644
--- a/src/kernel/start.S
+++ b/src/kernel/start.S
@@ -151,7 +151,7 @@ STD_INTERRUPT(data_storage, 0x300)
STD_INTERRUPT(data_segment, 0x380)
STD_INTERRUPT(inst_storage, 0x400)
STD_INTERRUPT(inst_segment, 0x480)
-UNIMPL_INTERRUPT(external, 0x500)
+STD_INTERRUPT(external, 0x500)
STD_INTERRUPT(alignment, 0x600)
STD_INTERRUPT(prog_ex, 0x700)
STD_INTERRUPT(fp_unavail, 0x800)
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index 013ffc78c..561218b00 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -39,6 +39,7 @@
#include <kernel/vmmmgr.H>
#include <kernel/stacksegment.H>
#include <kernel/heapmgr.H>
+#include <kernel/intmsghandler.H>
extern "C"
void kernel_execute_decrementer()
@@ -121,8 +122,8 @@ namespace Systemcalls
&FutexWait, // FUTEX_WAIT
&FutexWake, // FUTEX_WAKE
- &Shutdown, // MISC_SHUTDOWN
- &CpuCoreType, // MISC_CPUCORETYPE
+ &Shutdown, // MISC_SHUTDOWN
+ &CpuCoreType, // MISC_CPUCORETYPE
&CpuDDLevel, // MISC_CPUDDLEVEL
&MmAllocBlock, // MM_ALLOC_BLOCK
@@ -246,16 +247,47 @@ namespace Systemcalls
}
static MessageQueue* msgQRoot = NULL;
+ static MessageQueue* msgQIntr = NULL;
void MsgQRegisterRoot(task_t* t)
{
- msgQRoot = (MessageQueue*) TASK_GETARG0(t);
- TASK_SETRTN(t, 0);
+ switch(TASK_GETARG0(t))
+ {
+ case MSGQ_ROOT_VFS:
+ msgQRoot = (MessageQueue*) TASK_GETARG1(t);
+ TASK_SETRTN(t,0);
+ break;
+
+ case MSGQ_ROOT_INTR:
+ msgQIntr = (MessageQueue*) TASK_GETARG1(t);
+ InterruptMsgHdlr::create(msgQIntr);
+ TASK_SETRTN(t,0);
+ break;
+
+ default:
+ printk("ERROR MsgRegisterRoot invalid type %ld\n",
+ TASK_GETARG0(t));
+ TASK_SETRTN(t,-EINVAL);
+ }
}
void MsgQResolveRoot(task_t* t)
{
- TASK_SETRTN(t, (uint64_t) msgQRoot);
+ switch(TASK_GETARG0(t))
+ {
+ case MSGQ_ROOT_VFS:
+ TASK_SETRTN(t, (uint64_t) msgQRoot);
+ break;
+
+ case MSGQ_ROOT_INTR:
+ TASK_SETRTN(t, (uint64_t) msgQIntr);
+ break;
+
+ default:
+ printk("ERROR MsgQResolveRoot invalid type %ld\n",
+ TASK_GETARG0(t));
+ TASK_SETRTN(t,0);
+ }
}
void MsgSend(task_t* t)
@@ -563,3 +595,4 @@ namespace Systemcalls
}
};
+
diff --git a/src/lib/syscall_misc.C b/src/lib/syscall_misc.C
index 26ecc9bfe..ac9070a40 100644
--- a/src/lib/syscall_misc.C
+++ b/src/lib/syscall_misc.C
@@ -43,3 +43,25 @@ uint8_t cpu_dd_level()
return reinterpret_cast<uint64_t>(_syscall0(MISC_CPUDDLEVEL));
}
+size_t cpu_thread_count()
+{
+ size_t threads = 0;
+ ProcessorCoreType core_type = cpu_core_type();
+ switch(core_type)
+ {
+ case CORE_POWER7:
+ case CORE_POWER7_PLUS:
+ threads = 4;
+ break;
+
+ case CORE_POWER8_SALERNO:
+ case CORE_POWER8_VENICE:
+ threads = 8;
+ break;
+
+ default:
+ break;
+ }
+ return threads;
+}
+
diff --git a/src/lib/syscall_msg.C b/src/lib/syscall_msg.C
index 08fafcbef..1b0ea500a 100644
--- a/src/lib/syscall_msg.C
+++ b/src/lib/syscall_msg.C
@@ -21,6 +21,7 @@
//
// IBM_PROLOG_END
#include <sys/msg.h>
+#include <sys/interrupt.h>
#include <sys/syscall.h>
#include <sys/vfs.h>
@@ -42,11 +43,20 @@ int msg_q_register(msg_q_t q, const char* name)
{
if (0 == strcmp(VFS_ROOT, name))
{
- return (int64_t)_syscall1(MSGQ_REGISTER_ROOT, q);
+ return (int64_t)_syscall2(MSGQ_REGISTER_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_VFS),
+ q);
+ }
+ else if (0 == strcmp(INTR_MSGQ, name))
+ {
+ return (int64_t)_syscall2(MSGQ_REGISTER_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_INTR),
+ q);
}
else
{
- msg_q_t vfsQ = (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
+ msg_q_t vfsQ = (msg_q_t)_syscall1(MSGQ_RESOLVE_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_VFS));
msg_t* msg = msg_allocate();
msg->type = VFS_MSG_REGISTER_MSGQ;
msg->data[0] = (uint64_t) q;
@@ -61,11 +71,18 @@ msg_q_t msg_q_resolve(const char* name)
{
if (0 == strcmp(VFS_ROOT, name))
{
- return (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
+ return (msg_q_t)_syscall1(MSGQ_RESOLVE_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_VFS));
+ }
+ else if (0 == strcmp(INTR_MSGQ, name))
+ {
+ return (msg_q_t)_syscall1(MSGQ_RESOLVE_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_INTR));
}
else
{
- msg_q_t vfsQ = (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
+ msg_q_t vfsQ = (msg_q_t)_syscall1(MSGQ_RESOLVE_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_VFS));
msg_t* msg = msg_allocate();
msg->type = VFS_MSG_RESOLVE_MSGQ;
msg->extra_data = (void*) name;
diff --git a/src/lib/syscall_task.C b/src/lib/syscall_task.C
index a00b779f7..d40136a21 100644
--- a/src/lib/syscall_task.C
+++ b/src/lib/syscall_task.C
@@ -80,7 +80,8 @@ tid_t task_exec(const char* file, void* ptr)
int rc = 0;
// Create message, send.
- msg_q_t vfsQ = (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
+ msg_q_t vfsQ = (msg_q_t)_syscall1(MSGQ_RESOLVE_ROOT,
+ reinterpret_cast<void*>(MSGQ_ROOT_VFS));
msg_t* msg = msg_allocate();
msg->type = VFS_MSG_EXEC;
msg->data[0] = (uint64_t) file;
diff --git a/src/makefile b/src/makefile
index 626f1b05c..019a8ac17 100644
--- a/src/makefile
+++ b/src/makefile
@@ -29,7 +29,7 @@ EXTRA_LIDS = dslid
BASE_OBJECTS = console.o spinlock.o string.o string_ext.o stdlib.o ctype.o \
assert.o stdio.o builtins.o vfs_init.o heapmgr.o pagemgr.o \
- math.o barrier.o idebug.o
+ math.o barrier.o idebug.o intmsghandler.o
DIRECT_BOOT_OBJECTS = start.o kernel.o taskmgr.o cpumgr.o syscall.o \
scheduler.o exception.o vmmmgr.o timemgr.o \
@@ -48,14 +48,14 @@ BASE_MODULES = trace errl devicefw scom xscom initservice taskargs \
pnor vfs
EXTENDED_MODULES = targeting ecmddatabuffer fapi hwp plat \
- extinitsvc istepdisp hwas fsi fsiscom i2c
+ extinitsvc istepdisp hwas fsi fsiscom i2c intr
DIRECT_BOOT_MODULES = example
RUNTIME_MODULES =
TESTCASE_MODULES = cxxtest testerrl testdevicefw testsyslib \
testscom testxscom testtargeting testinitservice testkernel \
testhwpf testecmddatabuffer initsvctasktest2 testcxxtest \
- testpnor testi2c testfsi testvfs testhwas
+ testpnor testi2c testfsi testvfs testhwas testintr
RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic
diff --git a/src/usr/initservice/extinitsvc/extinitsvctasks.H b/src/usr/initservice/extinitsvc/extinitsvctasks.H
index fb8dfa1a6..03bc232c8 100644
--- a/src/usr/initservice/extinitsvc/extinitsvctasks.H
+++ b/src/usr/initservice/extinitsvc/extinitsvctasks.H
@@ -170,6 +170,19 @@ const TaskInfo g_exttaskinfolist[] = {
// NOTE: libistepdisp.so needs to always be last in this list!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/**
+ * @brief External interrupt resource provider
+ */
+ {
+ "libintr.so", // tasknmae
+ NULL, // no ptr to fnct
+ {
+ START_TASK, // task type
+ EXT_IMAGE, // Extended Module
+ START_INTR_ERRL_ID, // module id
+ }
+ },
+
+ /**
* @brief IStep Dispatcher task, runs ISteps
*
*
diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C
new file mode 100644
index 000000000..d328c75ae
--- /dev/null
+++ b/src/usr/intr/intrrp.C
@@ -0,0 +1,600 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/intr/intrrp.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+/**
+ * @file intrrp.C
+ * @brief Interrupt Resource Provider
+ */
+
+#include "intrrp.H"
+#include <trace/interface.H>
+#include <errno.h>
+#include <initservice/taskargs.H>
+#include <util/singleton.H>
+#include <intr/intr_reasoncodes.H>
+#include <sys/mmio.h>
+#include <sys/misc.h>
+#include <kernel/console.H>
+#include <sys/task.h>
+#include <targeting/targetservice.H>
+#include <vmmconst.h>
+
+using namespace INTR;
+
+trace_desc_t * g_trac_intr = NULL;
+TRAC_INIT(&g_trac_intr, INTR_COMP_NAME, 2 * 1024);
+
+
+/**
+ * setup _start and handle barrier
+ */
+TASK_ENTRY_MACRO( IntrRp::init );
+
+
+void IntrRp::init( void * i_taskArgs )
+{
+ errlHndl_t err = NULL;
+ err = Singleton<IntrRp>::instance()._init();
+ INITSERVICE::TaskArgs* args =
+ static_cast<INITSERVICE::TaskArgs*>(i_taskArgs);
+ if(err)
+ {
+ args->postErrorLog(err);
+ }
+}
+
+
+// ICPBAR = INTP.ICP_BAR[0:25] in P7 = 0x3FBFF90 + (8*node) + procPos
+// P7 Scom address 0x02011C09 P8 = 0x020109c9
+// BaseAddress:
+// BA[18:43] = ICPBAR (P8 says [14:43] (30 bits))
+// BA[47:49] = COREid (0-7)
+// BA[50:51] = cpu thread (0-3)
+//
+// BA+0 = XIRR (poll - Read/Write has no side effects))
+// BA+4 = XIRR (Read locks HW, Write -> EOI to HW))
+// BA+12 = MFRR (1 byte)
+// BA+16 = LINKA (4 bytes)
+// BA+20 = LINKB (4 bytes)
+// BA+24 = LINKC (4 bytes)
+errlHndl_t IntrRp::_init()
+{
+ errlHndl_t err = NULL;
+
+ // TODO Temporaritly DISABLE in VBU until P8 support is added
+ TARGETING::EntityPath syspath(TARGETING::EntityPath::PATH_PHYSICAL);
+ syspath.addLast(TARGETING::TYPE_SYS,0);
+ TARGETING::Target* sys = TARGETING::targetService().toTarget(syspath);
+ uint8_t vpo_mode = 0;
+ if( sys
+ && sys->tryGetAttr<TARGETING::ATTR_IS_SIMULATION>(vpo_mode)
+ && (vpo_mode == 1) )
+ {
+ iv_isVBU = true;
+ }
+
+ // get the PIR
+ // Which ever cpu core this is running on is the MASTER cpu
+ // Make master thread 0
+ iv_masterCpu.word = task_getcpuid();
+ iv_masterCpu.threadId = 0;
+
+ uint64_t realAddr = 0;
+
+ // TODO Does the BAR scom reg need to be read here or set here??
+ // Who sets the BAR?
+ //uint64_t size = sizeof(realAddr);
+ //TARGETING::TargetService& targetService = TARGETING::targetService();
+ //TARGETING::Target* procTarget = NULL;
+ //targetService.masterProcChipTargetHandle( procTarget );
+ //
+ // TODO What if this does not jive with with the PIR?
+
+ // TODO Does this need to be read here?
+ //err = deviceRead(procTarget,
+ // &realAddr,
+ // size,
+ // DEVICE_SCOM_ADDRESS(ICPBAR_SCOM_ADDR));
+ //if(err) return err;
+
+ if(realAddr == 0)
+ {
+ realAddr = (static_cast<uint64_t>(ICPBAR_VAL)) << 34;
+ }
+
+ // TODO Does this need to be set here?
+ // err = deviceWrite(procTarget,
+ // &realAddr,
+ // size,
+ // DEVICE_SCOM_ADDRESS(ICPBAR_SCOM_ADDR));
+
+ realAddr &= 0xFFFFFFFC00000000ul; //[0:29] is ICP_BAR
+ realAddr >>= 14; //[14:43] is BAR field in real address
+
+
+ // The realAddr is the base address for the whole system.
+ // Therefore the realAddr must be based on the processor with
+ // lowest BAR value in the system. (usually n0p0)
+ // TODO Adjust the realAddr if the BAR came from a processor other
+ // than cpuid 0
+
+ TRACDCOMP(g_trac_intr,"INTR: realAddr = %lx",realAddr);
+
+ // VADDR_SIZE is 1MB per chip - max 32 -> 32MB
+ iv_baseAddr = reinterpret_cast<uint64_t>
+ (mmio_dev_map(reinterpret_cast<void*>(realAddr),THIRTYTWO_MB));
+
+ TRACDCOMP(g_trac_intr,"INTR: vAddr = %lx",iv_baseAddr);
+
+ err = checkAddress(iv_baseAddr);
+ if(!err)
+ {
+
+ // Set up the interrupt provider registers
+ // NOTE: Simics only supports 4 threads, and two cores per proc chip.
+ //
+ // NOTE: P7 register address format only supports 4 threads per core.
+ // This will change for P8
+ //
+ // NOTE: It's only possible to set up the master core at this point.
+ //
+ // Set up link registers to forward all intrpts to master cpu.
+ //
+ // There is one register set per cpu thread or 1024 register sets max.
+ size_t threads = cpu_thread_count();
+
+ if(threads > 4) //TODO remove when true P8 support is added
+ {
+ TRACFCOMP(g_trac_intr,
+ "I>intrrp needs to be updated to handle > 4 threads");
+ threads = 4;
+ }
+
+ PIR_t pir = iv_masterCpu;
+ for(size_t thread = 0; thread < threads; ++thread)
+ {
+ pir.threadId = thread;
+ initInterruptPresenter(pir);
+ }
+
+ // Get the kernel msg queue for ext intr
+ // Create a task to handle the messages
+ iv_msgQ = msg_q_create();
+ msg_q_register(iv_msgQ, INTR_MSGQ);
+
+ task_create(IntrRp::msg_handler, NULL);
+ }
+
+ return err;
+}
+
+errlHndl_t IntrRp::enableInterrupts()
+{
+ errlHndl_t err = NULL;
+
+ // TODO Temporarily DISABLE in VBU until P8 support is added
+ if(iv_isVBU) return err;
+
+ // Enable the interrupt on master processor core, thread 0
+ uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(iv_masterCpu);
+
+ err = checkAddress(baseAddr);
+ if(!err)
+ {
+ uint8_t * cppr = reinterpret_cast<uint8_t*>(baseAddr+CPPR_OFFSET);
+ *cppr = 0xff;
+ }
+
+ return err;
+}
+
+errlHndl_t IntrRp::disableInterrupts()
+{
+ errlHndl_t err = NULL;
+
+ // Disable the interrupt on master processor core, thread 0
+ // TODO Temporarily DISABLE in VBU until P8 support is added
+ if(iv_isVBU) return err;
+
+ uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(iv_masterCpu);
+
+ err = checkAddress(baseAddr);
+ if(!err)
+ {
+ uint8_t * cppr = reinterpret_cast<uint8_t*>(baseAddr+CPPR_OFFSET);
+ *cppr = 0;
+ }
+
+ return err;
+}
+
+/**
+ * Helper function to start the messge handler
+ */
+void IntrRp::msg_handler(void * unused)
+{
+ Singleton<IntrRp>::instance().msgHandler();
+}
+
+
+void IntrRp::msgHandler()
+{
+ while(1)
+ {
+ msg_t* msg = msg_wait(iv_msgQ); // wait for interrupt msg
+
+ switch(msg->type)
+ {
+ case MSG_INTR_EXTERN:
+ {
+ // Acknowlege msg
+ msg->data[1] = 0;
+ msg_respond(iv_msgQ, msg);
+
+ ext_intr_t type = NO_INTERRUPT;
+
+ // type = XISR = XIRR[8:31]
+ // priority = XIRR[0:7]
+ uint32_t * xirrAddress =
+ reinterpret_cast<uint32_t *>(iv_baseAddr+ XIRR_OFFSET+
+ cpuOffsetAddr(iv_masterCpu));
+
+ // xirr was read by interrupt message handler.
+ // Passed in as data[0]
+ uint32_t xirr = static_cast<uint32_t>(msg->data[0]);
+ type = static_cast<ext_intr_t>(xirr & 0x00FFFFFF);
+
+ TRACDCOMP(g_trac_intr,"External Interrupt recieved, Type=%x",type);
+
+ Registry_t::iterator r = iv_registry.find(type);
+ if(r != iv_registry.end())
+ {
+ msg_q_t msgQ = r->second;
+ msg_t * rmsg = msg_allocate();
+ rmsg->type = type;
+ int rc = msg_sendrecv(msgQ,rmsg);
+ if(rc)
+ {
+ TRACFCOMP(g_trac_intr,ERR_MRK
+ "External Interrupt recieved type = %d, "
+ "but could not send message to registered"
+ " handler. Ignorming it. rc = %d",
+ (uint32_t) type, rc);
+ }
+ }
+ else // no queue registered for this interrupt type
+ {
+ // Throw it away for now.
+ TRACFCOMP(g_trac_intr,ERR_MRK
+ "External Interrupt recieved type = %d, but "
+ "nothing registered to handle it. "
+ "Ignoreing it.",
+ (uint32_t)type);
+ }
+
+ // Writing the XIRR with the same value read earlier
+ // tells the interrupt presenter hardware to signal an EOI.
+ *xirrAddress = xirr;
+ }
+ break;
+
+ case MSG_INTR_REGISTER_MSGQ:
+ {
+ msg_q_t l_msgQ= reinterpret_cast<msg_q_t>(msg->data[0]);
+ ext_intr_t l_t= static_cast<ext_intr_t>(msg->data[1]);
+ errlHndl_t err = registerInterrupt(l_msgQ,l_t);
+
+ msg->data[1] = reinterpret_cast<uint64_t>(err);
+ msg_respond(iv_msgQ,msg);
+ }
+ break;
+
+ case MSG_INTR_ENABLE:
+ {
+ errlHndl_t err = enableInterrupts();
+ msg->data[1] = reinterpret_cast<uint64_t>(err);
+ msg_respond(iv_msgQ,msg);
+ }
+ break;
+
+ case MSG_INTR_DISABLE:
+ {
+ errlHndl_t err =disableInterrupts();
+ msg->data[1] = reinterpret_cast<uint64_t>(err);
+ msg_respond(iv_msgQ,msg);
+ }
+ break;
+
+ // Called when a new cpu becomes active other than the master
+ // Expect a call for each new core
+ case MSG_INTR_ADD_CPU_USR:
+ case MSG_INTR_ADD_CPU:
+ {
+ PIR_t pir = msg->data[0];
+
+ size_t threads = cpu_thread_count();
+
+ for(size_t thread = 0; thread < threads; ++thread)
+ {
+ pir.threadId = thread;
+ initInterruptPresenter(pir);
+ }
+
+ msg->data[1] = 0;
+ msg_respond(iv_msgQ, msg);
+ }
+ break;
+
+ default:
+ msg->data[1] = -EINVAL;
+ msg_respond(iv_msgQ, msg);
+ }
+ }
+}
+
+
+errlHndl_t IntrRp::registerInterrupt(msg_q_t i_msgQ, ext_intr_t i_type)
+{
+ errlHndl_t err = NULL;
+
+ Registry_t::iterator r = iv_registry.find(i_type);
+ if(r == iv_registry.end())
+ {
+ iv_registry[i_type] = i_msgQ;
+ }
+ else
+ {
+ if(r->second != i_msgQ)
+ {
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR_MODULE_ID
+ * @reasoncode INTR_ALREADY_REGISTERED
+ * @userdata1 Interrupt type
+ * @userdata2 0
+ *
+ * @defdesc Interrupt type already registered
+ *
+ */
+ err = new ERRORLOG::ErrlEntry
+ (
+ ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity
+ INTR::INTR_MODULE_ID, // moduleid
+ INTR::INTR_ALREADY_REGISTERED, // reason code
+ i_type,
+ 0
+ );
+ }
+
+ }
+ return err;
+}
+
+void IntrRp::initInterruptPresenter(const PIR_t i_pir) const
+{
+ // TODO Temporaritly DISABLE in VBU until P8 support is added
+ if(iv_isVBU) return;
+
+ TARGETING::EntityPath syspath(TARGETING::EntityPath::PATH_PHYSICAL);
+ syspath.addLast(TARGETING::TYPE_SYS,0);
+ TARGETING::Target* sys = TARGETING::targetService().toTarget(syspath);
+ uint8_t vpo_mode = 0;
+ if( sys
+ && sys->tryGetAttr<TARGETING::ATTR_IS_SIMULATION>(vpo_mode)
+ && (vpo_mode == 1) )
+ {
+ return;
+ }
+
+ uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(i_pir);
+ uint8_t * cppr =
+ reinterpret_cast<uint8_t*>(baseAddr + CPPR_OFFSET);
+ uint32_t * plinkReg =
+ reinterpret_cast<uint32_t *>(baseAddr + LINKA_OFFSET);
+
+ TRACDCOMP(g_trac_intr,"PIR 0x%x offset: 0x%lx",
+ i_pir.word,
+ cpuOffsetAddr(i_pir));
+ if(i_pir.word == iv_masterCpu.word)
+ {
+ *cppr = 0xff;
+ }
+ else
+ {
+ *cppr = 0; // no interrupts allowed except on master
+ }
+
+ // Links are intended to be set up in rings. If an interrupt ends up
+ // where it started, it gets rejected by hardware.
+ //
+ // According to BOOK IV, The links regs are setup by firmware.
+ //
+ // Should be possible to link all interrupt forwarding directly to
+ // the master core and either make them direct (lspec = 0) or by setting
+ // the LOOPTRIP bit to stop the forwarding at the masterProc.
+ //
+ LinkReg_t linkReg;
+ linkReg.word = 0;
+ linkReg.loopTrip = 1; // needed?
+ linkReg.pchip= (iv_masterCpu.nodeId*8)+iv_masterCpu.chipId;
+ linkReg.pcore= iv_masterCpu.coreId;
+ linkReg.tspec= iv_masterCpu.threadId;
+
+ *(plinkReg) = linkReg.word;
+ *(plinkReg + 1) = linkReg.word;
+ linkReg.last = 1;
+ *(plinkReg + 2) = linkReg.word;
+}
+
+
+errlHndl_t IntrRp::checkAddress(uint64_t i_addr)
+{
+ errlHndl_t err = NULL;
+
+ if(i_addr < VMM_VADDR_DEVICE_SEGMENT)
+ {
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR_MODULE_ID
+ * @reasoncode INTR_BAD_VIRTUAL_IO_ADDRESS
+ * @userdata1 The bad virtual address
+ * @userdata2 0
+ *
+ * @defdesc The virutal address is not a valid IO address
+ *
+ */
+ err = new ERRORLOG::ErrlEntry
+ (
+ ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ INTR::INTR_MODULE_ID,
+ INTR::INTR_BAD_VIRTUAL_IO_ADDRESS,
+ i_addr,
+ 0
+ );
+ }
+
+ return err;
+}
+
+
+// Register a message queue with a particular intr type
+errlHndl_t INTR::registerMsgQ(msg_q_t i_msgQ, ext_intr_t i_type)
+{
+ errlHndl_t err = NULL;
+ // Can't add while handling an interrupt, so
+ // send msg instead of direct call
+ msg_q_t intr_msgQ = msg_q_resolve(INTR_MSGQ);
+ if(intr_msgQ)
+ {
+ msg_t * msg = msg_allocate();
+ msg->type = MSG_INTR_REGISTER_MSGQ;
+ msg->data[0] = reinterpret_cast<uint64_t>(i_msgQ);
+ msg->data[1] = static_cast<uint64_t>(i_type);
+
+ msg_sendrecv(intr_msgQ, msg);
+ err = reinterpret_cast<errlHndl_t>(msg->data[1]);
+ }
+ else
+ {
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR_MODULE_ID
+ * @reasoncode INTR_REGISTRY_NOT_READY
+ * @userdata1 Interrupt type to register
+ * @userdata2 0
+ *
+ * @defdesc Interrupt resource provider not initialized yet.
+ *
+ */
+ err = new ERRORLOG::ErrlEntry
+ (
+ ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity
+ INTR::INTR_MODULE_ID, // moduleid
+ INTR::INTR_REGISTRY_NOT_READY, // reason code
+ static_cast<uint64_t>(i_type),
+ 0
+ );
+ }
+ return err;
+}
+
+/*
+ * Enable hardware to report external interrupts
+ */
+errlHndl_t INTR::enableExternalInterrupts()
+{
+ errlHndl_t err = NULL;
+ msg_q_t intr_msgQ = msg_q_resolve(INTR_MSGQ);
+ if(intr_msgQ)
+ {
+ msg_t * msg = msg_allocate();
+ msg->type = MSG_INTR_ENABLE;
+
+ msg_sendrecv(intr_msgQ, msg);
+
+ err = reinterpret_cast<errlHndl_t>(msg->data[1]);
+ }
+ else
+ {
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR_MODULE_ID
+ * @reasoncode INTR_RP_NOT_INITIALIZED
+ * @userdata1 MSG_INTR_ENABLE
+ * @userdata2 0
+ *
+ * @defdesc Interrupt resource provider not initialized yet.
+ *
+ */
+ err = new ERRORLOG::ErrlEntry
+ (
+ ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity
+ INTR::INTR_MODULE_ID, // moduleid
+ INTR::INTR_RP_NOT_INITIALIZED, // reason code
+ static_cast<uint64_t>(MSG_INTR_ENABLE),
+ 0
+ );
+ }
+ return err;
+}
+
+/*
+ * Disable hardware from reporting external interrupts
+ */
+errlHndl_t INTR::disableExternalInterrupts()
+{
+ errlHndl_t err = NULL;
+ // Can't disable while handling interrupt, so send msg to serialize
+ msg_q_t intr_msgQ = msg_q_resolve(INTR_MSGQ);
+ if(intr_msgQ)
+ {
+ msg_t * msg = msg_allocate();
+ msg->type = MSG_INTR_DISABLE;
+
+ msg_sendrecv(intr_msgQ, msg);
+
+ err = reinterpret_cast<errlHndl_t>(msg->data[1]);
+ }
+ else
+ {
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR_MODULE_ID
+ * @reasoncode INTR_RP_NOT_INITIALIZED
+ * @userdata1 MSG_INTR_DISABLE
+ * @userdata2 0
+ *
+ * @defdesc Interrupt resource provider not initialized yet.
+ *
+ */
+ err = new ERRORLOG::ErrlEntry
+ (
+ ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity
+ INTR::INTR_MODULE_ID, // moduleid
+ INTR::INTR_RP_NOT_INITIALIZED, // reason code
+ static_cast<uint64_t>(MSG_INTR_DISABLE),
+ 0
+ );
+ }
+ return err;
+}
+
diff --git a/src/usr/intr/intrrp.H b/src/usr/intr/intrrp.H
new file mode 100644
index 000000000..6c54cf993
--- /dev/null
+++ b/src/usr/intr/intrrp.H
@@ -0,0 +1,191 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/intr/intrrp.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef INTRRP_H
+#define INTRRP_H
+
+#include <stdint.h>
+#include <builtins.h>
+#include <limits.h>
+#include <errl/errltypes.H>
+#include <sys/msg.h>
+#include <intr/interrupt.H>
+#include <map>
+
+struct msg_t;
+
+namespace INTR
+{
+ class IntrRp
+ {
+ public:
+
+ /**
+ * Prepare HW and system to recieve external interrupts
+ * @param[in] task args
+ */
+ static void init(void * i_taskArgs);
+
+ protected:
+
+ /**
+ * Constructor
+ */
+ IntrRp() :
+ iv_msgQ(NULL),
+ iv_baseAddr(0),
+ iv_masterCpu(0),
+ iv_isVBU(false) {}
+
+ /**
+ * Destructor
+ */
+ ~IntrRp() {}
+
+ /**
+ * Start message handler
+ */
+ static void msg_handler(void * unused);
+
+ private: //Data
+
+ enum
+ {
+ CPPR_OFFSET = 4, //!< offset to CPPR (1 byte)
+ XIRR_OFFSET = 4, //!< offset to XIRR (4 bytes)
+ LINKA_OFFSET = 16, //!< offset to LINKA register
+ LINKB_OFFSET = 20, //!< offset to LINKB register
+ LINKC_OFFSET = 24, //!< offset to LINKC register
+ };
+
+ // If the interrupt can't be handled by the current chip there are
+ // three link registers used provide targets to forward the
+ // interrupt to.
+ struct LinkReg_t
+ {
+ union
+ {
+ uint32_t word;
+ struct
+ {
+ uint32_t last:1; //!< RO, 0 means last reg
+ uint32_t loopTrip:1; //!< Stop forwarding
+ uint32_t reserved:17;//!< Not implemented
+ uint32_t pchip:6; //!< Target chip
+ uint32_t pcore:3; //!< Target core
+ uint32_t tspec:2; //!< Target tread
+ uint32_t lspec:2; //!< Target link register
+ } PACKED;
+ };
+ };
+
+ /**
+ * cpu PIR register
+ * @note TODO P7 bits - thread 2, core 3, chip 2, node 3,
+ * P8 will be different. Need P8 book IV
+ */
+ struct PIR_t
+ {
+ union
+ {
+ uint32_t word;
+ struct
+ {
+ uint32_t reserved:22; //!< zeros
+ uint32_t nodeId:3; //!< node (4)
+ uint32_t chipId:2; //!< chip pos on node (8)
+ uint32_t coreId:3; //!< Core number (12)
+ uint32_t threadId:2; //!< thread number (8)
+ } PACKED;
+ };
+ PIR_t(uint32_t i_word) : word(i_word) {}
+ };
+
+
+ typedef std::map<ext_intr_t,msg_q_t> Registry_t;
+
+
+ msg_q_t iv_msgQ; //!< Kernel Interrupt message queue
+ Registry_t iv_registry; //!< registered interrupt type
+ uint64_t iv_baseAddr; //!< Base address of hw INTR regs
+ PIR_t iv_masterCpu; //!< Master cpu PIR
+ bool iv_isVBU; //!< TODO Don't run on VBU for now
+
+
+ private: //functions
+
+ errlHndl_t _init();
+
+ /**
+ * Message handler
+ */
+ void msgHandler();
+
+ /**
+ * Register a message queue for an interrupt type
+ * @param[in] i_msgQ The message queue
+ * @param[in] i_type the interrupt type
+ */
+ errlHndl_t registerInterrupt(msg_q_t i_msgQ, ext_intr_t i_type);
+
+ /**
+ * Enable hardware to reporting external interrupts
+ */
+ errlHndl_t enableInterrupts();
+
+ /**
+ * Disable hardware from reporting external interupts
+ */
+ errlHndl_t disableInterrupts();
+
+ /**
+ * Initialize the interrupt presenter registers
+ * @param[in] i_pir PIR value for the presenter
+ */
+ void initInterruptPresenter(const PIR_t i_pir) const;
+
+ /**
+ * Calculate the adress offset for the given cpu
+ * @param[in] i_pir PIR value for the presenter
+ * @return the offset
+ */
+ ALWAYS_INLINE
+ uint64_t cpuOffsetAddr(const PIR_t i_pir) const
+ {
+ uint64_t offset = (i_pir.nodeId * 8) + i_pir.chipId;
+ offset <<= 20;
+ offset |= static_cast<uint64_t>(i_pir.coreId) << 14;
+ offset |= static_cast<uint64_t>(i_pir.threadId) << 12;
+ return offset;
+ }
+
+ /**
+ * Validity check for an I/O address
+ * @param[in] i_addr the address
+ * @return error log if not valid
+ */
+ static errlHndl_t checkAddress(uint64_t i_addr);
+
+ };
+}; // INTR namespace
+
+#endif
diff --git a/src/usr/intr/makefile b/src/usr/intr/makefile
new file mode 100644
index 000000000..e9b520654
--- /dev/null
+++ b/src/usr/intr/makefile
@@ -0,0 +1,30 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/intr/makefile $
+#
+# IBM CONFIDENTIAL
+#
+# COPYRIGHT International Business Machines Corp. 2011
+#
+# p1
+#
+# Object Code Only (OCO) source materials
+# Licensed Internal Code Source Materials
+# IBM HostBoot Licensed Internal Code
+#
+# The source code for this program is not published or other-
+# wise divested of its trade secrets, irrespective of what has
+# been deposited with the U.S. Copyright Office.
+#
+# Origin: 30
+#
+# IBM_PROLOG_END
+ROOTPATH = ../../..
+MODULE = intr
+
+OBJS = intrrp.o
+
+SUBDIRS = test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/intr/test/intrtest.H b/src/usr/intr/test/intrtest.H
new file mode 100644
index 000000000..9c0d4e412
--- /dev/null
+++ b/src/usr/intr/test/intrtest.H
@@ -0,0 +1,221 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/intr/test/intrtest.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef __INTRTEST_H
+#define __INTRTEST_H
+
+#include <cxxtest/TestSuite.H>
+#include <intr/interrupt.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <kernel/console.H>
+#include <targeting/targetservice.H>
+
+
+class IntrTest: public CxxTest::TestSuite
+{
+ public:
+ /**
+ * @brief INTR test setup values
+ */
+ void test_verifyState( void )
+ {
+
+ // TODO Temporaritly DISABLE in VBU until P8 support is added
+ TARGETING::EntityPath syspath(TARGETING::EntityPath::PATH_PHYSICAL);
+ syspath.addLast(TARGETING::TYPE_SYS,0);
+ TARGETING::Target* sys = TARGETING::targetService().toTarget(syspath);
+ uint8_t vpo_mode = 0;
+ if( sys
+ && sys->tryGetAttr<TARGETING::ATTR_IS_SIMULATION>(vpo_mode)
+ && (vpo_mode == 1) )
+ {
+ return;
+ }
+
+ // Add support for second chip (dummy)
+ uint32_t fake_pir = 0x00000001 << 5; // P7 chip 1 TODO P8=?
+ msg_q_t intr_msgQ = msg_q_resolve(INTR_MSGQ);
+ msg_t * msg = msg_allocate();
+ msg->type = INTR::MSG_INTR_ADD_CPU_USR;
+ msg->data[0] = fake_pir;
+
+ msg_sendrecv(intr_msgQ, msg);
+
+ // all the simics registers
+ for(uint64_t chip = 0; chip < 4; ++chip)
+ {
+ // simics P7 only supports 4 threads per core
+ // and 2 cores - let the thread field overflow
+ // into the core field -> 2 cores x 4 threads = 8 threads
+ for(uint64_t thread = 0; thread < 8; ++thread)
+ {
+ uint64_t offset = (chip << 20) | (thread << 12);
+
+ uint32_t * addr =
+ reinterpret_cast<uint32_t *>(cv_baseAddr + offset);
+
+ if(offset == 0) // Master cpu
+ {
+ if(*addr != 0xFF000000)
+ {
+ TS_FAIL
+ ("INTR:Master cpu not initialized-XIRR=0x%08x",
+ *addr);
+ }
+ }
+
+ if (chip < 2 && thread < 4) // TODO Change when all threads supported
+ {
+ if(offset != 0 && *addr != 0)
+ {
+ TS_FAIL("INTR:Chip %ld Thread %ld bad XIRR=0x%08x",
+ chip,thread,*addr);
+ }
+
+
+
+ if(*(addr+4) != 0x40000000 ||
+ *(addr+5) != 0x40000000 ||
+ *(addr+6) != 0xC0000000)
+ {
+ TS_FAIL("INTR:Chip %ld Thread %ld bad LINKS"
+ " 0x%08x 0x%08x 0x%08x",
+ chip,thread,
+ *(addr+4),*(addr+5),*(addr+6));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @brief Disable then Enable interrupt handling
+ */
+ void test_enableDisable( void )
+ {
+ // TODO Temporaritly DISABLE in VBU until P8 support is added
+ TARGETING::EntityPath syspath(TARGETING::EntityPath::PATH_PHYSICAL);
+ syspath.addLast(TARGETING::TYPE_SYS,0);
+ TARGETING::Target* sys = TARGETING::targetService().toTarget(syspath);
+ uint8_t vpo_mode = 0;
+ if( sys
+ && sys->tryGetAttr<TARGETING::ATTR_IS_SIMULATION>(vpo_mode)
+ && (vpo_mode == 1) )
+ {
+ return;
+ }
+
+ uint32_t * addr = reinterpret_cast<uint32_t *>(cv_baseAddr);
+
+ errlHndl_t err = INTR::disableExternalInterrupts();
+
+ if(err)
+ {
+ TS_FAIL("INTR::disableExternalInterrupts returned error log");
+ delete err;
+ err = NULL;
+ }
+
+ if((*addr & 0xFF000000) != 0)
+ {
+ TS_FAIL("INTR not disabled");
+ }
+
+ err = INTR::enableExternalInterrupts();
+
+ if(err)
+ {
+ TS_FAIL("INTR::enableExternalInterrupts returned error log");
+ delete err;
+ err = NULL;
+ }
+
+
+ if((*addr & 0xFF000000) != 0xFF000000)
+ {
+ TS_FAIL("INTR not enabled");
+ }
+ }
+
+ /**
+ * @brief Register an interrupt message queue, force an interrupt,
+ * then handle the interrupt.
+ */
+ void test_intr( void )
+ {
+ // Injecting interproc interrupt seems to work sometimes and not others
+ // TODO need to investigate.
+#ifdef __NOT_NOW__
+ // TODO Temporaritly DISABLE in VBU until P8 support is added
+ TARGETING::EntityPath syspath(TARGETING::EntityPath::PATH_PHYSICAL);
+ syspath.addLast(TARGETING::TYPE_SYS,0);
+ TARGETING::Target* sys = TARGETING::targetService().toTarget(syspath);
+ uint8_t vpo_mode = 0;
+ if( sys
+ && sys->tryGetAttr<TARGETING::ATTR_IS_SIMULATION>(vpo_mode)
+ && (vpo_mode == 1) )
+ {
+ return;
+ }
+
+ extern trace_desc_t * g_trac_intr;
+
+ errlHndl_t err = NULL;
+
+ // Need to register a msgq
+ msg_q_t msgQ = msg_q_create();
+ err = INTR::registerMsgQ(msgQ,INTR::INTERPROC);
+ if(err)
+ {
+ TS_FAIL("Errl from INTR::registerMsgQ()");
+ delete err;
+ err = NULL;
+ }
+
+ // Force an interrupt by writing to the MFFR on master
+ volatile uint8_t * mfrr =
+ reinterpret_cast<uint8_t *>(cv_baseAddr+12);
+ *(mfrr) = 0x55;
+ *(mfrr) = 0xff;
+
+ msg_t* msg = msg_wait(msgQ); // wait for interrupt msg
+ TRACFCOMP(g_trac_intr,"Interrupt handled! Type=%lx",msg->type);
+ if(msg->type != INTR::INTERPROC)
+ {
+ TS_FAIL("INTR::unexpected interrupt type %lx",msg->type);
+ }
+ msg_respond(msgQ,msg);
+#endif
+ }
+
+
+ private:
+
+ static uint64_t cv_baseAddr;
+};
+
+uint64_t IntrTest::cv_baseAddr = 0x20000000000ul;
+
+
+#endif
+
diff --git a/src/usr/intr/test/makefile b/src/usr/intr/test/makefile
new file mode 100644
index 000000000..8923d526a
--- /dev/null
+++ b/src/usr/intr/test/makefile
@@ -0,0 +1,29 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/intr/test/makefile $
+#
+# IBM CONFIDENTIAL
+#
+# COPYRIGHT International Business Machines Corp. 2011
+#
+# p1
+#
+# Object Code Only (OCO) source materials
+# Licensed Internal Code Source Materials
+# IBM HostBoot Licensed Internal Code
+#
+# The source code for this program is not published or other-
+# wise divested of its trade secrets, irrespective of what has
+# been deposited with the U.S. Copyright Office.
+#
+# Origin: 30
+#
+# IBM_PROLOG_END
+ROOTPATH = ../../../..
+
+MODULE = testintr
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
+
diff --git a/src/usr/makefile b/src/usr/makefile
index 10c88e94f..d9089f4d6 100644
--- a/src/usr/makefile
+++ b/src/usr/makefile
@@ -26,6 +26,7 @@ OBJS = module_init.o
SUBDIRS = example.d trace.d cxxtest.d testcore.d errl.d devicefw.d \
scom.d xscom.d targeting.d initservice.d hwpf.d \
- ecmddatabuffer.d pnor.d i2c.d vfs.d fsi.d hwas.d fsiscom.d
+ ecmddatabuffer.d pnor.d i2c.d vfs.d fsi.d hwas.d fsiscom.d \
+ intr.d
include ${ROOTPATH}/config.mk
diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C
index e39f49758..3b2e5cc0e 100644
--- a/src/usr/pnor/pnorrp.C
+++ b/src/usr/pnor/pnorrp.C
@@ -329,7 +329,7 @@ errlHndl_t PnorRP::readTOC()
// put some random sizes in here
iv_TOC[PNOR::SIDE_A][PNOR::TOC].size = 8 + 8 + PNOR::NUM_SECTIONS*sizeof(TOCEntry_t);
- iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].size = 500*1024; //500K
+ iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].size = 700*KILOBYTE; //700K
iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].size = PAGESIZE; //4K
iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].size = 128*KILOBYTE; //128K
diff --git a/src/usr/pnor/test/pnorrptest.H b/src/usr/pnor/test/pnorrptest.H
index 9f562a590..3bd139238 100644
--- a/src/usr/pnor/test/pnorrptest.H
+++ b/src/usr/pnor/test/pnorrptest.H
@@ -64,12 +64,12 @@ class PnorRpTest : public CxxTest::TestSuite
};
const ExpVals_t exp_data[] = {
/* TOC */ { 0x690, 0x80000000 },
- /* GLOBAL_DATA */ { PAGESIZE, 0x8007D690 },
+ /* GLOBAL_DATA */ { PAGESIZE, 0x800AF690 },
/* SBE_IPL */ { 0, 0 },
/* HB_BASE_CODE */ { 0, 0 },
- /* HB_DATA */ { 128*KILOBYTE, 0x8007E690 },
+ /* HB_DATA */ { 128*KILOBYTE, 0x800B0690 },
/* HB_ERRLOGS */ { 0, 0 },
- /* HB_EXT_CODE */ { 0x7D000, 0x80000690 },
+ /* HB_EXT_CODE */ { 0xAF000, 0x80000690 },
/* HB_RUNTIME */ { 0, 0 },
/* PAYLOAD */ { 0, 0 },
/* PFW_LITE_CODE */ { 0, 0 },
OpenPOWER on IntegriCloud