efi_loader: use events for efi_net_receive
A timer event is defined. The timer handler cares for receiving new
packets.
efi_timer_check is called both in efi_net_transmit and efi_net_receive
to enable events during network communication.
Calling efi_timer_check in efi_net_get_status is implemented in a
separate patch.
[agraf] This patch is needed to make efi_net_get_status() actually
report incoming packets.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
[agraf: fix spelling in comment]
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 569bf36..3704789 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -19,6 +19,11 @@
static struct efi_pxe_packet *dhcp_ack;
static bool new_rx_packet;
static void *new_tx_packet;
+/*
+ * The notification function of this event is called in every timer cycle
+ * to check if a new network packet has been received.
+ */
+static struct efi_event *network_timer_event;
struct efi_net_obj {
/* Generic EFI object parent class data */
@@ -143,6 +148,8 @@
EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size,
buffer_size, buffer, src_addr, dest_addr, protocol);
+ efi_timer_check();
+
if (header_size) {
/* We would need to create the header if header_size != 0 */
return EFI_EXIT(EFI_INVALID_PARAMETER);
@@ -174,9 +181,7 @@
EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
buffer_size, buffer, src_addr, dest_addr, protocol);
- push_packet = efi_net_push;
- eth_rx();
- push_packet = NULL;
+ efi_timer_check();
if (!new_rx_packet)
return EFI_EXIT(EFI_NOT_READY);
@@ -204,10 +209,32 @@
memcpy(dhcp_ack, pkt, min(len, maxsize));
}
+/*
+ * Check if a new network packet has been received.
+ *
+ * This notification function is called in every timer cycle.
+ *
+ * @event the event for which this notification function is registered
+ * @context event context - not used in this function
+ */
+static void EFIAPI efi_network_timer_notify(struct efi_event *event,
+ void *context)
+{
+ EFI_ENTRY("%p, %p", event, context);
+
+ if (!new_rx_packet) {
+ push_packet = efi_net_push;
+ eth_rx();
+ push_packet = NULL;
+ }
+ EFI_EXIT(EFI_SUCCESS);
+}
+
/* This gets called from do_bootefi_exec(). */
int efi_net_register(void)
{
struct efi_net_obj *netobj;
+ efi_status_t r;
if (!eth_get_dev()) {
/* No eth device active, don't expose any */
@@ -253,5 +280,25 @@
/* Hook net up to the device list */
list_add_tail(&netobj->parent.link, &efi_obj_list);
+ /*
+ * Create a timer event.
+ *
+ * The notification function is used to check if a new network packet
+ * has been received.
+ */
+ r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+ efi_network_timer_notify, NULL,
+ &network_timer_event);
+ if (r != EFI_SUCCESS) {
+ printf("ERROR: Failed to register network event\n");
+ return r;
+ }
+ /* Network is time critical, create event in every timer cyle */
+ r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
+ if (r != EFI_SUCCESS) {
+ printf("ERROR: Failed to set network timer\n");
+ return r;
+ }
+
return 0;
}