aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.24-sparse/arch/xeno/kernel/hypervisor.c
blob: 3f414e98762c8fb1f1af07e509bbfb5b03d60c7b (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
/******************************************************************************
 * hypervisor.c
 * 
 * Communication to/from hypervisor.
 * 
 * Copyright (c) 2002, K A Fraser
 */

#include <linux/config.h>
#include <asm/atomic.h>
#include <linux/irq.h>
#include <asm/hypervisor.h>
#include <asm/system.h>
#include <asm/ptrace.h>

multicall_entry_t multicall_list[8];
int nr_multicall_ents = 0;

static unsigned long event_mask = 0;

void frobb(void) {}

void do_hypervisor_callback(struct pt_regs *regs)
{
    unsigned long events, flags;
    shared_info_t *shared = HYPERVISOR_shared_info;

    do {
        /* Specialised local_irq_save(). */
        flags = test_and_clear_bit(EVENTS_MASTER_ENABLE_BIT, 
                                   &shared->events_mask);
        barrier();

        events  = xchg(&shared->events, 0);
        events &= event_mask;

        __asm__ __volatile__ (
            "   push %1                            ;"
            "   sub  $4,%%esp                      ;"
            "   jmp  2f                            ;"
            "1: btrl %%eax,%0                      ;" /* clear bit     */
            "   mov  %%eax,(%%esp)                 ;"
            "   call do_IRQ                        ;" /* do_IRQ(event) */
            "2: bsfl %0,%%eax                      ;" /* %eax == bit # */
            "   jnz  1b                            ;"
            "   add  $8,%%esp                      ;"
            /* we use %ebx because it is callee-saved */
            : : "b" (events), "r" (regs)
            /* clobbered by callback function calls */
            : "eax", "ecx", "edx", "memory" ); 

        /* Specialised local_irq_restore(). */
        if ( flags ) set_bit(EVENTS_MASTER_ENABLE_BIT, &shared->events_mask);
        barrier();
    }
    while ( shared->events );
}



/*
 * Define interface to generic handling in irq.c
 */

static void shutdown_hypervisor_event(unsigned int irq)
{
    clear_bit(irq, &event_mask);
    clear_bit(irq, &HYPERVISOR_shared_info->events_mask);
}

static void enable_hypervisor_event(unsigned int irq)
{
    set_bit(irq, &event_mask);
    set_bit(irq, &HYPERVISOR_shared_info->events_mask);
    if ( test_bit(EVENTS_MASTER_ENABLE_BIT, 
                  &HYPERVISOR_shared_info->events_mask) )
        do_hypervisor_callback(NULL);
}

static void disable_hypervisor_event(unsigned int irq)
{
    clear_bit(irq, &event_mask);
    clear_bit(irq, &HYPERVISOR_shared_info->events_mask);
}

static void ack_hypervisor_event(unsigned int irq)
{
    if ( !(event_mask & (1<<irq)) )
    {
        printk("Unexpected hypervisor event %d\n", irq);
        atomic_inc(&irq_err_count);
    }
    set_bit(irq, &HYPERVISOR_shared_info->events_mask);
}

static unsigned int startup_hypervisor_event(unsigned int irq)
{
    enable_hypervisor_event(irq);
    return 0;
}

static void end_hypervisor_event(unsigned int irq)
{
}

static struct hw_interrupt_type hypervisor_irq_type = {
    "Hypervisor-event",
    startup_hypervisor_event,
    shutdown_hypervisor_event,
    enable_hypervisor_event,
    disable_hypervisor_event,
    ack_hypervisor_event,
    end_hypervisor_event,
    NULL
};

void __init init_IRQ(void)
{
    int i;

    for ( i = 0; i < NR_IRQS; i++ )
    {
        irq_desc[i].status  = IRQ_DISABLED;
        irq_desc[i].action  = 0;
        irq_desc[i].depth   = 1;
        irq_desc[i].handler = &hypervisor_irq_type;
    }
}