uboot/drivers/xen/events.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
   4 * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
   5 * (C) 2020 - EPAM Systems Inc.
   6 *
   7 * File: events.c [1]
   8 * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
   9 * Changes: Grzegorz Milos (gm281@cam.ac.uk)
  10 *
  11 * Date: Jul 2003, changes Jun 2005
  12 *
  13 * Description: Deals with events received on event channels
  14 *
  15 * [1] - http://xenbits.xen.org/gitweb/?p=mini-os.git;a=summary
  16 */
  17#include <common.h>
  18#include <log.h>
  19
  20#include <asm/io.h>
  21#include <asm/xen/system.h>
  22
  23#include <xen/events.h>
  24#include <xen/hvm.h>
  25
  26extern u32 console_evtchn;
  27
  28#define NR_EVS 1024
  29
  30/**
  31 * struct _ev_action - represents a event handler.
  32 *
  33 * Chaining or sharing is not allowed
  34 */
  35struct _ev_action {
  36        void (*handler)(evtchn_port_t port, struct pt_regs *regs, void *data);
  37        void *data;
  38        u32 count;
  39};
  40
  41static struct _ev_action ev_actions[NR_EVS];
  42void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data);
  43
  44static unsigned long bound_ports[NR_EVS / (8 * sizeof(unsigned long))];
  45
  46void unbind_all_ports(void)
  47{
  48        int i;
  49        int cpu = 0;
  50        struct shared_info *s = HYPERVISOR_shared_info;
  51        struct vcpu_info *vcpu_info = &s->vcpu_info[cpu];
  52
  53        for (i = 0; i < NR_EVS; i++) {
  54                if (i == console_evtchn)
  55                        continue;
  56                if (test_and_clear_bit(i, bound_ports)) {
  57                        printf("port %d still bound!\n", i);
  58                        unbind_evtchn(i);
  59                }
  60        }
  61        vcpu_info->evtchn_upcall_pending = 0;
  62        vcpu_info->evtchn_pending_sel = 0;
  63}
  64
  65int do_event(evtchn_port_t port, struct pt_regs *regs)
  66{
  67        struct _ev_action *action;
  68
  69        clear_evtchn(port);
  70
  71        if (port >= NR_EVS) {
  72                printk("WARN: do_event(): Port number too large: %d\n", port);
  73                return 1;
  74        }
  75
  76        action = &ev_actions[port];
  77        action->count++;
  78
  79        /* call the handler */
  80        action->handler(port, regs, action->data);
  81
  82        return 1;
  83}
  84
  85evtchn_port_t bind_evtchn(evtchn_port_t port,
  86                          void (*handler)(evtchn_port_t, struct pt_regs *, void *),
  87                          void *data)
  88{
  89        if (ev_actions[port].handler != default_handler)
  90                printf("WARN: Handler for port %d already registered, replacing\n",
  91                       port);
  92
  93        ev_actions[port].data = data;
  94        wmb();
  95        ev_actions[port].handler = handler;
  96        synch_set_bit(port, bound_ports);
  97
  98        return port;
  99}
 100
 101/**
 102 * unbind_evtchn() - Unbind event channel for selected port
 103 */
 104void unbind_evtchn(evtchn_port_t port)
 105{
 106        struct evtchn_close close;
 107        int rc;
 108
 109        if (ev_actions[port].handler == default_handler)
 110                debug("Default handler for port %d when unbinding\n", port);
 111        mask_evtchn(port);
 112        clear_evtchn(port);
 113
 114        ev_actions[port].handler = default_handler;
 115        wmb();
 116        ev_actions[port].data = NULL;
 117        synch_clear_bit(port, bound_ports);
 118
 119        close.port = port;
 120        rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
 121        if (rc)
 122                printf("WARN: close_port %d failed rc=%d. ignored\n", port, rc);
 123}
 124
 125void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
 126{
 127        debug("[Port %d] - event received\n", port);
 128}
 129
 130/**
 131 * evtchn_alloc_unbound() - Create a port available to the pal for
 132 * exchanging notifications.
 133 *
 134 * Unfortunate confusion of terminology: the port is unbound as far
 135 * as Xen is concerned, but we automatically bind a handler to it.
 136 *
 137 * Return: The result of the hypervisor call.
 138 */
 139int evtchn_alloc_unbound(domid_t pal,
 140                         void (*handler)(evtchn_port_t, struct pt_regs *, void *),
 141                         void *data, evtchn_port_t *port)
 142{
 143        int rc;
 144
 145        struct evtchn_alloc_unbound op;
 146
 147        op.dom = DOMID_SELF;
 148        op.remote_dom = pal;
 149        rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
 150        if (rc) {
 151                printf("ERROR: alloc_unbound failed with rc=%d", rc);
 152                return rc;
 153        }
 154        if (!handler)
 155                handler = default_handler;
 156        *port = bind_evtchn(op.port, handler, data);
 157        return rc;
 158}
 159
 160/**
 161 * eventchn_poll() - Event channel polling function
 162 *
 163 * Check and process any pending events
 164 */
 165void eventchn_poll(void)
 166{
 167        do_hypervisor_callback(NULL);
 168}
 169
 170/**
 171 * init_events() - Initialize event handler
 172 *
 173 * Initially all events are without a handler and disabled.
 174 */
 175void init_events(void)
 176{
 177        int i;
 178
 179        debug("%s\n", __func__);
 180
 181        for (i = 0; i < NR_EVS; i++) {
 182                ev_actions[i].handler = default_handler;
 183                mask_evtchn(i);
 184        }
 185}
 186
 187/**
 188 * fini_events() - Close all ports
 189 *
 190 * Mask and clear event channels. Close port using EVTCHNOP_close
 191 * hypercall.
 192 */
 193void fini_events(void)
 194{
 195        debug("%s\n", __func__);
 196        /* Dealloc all events */
 197        unbind_all_ports();
 198}
 199