efi_loader: interrupts in simple network protocol

GetStatus() must clear the interrupt status.
Transmit() should set the TX interrupt.
Receive() should clear the RX interrupt.
Initialize() and Start() should clear the interrupt status.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
diff --git a/include/efi_api.h b/include/efi_api.h
index 4377819..7f7b67f 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -1281,6 +1281,8 @@
 			struct efi_mac_address *dest_addr, u16 *protocol);
 	struct efi_event *wait_for_packet;
 	struct efi_simple_network_mode *mode;
+	/* private fields */
+	u32 int_status;
 };
 
 #define EFI_PXE_BASE_CODE_PROTOCOL_GUID \
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 825e064..bf6d5ab 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -66,10 +66,13 @@
 		goto out;
 	}
 
-	if (this->mode->state != EFI_NETWORK_STOPPED)
+	if (this->mode->state != EFI_NETWORK_STOPPED) {
 		ret = EFI_ALREADY_STARTED;
-	else
+	} else {
+		this->int_status = 0;
+		wait_for_packet->is_signaled = false;
 		this->mode->state = EFI_NETWORK_STARTED;
+	}
 out:
 	return EFI_EXIT(ret);
 }
@@ -144,6 +147,8 @@
 		r = EFI_DEVICE_ERROR;
 		goto out;
 	} else {
+		this->int_status = 0;
+		wait_for_packet->is_signaled = false;
 		this->mode->state = EFI_NETWORK_INITIALIZED;
 	}
 out:
@@ -192,6 +197,8 @@
 	}
 
 	eth_halt();
+	this->int_status = 0;
+	wait_for_packet->is_signaled = false;
 	this->mode->state = EFI_NETWORK_STOPPED;
 
 out:
@@ -350,10 +357,8 @@
 	}
 
 	if (int_status) {
-		/* We send packets synchronously, so nothing is outstanding */
-		*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
-		if (new_rx_packet)
-			*int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+		*int_status = this->int_status;
+		this->int_status = 0;
 	}
 	if (txbuf)
 		*txbuf = new_tx_packet;
@@ -429,7 +434,7 @@
 	net_send_packet(transmit_buffer, buffer_size);
 
 	new_tx_packet = buffer;
-
+	this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
 out:
 	return EFI_EXIT(ret);
 }
@@ -487,12 +492,6 @@
 		ret = EFI_NOT_READY;
 		goto out;
 	}
-	/* Check that we at least received an Ethernet header */
-	if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
-		new_rx_packet = false;
-		ret = EFI_NOT_READY;
-		goto out;
-	}
 	/* Fill export parameters */
 	eth_hdr = (struct ethernet_hdr *)net_rx_packet;
 	protlen = ntohs(eth_hdr->et_protlen);
@@ -517,7 +516,8 @@
 	/* Copy packet */
 	memcpy(buffer, net_rx_packet, net_rx_packet_len);
 	*buffer_size = net_rx_packet_len;
-	new_rx_packet = false;
+	new_rx_packet = 0;
+	this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
 out:
 	return EFI_EXIT(ret);
 }
@@ -548,7 +548,6 @@
 static void efi_net_push(void *pkt, int len)
 {
 	new_rx_packet = true;
-	wait_for_packet->is_signaled = true;
 }
 
 /**
@@ -577,6 +576,17 @@
 		push_packet = efi_net_push;
 		eth_rx();
 		push_packet = NULL;
+		if (new_rx_packet) {
+			/* Check that we at least received an Ethernet header */
+			if (net_rx_packet_len >=
+			    sizeof(struct ethernet_hdr)) {
+				this->int_status |=
+					EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+				wait_for_packet->is_signaled = true;
+			} else {
+				new_rx_packet = 0;
+			}
+		}
 	}
 out:
 	EFI_EXIT(EFI_SUCCESS);