summaryrefslogtreecommitdiffstats
path: root/src/occ_gpe0/gpe0_main.c
blob: ada93fad72e8e587649d55530ba488ff43146d96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/occ_gpe0/gpe0_main.c $                                    */
/*                                                                        */
/* OpenPOWER OnChipController Project                                     */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/// \file gpe0_main.c
/// \brief Sample program that creates and starts a thread
///
/// This file demonstrates how to create a thread and run it.  It also provides
/// an example of how to add traces to the code.

#include "pk.h"
#include "ipc_api.h"
#include "ipc_ping.h"

#define KERNEL_STACK_SIZE  256
#define MAIN_THREAD_STACK_SIZE 512

uint8_t        G_kernel_stack[KERNEL_STACK_SIZE];
uint8_t        G_main_thread_stack[MAIN_THREAD_STACK_SIZE];
PkThread       G_main_thread;

//statically initialize a ping command message
IPC_PING_CMD_CREATE(G_ping_cmd);

//statically initialize an IPC message queue
IPC_MSGQ_CREATE(G_gpe0_test_msgq0);

//statically initialize an IPC message queue message.  Responses to
//this message will automatically be placed on the message queue.
IPC_MSGQ_MSG_CREATE(G_test_msg, IPC_ST_TEST_FUNC0, &G_gpe0_test_msgq0);


// Continuously ping each OCC instance
void main_thread(void* arg)
{
    uint8_t     instance;
    int         rc;
    int         func_id;
    ipc_msg_t   *test_msg;

    PK_TRACE("thread started");

    PK_TRACE("Waiting for ping response from all instances");
    for(instance = 0; instance < OCCHW_MAX_INSTANCES; instance++)
    {
        // Wait for each instance (including self) to start accepting IPC commands
        do
        {
            pk_sleep(PK_MILLISECONDS(10));
            rc = ipc_ping(&G_ping_cmd, instance);
        }while(rc == IPC_RC_TARGET_BLOCKED);

        if(rc && rc != IPC_RC_TARGET_BLOCKED)
        {
            PK_TRACE("phase 1 ipc_ping(%u) failed with rc = 0x%08x", instance, rc);
            PK_TRACE_BIN("G_ping_cmd:", &G_ping_cmd, sizeof(G_ping_cmd));
            pk_halt();
        }
        PK_TRACE("Ping response received from instance(%d)", instance);
    }

    PK_TRACE("Starting infinite loop test");
    while(1)
    {
        for(instance = 0; instance < OCCHW_MAX_INSTANCES; instance++)
        {
            // Ping each instance (including ourself)
            rc = ipc_ping(&G_ping_cmd, instance);
            if(rc)
            {
                PK_TRACE("phase 2 ipc_ping(%u) failed with rc = 0x%08x", instance, rc);
                PK_TRACE_BIN("G_ping_cmd:", &G_ping_cmd, sizeof(G_ping_cmd));
                pk_halt();
            }
        }

        // Send an IPC_ST_TEST_FUNC0 message (to ourselves) if the message
        // isnt' already in-flight.
        if(ipc_is_free(&G_test_msg))
        {
            rc = ipc_send_cmd(&G_test_msg);
            if(rc)
            {
                pk_halt();
            }
        }

        // wait for a IPC_ST_TEST_FUNC0 command or response message to arrive
        rc = ipc_msgq_recv(&test_msg, &G_gpe0_test_msgq0, PK_MILLISECONDS(1));
        if(!rc)
        {
            //verify that the command message type is what we expected
            func_id = ipc_get_funcid(test_msg);
            if(func_id != IPC_ST_TEST_FUNC0)
            {
                //unexpected func id
                //(probably caused by a mismatch between function table
                // and function id ordering)
                rc = ipc_send_rsp(test_msg, IPC_RC_CMD_NOT_SUPPORTED);
            }
            else
            {
                //Is this a response to the message we sent to ourselves?
                if(ipc_is_a_response(test_msg))
                {
                    //check that the remote end was successful
                    if(ipc_get_rc(test_msg) != IPC_RC_SUCCESS)
                    {
                        pk_halt();
                    }
                    //free up the message for sending again
                    ipc_free_msg(test_msg);
                }
                else
                {
                    //successfully recieved the command message.
                    //Send a response message back.
                    rc = ipc_send_rsp(test_msg, IPC_RC_SUCCESS);
                }
            }
            if(rc)
            {
                //failed to send the response back
                pk_halt();
            }
        }
        else
        {
            //Unless it's a timeout, a non-zero rc is an error
            if(rc != IPC_RC_TIMEOUT)
            {
                //Failure encountered while waiting for a new message
                pk_halt();
            }
        }
        pk_sleep(PK_MILLISECONDS(1));
    }
}

// The main function is called by the boot code (after initializing some
// registers)
int main(int argc, char **argv)
{
    int rc;

    // initializes kernel data (stack, threads, timebase, timers, etc.)
    pk_initialize((PkAddress)G_kernel_stack,
                  KERNEL_STACK_SIZE,
                  PK_TIMEBASE_CONTINUES,
                  PPE_TIMEBASE_HZ);

    PK_TRACE("Kernel init completed");

    // Disable IPC's and register the IPC interrupt handler 
    rc = ipc_init();
    if(rc)
    {
        PK_TRACE("ipc_init failed with rc = 0x%08x", rc);
        pk_halt();
    }

    // enable IPC's
    rc = ipc_enable();
    if(rc)
    {
        PK_TRACE("ipc_enable failed with rc = 0x%08x", rc);
        pk_halt();
    }

    //Initialize the thread control block for G_main_thread
    pk_thread_create(&G_main_thread,
                      (PkThreadRoutine)main_thread,
                      (void*)NULL,
                      (PkAddress)G_main_thread_stack,
                      (size_t)MAIN_THREAD_STACK_SIZE,
                      (PkThreadPriority)1);

    //PK_TRACE_BIN("G_main_thread", &G_main_thread, sizeof(G_main_thread));

    //Make G_main_thread runnable
    pk_thread_resume(&G_main_thread);

    PK_TRACE("Starting thread(s)");

    // Start running the highest priority thread.
    // This function never returns
    pk_start_threads();
    
    return 0;
}
OpenPOWER on IntegriCloud