[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH V5 04/15] evtchn: generalize event channel operations
Add evtchn_is_{pending,masked} and evtchn_clear_pending. Also use function pointers to refer to ABIs. This allows us to switch to alternate ABIs. 2-level ABI routines are moved to another file to separate interface and implementation. Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx> --- xen/arch/x86/irq.c | 7 +-- xen/common/Makefile | 1 + xen/common/event_channel.c | 119 +++++++++++++++------------------------- xen/common/evtchn_bitmap_abi.c | 116 +++++++++++++++++++++++++++++++++++++++ xen/common/keyhandler.c | 6 +- xen/common/schedule.c | 2 +- xen/include/xen/event.h | 13 +++++ xen/include/xen/sched.h | 3 + 8 files changed, 184 insertions(+), 83 deletions(-) create mode 100644 xen/common/evtchn_bitmap_abi.c diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index ca829bb..4033328 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1452,7 +1452,7 @@ int pirq_guest_unmask(struct domain *d) { pirq = pirqs[i]->pirq; if ( pirqs[i]->masked && - !test_bit(pirqs[i]->evtchn, &shared_info(d, evtchn_mask)) ) + !evtchn_is_masked(d, pirqs[i]->evtchn) ) pirq_guest_eoi(pirqs[i]); } } while ( ++pirq < d->nr_pirqs && n == ARRAY_SIZE(pirqs) ); @@ -2090,13 +2090,12 @@ static void dump_irqs(unsigned char key) info = pirq_info(d, pirq); printk("%u:%3d(%c%c%c%c)", d->domain_id, pirq, - (test_bit(info->evtchn, - &shared_info(d, evtchn_pending)) ? + (evtchn_is_pending(d, info->evtchn) ? 'P' : '-'), (test_bit(info->evtchn / BITS_PER_EVTCHN_WORD(d), &vcpu_info(d->vcpu[0], evtchn_pending_sel)) ? 'S' : '-'), - (test_bit(info->evtchn, &shared_info(d, evtchn_mask)) ? + (evtchn_is_masked(d, info->evtchn) ? 'M' : '-'), (info->masked ? 'M' : '-')); if ( i != action->nr_guests ) diff --git a/xen/common/Makefile b/xen/common/Makefile index 8a0c506..05e2160 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -6,6 +6,7 @@ obj-$(HAS_DEVICE_TREE) += device_tree.o obj-y += domctl.o obj-y += domain.o obj-y += event_channel.o +obj-y += evtchn_bitmap_abi.o obj-y += grant_table.o obj-y += irq.o obj-y += kernel.o diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 76de8ec..54ae281 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -51,6 +51,39 @@ #define consumer_is_xen(e) (!!(e)->xen_consumer) +struct evtchn_port_ops { + int (*is_pending)(struct domain *d, int port); + int (*is_masked)(struct domain *d, int port); + void (*set_pending)(struct vcpu *v, int port); + void (*clear_pending)(struct domain *d, int port); + int (*unmask)(unsigned int port); +}; + +int evtchn_is_pending(struct domain *d, int port) +{ + return d->evtchn_ops->is_pending(d, port); +} + +int evtchn_is_masked(struct domain *d, int port) +{ + return d->evtchn_ops->is_masked(d, port); +} + +void evtchn_set_pending(struct vcpu *v, int port) +{ + v->domain->evtchn_ops->set_pending(v, port); +} + +void evtchn_clear_pending(struct domain *d, int port) +{ + d->evtchn_ops->clear_pending(d, port); +} + +int evtchn_unmask(unsigned int port) +{ + return current->domain->evtchn_ops->unmask(port); +} + /* * The function alloc_unbound_xen_event_channel() allows an arbitrary * notifier function to be specified. However, very few unique functions @@ -94,8 +127,6 @@ static uint8_t get_xen_consumer(xen_event_channel_notification_t fn) /* Get the notification function for a given Xen-bound event channel. */ #define xen_notification_fn(e) (xen_consumers[(e)->xen_consumer-1]) -static void evtchn_set_pending(struct vcpu *v, int port); - static int virq_is_global(uint32_t virq) { int rc; @@ -540,7 +571,7 @@ static long __evtchn_close(struct domain *d1, int port1) } /* Clear pending event to avoid unexpected behavior on re-bind. */ - clear_bit(port1, &shared_info(d1, evtchn_pending)); + evtchn_clear_pending(d1, port1); /* Reset binding to vcpu0 when the channel is freed. */ chn1->state = ECS_FREE; @@ -623,47 +654,6 @@ out: return ret; } -static void evtchn_set_pending(struct vcpu *v, int port) -{ - struct domain *d = v->domain; - int vcpuid; - - /* - * The following bit operations must happen in strict order. - * NB. On x86, the atomic bit operations also act as memory barriers. - * There is therefore sufficiently strict ordering for this architecture -- - * others may require explicit memory barriers. - */ - - if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) ) - return; - - if ( !test_bit (port, &shared_info(d, evtchn_mask)) && - !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d), - &vcpu_info(v, evtchn_pending_sel)) ) - { - vcpu_mark_events_pending(v); - } - - /* Check if some VCPU might be polling for this event. */ - if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) - return; - - /* Wake any interested (or potentially interested) pollers. */ - for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus); - vcpuid < d->max_vcpus; - vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) ) - { - v = d->vcpu[vcpuid]; - if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) && - test_and_clear_bit(vcpuid, d->poll_mask) ) - { - v->poll_evtchn = 0; - vcpu_unblock(v); - } - } -} - int guest_enabled_event(struct vcpu *v, uint32_t virq) { return ((v != NULL) && (v->virq_to_evtchn[virq] != 0)); @@ -927,34 +917,6 @@ long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id) } -int evtchn_unmask(unsigned int port) -{ - struct domain *d = current->domain; - struct vcpu *v; - - ASSERT(spin_is_locked(&d->event_lock)); - - if ( unlikely(!port_is_valid(d, port)) ) - return -EINVAL; - - v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; - - /* - * These operations must happen in strict order. Based on - * include/xen/event.h:evtchn_set_pending(). - */ - if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && - test_bit (port, &shared_info(d, evtchn_pending)) && - !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d), - &vcpu_info(v, evtchn_pending_sel)) ) - { - vcpu_mark_events_pending(v); - } - - return 0; -} - - static long evtchn_reset(evtchn_reset_t *r) { domid_t dom = r->dom; @@ -1180,6 +1142,13 @@ void notify_via_xen_event_channel(struct domain *ld, int lport) spin_unlock(&ld->event_lock); } +const static struct evtchn_port_ops evtchn_2l_ops = { + .is_pending = evtchn_bitmap_is_pending, + .is_masked = evtchn_bitmap_is_masked, + .set_pending = evtchn_bitmap_set_pending, + .unmask = evtchn_bitmap_unmask, + .clear_pending = evtchn_bitmap_clear_pending +}; int evtchn_init(struct domain *d) { @@ -1188,6 +1157,8 @@ int evtchn_init(struct domain *d) return -EINVAL; evtchn_from_port(d, 0)->state = ECS_RESERVED; + d->evtchn_ops = &evtchn_2l_ops; + #if MAX_VIRT_CPUS > BITS_PER_LONG d->poll_mask = xmalloc_array(unsigned long, BITS_TO_LONGS(MAX_VIRT_CPUS)); if ( !d->poll_mask ) @@ -1290,8 +1261,8 @@ static void domain_dump_evtchn_info(struct domain *d) printk(" %4u [%d/%d]: s=%d n=%d x=%d", port, - !!test_bit(port, &shared_info(d, evtchn_pending)), - !!test_bit(port, &shared_info(d, evtchn_mask)), + !!evtchn_is_pending(d, port), + !!evtchn_is_masked(d, port), chn->state, chn->notify_vcpu_id, chn->xen_consumer); switch ( chn->state ) diff --git a/xen/common/evtchn_bitmap_abi.c b/xen/common/evtchn_bitmap_abi.c new file mode 100644 index 0000000..0d747bc --- /dev/null +++ b/xen/common/evtchn_bitmap_abi.c @@ -0,0 +1,116 @@ +/****************************************************************************** + * evtchn_bitmap_abi.c + * + * Event channel 2-level ABI implementation. + * + * Copyright (c) 2013 Citrix Systems + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/event.h> + +int evtchn_bitmap_is_pending(struct domain *d, int port) +{ + return test_bit(port, &shared_info(d, evtchn_pending)); +} + +int evtchn_bitmap_is_masked(struct domain *d, int port) +{ + return test_bit(port, &shared_info(d, evtchn_mask)); +} + +void evtchn_bitmap_set_pending(struct vcpu *v, int port) +{ + struct domain *d = v->domain; + int vcpuid; + + /* + * The following bit operations must happen in strict order. + * NB. On x86, the atomic bit operations also act as memory barriers. + * There is therefore sufficiently strict ordering for this architecture -- + * others may require explicit memory barriers. + */ + + if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) ) + return; + + if ( !test_bit (port, &shared_info(d, evtchn_mask)) && + !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d), + &vcpu_info(v, evtchn_pending_sel)) ) + { + vcpu_mark_events_pending(v); + } + + /* Check if some VCPU might be polling for this event. */ + if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) + return; + + /* Wake any interested (or potentially interested) pollers. */ + for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus); + vcpuid < d->max_vcpus; + vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) ) + { + v = d->vcpu[vcpuid]; + if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) && + test_and_clear_bit(vcpuid, d->poll_mask) ) + { + v->poll_evtchn = 0; + vcpu_unblock(v); + } + } +} + +void evtchn_bitmap_clear_pending(struct domain *d, int port) +{ + clear_bit(port, &shared_info(d, evtchn_pending)); +} + +int evtchn_bitmap_unmask(unsigned int port) +{ + struct domain *d = current->domain; + struct vcpu *v; + + ASSERT(spin_is_locked(&d->event_lock)); + + if ( unlikely(!port_is_valid(d, port)) ) + return -EINVAL; + + v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; + + /* + * These operations must happen in strict order. Based on + * include/xen/event.h:evtchn_set_pending(). + */ + if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && + test_bit (port, &shared_info(d, evtchn_pending)) && + !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d), + &vcpu_info(v, evtchn_pending_sel)) ) + { + vcpu_mark_events_pending(v); + } + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index e9ef45f..def3bf6 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -302,10 +302,8 @@ static void dump_domains(unsigned char key) printk("Notifying guest %d:%d (virq %d, port %d, stat %d/%d/%d)\n", d->domain_id, v->vcpu_id, VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG], - test_bit(v->virq_to_evtchn[VIRQ_DEBUG], - &shared_info(d, evtchn_pending)), - test_bit(v->virq_to_evtchn[VIRQ_DEBUG], - &shared_info(d, evtchn_mask)), + evtchn_is_pending(d, v->virq_to_evtchn[VIRQ_DEBUG]), + evtchn_is_masked(d, v->virq_to_evtchn[VIRQ_DEBUG]), test_bit(v->virq_to_evtchn[VIRQ_DEBUG] / BITS_PER_EVTCHN_WORD(d), &vcpu_info(v, evtchn_pending_sel))); diff --git a/xen/common/schedule.c b/xen/common/schedule.c index de11110..6362e64 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -702,7 +702,7 @@ static long do_poll(struct sched_poll *sched_poll) goto out; rc = 0; - if ( test_bit(port, &shared_info(d, evtchn_pending)) ) + if ( evtchn_is_pending(d, port) ) goto out; } diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index ff9332a..d3ee5e0 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -54,6 +54,12 @@ int evtchn_unmask(unsigned int port); /* Move all PIRQs after a vCPU was moved to another pCPU. */ void evtchn_move_pirqs(struct vcpu *v); +/* Tell a given event-channel port is pending or not */ +int evtchn_is_pending(struct domain *d, int port); + +/* Tell a given event-channel port is masked or not */ +int evtchn_is_masked(struct domain *d, int port); + /* Allocate/free a Xen-attached event channel port. */ typedef void (*xen_event_channel_notification_t)( struct vcpu *v, unsigned int port); @@ -110,4 +116,11 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); mb(); /* set blocked status /then/ caller does his work */ \ } while ( 0 ) +/* 2-level ABI routines */ +int evtchn_bitmap_is_pending(struct domain *d, int port); +int evtchn_bitmap_is_masked(struct domain *d, int port); +void evtchn_bitmap_set_pending(struct vcpu *v, int port); +void evtchn_bitmap_clear_pending(struct domain *d, int port); +int evtchn_bitmap_unmask(unsigned int port); + #endif /* __XEN_EVENT_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 7169ca0..1cd289e 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -236,6 +236,8 @@ struct mem_event_per_domain struct mem_event_domain access; }; +struct evtchn_port_ops; + struct domain { domid_t domain_id; @@ -267,6 +269,7 @@ struct domain /* Event channel information. */ struct evtchn **evtchn[NR_EVTCHN_GROUPS]; + const struct evtchn_port_ops *evtchn_ops; spinlock_t event_lock; struct grant_table *grant_table; -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |