1 /*
2  * Event channel port operations.
3  *
4  * Copyright (c) 2003-2006, K A Fraser.
5  *
6  * This source code is licensed under the GNU General Public License,
7  * Version 2 or later.  See the file COPYING for more details.
8  */
9 
10 #include <xen/init.h>
11 #include <xen/lib.h>
12 #include <xen/errno.h>
13 #include <xen/sched.h>
14 #include <xen/event.h>
15 
evtchn_2l_set_pending(struct vcpu * v,struct evtchn * evtchn)16 static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
17 {
18     struct domain *d = v->domain;
19     unsigned int port = evtchn->port;
20 
21     /*
22      * The following bit operations must happen in strict order.
23      * NB. On x86, the atomic bit operations also act as memory barriers.
24      * There is therefore sufficiently strict ordering for this architecture --
25      * others may require explicit memory barriers.
26      */
27 
28     if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
29         return;
30 
31     if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
32          !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
33                            &vcpu_info(v, evtchn_pending_sel)) )
34     {
35         vcpu_mark_events_pending(v);
36     }
37 
38     evtchn_check_pollers(d, port);
39 }
40 
evtchn_2l_clear_pending(struct domain * d,struct evtchn * evtchn)41 static void evtchn_2l_clear_pending(struct domain *d, struct evtchn *evtchn)
42 {
43     clear_bit(evtchn->port, &shared_info(d, evtchn_pending));
44 }
45 
evtchn_2l_unmask(struct domain * d,struct evtchn * evtchn)46 static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
47 {
48     struct vcpu *v = d->vcpu[evtchn->notify_vcpu_id];
49     unsigned int port = evtchn->port;
50 
51     /*
52      * These operations must happen in strict order. Based on
53      * evtchn_2l_set_pending() above.
54      */
55     if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) &&
56          test_bit          (port, &shared_info(d, evtchn_pending)) &&
57          !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d),
58                             &vcpu_info(v, evtchn_pending_sel)) )
59     {
60         vcpu_mark_events_pending(v);
61     }
62 }
63 
evtchn_2l_is_pending(const struct domain * d,evtchn_port_t port)64 static bool evtchn_2l_is_pending(const struct domain *d, evtchn_port_t port)
65 {
66     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
67 
68     ASSERT(port < max_ports);
69     return port < max_ports && test_bit(port, &shared_info(d, evtchn_pending));
70 }
71 
evtchn_2l_is_masked(const struct domain * d,evtchn_port_t port)72 static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
73 {
74     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
75 
76     ASSERT(port < max_ports);
77     return port >= max_ports || test_bit(port, &shared_info(d, evtchn_mask));
78 }
79 
evtchn_2l_print_state(struct domain * d,const struct evtchn * evtchn)80 static void evtchn_2l_print_state(struct domain *d,
81                                   const struct evtchn *evtchn)
82 {
83     struct vcpu *v = d->vcpu[evtchn->notify_vcpu_id];
84 
85     printk("%d", !!test_bit(evtchn->port / BITS_PER_EVTCHN_WORD(d),
86                             &vcpu_info(v, evtchn_pending_sel)));
87 }
88 
89 static const struct evtchn_port_ops evtchn_port_ops_2l =
90 {
91     .set_pending   = evtchn_2l_set_pending,
92     .clear_pending = evtchn_2l_clear_pending,
93     .unmask        = evtchn_2l_unmask,
94     .is_pending    = evtchn_2l_is_pending,
95     .is_masked     = evtchn_2l_is_masked,
96     .print_state   = evtchn_2l_print_state,
97 };
98 
evtchn_2l_init(struct domain * d)99 void evtchn_2l_init(struct domain *d)
100 {
101     d->evtchn_port_ops = &evtchn_port_ops_2l;
102     d->max_evtchns = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
103 }
104 
105 /*
106  * Local variables:
107  * mode: C
108  * c-file-style: "BSD"
109  * c-basic-offset: 4
110  * tab-width: 4
111  * indent-tabs-mode: nil
112  * End:
113  */
114