diff options
Diffstat (limited to 'src')
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 }, |