[PATCH 08/16] efi_driver: efi_net: UCLASS_ETH driver for EFI net devices

Adriano Cordova adrianox at gmail.com
Tue Mar 11 17:47:50 CET 2025


Ethernet driver that uses an underlying efi_simple_network_protocol
to send packages.

Signed-off-by: Adriano Cordova <adriano.cordova at canonical.com>
---
 include/efi_loader.h            |  12 +++
 lib/efi_driver/efi_net_device.c | 159 ++++++++++++++++++++++++++++++++
 2 files changed, 171 insertions(+)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 38ea0c5c672..35f500fd97d 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -656,6 +656,18 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
 			       const char *pdevname);
 /* Called by bootefi to make GOP (graphical) interface available */
 efi_status_t efi_gop_register(void);
+
+/**
+ * struct efi_netdev_plat - attributes of a network device
+ *
+ * @handle:	handle of the controller on which this driver is installed
+ * @snp:		simple network protocol proxied by this driver
+ */
+struct efi_netdev_plat {
+	efi_handle_t handle;
+	struct efi_simple_network *snp;
+	void *buffer;
+};
 /* Called to register an EFI network device */
 int efi_net_register(void *ctx, struct event *event);
 /* Called to unregister an EFI network device */
diff --git a/lib/efi_driver/efi_net_device.c b/lib/efi_driver/efi_net_device.c
index 90d695da2b1..3838cc47158 100644
--- a/lib/efi_driver/efi_net_device.c
+++ b/lib/efi_driver/efi_net_device.c
@@ -7,11 +7,146 @@
 #include <dm.h>
 #include <efi_driver.h>
 #include <malloc.h>
+#include <net.h>
 #include <dm/device-internal.h>
 #include <dm/root.h>
 #include <dm/tag.h>
 #include <dm/uclass-internal.h>
 
+#define DEFAULT_EFI_NET_BUFFER_SIZE 1024
+
+int efi_net_start(struct udevice *dev)
+{
+	struct efi_netdev_plat *plat;
+	efi_status_t ret;
+
+	plat = dev_get_plat(dev);
+	if (!plat || !plat->snp)
+		return -1;
+
+	ret = plat->snp->start(plat->snp);
+	if (ret != EFI_SUCCESS)
+		return -1;
+	ret = plat->snp->initialize(plat->snp, 0, 0);
+	if (ret != EFI_SUCCESS)
+		return -1;
+
+	return 0;
+}
+
+int efi_net_send(struct udevice *dev, void *packet, int length)
+{
+	struct efi_netdev_plat *plat;
+	efi_status_t ret;
+
+	plat = dev_get_plat(dev);
+	if (!plat || !plat->snp)
+		return -1;
+
+	ret = plat->snp->transmit(plat->snp, 0, length, packet, NULL, NULL, NULL);
+	if (ret != EFI_SUCCESS)
+		return -1;
+
+	return 0;
+}
+
+int efi_net_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct efi_netdev_plat *plat;
+	efi_status_t ret;
+	size_t buffer_size;
+
+	plat = dev_get_plat(dev);
+	if (!plat || !plat->snp)
+		return -1;
+
+	if (plat->buffer)
+		free(plat->buffer);
+
+	buffer_size = DEFAULT_EFI_NET_BUFFER_SIZE;
+	plat->buffer = calloc(1, buffer_size);
+	ret = plat->snp->receive(plat->snp, NULL, &buffer_size, plat->buffer,
+				 NULL, NULL, NULL);
+
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		free(plat->buffer);
+		plat->buffer = calloc(1, buffer_size);
+		ret = plat->snp->receive(plat->snp, NULL, &buffer_size, plat->buffer,
+					 NULL, NULL, NULL);
+	}
+
+	if (ret != EFI_SUCCESS || ret != EFI_NOT_READY)
+		return -1;
+
+	*packetp = plat->buffer;
+	return buffer_size;
+}
+
+void efi_net_stop(struct udevice *dev)
+{
+	struct efi_netdev_plat *plat;
+
+	plat = dev_get_plat(dev);
+	if (!plat || !plat->snp)
+		return;
+
+	plat->snp->stop(plat->snp);
+}
+
+/**
+ * efi_netdev_create() - create a net udevice for a handle
+ *
+ * @handle:	handle
+ * @interface:	simple network protocol
+ * Return:	status code
+ */
+static efi_status_t
+efi_netdev_create(efi_handle_t handle, void *interface)
+{
+	struct udevice *dev = NULL, *parent = dm_root();
+	efi_status_t ret;
+	char *name;
+	struct efi_netdev_plat *plat;
+	static int devnum;
+
+	name = calloc(1, 18); /* strlen("efinet#2147483648") + 1 */
+	if (!name)
+		return EFI_OUT_OF_RESOURCES;
+	sprintf(name, "efinet#%d", devnum);
+	devnum++;
+
+	/* Create driver model udevice for the EFI block io device */
+	if (eth_create_device(parent, "efi_netdev", name, &dev)) {
+		ret = EFI_OUT_OF_RESOURCES;
+		free(name);
+		goto err;
+	}
+
+	plat = dev_get_plat(dev);
+	plat->handle = handle;
+	plat->snp = interface;
+
+	if (efi_link_dev(handle, dev)) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto err;
+	}
+
+	if (device_probe(dev)) {
+		ret = EFI_DEVICE_ERROR;
+		goto err;
+	}
+	EFI_PRINT("%s: net udevice '%s' created\n", __func__, dev->name);
+
+	return EFI_SUCCESS;
+
+err:
+	efi_unlink_dev(handle);
+	if (dev)
+		device_unbind(dev);
+
+	return ret;
+}
+
 /**
  * efi_net_bind_drv() - TODO
  *
@@ -26,6 +161,14 @@ static efi_status_t efi_net_bind_drv(
 {
 	EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, interface);
 
+	efi_status_t ret;
+
+	if (!handle->dev) {
+		ret = efi_netdev_create(handle, interface);
+		if (ret != EFI_SUCCESS)
+			return ret;
+	}
+
 	return EFI_SUCCESS;
 }
 
@@ -72,6 +215,22 @@ efi_net_init_drv(struct efi_driver_binding_extended_protocol *this)
 	return EFI_SUCCESS;
 }
 
+/* Net device driver operators */
+static const struct eth_ops efi_eth_ops = {
+	.start	= efi_net_start,
+	.send	= efi_net_send,
+	.recv	= efi_net_recv,
+	.stop	= efi_net_stop,
+};
+
+/* Identify as net device driver */
+U_BOOT_DRIVER(efi_netdev) = {
+	.name		= "efi_netdev",
+	.id		= UCLASS_ETH,
+	.ops		= &efi_eth_ops,
+	.plat_auto	= sizeof(struct efi_netdev_plat),
+};
+
 /* EFI driver operators */
 static const struct efi_driver_ops driver_ops = {
 	.protocol	= &efi_net_guid,
-- 
2.48.1



More information about the U-Boot mailing list