drivers: xen: keep track of missed events on event channels

The current implementation for events channel is using an empty
callback for every unbind channel and the interrupt is clearing
every event and calling the callback.
However in a scenario where a domain fires a notification when
another has not yet bind the channel, the event will be missed.

To address this limitation, this commit is keeping track of
missed event channel notification when the empty callback is
used, a function to retrieve and clear the missed event is
introduced.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
This commit is contained in:
Luca Fancellu 2022-04-20 10:12:27 +01:00 committed by Carles Cufí
parent 847f68ae10
commit 58efbc6f4f
2 changed files with 29 additions and 3 deletions

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021 EPAM Systems * Copyright (c) 2021 EPAM Systems
* Copyright (c) 2022 Arm Limited (or its affiliates). All rights reserved.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -18,8 +19,15 @@ LOG_MODULE_REGISTER(xen_events);
extern shared_info_t *HYPERVISOR_shared_info; extern shared_info_t *HYPERVISOR_shared_info;
static evtchn_handle_t event_channels[EVTCHN_2L_NR_CHANNELS]; static evtchn_handle_t event_channels[EVTCHN_2L_NR_CHANNELS];
static bool events_missed[EVTCHN_2L_NR_CHANNELS];
static void empty_callback(void *data) { } static void empty_callback(void *data)
{
/* data is the event_channels entry, subtracting the base, it's the port */
unsigned int port = (((evtchn_handle_t *)data) - event_channels);
events_missed[port] = true;
}
void notify_evtchn(evtchn_port_t port) void notify_evtchn(evtchn_port_t port)
{ {
@ -60,7 +68,22 @@ int unbind_event_channel(evtchn_port_t port)
__func__, port); __func__, port);
event_channels[port].cb = empty_callback; event_channels[port].cb = empty_callback;
event_channels[port].priv = NULL; event_channels[port].priv = &event_channels[port];
events_missed[port] = false;
return 0;
}
int get_missed_events(evtchn_port_t port)
{
__ASSERT(port < EVTCHN_2L_NR_CHANNELS,
"%s: trying to get missed event from invalid port #%u\n",
__func__, port);
if (events_missed[port]) {
events_missed[port] = false;
return 1;
}
return 0; return 0;
} }
@ -170,7 +193,8 @@ int xen_events_init(void)
/* bind all ports with default callback */ /* bind all ports with default callback */
for (i = 0; i < EVTCHN_2L_NR_CHANNELS; i++) { for (i = 0; i < EVTCHN_2L_NR_CHANNELS; i++) {
event_channels[i].cb = empty_callback; event_channels[i].cb = empty_callback;
event_channels[i].priv = NULL; event_channels[i].priv = &event_channels[i];
events_missed[i] = false;
} }
IRQ_CONNECT(DT_IRQ_BY_IDX(DT_INST(0, xen_xen), 0, irq), IRQ_CONNECT(DT_IRQ_BY_IDX(DT_INST(0, xen_xen), 0, irq),

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021 EPAM Systems * Copyright (c) 2021 EPAM Systems
* Copyright (c) 2022 Arm Limited (or its affiliates). All rights reserved.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -22,6 +23,7 @@ typedef struct event_channel_handle evtchn_handle_t;
void notify_evtchn(evtchn_port_t port); void notify_evtchn(evtchn_port_t port);
int bind_event_channel(evtchn_port_t port, evtchn_cb_t cb, void *data); int bind_event_channel(evtchn_port_t port, evtchn_cb_t cb, void *data);
int unbind_event_channel(evtchn_port_t port); int unbind_event_channel(evtchn_port_t port);
int get_missed_events(evtchn_port_t port);
int xen_events_init(void); int xen_events_init(void);