aboutsummaryrefslogtreecommitdiffstats
path: root/xen/include/xen/event.h
blob: 30c59c99792738aa8e88e31e44f98be2698a924b (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
/******************************************************************************
 * event.h
 * 
 * A nice interface for passing asynchronous events to guest OSes.
 * 
 * Copyright (c) 2002-2006, K A Fraser
 */

#ifndef __XEN_EVENT_H__
#define __XEN_EVENT_H__

#include <xen/sched.h>
#include <xen/smp.h>
#include <xen/softirq.h>
#include <xen/bitops.h>
#include <asm/event.h>

/*
 * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ.
 *  @v:        VCPU to which virtual IRQ should be sent
 *  @virq:     Virtual IRQ number (VIRQ_*)
 */
void send_guest_vcpu_virq(struct vcpu *v, uint32_t virq);

/*
 * send_global_virq: Notify the domain handling a global VIRQ.
 *  @virq:     Virtual IRQ number (VIRQ_*)
 */
void send_global_virq(uint32_t virq);

/*
 * sent_global_virq_handler: Set a global VIRQ handler.
 *  @d:        New target domain for this VIRQ
 *  @virq:     Virtual IRQ number (VIRQ_*), must be global
 */
int set_global_virq_handler(struct domain *d, uint32_t virq);

/*
 * send_guest_pirq:
 *  @d:        Domain to which physical IRQ should be sent
 *  @pirq:     Physical IRQ number
 */
void send_guest_pirq(struct domain *, const struct pirq *);

/* Send a notification from a given domain's event-channel port. */
int evtchn_send(struct domain *d, unsigned int lport);

/* Bind a local event-channel port to the specified VCPU. */
long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id);

/* Unmask a local event-channel port. */
int evtchn_unmask(unsigned int port);

/* Move all PIRQs after a vCPU was moved to another pCPU. */
void evtchn_move_pirqs(struct vcpu *v);

/* Allocate/free a Xen-attached event channel port. */
typedef void (*xen_event_channel_notification_t)(
    struct vcpu *v, unsigned int port);
int alloc_unbound_xen_event_channel(
    struct vcpu *local_vcpu, domid_t remote_domid,
    xen_event_channel_notification_t notification_fn);
void free_xen_event_channel(
    struct vcpu *local_vcpu, int port);

/* Query if event channel is in use by the guest */
int guest_enabled_event(struct vcpu *v, uint32_t virq);

/* Notify remote end of a Xen-attached event channel.*/
void notify_via_xen_event_channel(struct domain *ld, int lport);

/* Internal event channel object accessors */
#define bucket_from_port(d,p) \
    ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
#define port_is_valid(d,p)    \
    (((p) >= 0) && ((p) < MAX_EVTCHNS(d)) && \
     (bucket_from_port(d,p) != NULL))
#define evtchn_from_port(d,p) \
    (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])


/* Wait on a Xen-attached event channel. */
#define wait_on_xen_event_channel(port, condition)                      \
    do {                                                                \
        if ( condition )                                                \
            break;                                                      \
        set_bit(_VPF_blocked_in_xen, &current->pause_flags);            \
        smp_mb(); /* set blocked status /then/ re-evaluate condition */ \
        if ( condition )                                                \
        {                                                               \
            clear_bit(_VPF_blocked_in_xen, &current->pause_flags);      \
            break;                                                      \
        }                                                               \
        raise_softirq(SCHEDULE_SOFTIRQ);                                \
        do_softirq();                                                   \
    } while ( 0 )

#define prepare_wait_on_xen_event_channel(port)                         \
    do {                                                                \
        set_bit(_VPF_blocked_in_xen, &current->pause_flags);            \
        raise_softirq(SCHEDULE_SOFTIRQ);                                \
        smp_mb(); /* set blocked status /then/ caller does his work */  \
    } while ( 0 )

void evtchn_check_pollers(struct domain *d, unsigned int port);

void evtchn_2l_init(struct domain *d);

/*
 * Low-level event channel port ops.
 */
struct evtchn_port_ops {
    void (*set_pending)(struct vcpu *v, struct evtchn *evtchn);
    void (*clear_pending)(struct domain *d, struct evtchn *evtchn);
    void (*unmask)(struct domain *d, struct evtchn *evtchn);
    bool_t (*is_pending)(struct domain *d, const struct evtchn *evtchn);
    bool_t (*is_masked)(struct domain *d, const struct evtchn *evtchn);
};

static inline void evtchn_port_set_pending(struct vcpu *v,
                                           struct evtchn *evtchn)
{
    v->domain->evtchn_port_ops->set_pending(v, evtchn);
}

static inline void evtchn_port_clear_pending(struct domain *d,
                                             struct evtchn *evtchn)
{
    d->evtchn_port_ops->clear_pending(d, evtchn);
}

static inline void evtchn_port_unmask(struct domain *d,
                                      struct evtchn *evtchn)
{
    d->evtchn_port_ops->unmask(d, evtchn);
}

static inline bool_t evtchn_port_is_pending(struct domain *d,
                                            const struct evtchn *evtchn)
{
    return d->evtchn_port_ops->is_pending(d, evtchn);
}

static inline bool_t evtchn_port_is_masked(struct domain *d,
                                           const struct evtchn *evtchn)
{
    return d->evtchn_port_ops->is_masked(d, evtchn);
}

#endif /* __XEN_EVENT_H__ */