[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