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