efi_loader: support all uclasses in device path
On devices with multiple USB mass storage devices errors like
Path /../USB(0x0,0x0)/USB(0x1,0x0)/Ctrl(0x0)
already installed.
are seen. This is due to creating non-unique device paths. To uniquely
identify devices we must provide path nodes for all devices on the path
from the root device.
Add support for generating device path nodes for all uclasses.
Reported-by: Suniel Mahesh <sunil@amarulasolutions.com>
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
diff --git a/include/efi_api.h b/include/efi_api.h
index 55a4c98..8f5ef5f 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -579,6 +579,13 @@
u8 vendor_data[];
} __packed;
+struct efi_device_path_udevice {
+ struct efi_device_path dp;
+ efi_guid_t guid;
+ int uclass_id;
+ int dev_number;
+} __packed;
+
struct efi_device_path_controller {
struct efi_device_path dp;
u32 controller_number;
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index c135e28..19e8861 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <blk.h>
#include <dm.h>
+#include <dm/root.h>
#include <log.h>
#include <net.h>
#include <usb.h>
@@ -38,16 +39,6 @@
.length = sizeof(END),
};
-/* template ROOT node: */
-static const struct efi_device_path_vendor ROOT = {
- .dp = {
- .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
- .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
- .length = sizeof(ROOT),
- },
- .guid = U_BOOT_GUID,
-};
-
#if defined(CONFIG_MMC)
/*
* Determine if an MMC device is an SD card.
@@ -497,13 +488,12 @@
__maybe_unused static unsigned int dp_size(struct udevice *dev)
{
if (!dev || !dev->driver)
- return sizeof(ROOT);
+ return sizeof(struct efi_device_path_udevice);
switch (device_get_uclass_id(dev)) {
case UCLASS_ROOT:
- case UCLASS_SIMPLE_BUS:
/* stop traversing parents at this point: */
- return sizeof(ROOT);
+ return sizeof(struct efi_device_path_udevice);
case UCLASS_ETH:
return dp_size(dev->parent) +
sizeof(struct efi_device_path_mac_addr);
@@ -582,8 +572,8 @@
return dp_size(dev->parent) +
sizeof(struct efi_device_path_usb);
default:
- /* just skip over unknown classes: */
- return dp_size(dev->parent);
+ return dp_size(dev->parent) +
+ sizeof(struct efi_device_path_udevice);
}
}
@@ -600,13 +590,6 @@
return buf;
switch (device_get_uclass_id(dev)) {
- case UCLASS_ROOT:
- case UCLASS_SIMPLE_BUS: {
- /* stop traversing parents at this point: */
- struct efi_device_path_vendor *vdp = buf;
- *vdp = ROOT;
- return &vdp[1];
- }
#ifdef CONFIG_NETDEVICES
case UCLASS_ETH: {
struct efi_device_path_mac_addr *dp =
@@ -805,11 +788,24 @@
return &udp[1];
}
- default:
- /* If the uclass driver is missing, this will show NULL */
- log_debug("unhandled device class: %s (%s)\n", dev->name,
- dev_get_uclass_name(dev));
- return dp_fill(buf, dev->parent);
+ default: {
+ struct efi_device_path_udevice *vdp;
+ enum uclass_id uclass_id = device_get_uclass_id(dev);
+
+ if (uclass_id == UCLASS_ROOT)
+ vdp = buf;
+ else
+ vdp = dp_fill(buf, dev->parent);
+
+ vdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+ vdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+ vdp->dp.length = sizeof(*vdp);
+ memcpy(&vdp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
+ vdp->uclass_id = uclass_id;
+ vdp->dev_number = dev->seq_;
+
+ return &vdp[1];
+ }
}
}
@@ -1046,14 +1042,12 @@
{
void *buf, *pos;
struct efi_device_path_uart *uart;
- size_t dpsize = sizeof(ROOT) + sizeof(*uart) + sizeof(END);
+ size_t dpsize = dp_size(dm_root()) + sizeof(*uart) + sizeof(END);
buf = efi_alloc(dpsize);
if (!buf)
return NULL;
- pos = buf;
- memcpy(pos, &ROOT, sizeof(ROOT));
- pos += sizeof(ROOT);
+ pos = dp_fill(buf, dm_root());
uart = pos;
uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;