efi_loader: interrupts in simple network protocol
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 31 Aug 2019 07:56:30 +0000 (09:56 +0200)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Thu, 5 Sep 2019 21:18:51 +0000 (23:18 +0200)
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>
include/efi_api.h
lib/efi_loader/efi_net.c

index 43778197af09bf8c7a117d532dfb42176ce05675..7f7b67fa00f29f620ffca8bf1944a9663f4bbcff 100644 (file)
@@ -1281,6 +1281,8 @@ struct efi_simple_network {
                        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 \
index 825e064f9aa83f99dd051c72ae836d21aa11ee9d..bf6d5ab0b3850b344e88c132ce74687bc3415c9f 100644 (file)
@@ -66,10 +66,13 @@ static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
                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 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
                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 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
        }
 
        eth_halt();
+       this->int_status = 0;
+       wait_for_packet->is_signaled = false;
        this->mode->state = EFI_NETWORK_STOPPED;
 
 out:
@@ -350,10 +357,8 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
        }
 
        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 @@ static efi_status_t EFIAPI efi_net_transmit
        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 @@ static efi_status_t EFIAPI efi_net_receive
                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 @@ static efi_status_t EFIAPI efi_net_receive
        /* 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 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
 static void efi_net_push(void *pkt, int len)
 {
        new_rx_packet = true;
-       wait_for_packet->is_signaled = true;
 }
 
 /**
@@ -577,6 +576,17 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event,
                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);