summaryrefslogtreecommitdiffstats
path: root/src/kernel/ipc.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/ipc.C')
-rw-r--r--src/kernel/ipc.C97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/kernel/ipc.C b/src/kernel/ipc.C
new file mode 100644
index 000000000..3f522c4ee
--- /dev/null
+++ b/src/kernel/ipc.C
@@ -0,0 +1,97 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/kernel/ipc.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* 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 otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include <arch/ppc.H>
+#include <kernel/ipc.H>
+#include <kernel/cpu.H>
+#include <kernel/intmsghandler.H>
+#include <kernel/console.H>
+
+using namespace KernelIpc;
+
+namespace KernelIpc
+{
+ void send(uint64_t i_q, msg_t * i_msg);
+};
+
+/**
+ * IPC communication area. Interrupt service provider initializes.
+ * @see intrrp.C
+ */
+KernelIpc::ipc_data_area_t KernelIpc::ipc_data_area;
+
+// Put the IPC message in the other nodes memory space
+// Two potential issues:
+// 1. The destination node is not there - memory location is nonexistant.
+// 2. The destination node never responds, potentially hanging this thread.
+void KernelIpc::send(uint64_t i_q, msg_t * i_msg)
+{
+ // @note
+ // Point to memory in the destination image.
+ // All host boot images are assured to be at the same code level.
+ // PIR node and physical node are not always the same. For instance a
+ // single node system with an alt-master could be designed such that the
+ // alt-master were on a different logical (power bus numbering) node.
+ // Since it's not in plan to use this IPC mechanism in a single node
+ // system, this case will ge ignored for now.
+ uint64_t this_node = getPIR()/KERNEL_MAX_SUPPORTED_CPUS_PER_NODE;
+ uint64_t hrmor_offset = getHRMOR()-(this_node*(ipc_data_area.hrmor_base));
+ uint64_t dest_node = (i_q >> 32) & 0x07;
+ uint64_t dest_hrmor = (ipc_data_area.hrmor_base*dest_node) + hrmor_offset;
+
+ uint64_t dest_addr = reinterpret_cast<uint64_t>(&ipc_data_area);
+ dest_addr += dest_hrmor;
+ dest_addr |= 0x8000000000000000ul;
+
+ printkd("IPC Dest addr %lx\n",dest_addr);
+
+ // pointer to the ipc_data_area in the destination node
+ ipc_data_area_t * p_dest =
+ reinterpret_cast<ipc_data_area_t*>(dest_addr);
+
+ // get lock on IPC data area in other node
+ while(false == __sync_bool_compare_and_swap(&(p_dest->msg_queue_id),
+ 0,
+ 0xFFFFFFFFFFFFFFFFul))
+ {
+ setThreadPriorityLow();
+ }
+ setThreadPriorityHigh();
+
+ p_dest->msg_payload = *i_msg; // copy in message
+ lwsync();
+
+ p_dest->msg_queue_id = i_q; // set destination queue id
+ lwsync();
+
+ // send IPI
+ InterruptMsgHdlr::sendIPI(p_dest->pir);
+
+ // The message allocation is freed here to make msg_send for IPC
+ // messages behave the same as non-IPC msg_send; that is, the message
+ // is freed by the consumer; however, i_msg was allocated in user space
+ // code and freed here in kernel space. The assumption is that this is OK.
+ msg_free(i_msg);
+
+ return;
+}
+
OpenPOWER on IntegriCloud