From 3f26bca262dcc5f50577981a66a08d80864de6a0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 19 Mar 2023 16:18:08 +0100 Subject: efi_loader: support for Ctrl() device path node * Add the definitions for Ctrl() device path nodes. * Implement Ctrl() nodes in the device path to text protocol. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Reviewed-by: Ilias Apalodimas --- include/efi_api.h | 6 ++++++ lib/efi_loader/efi_device_path_to_text.c | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/include/efi_api.h b/include/efi_api.h index 2d18d25a713..c57868abbd9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -570,6 +570,7 @@ struct efi_mac_addr { #define DEVICE_PATH_TYPE_HARDWARE_DEVICE 0x01 # define DEVICE_PATH_SUB_TYPE_MEMORY 0x03 # define DEVICE_PATH_SUB_TYPE_VENDOR 0x04 +# define DEVICE_PATH_SUB_TYPE_CONTROLLER 0x05 struct efi_device_path_memory { struct efi_device_path dp; @@ -584,6 +585,11 @@ struct efi_device_path_vendor { u8 vendor_data[]; } __packed; +struct efi_device_path_controller { + struct efi_device_path dp; + u32 controller_number; +} __packed; + #define DEVICE_PATH_TYPE_ACPI_DEVICE 0x02 # define DEVICE_PATH_SUB_TYPE_ACPI_DEVICE 0x01 diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 9062058ac22..4b2ade3803f 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -77,6 +77,13 @@ static char *dp_hardware(char *s, struct efi_device_path *dp) s += sprintf(s, ")"); break; } + case DEVICE_PATH_SUB_TYPE_CONTROLLER: { + struct efi_device_path_controller *cdp = + (struct efi_device_path_controller *)dp; + + s += sprintf(s, "Ctrl(0x%0x)", cdp->controller_number); + break; + } default: s = dp_unknown(s, dp); break; -- cgit v1.2.3 From 180b7118bed8433f9cfe4b5ad62c6b0d901924f5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 19 Mar 2023 16:18:09 +0100 Subject: efi_loader: fix device-path for USB devices EFI device paths for block devices must be unique. If a non-unique device path is discovered, probing of the block device fails. Currently we use UsbClass() device path nodes. As multiple devices may have the same vendor and product id these are non-unique. Instead we should use Usb() device path nodes. They include the USB port on the parent hub. Hence they are unique. A USB storage device may contain multiple logical units. These can be modeled as Ctrl() nodes. Reported-by: Patrick Delaunay Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- lib/efi_loader/efi_device_path.c | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 3b267b713e9..b6dd575b13b 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -147,7 +147,7 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp) * in practice fallback.efi just uses MEDIA:HARD_DRIVE * so not sure when we would see these other cases. */ - if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) || + if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB) || EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) || EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH)) return dp; @@ -564,6 +564,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; #endif +#ifdef CONFIG_USB + case UCLASS_MASS_STORAGE: + return dp_size(dev->parent) + + sizeof(struct efi_device_path_controller); +#endif #ifdef CONFIG_VIRTIO_BLK case UCLASS_VIRTIO: /* @@ -585,7 +590,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) case UCLASS_MASS_STORAGE: case UCLASS_USB_HUB: return dp_size(dev->parent) + - sizeof(struct efi_device_path_usb_class); + sizeof(struct efi_device_path_usb); default: /* just skip over unknown classes: */ return dp_size(dev->parent); @@ -741,6 +746,19 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) memcpy(&dp->ns_id, &ns_id, sizeof(ns_id)); return &dp[1]; } +#endif +#if defined(CONFIG_USB) + case UCLASS_MASS_STORAGE: { + struct blk_desc *desc = desc = dev_get_uclass_plat(dev); + struct efi_device_path_controller *dp = + dp_fill(buf, dev->parent); + + dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER; + dp->dp.length = sizeof(*dp); + dp->controller_number = desc->lun; + return &dp[1]; + } #endif default: debug("%s(%u) %s: unhandled parent class: %s (%u)\n", @@ -767,19 +785,22 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) #endif case UCLASS_MASS_STORAGE: case UCLASS_USB_HUB: { - struct efi_device_path_usb_class *udp = - dp_fill(buf, dev->parent); - struct usb_device *udev = dev_get_parent_priv(dev); - struct usb_device_descriptor *desc = &udev->descriptor; + struct efi_device_path_usb *udp = dp_fill(buf, dev->parent); + + switch (device_get_uclass_id(dev->parent)) { + case UCLASS_USB_HUB: { + struct usb_device *udev = dev_get_parent_priv(dev); + udp->parent_port_number = udev->portnr; + break; + } + default: + udp->parent_port_number = 0; + } udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; - udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS; + udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB; udp->dp.length = sizeof(*udp); - udp->vendor_id = desc->idVendor; - udp->product_id = desc->idProduct; - udp->device_class = desc->bDeviceClass; - udp->device_subclass = desc->bDeviceSubClass; - udp->device_protocol = desc->bDeviceProtocol; + udp->usb_interface = 0; return &udp[1]; } -- cgit v1.2.3