summaryrefslogtreecommitdiffstats
path: root/src/kernel/intmsghandler.C
blob: b7b86c2f5332a9ff9b9b5a4029699c7c459dcd19 (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
//  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;
}

OpenPOWER on IntegriCloud