diff --git a/repos/dde_ipxe/src/lib/dde_ipxe/nic.c b/repos/dde_ipxe/src/lib/dde_ipxe/nic.c
index 4650fbe91a..73c25ff550 100644
--- a/repos/dde_ipxe/src/lib/dde_ipxe/nic.c
+++ b/repos/dde_ipxe/src/lib/dde_ipxe/nic.c
@@ -174,6 +174,30 @@ static unsigned scan_pci(void)
 	return NO_DEVICE_FOUND;
 }
 
+/**
+ * Helper for pulling packets from RX queue.
+ *
+ * Must be called within dde_lock.
+ */
+int process_rx_data()
+{
+	struct io_buffer *iobuf;
+
+	int received = 0;
+
+	while ((iobuf = netdev_rx_dequeue(net_dev))) {
+		dde_lock_leave();
+		if (rx_callback) {
+			rx_callback(1, iobuf->data, iob_len(iobuf));
+			received++;
+		}
+		dde_lock_enter();
+		free_iob(iobuf);
+	}
+
+	return received;
+}
+
 
 /**
  * IRQ handler registered at DDE
@@ -190,17 +214,7 @@ static void irq_handler(void *p)
 	for (unsigned retry = 0; (retry < 2) && !processed_rx_data; retry++) {
 		/* poll the device for packets and also link-state changes */
 		netdev_poll(net_dev);
-
-		struct io_buffer *iobuf;
-		while ((iobuf = netdev_rx_dequeue(net_dev))) {
-			dde_lock_leave();
-			if (rx_callback) {
-				rx_callback(1, iobuf->data, iob_len(iobuf));
-				processed_rx_data = 1;
-			}
-			dde_lock_enter();
-			free_iob(iobuf);
-		}
+		processed_rx_data = process_rx_data();
 	}
 
 	dde_lock_leave();
@@ -282,6 +296,7 @@ int dde_ipxe_nic_tx(unsigned if_index, const char *packet, unsigned packet_len)
 
 	netdev_poll(net_dev);
 	netdev_tx(net_dev, iob_disown(iobuf));
+	process_rx_data();
 
 	dde_lock_leave();
 	return 0;