diff options
19 files changed, 16 insertions, 3554 deletions
| diff --git a/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_corebootfb b/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_corebootfb index 509e784e..7afbe427 100644 --- a/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_corebootfb +++ b/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_corebootfb @@ -288,7 +288,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_txtmode b/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_txtmode index 428bed87..3609c5a8 100644 --- a/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_txtmode +++ b/config/coreboot/dell9020mt-nri_12mb/config/libgfxinit_txtmode @@ -286,7 +286,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_corebootfb b/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_corebootfb index ac1d9f16..e2c82603 100644 --- a/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_corebootfb +++ b/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_corebootfb @@ -288,7 +288,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_txtmode b/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_txtmode index 179af9cc..4fe0c52c 100644 --- a/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_txtmode +++ b/config/coreboot/dell9020sff-nri_12mb/config/libgfxinit_txtmode @@ -286,7 +286,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/hp820g2_12mb/target.cfg b/config/coreboot/hp820g2_12mb/target.cfg index dbcf5a1c..5528b8ec 100644 --- a/config/coreboot/hp820g2_12mb/target.cfg +++ b/config/coreboot/hp820g2_12mb/target.cfg @@ -1,7 +1,6 @@  tree="default"  xarch="i386-elf"  payload_seabios="y" -payload_seabios_withgrub="y"  payload_memtest="y"  grub_scan_disk="ahci"  release="n" diff --git a/config/coreboot/t440plibremrc_12mb/config/libgfxinit_corebootfb b/config/coreboot/t440plibremrc_12mb/config/libgfxinit_corebootfb index dd614202..ab3c464b 100644 --- a/config/coreboot/t440plibremrc_12mb/config/libgfxinit_corebootfb +++ b/config/coreboot/t440plibremrc_12mb/config/libgfxinit_corebootfb @@ -325,7 +325,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/t440plibremrc_12mb/config/libgfxinit_txtmode b/config/coreboot/t440plibremrc_12mb/config/libgfxinit_txtmode index a0dce901..b6a9afd1 100644 --- a/config/coreboot/t440plibremrc_12mb/config/libgfxinit_txtmode +++ b/config/coreboot/t440plibremrc_12mb/config/libgfxinit_txtmode @@ -323,7 +323,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/w541_12mb/config/libgfxinit_corebootfb b/config/coreboot/w541_12mb/config/libgfxinit_corebootfb index ae155585..7db59d7b 100644 --- a/config/coreboot/w541_12mb/config/libgfxinit_corebootfb +++ b/config/coreboot/w541_12mb/config/libgfxinit_corebootfb @@ -325,7 +325,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/coreboot/w541_12mb/config/libgfxinit_txtmode b/config/coreboot/w541_12mb/config/libgfxinit_txtmode index 9a891434..a4a33d25 100644 --- a/config/coreboot/w541_12mb/config/libgfxinit_txtmode +++ b/config/coreboot/w541_12mb/config/libgfxinit_txtmode @@ -323,7 +323,7 @@ CONFIG_USE_NATIVE_RAMINIT=y  # CONFIG_PCIEXP_HOTPLUG is not set  CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y  CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT=y -CONFIG_FINALIZE_USB_ROUTE_XHCI=y +# CONFIG_FINALIZE_USB_ROUTE_XHCI is not set  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC=y  CONFIG_SOUTHBRIDGE_INTEL_COMMON_PMCLIB=y diff --git a/config/grub/modules.list b/config/grub/modules.list index 5943a9ae..381451b9 100644 --- a/config/grub/modules.list +++ b/config/grub/modules.list @@ -36,7 +36,6 @@ crypto \  cryptodisk \  diskfilter \  echo \ -xhci \  ehci \  eval \  exfat \ diff --git a/config/grub/patches/0005-xhci/0001-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch b/config/grub/patches/0005-xhci/0001-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch deleted file mode 100644 index f533269f..00000000 --- a/config/grub/patches/0005-xhci/0001-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch +++ /dev/null @@ -1,245 +0,0 @@ -From 90c9011f2e0350a97e3df44b0fc6dd022e04c276 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Sun, 15 Nov 2020 19:00:27 +0100 -Subject: [PATCH 1/8] grub-core/bus/usb: Parse SuperSpeed companion descriptors - -Parse the SS_ENDPOINT_COMPANION descriptor, which is only present on USB 3.0 -capable devices and xHCI controllers. Make the descendp an array of pointers -to the endpoint descriptor as it's no longer an continous array. - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - grub-core/bus/usb/serial/common.c |  2 +- - grub-core/bus/usb/usb.c           | 44 +++++++++++++++++++------------ - grub-core/bus/usb/usbhub.c        | 22 ++++++++++++---- - grub-core/commands/usbtest.c      |  2 +- - grub-core/disk/usbms.c            |  2 +- - grub-core/term/usb_keyboard.c     |  2 +- - include/grub/usb.h                |  2 +- - include/grub/usbdesc.h            | 11 +++++++- - 8 files changed, 59 insertions(+), 28 deletions(-) - -diff --git a/grub-core/bus/usb/serial/common.c b/grub-core/bus/usb/serial/common.c -index e9c995a0a..fc847d66d 100644 ---- a/grub-core/bus/usb/serial/common.c -+++ b/grub-core/bus/usb/serial/common.c -@@ -72,7 +72,7 @@ grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno, -   for (j = 0; j < interf->endpointcnt; j++) -     { -       struct grub_usb_desc_endp *endp; --      endp = &usbdev->config[0].interf[interfno].descendp[j]; -+      endp = usbdev->config[0].interf[interfno].descendp[j]; -  -       if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2 - 	  && (in_endp == GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING -diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c -index 7bd49d201..e578af793 100644 ---- a/grub-core/bus/usb/usb.c -+++ b/grub-core/bus/usb/usb.c -@@ -118,7 +118,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) -   struct grub_usb_desc_device *descdev; -   struct grub_usb_desc_config config; -   grub_usb_err_t err; --  int i; -+  int i, j; -  -   /* First we have to read first 8 bytes only and determine -    * max. size of packet */ -@@ -152,6 +152,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) -       int currif; -       char *data; -       struct grub_usb_desc *desc; -+      struct grub_usb_desc_endp *endp; -  -       /* First just read the first 4 bytes of the configuration - 	 descriptor, after that it is known how many bytes really have -@@ -201,24 +202,27 @@ grub_usb_device_initialize (grub_usb_device_t dev) - 	    = (struct grub_usb_desc_if *) &data[pos]; - 	  pos += dev->config[i].interf[currif].descif->length; -  -+    dev->config[i].interf[currif].descendp = grub_malloc ( -+            dev->config[i].interf[currif].descif->endpointcnt * -+            sizeof(struct grub_usb_desc_endp)); -+ -+    j = 0; - 	  while (pos < config.totallen) -             { -               desc = (struct grub_usb_desc *)&data[pos]; --              if (desc->type == GRUB_USB_DESCRIPTOR_ENDPOINT) --                break; --              if (!desc->length) --                { --                  err = GRUB_USB_ERR_BADDEVICE; --                  goto fail; --                } --              pos += desc->length; --            } -- --	  /* Point to the first endpoint.  */ --	  dev->config[i].interf[currif].descendp --	    = (struct grub_usb_desc_endp *) &data[pos]; --	  pos += (sizeof (struct grub_usb_desc_endp) --		  * dev->config[i].interf[currif].descif->endpointcnt); -+              if (desc->type == GRUB_USB_DESCRIPTOR_ENDPOINT) { -+                endp = (struct grub_usb_desc_endp *) &data[pos]; -+                dev->config[i].interf[currif].descendp[j++] = endp; -+                pos += desc->length; -+              } else { -+                if (!desc->length) -+                  { -+                    err = GRUB_USB_ERR_BADDEVICE; -+                    goto fail; -+                  } -+                pos += desc->length; -+             } -+	  } - 	} -     } -  -@@ -226,8 +230,14 @@ grub_usb_device_initialize (grub_usb_device_t dev) -  -  fail: -  --  for (i = 0; i < GRUB_USB_MAX_CONF; i++) -+  for (i = 0; i < GRUB_USB_MAX_CONF; i++) { -+    int currif; -+ -+    for (currif = 0; currif < dev->config[i].descconf->numif; currif++) -+      grub_free (dev->config[i].interf[currif].descendp); -+ -     grub_free (dev->config[i].descconf); -+  } -  -   return err; - } -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index f5608e330..2ae29cba1 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -82,8 +82,14 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, -   if (i == GRUB_USBHUB_MAX_DEVICES) -     { -       grub_error (GRUB_ERR_IO, "can't assign address to USB device"); --      for (i = 0; i < GRUB_USB_MAX_CONF; i++) --        grub_free (dev->config[i].descconf); -+      for (i = 0; i < GRUB_USB_MAX_CONF; i++) { -+	int currif; -+ -+	for (currif = 0; currif < dev->config[i].descconf->numif; currif++) -+	  grub_free (dev->config[i].interf[currif].descendp); -+ -+	grub_free (dev->config[i].descconf); -+      } -       grub_free (dev); -       return NULL; -     } -@@ -96,8 +102,14 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, - 			      i, 0, 0, NULL); -   if (err) -     { --      for (i = 0; i < GRUB_USB_MAX_CONF; i++) --        grub_free (dev->config[i].descconf); -+      for (i = 0; i < GRUB_USB_MAX_CONF; i++) { -+	int currif; -+ -+	for (currif = 0; currif < dev->config[i].descconf->numif; currif++) -+	  grub_free (dev->config[i].interf[currif].descendp); -+ -+	grub_free (dev->config[i].descconf); -+      } -       grub_free (dev); -       return NULL; -     } -@@ -176,7 +188,7 @@ grub_usb_add_hub (grub_usb_device_t dev) -        i++) -     { -       struct grub_usb_desc_endp *endp = NULL; --      endp = &dev->config[0].interf[0].descendp[i]; -+      endp = dev->config[0].interf[0].descendp[i]; -  -       if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) - 	  == GRUB_USB_EP_INTERRUPT) -diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c -index 2c6d93fe6..55a657635 100644 ---- a/grub-core/commands/usbtest.c -+++ b/grub-core/commands/usbtest.c -@@ -185,7 +185,7 @@ usb_iterate (grub_usb_device_t dev, void *data __attribute__ ((unused))) -       for (j = 0; j < interf->endpointcnt; j++) - 	{ - 	  struct grub_usb_desc_endp *endp; --	  endp = &dev->config[0].interf[i].descendp[j]; -+	  endp = dev->config[0].interf[i].descendp[j]; -  - 	  grub_printf ("Endpoint #%d: %s, max packed size: %d, transfer type: %s, latency: %d\n", - 		       endp->endp_addr & 15, -diff --git a/grub-core/disk/usbms.c b/grub-core/disk/usbms.c -index b81e3ad9d..b1512dc12 100644 ---- a/grub-core/disk/usbms.c -+++ b/grub-core/disk/usbms.c -@@ -184,7 +184,7 @@ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno) -   for (j = 0; j < interf->endpointcnt; j++) -     { -       struct grub_usb_desc_endp *endp; --      endp = &usbdev->config[0].interf[interfno].descendp[j]; -+      endp = usbdev->config[0].interf[interfno].descendp[j]; -  -       if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2) - 	/* Bulk IN endpoint.  */ -diff --git a/grub-core/term/usb_keyboard.c b/grub-core/term/usb_keyboard.c -index 7322d8dff..d590979f5 100644 ---- a/grub-core/term/usb_keyboard.c -+++ b/grub-core/term/usb_keyboard.c -@@ -175,7 +175,7 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) -   for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt; -        j++) -     { --      endp = &usbdev->config[configno].interf[interfno].descendp[j]; -+      endp = usbdev->config[configno].interf[interfno].descendp[j]; -  -       if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) - 	  == GRUB_USB_EP_INTERRUPT) -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 0f346af12..688c11f6d 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -153,7 +153,7 @@ struct grub_usb_interface - { -   struct grub_usb_desc_if *descif; -  --  struct grub_usb_desc_endp *descendp; -+  struct grub_usb_desc_endp **descendp; -  -   /* A driver is handling this interface. Do we need to support multiple drivers -      for single interface? -diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h -index aac5ab05a..bb2ab2e27 100644 ---- a/include/grub/usbdesc.h -+++ b/include/grub/usbdesc.h -@@ -29,7 +29,8 @@ typedef enum { -   GRUB_USB_DESCRIPTOR_INTERFACE, -   GRUB_USB_DESCRIPTOR_ENDPOINT, -   GRUB_USB_DESCRIPTOR_DEBUG = 10, --  GRUB_USB_DESCRIPTOR_HUB = 0x29 -+  GRUB_USB_DESCRIPTOR_HUB = 0x29, -+  GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 - } grub_usb_descriptor_t; -  - struct grub_usb_desc -@@ -105,6 +106,14 @@ struct grub_usb_desc_endp -   grub_uint8_t interval; - } GRUB_PACKED; -  -+struct grub_usb_desc_ssep { -+  grub_uint8_t  length; -+  grub_uint8_t  type; -+  grub_uint8_t  maxburst; -+  grub_uint8_t  attrib; -+  grub_uint16_t interval; -+} GRUB_PACKED; -+ - struct grub_usb_desc_str - { -   grub_uint8_t length; ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0002-usb-Add-enum-for-xHCI.patch b/config/grub/patches/0005-xhci/0002-usb-Add-enum-for-xHCI.patch deleted file mode 100644 index d61da615..00000000 --- a/config/grub/patches/0005-xhci/0002-usb-Add-enum-for-xHCI.patch +++ /dev/null @@ -1,29 +0,0 @@ -From e111983ca5e2a52bfe2bdc5cd639b06bb2f7902d Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Sun, 15 Nov 2020 19:47:06 +0100 -Subject: [PATCH 2/8] usb: Add enum for xHCI - -Will be used in future patches. - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - include/grub/usb.h | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 688c11f6d..ea6ee8c2c 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -51,7 +51,8 @@ typedef enum -     GRUB_USB_SPEED_NONE, -     GRUB_USB_SPEED_LOW, -     GRUB_USB_SPEED_FULL, --    GRUB_USB_SPEED_HIGH -+    GRUB_USB_SPEED_HIGH, -+    GRUB_USB_SPEED_SUPER -   } grub_usb_speed_t; -  - typedef int (*grub_usb_iterate_hook_t) (grub_usb_device_t dev, void *data); ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0003-usbtrans-Set-default-maximum-packet-size.patch b/config/grub/patches/0005-xhci/0003-usbtrans-Set-default-maximum-packet-size.patch deleted file mode 100644 index 70e73ca2..00000000 --- a/config/grub/patches/0005-xhci/0003-usbtrans-Set-default-maximum-packet-size.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 3e25c83a1d1c6e149c7e9f0660ddadb2beca2476 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Sun, 15 Nov 2020 19:48:03 +0100 -Subject: [PATCH 3/8] usbtrans: Set default maximum packet size - -Set the maximum packet size to 512 for SuperSpeed devices. - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - grub-core/bus/usb/usbtrans.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c -index c5680b33a..c1080bb33 100644 ---- a/grub-core/bus/usb/usbtrans.c -+++ b/grub-core/bus/usb/usbtrans.c -@@ -128,8 +128,12 @@ grub_usb_control_msg (grub_usb_device_t dev, -   setupdata_addr = grub_dma_get_phys (setupdata_chunk); -  -   /* Determine the maximum packet size.  */ --  if (dev->descdev.maxsize0) -+  if (dev->descdev.maxsize0 && dev->speed != GRUB_USB_SPEED_SUPER) -     max = dev->descdev.maxsize0; -+  else if (dev->descdev.maxsize0 && dev->speed == GRUB_USB_SPEED_SUPER) -+    max = 1UL << dev->descdev.maxsize0; -+  else if (dev->speed == GRUB_USB_SPEED_SUPER) -+    max = 512; -   else -     max = 64; -  ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0004-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch b/config/grub/patches/0005-xhci/0004-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch deleted file mode 100644 index a090e0ea..00000000 --- a/config/grub/patches/0005-xhci/0004-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 89701aba00caa81bb566ab10da0c89264393be30 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Sun, 15 Nov 2020 19:51:42 +0100 -Subject: [PATCH 4/8] grub-core/bus/usb: Add function pointer for attach/detach - events - -The xHCI code needs to be called for attaching or detaching a device. -Introduce two functions pointers and call it from the USB hub code. - -Will be used in future commits, currently this doesn't change any functionality. - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - grub-core/bus/usb/ehci.c   |  2 ++ - grub-core/bus/usb/ohci.c   |  2 ++ - grub-core/bus/usb/uhci.c   |  2 ++ - grub-core/bus/usb/usbhub.c | 19 +++++++++++++++++++ - include/grub/usb.h         |  4 ++++ - 5 files changed, 29 insertions(+) - -diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c -index 9abebc6bd..953b851c0 100644 ---- a/grub-core/bus/usb/ehci.c -+++ b/grub-core/bus/usb/ehci.c -@@ -1812,6 +1812,8 @@ static struct grub_usb_controller_dev usb_controller = { -   .hubports = grub_ehci_hubports, -   .portstatus = grub_ehci_portstatus, -   .detect_dev = grub_ehci_detect_dev, -+  .attach_dev = NULL, -+  .detach_dev = NULL, -   /* estimated max. count of TDs for one bulk transfer */ -   .max_bulk_tds = GRUB_EHCI_N_TD * 3 / 4 - }; -diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c -index 5363a61f6..7a3f3e154 100644 ---- a/grub-core/bus/usb/ohci.c -+++ b/grub-core/bus/usb/ohci.c -@@ -1440,6 +1440,8 @@ static struct grub_usb_controller_dev usb_controller = -   .hubports = grub_ohci_hubports, -   .portstatus = grub_ohci_portstatus, -   .detect_dev = grub_ohci_detect_dev, -+  .attach_dev = NULL, -+  .detach_dev = NULL, -   /* estimated max. count of TDs for one bulk transfer */ -   .max_bulk_tds = GRUB_OHCI_TDS * 3 / 4 - }; -diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c -index 0fdea4c1e..03c4605b2 100644 ---- a/grub-core/bus/usb/uhci.c -+++ b/grub-core/bus/usb/uhci.c -@@ -845,6 +845,8 @@ static struct grub_usb_controller_dev usb_controller = -   .hubports = grub_uhci_hubports, -   .portstatus = grub_uhci_portstatus, -   .detect_dev = grub_uhci_detect_dev, -+  .attach_dev = NULL, -+  .detach_dev = NULL, -   /* estimated max. count of TDs for one bulk transfer */ -   .max_bulk_tds = N_TD * 3 / 4 - }; -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index 2ae29cba1..8e963e84b 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -66,6 +66,15 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, -   dev->split_hubport = split_hubport; -   dev->split_hubaddr = split_hubaddr; -  -+  if (controller->dev->attach_dev) { -+    err = controller->dev->attach_dev (controller, dev); -+    if (err) -+      { -+	grub_free (dev); -+	return NULL; -+      } -+  } -+ -   err = grub_usb_device_initialize (dev); -   if (err) -     { -@@ -405,6 +414,8 @@ static void - detach_device (grub_usb_device_t dev) - { -   unsigned i; -+  grub_usb_err_t err; -+ -   int k; -   if (!dev) -     return; -@@ -425,6 +436,14 @@ detach_device (grub_usb_device_t dev) - 	  if (inter && inter->detach_hook) - 	    inter->detach_hook (dev, i, k); - 	} -+  if (dev->controller.dev->detach_dev) { -+    err = dev->controller.dev->detach_dev (&dev->controller, dev); -+    if (err) -+      { -+	// XXX -+      } -+  } -+ -   grub_usb_devs[dev->addr] = 0; - } -  -diff --git a/include/grub/usb.h b/include/grub/usb.h -index ea6ee8c2c..4dd179db2 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -126,6 +126,10 @@ struct grub_usb_controller_dev -  -   grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed); -  -+  grub_usb_err_t (*attach_dev) (grub_usb_controller_t ctrl, grub_usb_device_t dev); -+ -+  grub_usb_err_t (*detach_dev) (grub_usb_controller_t ctrl, grub_usb_device_t dev); -+ -   /* Per controller flag - port reset pending, don't do another reset */ -   grub_uint64_t pending_reset; -  ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0005-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch b/config/grub/patches/0005-xhci/0005-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch deleted file mode 100644 index 7d69c3a6..00000000 --- a/config/grub/patches/0005-xhci/0005-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 5e5d74a4531770258e21dedd45c33f1a9d3afa6b Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Sun, 15 Nov 2020 19:54:40 +0100 -Subject: [PATCH 5/8] grub-core/bus/usb/usbhub: Add new private fields for xHCI - controller - -Store the root port number, the route, consisting out of the port ID -in each nibble, and a pointer to driver private data. - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - grub-core/bus/usb/usbhub.c | 11 ++++++++--- - include/grub/usb.h         |  5 +++++ - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index 8e963e84b..b4b3a1a61 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -49,7 +49,9 @@ static grub_usb_controller_dev_t grub_usb_list; - static grub_usb_device_t - grub_usb_hub_add_dev (grub_usb_controller_t controller, -                       grub_usb_speed_t speed, --                      int split_hubport, int split_hubaddr) -+                      int split_hubport, int split_hubaddr, -+                      int root_portno, -+                      grub_uint32_t route) - { -   grub_usb_device_t dev; -   int i; -@@ -65,6 +67,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, -   dev->speed = speed; -   dev->split_hubport = split_hubport; -   dev->split_hubaddr = split_hubaddr; -+  dev->root_port = root_portno; -+  dev->route = route; -  -   if (controller->dev->attach_dev) { -     err = controller->dev->attach_dev (controller, dev); -@@ -245,7 +249,7 @@ attach_root_port (struct grub_usb_hub *hub, int portno, -      and full/low speed device connected to OHCI/UHCI needs not -      transaction translation - e.g. hubport and hubaddr should be -      always none (zero) for any device connected to any root hub. */ --  dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0); -+  dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0, portno, 0); -   hub->controller->dev->pending_reset = 0; -   npending--; -   if (! dev) -@@ -676,7 +680,8 @@ poll_nonroot_hub (grub_usb_device_t dev) -  - 	      /* Add the device and assign a device address to it.  */ - 	      next_dev = grub_usb_hub_add_dev (&dev->controller, speed, --					       split_hubport, split_hubaddr); -+					       split_hubport, split_hubaddr, dev->root_port, -+					       dev->route << 4 | (i & 0xf)); - 	      if (dev->controller.dev->pending_reset) - 		{ - 		  dev->controller.dev->pending_reset = 0; -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 4dd179db2..609faf7d0 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -237,6 +237,11 @@ struct grub_usb_device -   int split_hubport; -  -   int split_hubaddr; -+ -+  /* xHCI specific information */ -+  int root_port; -+  grub_uint32_t route; -+  void *xhci_priv; - }; -  -  ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0006-grub-core-bus-usb-Add-xhci-support.patch b/config/grub/patches/0005-xhci/0006-grub-core-bus-usb-Add-xhci-support.patch deleted file mode 100644 index 11df42d8..00000000 --- a/config/grub/patches/0005-xhci/0006-grub-core-bus-usb-Add-xhci-support.patch +++ /dev/null @@ -1,2814 +0,0 @@ -From fe3a0bce527e059e9121eb5ad2c3cc099f07a4bf Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Sun, 15 Nov 2020 19:59:25 +0100 -Subject: [PATCH 6/8] grub-core/bus/usb: Add xhci support - -Add support for xHCI USB controllers. -The code is based on seabios implementation, but has been heavily -modified to match grubs internals. - -Changes done in version 2: -* Code cleanup -* Code style fixes -* Don't leak memory buffers -* Compile without warnings -* Add more defines -* Add more helper functions -* Don't assume a 1:1 virtual to physical mapping -* Flush cachelines after writing buffers -* Don't use hardcoded page size -* Proper scratchpad register setup -* xHCI bios ownership handoff - -Changes done in version 3: -* Fixed a race condition detecting events, which doesn't appear on -  qemu based xHCI controllers -* Don't accidently disable USB3.0 devices after first command -* Support arbitrary protocol speed IDs -* Coding style cleanup - -Tested: -* Qemu system x86_64 -  * virtual USB HID keyboard (usb-kbd) -  * virtual USB HID mass storage (usb-storage) -* init Supermicro X11SSH-F -  * iKVM HID keyboard -  * USB3 HID mass storage (controller root port) -  * USB HID keyboard - -TODO: -  * Test on more hardware -  * Test on USB3 hubs -  * Support for USB 3.1 and USB 3.2 controllers - -Tested on qemu using coreboot and grub as payload: - -qemu-system-x86_64 -M q35 -bios $firmware -device qemu-xhci,id=xhci -accel kvm -m 1024M \ -	-device usb-storage,drive=thumbdrive,bus=xhci.0,port=3 \ -	-drive if=none,format=raw,id=thumbdrive,file=ubuntu-20.04.1-desktop-amd64.iso \ -	-device usb-kbd,bus=xhci.0 - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> -Signed-off-by: sylv <sylv@sylv.io> ---- - Makefile.am                  |    2 +- - grub-core/Makefile.core.def  |    7 + - grub-core/bus/usb/xhci-pci.c |  195 +++ - grub-core/bus/usb/xhci.c     | 2496 ++++++++++++++++++++++++++++++++++ - include/grub/usb.h           |    4 + - 5 files changed, 2703 insertions(+), 1 deletion(-) - create mode 100644 grub-core/bus/usb/xhci-pci.c - create mode 100644 grub-core/bus/usb/xhci.c - -diff --git a/Makefile.am b/Makefile.am -index 43635d5ff..65016f856 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -434,7 +434,7 @@ if COND_i386_coreboot - FS_PAYLOAD_MODULES ?= $(shell cat grub-core/fs.lst) - default_payload.elf: grub-mkstandalone grub-mkimage FORCE - 	test -f $@ && rm $@ || true --	pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg -+	pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata xhci ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg - endif -  - endif -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index fb6078a34..64c3806ab 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -667,6 +667,13 @@ module = { -   enable = arm_coreboot; - }; -  -+module = { -+  name = xhci; -+  common = bus/usb/xhci.c; -+  pci = bus/usb/xhci-pci.c; -+  enable = pci; -+}; -+ - module = { -   name = pci; -   common = bus/pci.c; -diff --git a/grub-core/bus/usb/xhci-pci.c b/grub-core/bus/usb/xhci-pci.c -new file mode 100644 -index 000000000..a5bd3c97d ---- /dev/null -+++ b/grub-core/bus/usb/xhci-pci.c -@@ -0,0 +1,195 @@ -+/* xhci.c - XHCI Support.  */ -+/* -+ *  GRUB  --  GRand Unified Bootloader -+ *  Copyright (C) 2020 9elements Cyber Security -+ * -+ *  GRUB is free software: you can redistribute it and/or modify -+ *  it under the terms of the GNU General Public License as published by -+ *  the Free Software Foundation, either version 3 of the License, or -+ *  (at your option) any later version. -+ * -+ *  GRUB is distributed in the hope that it will be useful, -+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of -+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -+ *  GNU General Public License for more details. -+ * -+ *  You should have received a copy of the GNU General Public License -+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#include <grub/pci.h> -+#include <grub/cpu/pci.h> -+#include <grub/cs5536.h> -+#include <grub/misc.h> -+#include <grub/mm.h> -+#include <grub/time.h> -+#include <grub/usb.h> -+ -+#define GRUB_XHCI_PCI_SBRN_REG  0x60 -+#define GRUB_XHCI_ADDR_MEM_MASK	(~0xff) -+ -+/* USBLEGSUP bits and related OS OWNED byte offset */ -+enum -+{ -+  GRUB_XHCI_BIOS_OWNED = (1 << 16), -+  GRUB_XHCI_OS_OWNED = (1 << 24) -+}; -+ -+/* PCI iteration function... */ -+static int -+grub_xhci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid, -+		    void *data __attribute__ ((unused))) -+{ -+  volatile grub_uint32_t *regs; -+  grub_uint32_t base, base_h; -+  grub_uint32_t eecp_offset; -+  grub_uint32_t usblegsup = 0; -+  grub_uint64_t maxtime; -+  grub_uint32_t interf; -+  grub_uint32_t subclass; -+  grub_uint32_t class; -+  grub_uint8_t release; -+  grub_uint32_t class_code; -+ -+  grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: begin\n"); -+ -+  if (pciid == GRUB_CS5536_PCIID) -+    { -+	grub_dprintf ("xhci", "CS5536 not supported\n"); -+	return 0; -+    } -+  else -+    { -+      grub_pci_address_t addr; -+      addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); -+      class_code = grub_pci_read (addr) >> 8; -+      interf = class_code & 0xFF; -+      subclass = (class_code >> 8) & 0xFF; -+      class = class_code >> 16; -+ -+      /* If this is not an XHCI controller, just return.  */ -+      if (class != 0x0c || subclass != 0x03 || interf != 0x30) -+	return 0; -+ -+      grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: class OK\n"); -+ -+      /* Check Serial Bus Release Number */ -+      addr = grub_pci_make_address (dev, GRUB_XHCI_PCI_SBRN_REG); -+      release = grub_pci_read_byte (addr); -+      if (release != 0x30) -+	{ -+	  grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: Wrong SBRN: %0x\n", -+			release); -+	  return 0; -+	} -+      grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: bus rev. num. OK\n"); -+ -+      /* Determine XHCI XHCC registers base address.  */ -+      addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); -+      base = grub_pci_read (addr); -+      addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1); -+      base_h = grub_pci_read (addr); -+      /* Stop if registers are mapped above 4G - GRUB does not currently -+       * work with registers mapped above 4G */ -+      if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32) -+	  && (base_h != 0)) -+	{ -+	  grub_dprintf ("xhci", -+			"XHCI grub_xhci_pci_iter: registers above 4G are not supported\n"); -+	  return 0; -+	} -+      base &= GRUB_PCI_ADDR_MEM_MASK; -+      if (!base) -+	{ -+	  grub_dprintf ("xhci", -+			"XHCI: XHCI is not mapped\n"); -+	  return 0; -+	} -+ -+      /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */ -+      addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); -+      grub_pci_write_word(addr, -+			  GRUB_PCI_COMMAND_MEM_ENABLED -+			  | GRUB_PCI_COMMAND_BUS_MASTER -+			  | grub_pci_read_word(addr)); -+ -+      grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: 32-bit XHCI OK\n"); -+    } -+ -+  grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: iobase of XHCC: %08x\n", -+		(base & GRUB_XHCI_ADDR_MEM_MASK)); -+ -+  regs = grub_pci_device_map_range (dev, -+				    (base & GRUB_XHCI_ADDR_MEM_MASK), -+				    0x100); -+ -+  /* Is there EECP ? */ -+  eecp_offset = (grub_le_to_cpu32 (regs[2]) >> 8) & 0xff; -+ -+    /* Determine and change ownership. */ -+  /* EECP offset valid in HCCPARAMS */ -+  /* Ownership can be changed via EECP only */ -+  if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40) -+    { -+      grub_pci_address_t pciaddr_eecp; -+      pciaddr_eecp = grub_pci_make_address (dev, eecp_offset); -+ -+      usblegsup = grub_pci_read (pciaddr_eecp); -+      if (usblegsup & GRUB_XHCI_BIOS_OWNED) -+	{ -+	  grub_boot_time ("Taking ownership of XHCI controller"); -+	  grub_dprintf ("xhci", -+			"XHCI grub_xhci_pci_iter: XHCI owned by: BIOS\n"); -+	  /* Ownership change - set OS_OWNED bit */ -+	  grub_pci_write (pciaddr_eecp, usblegsup | GRUB_XHCI_OS_OWNED); -+	  /* Ensure PCI register is written */ -+	  grub_pci_read (pciaddr_eecp); -+ -+	  /* Wait for finish of ownership change, XHCI specification -+	   * doesn't say how long it can take... */ -+	  maxtime = grub_get_time_ms () + 1000; -+	  while ((grub_pci_read (pciaddr_eecp) & GRUB_XHCI_BIOS_OWNED) -+		 && (grub_get_time_ms () < maxtime)); -+	  if (grub_pci_read (pciaddr_eecp) & GRUB_XHCI_BIOS_OWNED) -+	    { -+	      grub_dprintf ("xhci", -+			    "XHCI grub_xhci_pci_iter: XHCI change ownership timeout"); -+	      /* Change ownership in "hard way" - reset BIOS ownership */ -+	      grub_pci_write (pciaddr_eecp, GRUB_XHCI_OS_OWNED); -+	      /* Ensure PCI register is written */ -+	      grub_pci_read (pciaddr_eecp); -+	    } -+	} -+      else if (usblegsup & GRUB_XHCI_OS_OWNED) -+	/* XXX: What to do in this case - nothing ? Can it happen ? */ -+	grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: XHCI owned by: OS\n"); -+      else -+	{ -+	  grub_dprintf ("xhci", -+			"XHCI grub_Xhci_pci_iter: XHCI owned by: NONE\n"); -+	  /* XXX: What to do in this case ? Can it happen ? -+	   * Is code below correct ? */ -+	  /* Ownership change - set OS_OWNED bit */ -+	  grub_pci_write (pciaddr_eecp, GRUB_XHCI_OS_OWNED); -+	  /* Ensure PCI register is written */ -+	  grub_pci_read (pciaddr_eecp); -+	} -+ -+      /* Disable SMI, just to be sure.  */ -+      pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4); -+      grub_pci_write (pciaddr_eecp, 0); -+      /* Ensure PCI register is written */ -+      grub_pci_read (pciaddr_eecp); -+    } -+ -+  grub_dprintf ("xhci", "inithw: XHCI grub_xhci_pci_iter: ownership OK\n"); -+ -+  grub_xhci_init_device (regs); -+  return 0; -+} -+ -+void -+grub_xhci_pci_scan (void) -+{ -+  grub_pci_iterate (grub_xhci_pci_iter, NULL); -+} -diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c -new file mode 100644 -index 000000000..f4591ffb5 ---- /dev/null -+++ b/grub-core/bus/usb/xhci.c -@@ -0,0 +1,2496 @@ -+/* xhci.c - XHCI Support.  */ -+/* -+ *  GRUB  --  GRand Unified Bootloader -+ *  Copyright (C) 2020 9elements Cyber Security -+ * -+ *  GRUB is free software: you can redistribute it and/or modify -+ *  it under the terms of the GNU General Public License as published by -+ *  the Free Software Foundation, either version 3 of the License, or -+ *  (at your option) any later version. -+ * -+ *  GRUB is distributed in the hope that it will be useful, -+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of -+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -+ *  GNU General Public License for more details. -+ * -+ *  You should have received a copy of the GNU General Public License -+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. -+ * -+ * Big parts of this software are inspired by seabios XHCI implementation -+ * Released under LGPLv3. Credits to: -+ * -+ * Copyright (C) 2013  Gerd Hoffmann <kraxel@redhat.com> -+ * Copyright (C) 2014  Kevin O'Connor <kevin@koconnor.net> -+ */ -+ -+#include <grub/dl.h> -+#include <grub/err.h> -+#include <grub/mm.h> -+#include <grub/usb.h> -+#include <grub/usbtrans.h> -+#include <grub/misc.h> -+#include <grub/time.h> -+#include <grub/loader.h> -+#include <grub/disk.h> -+#include <grub/dma.h> -+#include <grub/cache.h> -+#include <grub/i386/cpuid.h> -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+/* This simple GRUB implementation of XHCI driver */ -+/* Based on the specification -+ * "eXtensible Host Controller Interface for Universal Serial Bus" Revision 1.2 -+ */ -+ -+ -+#define xhci_get_field(data, field)	     \ -+    (((data) >> field##_SHIFT) & field##_MASK) -+#define XHCI_PORTSC_PLS_MASK     0xf -+#define XHCI_PORTSC_PLS_SHIFT    5 -+#define XHCI_PORTSC_SPEED_MASK   0xf -+#define XHCI_PORTSC_SPEED_SHIFT  10 -+ -+enum -+{ -+  XHCI_USB_FULLSPEED = 1, -+  XHCI_USB_LOWSPEED, -+  XHCI_USB_HIGHSPEED, -+  XHCI_USB_SUPERSPEED -+}; -+ -+/* Chapter 5.3 Host Controller Capability Registers */ -+struct grub_xhci_caps { -+    grub_uint8_t  caplength; -+    grub_uint8_t  reserved_01; -+    grub_uint16_t hciversion; -+    grub_uint32_t hcsparams1; -+    grub_uint32_t hcsparams2; -+    grub_uint32_t hcsparams3; -+    grub_uint32_t hccparams; -+    grub_uint32_t dboff; -+    grub_uint32_t rtsoff; -+    grub_uint32_t hccparams2; -+} GRUB_PACKED; -+ -+/* extended capabilities */ -+struct grub_xhci_xcap { -+    grub_uint32_t cap; -+    grub_uint32_t data[]; -+} GRUB_PACKED; -+ -+#define XHCI_CAP_LEGACY_SUPPORT 1 -+#define XHCI_CAP_SUPPORTED_PROTOCOL 2 -+ -+struct xhci_portmap { -+    grub_uint8_t start; -+    grub_uint8_t count; -+} GRUB_PACKED; -+ -+struct grub_xhci_op { -+    grub_uint32_t usbcmd; -+    grub_uint32_t usbsts; -+    grub_uint32_t pagesize; -+    grub_uint32_t reserved_01[2]; -+    grub_uint32_t dnctl; -+    grub_uint32_t crcr_low; -+    grub_uint32_t crcr_high; -+    grub_uint32_t reserved_02[4]; -+    grub_uint32_t dcbaap_low; -+    grub_uint32_t dcbaap_high; -+    grub_uint32_t config; -+} GRUB_PACKED; -+ -+enum -+{ -+  GRUB_XHCI_CMD_RS = (1<<0), -+  GRUB_XHCI_CMD_HCRST = (1<<1), -+  GRUB_XHCI_CMD_INTE = (1<<2), -+  GRUB_XHCI_CMD_HSEE = (1<<3), -+  GRUB_XHCI_CMD_LHCRST = (1<<7), -+  GRUB_XHCI_CMD_CSS = (1<<8), -+  GRUB_XHCI_CMD_CRS = (1<<9), -+  GRUB_XHCI_CMD_EWE = (1<<10), -+  GRUB_XHCI_CMD_EU3S = (1<<11) -+}; -+ -+enum -+{ -+  GRUB_XHCI_STS_HCH = (1<<0), -+  GRUB_XHCI_STS_HSE = (1<<2), -+  GRUB_XHCI_STS_EINT = (1<<3), -+  GRUB_XHCI_STS_PCD = (1<<4), -+  GRUB_XHCI_STS_SSS = (1<<8), -+  GRUB_XHCI_STS_RSS = (1<<9), -+  GRUB_XHCI_STS_SRE = (1<<10), -+  GRUB_XHCI_STS_CNR = (1<<11), -+  GRUB_XHCI_STS_HCE = (1<<12) -+}; -+ -+ -+/* Port Registers Offset */ -+#define GRUB_XHCI_PR_OFFSET 0x400 -+/* Interrupter Registers Offset */ -+#define GRUB_XHCI_IR_OFFSET 0x20 -+ -+/* Port Status and Control registers offsets */ -+ -+/* Chapter 6 Data Structures */ -+#define ALIGN_SPBA 64 -+#define ALIGN_DCBAA 64 -+#define ALIGN_CMD_RING_SEG 64 -+#define ALIGN_EVT_RING_SEG 64 -+#define ALIGN_EVT_RING_TABLE 64 -+#define ALIGN_TRB 16 -+#define ALIGN_INCTX 64 -+#define ALIGN_SLOTCTX 32 -+ -+#define BOUNDARY_RING 0x10000 -+ -+enum -+{ -+  GRUB_XHCI_PORTSC_CCS = (1<<0), -+  GRUB_XHCI_PORTSC_PED = (1<<1), -+  GRUB_XHCI_PORTSC_OCA = (1<<3), -+  GRUB_XHCI_PORTSC_PR = (1<<4), -+  GRUB_XHCI_PORTSC_PP = (1<<9), -+  GRUB_XHCI_PORTSC_SPEED_FULL = (1<<10), -+  GRUB_XHCI_PORTSC_SPEED_LOW = (2<<10), -+  GRUB_XHCI_PORTSC_SPEED_HIGH = (3<<10), -+  GRUB_XHCI_PORTSC_SPEED_SUPER = (4<<10), -+  GRUB_XHCI_PORTSC_LWS = (1<<16), -+  GRUB_XHCI_PORTSC_CSC = (1<<17), -+  GRUB_XHCI_PORTSC_PEC = (1<<18), -+  GRUB_XHCI_PORTSC_WRC = (1<<19), -+  GRUB_XHCI_PORTSC_OCC = (1<<20), -+  GRUB_XHCI_PORTSC_PRC = (1<<21), -+  GRUB_XHCI_PORTSC_PLC = (1<<22), -+  GRUB_XHCI_PORTSC_CEC = (1<<23), -+  GRUB_XHCI_PORTSC_CAS = (1<<24), -+  GRUB_XHCI_PORTSC_WCE = (1<<25), -+  GRUB_XHCI_PORTSC_WDE = (1<<26), -+  GRUB_XHCI_PORTSC_WOE = (1<<27), -+  GRUB_XHCI_PORTSC_DR = (1<<30), -+  GRUB_XHCI_PORTSC_WPR = (1<<31) -+}; -+ -+/* XHCI memory data structs */ -+#define GRUB_XHCI_MAX_ENDPOINTS 32 -+ -+#define GRUB_XHCI_RING_ITEMS 128 -+#define GRUB_XHCI_RING_SIZE (GRUB_XHCI_RING_ITEMS*sizeof(struct grub_xhci_trb)) -+/* -+ *  xhci_ring structs are allocated with XHCI_RING_SIZE alignment, -+ *  then we can get it from a trb pointer (provided by evt ring). -+ */ -+#define XHCI_RING(_trb)	  \ -+    ((struct grub_xhci_ring*)((grub_uint32_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) -+ -+/* slot context */ -+struct grub_xhci_slotctx { -+  grub_uint32_t ctx[4]; -+  grub_uint32_t reserved_01[4]; -+} GRUB_PACKED; -+ -+/* endpoint context */ -+struct grub_xhci_epctx { -+  grub_uint32_t ctx[2]; -+  grub_uint32_t deq_low; -+  grub_uint32_t deq_high; -+  grub_uint32_t length; -+  grub_uint32_t reserved_01[3]; -+} GRUB_PACKED; -+ -+/* device context array element */ -+struct grub_xhci_devlist { -+  grub_uint32_t ptr_low; -+  grub_uint32_t ptr_high; -+} GRUB_PACKED; -+ -+/* input context */ -+struct grub_xhci_inctx { -+  grub_uint32_t del; -+  grub_uint32_t add; -+  grub_uint32_t reserved_01[6]; -+} GRUB_PACKED; -+ -+/* transfer block (ring element) */ -+struct grub_xhci_trb { -+  grub_uint32_t ptr_low; -+  grub_uint32_t ptr_high; -+  grub_uint32_t status; -+  grub_uint32_t control; -+} GRUB_PACKED; -+ -+#define TRB_C	       (1<<0) -+#define TRB_TYPE_SHIFT	  10 -+#define TRB_TYPE_MASK       0x3f -+#define TRB_TYPE(t)	 (((t) >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK) -+ -+#define TRB_EV_ED	   (1<<2) -+ -+#define TRB_TR_ENT	  (1<<1) -+#define TRB_TR_ISP	  (1<<2) -+#define TRB_TR_NS	   (1<<3) -+#define TRB_TR_CH	   (1<<4) -+#define TRB_TR_IOC	  (1<<5) -+#define TRB_TR_IDT	  (1<<6) -+#define TRB_TR_TBC_SHIFT	7 -+#define TRB_TR_TBC_MASK     0x3 -+#define TRB_TR_BEI	  (1<<9) -+#define TRB_TR_TLBPC_SHIFT      16 -+#define TRB_TR_TLBPC_MASK   0xf -+#define TRB_TR_FRAMEID_SHIFT    20 -+#define TRB_TR_FRAMEID_MASK 0x7ff -+#define TRB_TR_SIA	  (1<<31) -+ -+#define TRB_TR_DIR	  (1<<16) -+ -+#define TRB_CR_SLOTID_SHIFT     24 -+#define TRB_CR_SLOTID_MASK  0xff -+#define TRB_CR_EPID_SHIFT       16 -+#define TRB_CR_EPID_MASK    0x1f -+ -+#define TRB_CR_BSR	  (1<<9) -+#define TRB_CR_DC	   (1<<9) -+ -+#define TRB_LK_TC	   (1<<1) -+ -+#define TRB_INTR_SHIFT	  22 -+#define TRB_INTR_MASK       0x3ff -+#define TRB_INTR(t)	 (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) -+ -+typedef enum TRBType { -+    TRB_RESERVED = 0, -+    TR_NORMAL, -+    TR_SETUP, -+    TR_DATA, -+    TR_STATUS, -+    TR_ISOCH, -+    TR_LINK, -+    TR_EVDATA, -+    TR_NOOP, -+    CR_ENABLE_SLOT, -+    CR_DISABLE_SLOT, -+    CR_ADDRESS_DEVICE, -+    CR_CONFIGURE_ENDPOINT, -+    CR_EVALUATE_CONTEXT, -+    CR_RESET_ENDPOINT, -+    CR_STOP_ENDPOINT, -+    CR_SET_TR_DEQUEUE, -+    CR_RESET_DEVICE, -+    CR_FORCE_EVENT, -+    CR_NEGOTIATE_BW, -+    CR_SET_LATENCY_TOLERANCE, -+    CR_GET_PORT_BANDWIDTH, -+    CR_FORCE_HEADER, -+    CR_NOOP, -+    ER_TRANSFER = 32, -+    ER_COMMAND_COMPLETE, -+    ER_PORT_STATUS_CHANGE, -+    ER_BANDWIDTH_REQUEST, -+    ER_DOORBELL, -+    ER_HOST_CONTROLLER, -+    ER_DEVICE_NOTIFICATION, -+    ER_MFINDEX_WRAP, -+} TRBType; -+ -+typedef enum TRBCCode { -+    CC_INVALID = 0, -+    CC_SUCCESS, -+    CC_DATA_BUFFER_ERROR, -+    CC_BABBLE_DETECTED, -+    CC_USB_TRANSACTION_ERROR, -+    CC_TRB_ERROR, -+    CC_STALL_ERROR, -+    CC_RESOURCE_ERROR, -+    CC_BANDWIDTH_ERROR, -+    CC_NO_SLOTS_ERROR, -+    CC_INVALID_STREAM_TYPE_ERROR, -+    CC_SLOT_NOT_ENABLED_ERROR, -+    CC_EP_NOT_ENABLED_ERROR, -+    CC_SHORT_PACKET, -+    CC_RING_UNDERRUN, -+    CC_RING_OVERRUN, -+    CC_VF_ER_FULL, -+    CC_PARAMETER_ERROR, -+    CC_BANDWIDTH_OVERRUN, -+    CC_CONTEXT_STATE_ERROR, -+    CC_NO_PING_RESPONSE_ERROR, -+    CC_EVENT_RING_FULL_ERROR, -+    CC_INCOMPATIBLE_DEVICE_ERROR, -+    CC_MISSED_SERVICE_ERROR, -+    CC_COMMAND_RING_STOPPED, -+    CC_COMMAND_ABORTED, -+    CC_STOPPED, -+    CC_STOPPED_LENGTH_INVALID, -+    CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29, -+    CC_ISOCH_BUFFER_OVERRUN = 31, -+    CC_EVENT_LOST_ERROR, -+    CC_UNDEFINED_ERROR, -+    CC_INVALID_STREAM_ID_ERROR, -+    CC_SECONDARY_BANDWIDTH_ERROR, -+    CC_SPLIT_TRANSACTION_ERROR -+} TRBCCode; -+ -+enum { -+    PLS_U0	      =  0, -+    PLS_U1	      =  1, -+    PLS_U2	      =  2, -+    PLS_U3	      =  3, -+    PLS_DISABLED	=  4, -+    PLS_RX_DETECT       =  5, -+    PLS_INACTIVE	=  6, -+    PLS_POLLING	 =  7, -+    PLS_RECOVERY	=  8, -+    PLS_HOT_RESET       =  9, -+    PLS_COMPILANCE_MODE = 10, -+    PLS_TEST_MODE       = 11, -+    PLS_RESUME	  = 15, -+}; -+ -+/* event ring segment */ -+struct grub_xhci_er_seg { -+  grub_uint32_t ptr_low; -+  grub_uint32_t ptr_high; -+  grub_uint32_t size; -+  grub_uint32_t reserved_01; -+} GRUB_PACKED; -+ -+struct grub_xhci_ring { -+    struct grub_xhci_trb      ring[GRUB_XHCI_RING_ITEMS]; -+    struct grub_xhci_trb      evt; -+    grub_uint32_t	     eidx; -+    grub_uint32_t	     nidx; -+    grub_uint32_t	     cs; -+}; -+ -+/* port registers */ -+struct grub_xhci_pr { -+    grub_uint32_t portsc; -+    grub_uint32_t portpmsc; -+    grub_uint32_t portli; -+    grub_uint32_t reserved_01; -+} GRUB_PACKED; -+ -+/* doorbell registers */ -+struct grub_xhci_db { -+    grub_uint32_t doorbell; -+} GRUB_PACKED; -+ -+/* runtime registers */ -+struct grub_xhci_rts { -+    grub_uint32_t mfindex; -+} GRUB_PACKED; -+ -+/* interrupter registers */ -+struct grub_xhci_ir { -+    grub_uint32_t iman; -+    grub_uint32_t imod; -+    grub_uint32_t erstsz; -+    grub_uint32_t reserved_01; -+    grub_uint32_t erstba_low; -+    grub_uint32_t erstba_high; -+    grub_uint32_t erdp_low; -+    grub_uint32_t erdp_high; -+} GRUB_PACKED; -+ -+struct grub_xhci_psid { -+	grub_uint8_t id; -+	grub_uint8_t psie; -+	grub_uint16_t psim; -+	grub_uint64_t bitrate; -+	grub_usb_speed_t grub_usb_speed; -+}; -+ -+struct grub_xhci_psids { -+	grub_uint8_t major; -+	grub_uint8_t minor; -+	struct grub_xhci_psid psids[16]; -+}; -+ -+struct grub_xhci -+{ -+  grub_uint8_t shutdown; /* 1 if preparing shutdown of controller */ -+  /* xhci registers */ -+  volatile struct grub_xhci_caps *caps;	/* Capability registers */ -+  volatile struct grub_xhci_op *op;	/* Operational registers */ -+  volatile struct grub_xhci_pr *pr;	/* Port Registers */ -+  volatile struct grub_xhci_db *db;	/* doorbell */ -+  volatile struct grub_xhci_ir *ir;	/* Interrupt Registers */ -+  /* devinfo */ -+  grub_uint32_t xcap; -+  grub_uint32_t ports; -+  grub_uint32_t slots; -+  grub_uint8_t flag64; -+  grub_uint16_t spb; -+  grub_uint32_t pagesize; -+  struct xhci_portmap usb2; -+  struct xhci_portmap usb3; -+  struct grub_xhci_psids *psids; -+  /* xhci data structures */ -+  struct grub_pci_dma_chunk *devs_dma; -+  volatile struct grub_xhci_devlist *devs; -+  struct grub_pci_dma_chunk *cmds_dma; -+  volatile struct grub_xhci_ring *cmds; -+  struct grub_pci_dma_chunk *evts_dma; -+  volatile struct grub_xhci_ring *evts; -+  struct grub_pci_dma_chunk *eseg_dma; -+  volatile struct grub_xhci_er_seg *eseg; -+  struct grub_pci_dma_chunk *spba_dma; -+  struct grub_pci_dma_chunk *spad_dma; -+ -+  struct grub_xhci *next; -+}; -+ -+struct grub_xhci_priv { -+  grub_uint8_t                    slotid; -+  grub_uint32_t                   max_packet; -+  struct grub_pci_dma_chunk       *enpoint_trbs_dma[32]; -+  volatile struct grub_xhci_ring  *enpoint_trbs[32]; -+  struct grub_pci_dma_chunk       *slotctx_dma; -+}; -+ -+struct grub_xhci_port { -+  grub_uint32_t portsc; -+  grub_uint32_t portpmsc; -+  grub_uint32_t portli; -+  grub_uint32_t reserved_01; -+}; -+ -+struct grub_xhci_transfer_controller_data { -+  grub_uint32_t transfer_size; -+}; -+ -+static struct grub_xhci *xhci; -+ -+/**************************************************************** -+ * general access functions -+ ****************************************************************/ -+ -+static inline void -+grub_xhci_write32(volatile void *addr, grub_uint32_t val) { -+    *(volatile grub_uint32_t *)addr = val; -+} -+static inline void -+grub_xhci_write16(volatile void *addr, grub_uint16_t val) { -+    *(volatile grub_uint16_t *)addr = val; -+} -+static inline void -+grub_xhci_write8(void *addr, grub_uint8_t val) { -+    *(volatile grub_uint8_t *)addr = val; -+} -+ -+static inline grub_uint32_t -+grub_xhci_read32(volatile void *addr) { -+  return grub_le_to_cpu32 (*((volatile grub_uint32_t *)addr)); -+} -+ -+static inline grub_uint16_t -+grub_xhci_read16(volatile void *addr) { -+  return grub_le_to_cpu16 (*((volatile grub_uint32_t *)addr)); -+} -+static inline grub_uint8_t -+grub_xhci_read8(volatile void *addr) { -+  return (*((volatile grub_uint32_t *)addr)); -+} -+ -+static inline grub_uint32_t -+grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port) -+{ -+  return grub_xhci_read32(&x->pr[port].portsc); -+} -+ -+static inline void -+grub_xhci_port_write (struct grub_xhci *x, grub_uint32_t port, -+		      grub_uint32_t and_mask, grub_uint32_t or_mask) -+{ -+  grub_uint32_t reg = grub_xhci_port_read(x, port); -+  reg &= and_mask; -+  reg |= or_mask; -+ -+  grub_xhci_write32(&x->pr[port].portsc, reg); -+} -+ -+/**************************************************************** -+ * xhci status and support functions -+ ****************************************************************/ -+ -+static grub_uint32_t xhci_get_pagesize(struct grub_xhci *x) -+{ -+  /* Chapter 5.4.3 Page Size Register (PAGESIZE) */ -+  for (grub_uint8_t i = 0; i < 16; i++) -+    { -+      if (grub_xhci_read32(&x->op->pagesize) & (1 << i)) -+	return 1 << (12 + i); -+    } -+  return 0; -+} -+ -+static grub_uint8_t xhci_is_halted(struct grub_xhci *x) -+{ -+  return !!(grub_xhci_read32(&x->op->usbsts) & 1); -+} -+ -+/* Just for debugging */ -+static void xhci_check_status(struct grub_xhci *x) -+{ -+  grub_uint32_t reg; -+ -+  reg = grub_xhci_read32(&x->op->usbsts); -+  if (reg & 1) -+    grub_dprintf("xhci", "%s: xHCI halted\n", __func__); -+  if (reg & 2) -+    grub_dprintf("xhci", "%s: Host system error detected\n", __func__); -+  if (reg & (1 << 12)) -+    grub_dprintf("xhci", "%s: Internal error detected\n", __func__); -+  reg = grub_xhci_read32(&x->op->crcr_low); -+  if (reg & (1 << 3)) -+    grub_dprintf("xhci", "%s: Command ring running\n", __func__); -+} -+ -+/* xhci_memalign_dma32 allocates DMA memory satisfying alignment and boundary -+ * requirements without wasting to much memory */ -+static struct grub_pci_dma_chunk * -+xhci_memalign_dma32(grub_size_t align, -+		    grub_size_t size, -+		    grub_size_t boundary) -+{ -+	struct grub_pci_dma_chunk *tmp; -+	const grub_uint32_t mask = boundary - 1; -+	grub_uint32_t start, end; -+ -+	/* Allocate some memory and check if it doesn't cross boundary */ -+	tmp = grub_memalign_dma32(align, size); -+	start = grub_dma_get_phys(tmp); -+	end = start + size - 1; -+	if ((start & mask) == (end & mask)) -+		return tmp; -+	/* Buffer isn't usable, allocate bigger one */ -+	grub_dma_free(tmp); -+ -+	return grub_memalign_dma32(boundary, size); -+} -+ -+/**************************************************************** -+ * helper functions for in context DMA buffer -+ ****************************************************************/ -+ -+static int -+grub_xhci_inctx_size(struct grub_xhci *x) -+{ -+  const grub_uint8_t cnt = GRUB_XHCI_MAX_ENDPOINTS + 1; -+  return (sizeof(struct grub_xhci_inctx) * cnt) << x->flag64; -+} -+ -+static void -+grub_xhci_inctx_sync_dma_caches(struct grub_xhci *x, struct grub_pci_dma_chunk *inctx) -+{ -+  grub_arch_sync_dma_caches(inctx, grub_xhci_inctx_size(x)); -+} -+ -+static struct grub_pci_dma_chunk * -+grub_xhci_alloc_inctx(struct grub_xhci *x, int maxepid, -+		      struct grub_usb_device *dev) -+{ -+  int size = grub_xhci_inctx_size(x); -+  struct grub_pci_dma_chunk *dma = xhci_memalign_dma32(ALIGN_INCTX, size, -+						       x->pagesize); -+  if (!dma) -+    return NULL; -+ -+  volatile struct grub_xhci_inctx *in = grub_dma_get_virt(dma); -+  grub_memset((void *)in, 0, size); -+ -+  struct grub_xhci_slotctx *slot = (void*)&in[1 << x->flag64]; -+  slot->ctx[0]    |= maxepid << 27; /* context entries */ -+  grub_dprintf("xhci", "%s: speed=%d root_port=%d\n", __func__, dev->speed, dev->root_port); -+  switch (dev->speed) { -+    case GRUB_USB_SPEED_FULL: -+      slot->ctx[0]    |= XHCI_USB_FULLSPEED << 20; -+      break; -+    case GRUB_USB_SPEED_HIGH: -+     slot->ctx[0]     |= XHCI_USB_HIGHSPEED << 20; -+      break; -+    case GRUB_USB_SPEED_LOW: -+      slot->ctx[0]    |= XHCI_USB_LOWSPEED << 20; -+      break; -+    case GRUB_USB_SPEED_SUPER: -+      slot->ctx[0]    |= XHCI_USB_SUPERSPEED << 20; -+      break; -+    case GRUB_USB_SPEED_NONE: -+      slot->ctx[0]    |= 0 << 20; -+      break; -+  } -+ -+  /* Route is greater zero on devices that are connected to a non root hub */ -+  if (dev->route) -+    { -+      /* FIXME: Implement this code for non SuperSpeed hub devices */ -+    } -+  slot->ctx[0]    |= dev->route; -+  slot->ctx[1]    |= (dev->root_port+1) << 16; -+ -+  grub_arch_sync_dma_caches(in, size); -+ -+  return dma; -+} -+ -+/**************************************************************** -+ * xHCI event processing -+ ****************************************************************/ -+ -+/* Dequeue events on the XHCI event ring generated by the hardware */ -+static void xhci_process_events(struct grub_xhci *x) -+{ -+    volatile struct grub_xhci_ring *evts = x->evts; -+    /* XXX invalidate caches */ -+ -+    for (;;) { -+	/* check for event */ -+	grub_uint32_t nidx = grub_xhci_read32(&evts->nidx); -+	grub_uint32_t cs = grub_xhci_read32(&evts->cs); -+	volatile struct grub_xhci_trb *etrb = evts->ring + nidx; -+	grub_uint32_t control = grub_xhci_read32(&etrb->control); -+	if ((control & TRB_C) != (cs ? 1 : 0)) -+	    return; -+ -+	/* process event */ -+	grub_uint32_t evt_type = TRB_TYPE(control); -+	grub_uint32_t evt_cc = (grub_xhci_read32(&etrb->status) >> 24) & 0xff; -+ -+	switch (evt_type) -+	  { -+	    case ER_TRANSFER: -+	    case ER_COMMAND_COMPLETE: -+	      { -+		struct grub_xhci_trb  *rtrb = (void*)grub_xhci_read32(&etrb->ptr_low); -+		struct grub_xhci_ring *ring = XHCI_RING(rtrb); -+		volatile struct grub_xhci_trb  *evt = &ring->evt; -+		grub_uint32_t eidx = rtrb - ring->ring + 1; -+		grub_dprintf("xhci", "%s: ring %p [trb %p, evt %p, type %d, eidx %d, cc %d]\n", -+			      __func__, ring, rtrb, evt, evt_type, eidx, evt_cc); -+		*evt = *etrb; -+		grub_xhci_write32(&ring->eidx, eidx); -+		break; -+	      } -+	    case ER_PORT_STATUS_CHANGE: -+	      { -+		/* Nothing to do here. grub_xhci_detect_dev will handle it */ -+		break; -+	      } -+	    default: -+	      { -+		grub_dprintf("xhci", "%s: unknown event, type %d, cc %d\n", -+			      __func__, evt_type, evt_cc); -+		break; -+	      } -+	} -+ -+	/* move ring index, notify xhci */ -+	nidx++; -+	if (nidx == GRUB_XHCI_RING_ITEMS) -+	  { -+	    nidx = 0; -+	    cs = cs ? 0 : 1; -+	    grub_xhci_write32(&evts->cs, cs); -+	  } -+	grub_xhci_write32(&evts->nidx, nidx); -+	volatile struct grub_xhci_ir *ir = x->ir; -+	grub_uint32_t erdp = (grub_uint32_t)(evts->ring + nidx); -+	grub_xhci_write32(&ir->erdp_low, erdp); -+	grub_xhci_write32(&ir->erdp_high, 0); -+    } -+} -+ -+/**************************************************************** -+ * TRB handling -+ ****************************************************************/ -+ -+/* Signal the hardware to process events on a TRB ring */ -+static void xhci_doorbell(struct grub_xhci *x, grub_uint32_t slotid, grub_uint32_t value) -+{ -+  xhci_check_status(x); -+  grub_dprintf("xhci", "%s: slotid %d, epid %d\n", __func__, slotid, value); -+  grub_xhci_write32(&x->db[slotid].doorbell, value); -+} -+ -+/* Check if a ring has any pending TRBs */ -+static int xhci_ring_busy(volatile struct grub_xhci_ring *ring) -+{ -+  grub_uint32_t eidx = grub_xhci_read32(&ring->eidx); -+  grub_uint32_t nidx = grub_xhci_read32(&ring->nidx); -+ -+  return (eidx != nidx); -+} -+ -+/* Returns free space in ring */ -+static int xhci_ring_free_space(volatile struct grub_xhci_ring *ring) -+{ -+  grub_uint32_t eidx = grub_xhci_read32(&ring->eidx); -+  grub_uint32_t nidx = grub_xhci_read32(&ring->nidx); -+ -+  /* nidx is never 0, so reduce ring buffer size by one */ -+  return (eidx > nidx) ? eidx-nidx -+		: (ARRAY_SIZE(ring->ring) - 1) - nidx + eidx; -+} -+ -+/* Check if a ring is full */ -+static int xhci_ring_full(volatile struct grub_xhci_ring *ring) -+{ -+  /* Might need to insert one link TRB */ -+  return xhci_ring_free_space(ring) <= 1; -+} -+ -+/* Check if a ring is almost full */ -+static int xhci_ring_almost_full(volatile struct grub_xhci_ring *ring) -+{ -+  /* Might need to insert one link TRB */ -+  return xhci_ring_free_space(ring) <= 2; -+} -+ -+/* Wait for a ring to empty (all TRBs processed by hardware) */ -+static int xhci_event_wait(struct grub_xhci *x, -+			   volatile struct grub_xhci_ring *ring, -+			   grub_uint32_t timeout) -+{ -+    grub_uint32_t end = grub_get_time_ms () + timeout; -+ -+    for (;;) -+      { -+	xhci_check_status(x); -+	xhci_process_events(x); -+	if (!xhci_ring_busy(ring)) -+	  { -+	    grub_uint32_t status = ring->evt.status; -+	    return (status >> 24) & 0xff; -+	  } -+	if (grub_get_time_ms () > end) -+	  { -+	    xhci_check_status(x); -+	    grub_dprintf("xhci", "%s: Timeout waiting for event\n", __func__); -+	    return -1; -+	  } -+      } -+} -+ -+/* Add a TRB to the given ring, either regular or inline */ -+static void xhci_trb_fill(volatile struct grub_xhci_ring *ring, -+			  grub_uint64_t ptr, grub_uint32_t xferlen, -+			  grub_uint32_t flags) -+{ -+  volatile struct grub_xhci_trb *dst = &ring->ring[ring->nidx]; -+  dst->ptr_low = ptr & 0xffffffff; -+  dst->ptr_high = ptr >> 32; -+  dst->status = xferlen; -+  dst->control = flags | (ring->cs ? TRB_C : 0); -+ -+  grub_arch_sync_dma_caches(dst, sizeof(ring->ring[0])); -+} -+ -+/* -+ * Queue a TRB onto a ring. -+ * -+ * The caller must pass a pointer to the data in physical address-space or the -+ * data itself (but no more than 8 bytes) in data_or_addr. Inline data must have -+ * the flag TRB_TR_IDT set. -+ */ -+static void xhci_trb_queue(volatile struct grub_xhci_ring *ring, -+			   grub_uint64_t data_or_addr, -+			   grub_uint32_t xferlen, grub_uint32_t flags) -+{ -+  grub_dprintf("xhci", "%s: ring %p data %llx len %d flags 0x%x remain 0x%x\n", __func__, -+      ring, data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); -+ -+  if (xhci_ring_full(ring)) -+    { -+      grub_dprintf("xhci", "%s: ERROR: ring %p is full, discarding TRB\n", -+	__func__, ring); -+      return; -+    } -+ -+  if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) -+    { -+      /* Reset to command buffer pointer to the first element */ -+      xhci_trb_fill(ring, (grub_addr_t)ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC); -+      ring->nidx = 0; -+      ring->cs ^= 1; -+      grub_dprintf("xhci", "%s: ring %p [linked]\n", __func__, ring); -+    } -+ -+  xhci_trb_fill(ring, data_or_addr, xferlen, flags); -+  ring->nidx++; -+  grub_dprintf("xhci", "%s: ring %p [nidx %d, len %d]\n", -+	       __func__, ring, ring->nidx, xferlen); -+} -+ -+/* -+ * Queue a TRB onto a ring and flush it if necessary. -+ * -+ * The caller must pass a pointer to the data in physical address-space or the -+ * data itself (but no more than 8 bytes) in data_or_addr. Inline data must have -+ * the flag TRB_TR_IDT set. -+ */ -+static int xhci_trb_queue_and_flush(struct grub_xhci *x, -+				    grub_uint32_t slotid, -+				    grub_uint32_t epid, -+				    volatile struct grub_xhci_ring *ring, -+				    grub_uint64_t data_or_addr, -+				    grub_uint32_t xferlen, grub_uint32_t flags) -+{ -+  grub_uint8_t submit = 0; -+  if (xhci_ring_almost_full(ring)) -+    { -+      grub_dprintf("xhci", "%s: almost full e %d n %d\n", __func__, ring->eidx, ring->nidx); -+      flags |= TRB_TR_IOC; -+      submit = 1; -+    } -+  /* Note: xhci_trb_queue might queue on or two elements, if the end of the TRB -+   * has been reached. The caller must account for that when filling the TRB. */ -+  xhci_trb_queue(ring, data_or_addr, xferlen, flags); -+  /* Submit if less no free slot is remaining, we might need an additional -+   * one on the next call to this function. */ -+  if (submit) -+    { -+      xhci_doorbell(x, slotid, epid); -+      int rc = xhci_event_wait(x, ring, 1000); -+      grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+      return rc; -+    } -+  return 0; -+} -+ -+/**************************************************************** -+ * xHCI command functions -+ ****************************************************************/ -+ -+/* Submit a command to the xHCI command TRB */ -+static int xhci_cmd_submit(struct grub_xhci *x, -+			   struct grub_pci_dma_chunk *inctx_dma, -+			   grub_uint32_t flags) -+{ -+  volatile struct grub_xhci_inctx *inctx; -+  /* Don't submit if halted, it will fail */ -+  if (xhci_is_halted(x)) -+    return -1; -+ -+  if (inctx_dma) -+    { -+      grub_xhci_inctx_sync_dma_caches(x, inctx_dma); -+ -+      inctx = grub_dma_get_virt(inctx_dma); -+ -+      struct grub_xhci_slotctx *slot = (void*)&inctx[1 << x->flag64]; -+      grub_uint32_t port = ((slot->ctx[1] >> 16) & 0xff) - 1; -+      grub_uint32_t portsc = grub_xhci_port_read(x, port); -+      if (!(portsc & GRUB_XHCI_PORTSC_CCS)) -+	{ -+	  grub_dprintf("xhci", "%s: root port %d no longer connected\n", -+	    __func__, port); -+	  return -1; -+	} -+      xhci_trb_queue(x->cmds, grub_dma_get_phys(inctx_dma), 0, flags); -+    } -+    else -+    { -+      xhci_trb_queue(x->cmds, 0, 0, flags); -+    } -+ -+    xhci_doorbell(x, 0, 0); -+    int rc = xhci_event_wait(x, x->cmds, 1000); -+    grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+ -+    return rc; -+} -+ -+static int xhci_cmd_enable_slot(struct grub_xhci *x) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_ENABLE_SLOT << 10); -+ -+  grub_dprintf("xhci", "%s:\n", __func__); -+  int cc = xhci_cmd_submit(x, NULL, flags); -+  if (cc != CC_SUCCESS) -+      return -1; -+  grub_dprintf("xhci", "%s: %p\n", __func__, &x->cmds->evt.control); -+  grub_dprintf("xhci", "%s: %x\n", __func__, grub_xhci_read32(&x->cmds->evt.control)); -+ -+  return (grub_xhci_read32(&x->cmds->evt.control) >> 24) & 0xff; -+} -+ -+static int xhci_cmd_disable_slot(struct grub_xhci *x, grub_uint32_t slotid) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_DISABLE_SLOT << 10); -+  flags |= (slotid << 24); -+ -+  grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+  return xhci_cmd_submit(x, NULL, flags); -+} -+ -+static int xhci_cmd_stop_endpoint(struct grub_xhci *x, grub_uint32_t slotid -+				       , grub_uint32_t epid -+				       , grub_uint32_t suspend) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_STOP_ENDPOINT << 10); -+  flags |= (epid << 16); -+  flags |= (suspend << 23) ; -+  flags |= (slotid << 24); -+ -+  return xhci_cmd_submit(x, NULL, flags); -+} -+ -+static int xhci_cmd_reset_endpoint(struct grub_xhci *x, grub_uint32_t slotid -+				       , grub_uint32_t epid -+				       , grub_uint32_t preserve) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (preserve << 9); -+  flags |= (CR_RESET_ENDPOINT << 10); -+  flags |= (epid << 16); -+  flags |= (slotid << 24); -+ -+  return xhci_cmd_submit(x, NULL, flags); -+} -+ -+static int xhci_cmd_set_dequeue_pointer(struct grub_xhci *x, grub_uint32_t slotid -+				       , grub_uint32_t epid -+				       , grub_addr_t tr_deque_pointer) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_SET_TR_DEQUEUE << 10); -+  flags |= (epid << 16); -+  flags |= (slotid << 24); -+ -+  xhci_trb_queue(x->cmds, tr_deque_pointer, 0, flags); -+ -+  xhci_doorbell(x, 0, 0); -+  int rc = xhci_event_wait(x, x->cmds, 1000); -+  grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+ -+  return rc; -+} -+ -+static int xhci_cmd_address_device(struct grub_xhci *x, grub_uint32_t slotid, -+				   struct grub_pci_dma_chunk *inctx_dma) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_ADDRESS_DEVICE << 10); -+  flags |= (slotid << 24); -+ -+  grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+  return xhci_cmd_submit(x, inctx_dma, flags); -+} -+ -+static int xhci_cmd_configure_endpoint(struct grub_xhci *x, grub_uint32_t slotid, -+				       struct grub_pci_dma_chunk *inctx_dma) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_CONFIGURE_ENDPOINT << 10); -+  flags |= (slotid << 24); -+ -+  grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+  return xhci_cmd_submit(x, inctx_dma, flags); -+} -+ -+static int xhci_cmd_evaluate_context(struct grub_xhci *x, grub_uint32_t slotid, -+				     struct grub_pci_dma_chunk *inctx_dma) -+{ -+  grub_uint32_t flags = 0; -+  flags |= (CR_EVALUATE_CONTEXT << 10); -+  flags |= (slotid << 24); -+ -+  grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+  return xhci_cmd_submit(x, inctx_dma, flags); -+} -+ -+/**************************************************************** -+ * xHCI host controller initialization -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_reset (struct grub_xhci *x) -+{ -+  grub_uint32_t reg; -+  grub_uint32_t end; -+ -+  reg = grub_xhci_read32(&x->op->usbcmd); -+  if (reg & GRUB_XHCI_CMD_RS) -+    { -+      reg &= ~GRUB_XHCI_CMD_RS; -+      grub_xhci_write32(&x->op->usbcmd, reg); -+ -+      end = grub_get_time_ms () + 32; -+      while (grub_xhci_read32(&x->op->usbcmd) & GRUB_XHCI_STS_HCH) -+	{ -+	  if (grub_get_time_ms () > end) -+	      return GRUB_USB_ERR_TIMEOUT; -+ -+	  grub_millisleep(1); -+	} -+    } -+ -+  grub_dprintf("xhci", "grub_xhci_reset: resetting HC\n"); -+  grub_xhci_write32(&x->op->usbcmd, GRUB_XHCI_CMD_HCRST); -+ -+  /* Wait for device to complete reset and be enabled */ -+  end = grub_get_time_ms () + 100; -+  while (grub_xhci_read32(&x->op->usbcmd) & GRUB_XHCI_CMD_HCRST) -+    { -+      if (grub_get_time_ms () > end) -+	  return GRUB_USB_ERR_TIMEOUT; -+ -+      grub_millisleep(1); -+    } -+ -+  /* Wait for device to complete reset and be enabled */ -+  end = grub_get_time_ms () + 100; -+  while (grub_xhci_read32(&x->op->usbsts) & GRUB_XHCI_STS_CNR) -+    { -+      if (grub_get_time_ms () > end) -+	  return GRUB_USB_ERR_TIMEOUT; -+ -+      grub_millisleep(1); -+    } -+ -+  grub_xhci_write32(&x->op->config, x->slots); -+  grub_xhci_write32(&x->op->dcbaap_low, grub_dma_get_phys(x->devs_dma)); -+  grub_xhci_write32(&x->op->dcbaap_high, 0); -+  grub_xhci_write32(&x->op->crcr_low, grub_dma_get_phys(x->cmds_dma)| 1); -+  grub_xhci_write32(&x->op->crcr_high, 0); -+  x->cmds->cs = 1; -+ -+  grub_arch_sync_dma_caches(x->cmds, sizeof(*x->cmds)); -+ -+  x->eseg->ptr_low = grub_dma_get_phys(x->evts_dma); -+  x->eseg->ptr_high = 0; -+  x->eseg->size = GRUB_XHCI_RING_ITEMS; -+ -+  grub_arch_sync_dma_caches(x->eseg, sizeof(*x->eseg)); -+ -+  grub_xhci_write32(&x->ir->erstsz, 1); -+  grub_xhci_write32(&x->ir->erdp_low, grub_dma_get_phys(x->evts_dma)); -+  grub_xhci_write32(&x->ir->erdp_high, 0); -+  grub_xhci_write32(&x->ir->erstba_low, grub_dma_get_phys(x->eseg_dma)); -+  grub_xhci_write32(&x->ir->erstba_high, 0); -+  x->evts->cs = 1; -+ -+  grub_arch_sync_dma_caches(x->evts, sizeof(*x->eseg)); -+ -+  xhci_check_status(x); -+ -+  grub_dprintf ("xhci", "XHCI OP COMMAND: %08x\n", -+		grub_xhci_read32 (&x->op->usbcmd)); -+  grub_dprintf ("xhci", "XHCI OP STATUS: %08x\n", -+		grub_xhci_read32 (&x->op->usbsts)); -+  grub_dprintf ("xhci", "XHCI OP PAGESIZE: %08x\n", -+		grub_xhci_read32 (&x->op->pagesize)); -+  grub_dprintf ("xhci", "XHCI OP DNCTRL: %08x\n", -+		grub_xhci_read32 (&x->op->dnctl)); -+  grub_dprintf ("xhci", "XHCI OP CRCR_LOW: %08x\n", -+		grub_xhci_read32 (&x->op->crcr_low)); -+  grub_dprintf ("xhci", "XHCI OP CRCR_HIGH: %08x\n", -+		grub_xhci_read32 (&x->op->crcr_high)); -+  grub_dprintf ("xhci", "XHCI OP DCBAAP_LOW: %08x\n", -+		grub_xhci_read32 (&x->op->dcbaap_low)); -+  grub_dprintf ("xhci", "XHCI OP DCBAAP_HIGH: %08x\n", -+		grub_xhci_read32 (&x->op->dcbaap_high)); -+  grub_dprintf ("xhci", "XHCI OP CONFIG: %08x\n", -+		grub_xhci_read32 (&x->op->config)); -+  grub_dprintf ("xhci", "XHCI IR ERSTSZ: %08x\n", -+		grub_xhci_read32 (&x->ir->erstsz)); -+  grub_dprintf ("xhci", "XHCI IR ERDP: %08x\n", -+		grub_xhci_read32 (&x->ir->erdp_low)); -+  grub_dprintf ("xhci", "XHCI IR ERSTBA: %08x\n", -+		grub_xhci_read32 (&x->ir->erstba_low)); -+ -+  xhci_check_status(x); -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+static grub_usb_err_t -+grub_xhci_request_legacy_handoff(volatile struct grub_xhci_xcap *xcap) -+{ -+  grub_uint32_t end; -+ -+  end = grub_get_time_ms () + 10; -+  for (;;) -+    { -+      grub_uint32_t cap = grub_xhci_read32(&xcap->cap); -+      if (cap & (1 << 16)) -+	grub_xhci_write32(&xcap->cap, cap | (1 << 24)); -+      else -+        break; -+ -+      if (grub_get_time_ms () > end) -+	{ -+	  grub_dprintf ("xhci","ERROR: %s TIMEOUT\n", __func__); -+	  return GRUB_USB_ERR_TIMEOUT; -+	} -+      grub_millisleep(1); -+    } -+  return GRUB_USB_ERR_NONE; -+} -+ -+static void -+grub_xhci_fill_default_speed_mapping(struct grub_xhci_psids *ids) -+{ -+	/* Chapter 7.2.2.1.1 "Default USB Speed ID Mapping" */ -+	ids->psids[0].id = 1; -+	ids->psids[0].psie = 2; -+	ids->psids[0].psim = 12; -+	ids->psids[1].id = 2; -+	ids->psids[1].psie = 1; -+	ids->psids[1].psim = 1500; -+	ids->psids[2].id = 3; -+	ids->psids[2].psie = 2; -+	ids->psids[2].psim = 480; -+	ids->psids[3].id = 4; -+	ids->psids[3].psie = 3; -+	ids->psids[3].psim = 5; -+	ids->psids[4].id = 5; -+	ids->psids[4].psie = 3; -+	ids->psids[4].psim = 10; -+	ids->psids[5].id = 6; -+	ids->psids[5].psie = 3; -+	ids->psids[5].psim = 10; -+	ids->psids[6].id = 7; -+	ids->psids[6].psie = 3; -+	ids->psids[6].psim = 20; -+} -+ -+static void -+grub_xhci_calc_speed_mapping(struct grub_xhci_psids *ids) -+{ -+  const grub_uint64_t mult[4] = {1ULL, 1000ULL, 1000000ULL, 1000000000ULL}; -+ -+  for (grub_uint8_t i = 0; i < 16; i++) -+    { -+      if (ids->psids[i].id == 0) -+	continue; -+      ids->psids[i].bitrate = mult[ids->psids[i].psie & 3] * (grub_uint64_t)ids->psids[i].psim; -+      if (ids->psids[i].bitrate < 12000000ULL) -+	ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_LOW; -+      else if (ids->psids[i].bitrate < 480000000ULL) -+	ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_FULL; -+      else if (ids->psids[i].bitrate > 1200000000ULL) -+	ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_SUPER; -+      else -+	ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_HIGH; -+    } -+} -+ -+ -+/* PCI iteration function... */ -+void -+grub_xhci_init_device (volatile void *regs) -+{ -+  struct grub_xhci *x; -+  grub_uint32_t hcs1, hcc, reg; -+ -+  /* Allocate memory for the controller and fill basic values. */ -+  x = grub_zalloc (sizeof (*x)); -+  if (!x) -+    { -+      grub_dprintf("xhci", "Failed to allocate memory\n"); -+      return; -+    } -+  x->caps = (volatile struct grub_xhci_caps *) regs; -+  x->op = (volatile struct grub_xhci_op *) (((grub_uint8_t *)regs) + -+      grub_xhci_read8(&x->caps->caplength)); -+  x->pr = (volatile struct grub_xhci_pr *) (((grub_uint8_t *)x->op) + -+      GRUB_XHCI_PR_OFFSET); -+  x->db = (volatile struct grub_xhci_db *) (((grub_uint8_t *)regs) + -+      grub_xhci_read32(&x->caps->dboff)); -+  x->ir = (volatile struct grub_xhci_ir *) (((grub_uint8_t *)regs) + -+		  grub_xhci_read32(&x->caps->rtsoff) + GRUB_XHCI_IR_OFFSET); -+ -+  grub_dprintf ("xhci", "XHCI init: CAPLENGTH: 0x%02x\n", -+		grub_xhci_read8 (&x->caps->caplength)); -+  grub_dprintf ("xhci", "XHCI init: HCIVERSION: 0x%04x\n", -+		grub_xhci_read16 (&x->caps->hciversion)); -+  grub_dprintf ("xhci", "XHCI init: HCSPARAMS1: 0x%08x\n", -+		grub_xhci_read32 (&x->caps->hcsparams1)); -+  grub_dprintf ("xhci", "XHCI init: HCSPARAMS2: 0x%08x\n", -+		grub_xhci_read32 (&x->caps->hcsparams2)); -+  grub_dprintf ("xhci", "XHCI init: HCSPARAMS3: 0x%08x\n", -+		grub_xhci_read32 (&x->caps->hcsparams3)); -+  grub_dprintf ("xhci", "XHCI init: HCCPARAMS: 0x%08x\n", -+		grub_xhci_read32 (&x->caps->hcsparams3)); -+  grub_dprintf ("xhci", "XHCI init: DBOFF: 0x%08x\n", -+		grub_xhci_read32 (&x->caps->dboff)); -+  grub_dprintf ("xhci", "XHCI init: RTOFF: 0x%08x\n", -+		grub_xhci_read32 (&x->caps->rtsoff)); -+ -+  hcs1 = grub_xhci_read32(&x->caps->hcsparams1); -+  hcc = grub_xhci_read32(&x->caps->hccparams); -+  x->ports = (grub_uint32_t) ((hcs1 >> 24) & 0xff); -+  x->slots = (grub_uint32_t) (hcs1	 & 0xff); -+  x->xcap  = (grub_uint32_t) ((hcc >> 16) & 0xffff) * sizeof(grub_uint32_t); -+  x->flag64 = (grub_uint8_t) ((hcc & 0x04) ? 1 : 0); -+  grub_dprintf("xhci", "XHCI init: %d ports, %d slots, %d byte contexts\n" -+	       , x->ports, x->slots, x->flag64 ? 64 : 32); -+ -+  x->psids = grub_zalloc (sizeof (struct grub_xhci_psids) * x->ports); -+  if (x->xcap) -+    { -+      grub_uint32_t off; -+      volatile grub_uint8_t *addr = (grub_uint8_t *) x->caps + x->xcap; -+      do -+	{ -+	  volatile struct grub_xhci_xcap *xcap = (void *)addr; -+	  grub_uint32_t ports, name, cap = grub_xhci_read32(&xcap->cap); -+	  switch (cap & 0xff) { -+	    case XHCI_CAP_LEGACY_SUPPORT: -+	      { -+		if (grub_xhci_request_legacy_handoff(xcap) != GRUB_USB_ERR_NONE) -+		  { -+		    grub_dprintf("xhci", "XHCI init: Failed to get xHCI ownership\n"); -+		    goto fail; -+		  } -+	        break; -+	      } -+	    case XHCI_CAP_SUPPORTED_PROTOCOL: -+	      { -+		name  = grub_xhci_read32(&xcap->data[0]); -+		ports = grub_xhci_read32(&xcap->data[1]); -+		const grub_uint8_t major = (cap >> 24) & 0xff; -+		const grub_uint8_t minor = (cap >> 16) & 0xff; -+		const grub_uint8_t psic = (ports >> 28) & 0xf; -+		const grub_uint8_t count = (ports >> 8) & 0xff; -+		const grub_uint8_t start = (ports >> 0) & 0xff; -+		grub_dprintf("xhci", "XHCI init: protocol %c%c%c%c %x.%02x" -+				", %d ports (offset %d), def %x, psic %d\n" -+				, (name >>  0) & 0xff -+				, (name >>  8) & 0xff -+				, (name >> 16) & 0xff -+				, (name >> 24) & 0xff -+				, major, minor -+				, count, start -+				, ports >> 16 -+				, psic); -+		if (name == 0x20425355 /* "USB " */) -+		  { -+		    if (major == 2) -+		      { -+			x->usb2.start = start; -+			x->usb2.count = count; -+		      } -+		    else if (major == 3) -+		      { -+			x->usb3.start = start; -+			x->usb3.count = count; -+		      } -+ -+		    for (grub_uint32_t p = start - 1; p < start + count - 1UL; p++) -+		      { -+			x->psids[p].major = major; -+			x->psids[p].minor = minor; -+			grub_xhci_fill_default_speed_mapping(&x->psids[p]); -+			for (grub_uint8_t i = 0; i < psic; i++) -+			  { -+			    grub_uint32_t psid = grub_xhci_read32(&xcap->data[3 + i]); -+			    x->psids[p].psids[i].id = (psid >> 0) & 0xf; -+			    x->psids[p].psids[i].psie = (psid >> 4) & 0x3; -+			    x->psids[p].psids[i].psim = (psid >> 16) & 0xfffff; -+			  } -+			grub_xhci_calc_speed_mapping(&x->psids[p]); -+		      } -+		  } -+ -+		break; -+	      } -+	    default: -+	      { -+	        grub_dprintf("xhci", "XHCI    extcap 0x%x @ %p\n", cap & 0xff, addr); -+	        break; -+	      } -+	  } -+	off = (cap >> 8) & 0xff; -+	addr += off << 2; -+	} -+      while (off > 0); -+    } -+ -+  x->pagesize = xhci_get_pagesize(x); -+  grub_dprintf("xhci", "XHCI init: Minimum supported page size 0x%x\n", -+	       x->pagesize); -+ -+  /* Chapter 6.1 Device Context Base Address Array */ -+  x->devs_dma = xhci_memalign_dma32(ALIGN_DCBAA, -+				    sizeof(*x->devs) * (x->slots + 1), -+				    x->pagesize); -+  if (!x->devs_dma) -+      goto fail; -+  x->devs = grub_dma_get_virt(x->devs_dma); -+  grub_memset((void *)x->devs, 0, sizeof(*x->devs) * (x->slots + 1)); -+  grub_arch_sync_dma_caches(x->devs, sizeof(*x->devs) * (x->slots + 1)); -+  grub_dprintf ("xhci", "XHCI init: device memory %p (%x)\n", -+		grub_dma_get_virt(x->devs_dma), -+		grub_dma_get_phys(x->devs_dma)); -+ -+  /* Chapter 6.5 Event Ring Segment Table */ -+  x->eseg_dma = xhci_memalign_dma32(ALIGN_EVT_RING_TABLE, sizeof(*x->eseg), 0); -+  if (!x->eseg_dma) -+      goto fail; -+  x->eseg = grub_dma_get_virt(x->eseg_dma); -+  grub_memset((void *)x->eseg, 0, sizeof(*x->eseg)); -+  grub_arch_sync_dma_caches(x->eseg, sizeof(*x->eseg)); -+  grub_dprintf ("xhci", "XHCI init: event ring table memory %p (%x)\n", -+		grub_dma_get_virt(x->eseg_dma), -+		grub_dma_get_phys(x->eseg_dma)); -+ -+  x->cmds_dma = xhci_memalign_dma32(ALIGN_CMD_RING_SEG, sizeof(*x->cmds), -+				    BOUNDARY_RING); -+  if (!x->cmds_dma) -+      goto fail; -+  x->cmds = grub_dma_get_virt(x->cmds_dma); -+  grub_memset((void *)x->cmds, 0, sizeof(*x->cmds)); -+  grub_arch_sync_dma_caches(x->cmds, sizeof(*x->cmds)); -+  grub_dprintf ("xhci", "XHCI init: command ring memory %p (%x)\n", -+		grub_dma_get_virt(x->cmds_dma), -+		grub_dma_get_phys(x->cmds_dma)); -+ -+  x->evts_dma = xhci_memalign_dma32(ALIGN_EVT_RING_SEG, sizeof(*x->evts), -+				    BOUNDARY_RING); -+  if (!x->evts_dma) -+      goto fail; -+  x->evts = grub_dma_get_virt(x->evts_dma); -+  grub_memset((void *)x->evts, 0, sizeof(*x->evts)); -+  grub_arch_sync_dma_caches(x->evts, sizeof(*x->evts)); -+  grub_dprintf ("xhci", "XHCI init: event ring memory %p (%x)\n", -+		grub_dma_get_virt(x->evts_dma), -+		grub_dma_get_phys(x->evts_dma)); -+ -+  /* Chapter 4.20 Scratchpad Buffers */ -+  reg = grub_xhci_read32(&x->caps->hcsparams2); -+  x->spb = (reg >> 21 & 0x1f) << 5 | reg >> 27; -+  if (x->spb) -+    { -+      volatile grub_uint64_t *spba; -+      grub_dprintf("xhci", "XHCI init: set up %d scratch pad buffers\n", -+		   x->spb); -+      x->spba_dma = xhci_memalign_dma32(ALIGN_SPBA, sizeof(*spba) * x->spb, -+					x->pagesize); -+      if (!x->spba_dma) -+	goto fail; -+ -+      x->spad_dma = xhci_memalign_dma32(x->pagesize, x->pagesize * x->spb, -+					x->pagesize); -+      if (!x->spad_dma) -+	{ -+	  grub_dma_free(x->spba_dma); -+	  goto fail; -+	} -+ -+      spba = grub_dma_get_virt(x->spba_dma); -+      for (grub_uint32_t i = 0; i < x->spb; i++) -+	spba[i] = (grub_addr_t)grub_dma_get_phys(x->spad_dma) + (i * x->pagesize); -+      grub_arch_sync_dma_caches(x->spba_dma, sizeof(*spba) * x->spb); -+ -+      x->devs[0].ptr_low = grub_dma_get_phys(x->spba_dma); -+      x->devs[0].ptr_high = 0; -+      grub_arch_sync_dma_caches(x->devs_dma, sizeof(x->devs[0])); -+      grub_dprintf ("xhci", "XHCI init: Allocated %d scratch buffers of size 0x%x\n", -+		    x->spb, x->pagesize); -+    } -+ -+  grub_xhci_reset(x); -+ -+  /* Set the running bit */ -+  reg = grub_xhci_read32 (&x->op->usbcmd); -+  reg |= GRUB_XHCI_CMD_RS; -+  grub_xhci_write32 (&x->op->usbcmd, reg); -+ -+ -+  /* Link to xhci now that initialisation is successful.  */ -+  x->next = xhci; -+  xhci = x; -+ -+  return; -+ -+fail: -+  grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: FAILED!\n"); -+  if (x) -+    { -+      if (x->devs_dma) -+	grub_dma_free (x->devs_dma); -+      if (x->eseg_dma) -+	grub_dma_free (x->eseg_dma); -+      if (x->cmds_dma) -+	grub_dma_free (x->cmds_dma); -+      if (x->evts_dma) -+	grub_dma_free (x->evts_dma); -+      if (x->spad_dma) -+	grub_dma_free (x->spad_dma); -+      if (x->spba_dma) -+	grub_dma_free (x->spba_dma); -+    } -+  grub_free (x); -+ -+  return; -+} -+ -+static int -+grub_xhci_iterate (grub_usb_controller_iterate_hook_t hook, void *hook_data) -+{ -+  struct grub_xhci *x; -+  struct grub_usb_controller dev; -+ -+  for (x = xhci; x; x = x->next) -+    { -+      dev.data = x; -+      if (hook (&dev, hook_data)) -+	return 1; -+    } -+ -+  return 0; -+} -+ -+/**************************************************************** -+ * xHCI maintainance functions  -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_update_hub_portcount (struct grub_xhci *x, -+				grub_usb_transfer_t transfer, -+				grub_uint32_t slotid) -+{ -+  struct grub_pci_dma_chunk *in_dma; -+  volatile struct grub_xhci_slotctx *hdslot; -+  grub_uint32_t epid = 0; -+ -+  if (!transfer || !transfer->dev || !transfer->dev->nports) -+    return GRUB_USB_ERR_NONE; -+ -+  hdslot = grub_dma_phys2virt(x->devs[slotid].ptr_low, x->devs_dma); -+  if ((hdslot->ctx[3] >> 27) == 3) -+    /* Already configured */ -+    return 0; -+ -+  grub_dprintf("xhci", "%s: updating hub config to %d ports\n", __func__, -+	       transfer->dev->nports); -+ -+  xhci_check_status(x); -+ -+  /* Allocate input context and initialize endpoint info. */ -+  in_dma = grub_xhci_alloc_inctx(x, epid, transfer->dev); -+  if (!in_dma) -+    return GRUB_USB_ERR_INTERNAL; -+  volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); -+ -+  in->add = (1 << epid); -+ -+  struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; -+  ep->ctx[0]   |= 1 << 26; -+  ep->ctx[1]   |= transfer->dev->nports << 24; -+ -+  int cc = xhci_cmd_configure_endpoint(x, slotid, in_dma); -+  grub_dma_free(in_dma); -+ -+  if (cc != CC_SUCCESS) -+    { -+      grub_dprintf("xhci", "%s: reconf ctl endpoint: failed (cc %d)\n", -+		   __func__, cc); -+      return GRUB_USB_ERR_BADDEVICE; -+    } -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+static grub_usb_err_t -+grub_xhci_update_max_paket_size (struct grub_xhci *x, -+				 grub_usb_transfer_t transfer, -+				 grub_uint32_t slotid, -+				 grub_uint32_t max_packet) -+{ -+  struct grub_pci_dma_chunk *in_dma; -+  grub_uint32_t epid = 1; -+ -+  if (!transfer || !transfer->dev || !max_packet) -+    return GRUB_USB_ERR_NONE; -+ -+  grub_dprintf("xhci", "%s: updating max packet size to 0x%x\n", __func__, -+	       max_packet); -+ -+  xhci_check_status(x); -+ -+  /* Allocate input context and initialize endpoint info. */ -+  in_dma = grub_xhci_alloc_inctx(x, epid, transfer->dev); -+  if (!in_dma) -+    return GRUB_USB_ERR_INTERNAL; -+  volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); -+  in->add = (1 << epid); -+ -+  struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; -+  ep->ctx[1]   |= max_packet << 16; -+ -+  int cc = xhci_cmd_evaluate_context(x, slotid, in_dma); -+  grub_dma_free(in_dma); -+ -+  if (cc != CC_SUCCESS) -+    { -+      grub_dprintf("xhci", "%s: reconf ctl endpoint: failed (cc %d)\n", -+		   __func__, cc); -+      return GRUB_USB_ERR_BADDEVICE; -+    } -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI endpoint enablement functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_prepare_endpoint (struct grub_xhci *x, -+			    struct grub_usb_device *dev, -+			    grub_uint8_t endpoint, -+			    grub_transfer_type_t dir, -+			    grub_transaction_type_t type, -+			    grub_uint32_t maxpaket, -+			    struct grub_xhci_priv *priv) -+{ -+  grub_uint32_t epid; -+  struct grub_pci_dma_chunk *reqs_dma; -+  struct grub_pci_dma_chunk *in_dma; -+  volatile struct grub_xhci_ring *reqs; -+  volatile struct grub_xhci_slotctx *slotctx; -+ -+  if (!x || !priv) -+    return GRUB_USB_ERR_INTERNAL; -+ -+  xhci_check_status(x); -+ -+  if (endpoint == 0) -+    { -+      epid = 1; -+    } -+  else -+    { -+      epid = (endpoint & 0x0f) * 2; -+      epid += (dir == GRUB_USB_TRANSFER_TYPE_IN) ? 1 : 0; -+    } -+  grub_dprintf("xhci", "%s: epid %d\n", __func__, epid); -+ -+  /* Test if already prepared */ -+  if (priv->slotid > 0 && priv->enpoint_trbs[epid] != NULL) -+    return GRUB_USB_ERR_NONE; -+ -+  /* Allocate DMA buffer as endpoint cmd TRB */ -+  reqs_dma = xhci_memalign_dma32(ALIGN_TRB, sizeof(*reqs), -+				 BOUNDARY_RING); -+  if (!reqs_dma) -+    return GRUB_USB_ERR_INTERNAL; -+  reqs = grub_dma_get_virt(reqs_dma); -+  grub_memset((void *)reqs, 0, sizeof(*reqs)); -+  reqs->cs = 1; -+ -+  grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); -+ -+  /* Allocate input context and initialize endpoint info. */ -+  in_dma = grub_xhci_alloc_inctx(x, epid, dev); -+  if (!in_dma) -+    { -+      grub_dma_free(reqs_dma); -+      return GRUB_USB_ERR_INTERNAL; -+    } -+  volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); -+  in->add = 0x01 | (1 << epid); -+ -+  struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; -+  switch (type) -+    { -+      case GRUB_USB_TRANSACTION_TYPE_CONTROL: -+        ep->ctx[1]   |= 0 << 3; -+        break; -+      case GRUB_USB_TRANSACTION_TYPE_BULK: -+        ep->ctx[1]   |= 2 << 3; -+        break; -+    } -+  if (dir == GRUB_USB_TRANSFER_TYPE_IN -+      || type== GRUB_USB_TRANSACTION_TYPE_CONTROL) -+      ep->ctx[1] |= 1 << 5; -+  ep->ctx[1]   |= maxpaket << 16; -+  ep->deq_low  = grub_dma_get_phys(reqs_dma); -+  ep->deq_low  |= 1;	 /* dcs */ -+  ep->length   = maxpaket; -+ -+  grub_dprintf("xhci", "%s: ring %p, epid %d, max %d\n", __func__, -+	       reqs, epid, maxpaket); -+  if (epid == 1 || priv->slotid == 0) { -+    /* Enable slot. */ -+    int slotid = xhci_cmd_enable_slot(x); -+    if (slotid < 0) -+      { -+	grub_dprintf("xhci", "%s: enable slot: failed\n", __func__); -+	grub_dma_free(reqs_dma); -+	grub_dma_free(in_dma); -+	return GRUB_USB_ERR_BADDEVICE; -+      } -+    grub_dprintf("xhci", "%s: get slot %d assigned\n", __func__, slotid); -+ -+    grub_uint32_t size = (sizeof(struct grub_xhci_slotctx) * GRUB_XHCI_MAX_ENDPOINTS) << x->flag64; -+ -+    /* Allocate memory for the device specific slot context */ -+    priv->slotctx_dma = xhci_memalign_dma32(ALIGN_SLOTCTX, size, -+					    x->pagesize); -+    if (!priv->slotctx_dma) -+      { -+	grub_dprintf("xhci", "%s: grub_memalign_dma32 failed\n", __func__); -+	grub_dma_free(reqs_dma); -+	grub_dma_free(in_dma); -+	return GRUB_USB_ERR_INTERNAL; -+      } -+    slotctx = grub_dma_get_virt(priv->slotctx_dma); -+ -+    grub_dprintf("xhci", "%s: enable slot: got slotid %d\n", __func__, slotid); -+    grub_memset((void *)slotctx, 0, size); -+    grub_arch_sync_dma_caches(slotctx, size); -+ -+    x->devs[slotid].ptr_low = grub_dma_get_phys(priv->slotctx_dma); -+    x->devs[slotid].ptr_high = 0; -+    grub_arch_sync_dma_caches(&x->devs[slotid], sizeof(x->devs[0])); -+ -+    /* Send set_address command. */ -+    int cc = xhci_cmd_address_device(x, slotid, in_dma); -+    if (cc != CC_SUCCESS) -+      { -+	grub_dprintf("xhci","%s: address device: failed (cc %d)\n", __func__, cc); -+	cc = xhci_cmd_disable_slot(x, slotid); -+	if (cc != CC_SUCCESS) { -+	    grub_dprintf("xhci", "%s: disable failed (cc %d)\n", __func__, cc); -+	} else { -+	  x->devs[slotid].ptr_low = 0; -+	  x->devs[slotid].ptr_high = 0; -+	  grub_arch_sync_dma_caches(&x->devs[slotid], sizeof(x->devs[0])); -+	} -+	grub_dma_free(priv->slotctx_dma); -+	grub_dma_free(reqs_dma); -+	grub_dma_free(in_dma); -+	return GRUB_USB_ERR_BADDEVICE; -+      } -+    priv->enpoint_trbs[epid] = reqs; -+    priv->enpoint_trbs_dma[epid] = reqs_dma; -+    priv->slotid = slotid; -+    priv->max_packet = 0; -+  } -+  if (epid != 1) -+    { -+	/* Send configure command. */ -+	int cc = xhci_cmd_configure_endpoint(x, priv->slotid, in_dma); -+	if (cc != CC_SUCCESS) -+	  { -+	    grub_dprintf("xhci", "%s: configure endpoint: failed (cc %d)\n", -+			 __func__, cc); -+	    grub_dma_free(reqs_dma); -+	    grub_dma_free(in_dma); -+	    return GRUB_USB_ERR_BADDEVICE; -+	  } -+      priv->enpoint_trbs[epid] = reqs; -+      priv->enpoint_trbs_dma[epid] = reqs_dma; -+    } -+ -+  grub_dprintf("xhci", "%s: done\n", __func__); -+  grub_dma_free(in_dma); -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+ -+/**************************************************************** -+ * xHCI transfer helper functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_usb_to_grub_err (unsigned char status) -+{ -+  if (status != CC_SUCCESS) -+    grub_dprintf("xhci", "%s: xfer failed (cc %d)\n", __func__, status); -+  else -+    grub_dprintf("xhci", "%s: xfer done   (cc %d)\n", __func__, status); -+ -+  if (status == CC_BABBLE_DETECTED) -+    return GRUB_USB_ERR_BABBLE; -+  else if (status == CC_DATA_BUFFER_ERROR) -+    return GRUB_USB_ERR_DATA; -+  else if (status == CC_STALL_ERROR) -+    return GRUB_USB_ERR_STALL; -+  else if (status != CC_SUCCESS) -+    return GRUB_USB_ERR_NAK; -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+static int -+grub_xhci_transfer_is_zlp(grub_usb_transfer_t transfer, int idx) -+{ -+  if (idx >= transfer->transcnt) -+    return 0; -+ -+  grub_usb_transaction_t tr = &transfer->transactions[idx]; -+ -+  return (tr->size == 0) && -+    ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || -+    (tr->pid == GRUB_USB_TRANSFER_TYPE_IN)); -+} -+ -+static int -+grub_xhci_transfer_is_last(grub_usb_transfer_t transfer, int idx) -+{ -+    return (idx + 1) == transfer->transcnt; -+} -+ -+static int -+grub_xhci_transfer_is_data(grub_usb_transfer_t transfer, int idx) -+{ -+  grub_usb_transaction_t tr; -+ -+  if (idx >= transfer->transcnt) -+    return 0; -+ -+  tr = &transfer->transactions[idx]; -+  if (tr->size == 0 || -+      (tr->pid == GRUB_USB_TRANSFER_TYPE_SETUP)) -+    return 0; -+ -+  /* If there's are no DATA pakets before it's a DATA paket */ -+  for (int i = idx - 1; i >= 0; i--) -+    { -+      tr = &transfer->transactions[i]; -+      if (tr->size > 0 && -+	  ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || -+	  (tr->pid == GRUB_USB_TRANSFER_TYPE_IN))) -+	    return 0; -+    } -+  return 1; -+} -+ -+static int -+grub_xhci_transfer_is_in(grub_usb_transfer_t transfer, int idx) -+{ -+  grub_usb_transaction_t tr; -+ -+  if (idx >= transfer->transcnt) -+    return 0; -+ -+  tr = &transfer->transactions[idx]; -+ -+  return tr->pid == GRUB_USB_TRANSFER_TYPE_IN; -+} -+ -+static int -+grub_xhci_transfer_is_normal(grub_usb_transfer_t transfer, int idx) -+{ -+  grub_usb_transaction_t tr; -+ -+  if (idx >= transfer->transcnt) -+    return 0; -+ -+  tr = &transfer->transactions[idx]; -+  if (tr->size == 0 || -+      (tr->pid == GRUB_USB_TRANSFER_TYPE_SETUP)) -+    return 0; -+ -+  /* If there's at least one DATA paket before it's a normal */ -+  for (int i = idx - 1; i >= 0; i--) -+    { -+      tr = &transfer->transactions[i]; -+      if (tr->size > 0 && -+	  ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || -+	  (tr->pid == GRUB_USB_TRANSFER_TYPE_IN))) -+	    return 1; -+ -+    } -+  return 0; -+} -+ -+static int -+grub_xhci_transfer_next_is_normal(grub_usb_transfer_t transfer, int idx) -+{ -+  return grub_xhci_transfer_is_normal(transfer, idx + 1); -+} -+ -+static int -+grub_xhci_transfer_next_is_in(grub_usb_transfer_t transfer, int idx) -+{ -+  return grub_xhci_transfer_is_in(transfer, idx + 1); -+} -+ -+static grub_uint8_t grub_xhci_epid_from_transfer(grub_usb_transfer_t transfer) -+{ -+  grub_uint8_t epid; -+ -+  if (transfer->endpoint == 0) { -+      epid = 1; -+  } else { -+    epid = (transfer->endpoint & 0x0f) * 2; -+    epid += (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN) ? 1 : 0; -+  } -+  return epid; -+} -+ -+/**************************************************************** -+ * xHCI transfer functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_setup_transfer (grub_usb_controller_t dev, -+			  grub_usb_transfer_t transfer) -+{ -+  struct grub_xhci_transfer_controller_data *cdata; -+  struct grub_xhci *x = (struct grub_xhci *) dev->data; -+  grub_uint8_t epid; -+  grub_usb_err_t err; -+  volatile struct grub_xhci_ring *reqs; -+  int rc; -+  struct grub_xhci_priv *priv; -+ -+   xhci_check_status(x); -+ -+  if (!dev || !transfer || !transfer->dev || !transfer->dev->xhci_priv) -+    return GRUB_USB_ERR_INTERNAL; -+ -+  priv = transfer->dev->xhci_priv; -+  err = grub_xhci_prepare_endpoint(x, transfer->dev, -+				   transfer->endpoint, -+				   transfer->dir, -+				   transfer->type, -+				   transfer->max, -+				   priv); -+ -+  if (err != GRUB_USB_ERR_NONE) -+    return err; -+ -+  epid = grub_xhci_epid_from_transfer(transfer); -+ -+  /* Update the max packet size once descdev.maxsize0 is valid */ -+  if (epid == 1 && -+      (priv->max_packet == 0) && -+      (transfer->dev->descdev.maxsize0 > 0)) -+    { -+      if (transfer->dev->speed == GRUB_USB_SPEED_SUPER) -+        priv->max_packet = 1UL << transfer->dev->descdev.maxsize0; -+      else -+        priv->max_packet = transfer->dev->descdev.maxsize0; -+      err = grub_xhci_update_max_paket_size(x, transfer, priv->slotid, priv->max_packet); -+      if (err != GRUB_USB_ERR_NONE) -+        { -+          grub_dprintf("xhci", "%s: Updating max paket size failed\n", __func__); -+          return err; -+        } -+    } -+  if (epid == 1 && -+      transfer->dev->descdev.class == 9 && -+      transfer->dev->nports > 0) -+    { -+      err = grub_xhci_update_hub_portcount(x, transfer, priv->slotid); -+      if (err != GRUB_USB_ERR_NONE) -+        { -+          grub_dprintf("xhci", "%s: Updating max paket size failed\n", __func__); -+          return err; -+        } -+    } -+ -+  /* Allocate private data for the transfer */ -+  cdata = grub_zalloc(sizeof(*cdata)); -+  if (!cdata) -+    return GRUB_USB_ERR_INTERNAL; -+ -+  reqs = priv->enpoint_trbs[epid]; -+ -+  transfer->controller_data = cdata; -+ -+  /* Now queue the transfer onto the TRB */ -+  if (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL) -+  { -+    volatile struct grub_usb_packet_setup *setupdata; -+    setupdata = (void *)transfer->transactions[0].data; -+    grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request); -+    grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length); -+ -+    if (setupdata && setupdata->request == GRUB_USB_REQ_SET_ADDRESS) -+      return GRUB_USB_ERR_NONE; -+ -+    if (transfer->transcnt < 2) -+      return GRUB_USB_ERR_INTERNAL; -+ -+    for (int i = 0; i < transfer->transcnt; i++) -+      { -+	grub_uint32_t flags = 0; -+	grub_uint64_t inline_data; -+	grub_usb_transaction_t tr = &transfer->transactions[i]; -+ -+	switch (tr->pid) -+	  { -+	    case GRUB_USB_TRANSFER_TYPE_SETUP: -+	      { -+		grub_dprintf("xhci", "%s: SETUP PKG\n", __func__); -+		grub_dprintf("xhci", "%s: transfer->size %d\n", __func__, transfer->size); -+		grub_dprintf("xhci", "%s: tr->size %d SETUP PKG\n", __func__, tr->size); -+ -+		flags |= (TR_SETUP << 10); -+		flags |= TRB_TR_IDT; -+ -+		if (transfer->size > 0) -+		  { -+		    if (grub_xhci_transfer_next_is_in(transfer, i)) -+		      flags |= (3 << 16); /* TRT IN */ -+		    else -+		      flags |= (2 << 16); /* TRT OUT */ -+		  } -+		break; -+	      } -+	    case GRUB_USB_TRANSFER_TYPE_OUT: -+	      { -+		grub_dprintf("xhci", "%s: OUT PKG\n", __func__); -+		cdata->transfer_size += tr->size; -+		break; -+	      } -+	    case GRUB_USB_TRANSFER_TYPE_IN: -+	      { -+		grub_dprintf("xhci", "%s: IN PKG\n", __func__); -+		cdata->transfer_size += tr->size; -+		flags |= TRB_TR_DIR; -+		break; -+	      } -+	  } -+ -+	if (grub_xhci_transfer_is_normal(transfer, i)) -+	  flags |= (TR_NORMAL << 10); -+	else if (grub_xhci_transfer_is_data(transfer, i)) -+	  flags |= (TR_DATA << 10); -+	else if (grub_xhci_transfer_is_zlp(transfer, i)) -+	  flags |= (TR_STATUS << 10); -+ -+	if (grub_xhci_transfer_next_is_normal(transfer, i)) -+	  flags |= TRB_TR_CH; -+ -+	if (grub_xhci_transfer_is_last(transfer, i)) -+	  flags |= TRB_TR_IOC; -+ -+	/* Assume the ring has enough free space for all TRBs */ -+	if (flags & TRB_TR_IDT && tr->size <= (int)sizeof(inline_data)) -+	  { -+	    grub_memcpy(&inline_data, (void *)tr->data, tr->size); -+	    xhci_trb_queue(reqs, inline_data, tr->size, flags); -+	  } -+	else -+	  { -+	    xhci_trb_queue(reqs, tr->data, tr->size, flags); -+	  } -+      } -+  } -+  else if (transfer->type == GRUB_USB_TRANSACTION_TYPE_BULK) -+    { -+      for (int i = 0; i < transfer->transcnt; i++) -+	{ -+	  grub_uint32_t flags = (TR_NORMAL << 10); -+	  grub_usb_transaction_t tr = &transfer->transactions[i]; -+	  switch (tr->pid) -+	    { -+	      case GRUB_USB_TRANSFER_TYPE_OUT: -+		{ -+		  grub_dprintf("xhci", "%s: OUT PKG\n", __func__); -+		  cdata->transfer_size += tr->size; -+		  break; -+		} -+	      case GRUB_USB_TRANSFER_TYPE_IN: -+		{ -+		  grub_dprintf("xhci", "%s: IN PKG\n", __func__); -+		  cdata->transfer_size += tr->size; -+		  flags |= TRB_TR_DIR; -+		  break; -+		} -+		case GRUB_USB_TRANSFER_TYPE_SETUP: -+		  break; -+	    } -+	  if (grub_xhci_transfer_is_last(transfer, i)) -+	    flags |= TRB_TR_IOC; -+ -+	  /* The ring might be to small, submit while adding new entries */ -+	  rc = xhci_trb_queue_and_flush(x, priv->slotid, epid, -+				  reqs, tr->data, tr->size, flags); -+	  if (rc < 0) -+	    return GRUB_USB_ERR_TIMEOUT; -+	  else if (rc > 1) -+	    return grub_xhci_usb_to_grub_err(rc); -+ -+	} -+    } -+  xhci_doorbell(x, priv->slotid, epid); -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+static grub_usb_err_t -+grub_xhci_check_transfer (grub_usb_controller_t dev, -+			  grub_usb_transfer_t transfer, grub_size_t * actual) -+{ -+  grub_uint32_t status; -+  grub_uint32_t remaining; -+  grub_uint8_t epid; -+  volatile struct grub_xhci_ring *reqs; -+  grub_usb_err_t err; -+  int rc; -+ -+  if (!dev->data || !transfer->controller_data || !transfer->dev || -+      !transfer->dev->xhci_priv) -+    return GRUB_USB_ERR_INTERNAL; -+ -+ -+  struct grub_xhci_priv *priv = transfer->dev->xhci_priv; -+  struct grub_xhci *x = (struct grub_xhci *) dev->data; -+  struct grub_xhci_transfer_controller_data *cdata = -+    transfer->controller_data; -+ -+  xhci_check_status(x); -+  xhci_process_events(x); -+ -+  epid = grub_xhci_epid_from_transfer(transfer); -+ -+  reqs = priv->enpoint_trbs[epid]; -+ -+  /* XXX: invalidate caches */ -+ -+  /* Get current status from event ring buffer */ -+  status = (reqs->evt.status>> 24) & 0xff; -+  remaining = reqs->evt.status & 0xffffff; -+ -+  if (status != CC_STOPPED_LENGTH_INVALID) -+      *actual = cdata->transfer_size - remaining; -+  else -+    *actual = 0; -+ -+  if (xhci_ring_busy(reqs)) -+      return GRUB_USB_ERR_WAIT; -+ -+  grub_free(cdata); -+ -+  grub_dprintf("xhci", "%s: xfer done\n", __func__); -+ -+  err = grub_xhci_usb_to_grub_err(status); -+  if (err != GRUB_USB_ERR_NONE) -+    { -+      if (status == CC_STALL_ERROR) -+	{ -+	  /* Clear the stall by resetting the endpoint */ -+	  rc = xhci_cmd_reset_endpoint(x, priv->slotid, epid, 1); -+ -+	  if (rc < 0) -+	    return GRUB_USB_ERR_TIMEOUT; -+ -+	  return GRUB_USB_ERR_STALL; -+	} -+      else if (remaining > 0) -+	{ -+	  return GRUB_USB_ERR_DATA; -+	} -+    } -+ -+  return err; -+} -+ -+static grub_usb_err_t -+grub_xhci_cancel_transfer (grub_usb_controller_t dev, -+			grub_usb_transfer_t transfer) -+{ -+  grub_uint8_t epid; -+  volatile struct grub_xhci_ring *reqs; -+  struct grub_pci_dma_chunk *enpoint_trbs_dma; -+  grub_addr_t deque_pointer; -+  int rc; -+ -+  if (!dev->data || !transfer->controller_data || !transfer->dev || -+      !transfer->dev->xhci_priv) -+      return GRUB_USB_ERR_INTERNAL; -+ -+  struct grub_xhci *x = (struct grub_xhci *) dev->data; -+  struct grub_xhci_transfer_controller_data *cdata = -+    transfer->controller_data; -+  struct grub_xhci_priv *priv = transfer->dev->xhci_priv; -+ -+  epid = grub_xhci_epid_from_transfer(transfer); -+ -+  enpoint_trbs_dma = priv->enpoint_trbs_dma[epid]; -+  reqs = priv->enpoint_trbs[epid]; -+ -+  /* Abort current command */ -+  rc = xhci_cmd_stop_endpoint(x, priv->slotid, epid, 0); -+  if (rc < 0) -+    return GRUB_USB_ERR_TIMEOUT; -+ -+  /* Reset state */ -+  reqs->nidx = 0; -+  reqs->eidx = 0; -+  reqs->cs = 1; -+ -+  grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); -+ -+  /* Reset the dequeue pointer to the begging of the TRB */ -+  deque_pointer = grub_dma_get_phys(enpoint_trbs_dma); -+  rc = xhci_cmd_set_dequeue_pointer(x, priv->slotid, epid, deque_pointer| 1 ); -+  if (rc < 0) -+    return GRUB_USB_ERR_TIMEOUT; -+ -+  reqs->evt.ptr_low = 0; -+  reqs->evt.ptr_high = 0; -+  reqs->evt.control = 0; -+  reqs->evt.status = 0; -+ -+  grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); -+ -+  /* Restart ring buffer processing */ -+  xhci_doorbell(x, priv->slotid, epid); -+ -+  grub_free (cdata); -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI port status functions -+ ****************************************************************/ -+ -+static int -+grub_xhci_hubports (grub_usb_controller_t dev) -+{ -+  struct grub_xhci *x = (struct grub_xhci *) dev->data; -+  grub_uint32_t portinfo; -+ -+  portinfo = x->ports; -+  grub_dprintf ("xhci", "root hub ports=%d\n", portinfo); -+  return portinfo; -+} -+ -+static grub_usb_err_t -+grub_xhci_portstatus (grub_usb_controller_t dev, -+			  unsigned int port, unsigned int enable) -+{ -+  struct grub_xhci *x = (struct grub_xhci *) dev->data; -+  grub_uint32_t portsc, pls; -+  grub_uint32_t end; -+ -+  portsc = grub_xhci_port_read(x, port); -+  pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); -+ -+  grub_dprintf("xhci", "grub_xhci_portstatus port #%d: 0x%08x,%s%s pls %d enable %d\n", -+	       port, portsc, -+	       (portsc & GRUB_XHCI_PORTSC_PP)  ? " powered," : "", -+	       (portsc & GRUB_XHCI_PORTSC_PED) ? " enabled," : "", -+	       pls, enable); -+  xhci_check_status(x); -+ -+  if ((enable && (portsc & GRUB_XHCI_PORTSC_PED)) || -+      (!enable && !(portsc & GRUB_XHCI_PORTSC_PED))) -+    return GRUB_USB_ERR_NONE; -+ -+  if (!enable) -+    { -+      /* Disable port */ -+      grub_xhci_port_write(x, port, ~0, GRUB_XHCI_PORTSC_PED); -+      return GRUB_USB_ERR_NONE; -+    } -+ -+  grub_dprintf ("xhci", "portstatus: XHCI STATUS: %08x\n", -+		grub_xhci_read32(&x->op->usbsts)); -+  grub_dprintf ("xhci", -+		"portstatus: begin, iobase=%p, port=%d, status=0x%08x\n", -+		x->caps, port, portsc); -+ -+  switch (pls) -+    { -+      case PLS_U0: -+	/* A USB3 port - controller automatically performs reset */ -+	break; -+      case PLS_POLLING: -+	/* A USB2 port - perform device reset */ -+	grub_xhci_port_write(x, port, ~GRUB_XHCI_PORTSC_PED, GRUB_XHCI_PORTSC_PR); -+	break; -+      default: -+        return GRUB_USB_ERR_NONE; -+    } -+ -+  /* Wait for device to complete reset and be enabled */ -+  end = grub_get_time_ms () + 100; -+  for (;;) -+    { -+      portsc = grub_xhci_port_read(x, port); -+      if (!(portsc & GRUB_XHCI_PORTSC_CCS)) -+	{ -+	  /* Device disconnected during reset */ -+	  grub_dprintf ("xhci","ERROR: %s device disconnected\n", __func__); -+	  return GRUB_USB_ERR_BADDEVICE; -+	} -+      if (portsc & GRUB_XHCI_PORTSC_PED) -+	  /* Reset complete */ -+	  break; -+      if (grub_get_time_ms () > end) -+	{ -+	  grub_dprintf ("xhci","ERROR: %s TIMEOUT\n", __func__); -+	  return GRUB_USB_ERR_TIMEOUT; -+	} -+    } -+  xhci_check_status(x); -+ -+  return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI detect device functions -+ ****************************************************************/ -+ -+static grub_usb_speed_t -+grub_xhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) -+{ -+  struct grub_xhci *x = (struct grub_xhci *) dev->data; -+  grub_uint32_t portsc, speed; -+ -+  *changed = 0; -+  grub_dprintf("xhci", "%s: dev=%p USB%d_%d port %d\n", __func__, dev, -+	       x->psids[port-1].major, x->psids[port-1].minor, port); -+ -+  /* On shutdown advertise all ports as disconnected. This will trigger -+   * a gracefull detatch. */ -+  if (x->shutdown) -+    { -+      *changed = 1; -+      return GRUB_USB_SPEED_NONE; -+    } -+ -+  /* Don't advertise new devices, connecting will fail if halted */ -+  if (xhci_is_halted(x)) -+    return GRUB_USB_SPEED_NONE; -+ -+  portsc = grub_xhci_port_read(x, port); -+  speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED); -+  grub_uint8_t pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); -+ -+  grub_dprintf("xhci", "grub_xhci_portstatus port #%d: 0x%08x,%s%s pls %d\n", -+	       port, portsc, -+	       (portsc & GRUB_XHCI_PORTSC_PP)  ? " powered," : "", -+	       (portsc & GRUB_XHCI_PORTSC_PED) ? " enabled," : "", -+	       pls); -+ -+  /* Connect Status Change bit - it detects change of connection */ -+  if (portsc & GRUB_XHCI_PORTSC_CSC) -+    { -+      *changed = 1; -+ -+      grub_xhci_port_write(x, port, ~GRUB_XHCI_PORTSC_PED, GRUB_XHCI_PORTSC_CSC); -+    } -+ -+  if (!(portsc & GRUB_XHCI_PORTSC_CCS)) -+    return GRUB_USB_SPEED_NONE; -+ -+  for (grub_uint8_t i = 0; i < 16 && x->psids[port-1].psids[i].id > 0; i++) -+    { -+      if (x->psids[port-1].psids[i].id == speed) -+        { -+	  grub_dprintf("xhci", "%s: grub_usb_speed = %d\n", __func__, -+		       x->psids[port-1].psids[i].grub_usb_speed ); -+	  return x->psids[port-1].psids[i].grub_usb_speed; -+	} -+    } -+ -+  return GRUB_USB_SPEED_NONE; -+} -+ -+/**************************************************************** -+ * xHCI attach/detach functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_attach_dev (grub_usb_controller_t ctrl, grub_usb_device_t dev) -+{ -+  struct grub_xhci *x = (struct grub_xhci *) ctrl->data; -+  grub_usb_err_t err; -+  grub_uint32_t max; -+ -+  grub_dprintf("xhci", "%s: dev=%p\n", __func__, dev); -+ -+  if (!dev || !x) -+    return GRUB_USB_ERR_INTERNAL; -+ -+  dev->xhci_priv = grub_zalloc (sizeof (struct grub_xhci_priv)); -+  if (!dev->xhci_priv) -+    return GRUB_USB_ERR_INTERNAL; -+ -+ -+  switch (dev->speed) -+    { -+      case GRUB_USB_SPEED_LOW: -+	{ -+	  max = 8; -+	  break; -+	} -+      case GRUB_USB_SPEED_FULL: -+      case GRUB_USB_SPEED_HIGH: -+	{ -+	  max = 64; -+	  break; -+	} -+      case GRUB_USB_SPEED_SUPER: -+	{ -+	  max = 512; -+	  break; -+	} -+      default: -+      case GRUB_USB_SPEED_NONE: -+	{ -+	  max = 0; -+	} -+    } -+ -+  /* Assign a slot, assign an address and configure endpoint 0 */ -+  err = grub_xhci_prepare_endpoint(x, dev, -+				  0, -+				  0, -+				  GRUB_USB_TRANSACTION_TYPE_CONTROL, -+				  max, -+				  dev->xhci_priv); -+ -+  return err; -+} -+ -+static grub_usb_err_t -+grub_xhci_detach_dev (grub_usb_controller_t ctrl, grub_usb_device_t dev) -+{ -+  struct grub_xhci *x = (struct grub_xhci *) ctrl->data; -+  struct grub_xhci_priv *priv; -+  int cc = CC_SUCCESS; -+ -+  grub_dprintf("xhci", "%s: dev=%p\n", __func__, dev); -+ -+  if (!dev) -+    return GRUB_USB_ERR_INTERNAL; -+ -+  if (dev->xhci_priv) -+    { -+      priv = dev->xhci_priv; -+      /* Stop endpoints and free ring buffer */ -+      for (int i = 0; i < GRUB_XHCI_MAX_ENDPOINTS; i++) -+	{ -+	  if (priv->enpoint_trbs[i] != NULL) -+	    { -+	      cc = xhci_cmd_stop_endpoint(x, priv->slotid, i, 1); -+	      if (cc != CC_SUCCESS) -+		grub_dprintf("xhci", "Failed to disable EP%d on slot %d\n", i, -+			     priv->slotid); -+ -+	      grub_dprintf("xhci", "grub_dma_free[%d]\n", i); -+ -+	      grub_dma_free(priv->enpoint_trbs_dma[i]); -+	      priv->enpoint_trbs[i] = NULL; -+	      priv->enpoint_trbs_dma[i] = NULL; -+	    } -+	} -+ -+      cc = xhci_cmd_disable_slot(x, priv->slotid); -+      if (cc == CC_SUCCESS) -+	{ -+	  if (priv->slotctx_dma) -+	    grub_dma_free(priv->slotctx_dma); -+	  x->devs[priv->slotid].ptr_low = 0; -+	  x->devs[priv->slotid].ptr_high = 0; -+	  grub_arch_sync_dma_caches(&x->devs[priv->slotid], sizeof(x->devs[0])); -+	} -+	else -+	  grub_dprintf("xhci", "Failed to disable slot %d\n", priv->slotid); -+ -+      grub_free(dev->xhci_priv); -+    } -+ -+  dev->xhci_priv = NULL; -+ -+  if (cc != CC_SUCCESS) -+    return GRUB_USB_ERR_BADDEVICE; -+  return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI terminate functions -+ ****************************************************************/ -+ -+static void -+grub_xhci_halt(struct grub_xhci *x) -+{ -+  grub_uint32_t reg; -+ -+  /* Halt the command ring */ -+  reg = grub_xhci_read32(&x->op->crcr_low); -+  grub_xhci_write32(&x->op->crcr_low, reg | 4); -+ -+  int rc = xhci_event_wait(x, x->cmds, 100); -+  grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+  if (rc < 0) -+    return; -+ -+  /* Stop the controller */ -+  reg = grub_xhci_read32(&x->op->usbcmd); -+  if (reg & GRUB_XHCI_CMD_RS) -+    { -+      reg &= ~GRUB_XHCI_CMD_RS; -+      grub_xhci_write32(&x->op->usbcmd, reg); -+    } -+ -+  return; -+} -+ -+static grub_err_t -+grub_xhci_fini_hw (int noreturn __attribute__ ((unused))) -+{ -+  struct grub_xhci *x; -+ -+  /* We should disable all XHCI HW to prevent any DMA access etc. */ -+  for (x = xhci; x; x = x->next) -+    { -+      x->shutdown = 1; -+ -+      /* Gracefully detach active devices */ -+      grub_usb_poll_devices(0); -+ -+      /* Check if xHCI is halted and halt it if not */ -+      grub_xhci_halt (x); -+ -+      /* Reset xHCI */ -+      if (grub_xhci_reset (x) != GRUB_USB_ERR_NONE) -+	return GRUB_ERR_BAD_DEVICE; -+    } -+ -+  return GRUB_ERR_NONE; -+} -+ -+static struct grub_usb_controller_dev usb_controller = { -+  .name = "xhci", -+  .iterate = grub_xhci_iterate, -+  .setup_transfer = grub_xhci_setup_transfer, -+  .check_transfer = grub_xhci_check_transfer, -+  .cancel_transfer = grub_xhci_cancel_transfer, -+  .hubports = grub_xhci_hubports, -+  .portstatus = grub_xhci_portstatus, -+  .detect_dev = grub_xhci_detect_dev, -+  .attach_dev = grub_xhci_attach_dev, -+  .detach_dev = grub_xhci_detach_dev, -+  /* estimated max. count of TDs for one bulk transfer */ -+  .max_bulk_tds = GRUB_XHCI_RING_ITEMS - 3 -+}; -+ -+GRUB_MOD_INIT (xhci) -+{ -+  grub_stop_disk_firmware (); -+ -+  grub_boot_time ("Initing XHCI hardware"); -+  grub_xhci_pci_scan (); -+  grub_boot_time ("Registering XHCI driver"); -+  grub_usb_controller_dev_register (&usb_controller); -+  grub_boot_time ("XHCI driver registered"); -+} -+ -+GRUB_MOD_FINI (xhci) -+{ -+  grub_xhci_fini_hw (0); -+  grub_usb_controller_dev_unregister (&usb_controller); -+} -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 609faf7d0..eb71fa1c7 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -338,6 +338,10 @@ grub_usb_cancel_transfer (grub_usb_transfer_t trans); - void - grub_ehci_init_device (volatile void *regs); - void -+grub_xhci_init_device (volatile void *regs); -+void - grub_ehci_pci_scan (void); -+void -+grub_xhci_pci_scan (void); -  - #endif /* GRUB_USB_H */ ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0007-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch b/config/grub/patches/0005-xhci/0007-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch deleted file mode 100644 index a37bbd6b..00000000 --- a/config/grub/patches/0005-xhci/0007-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 2a2c64f6ea62337c1263a70f6ca9a9bade66b78b Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Thu, 3 Dec 2020 13:44:55 +0100 -Subject: [PATCH 7/8] grub-core/bus/usb/usbhub: Add xHCI non root hub support - -Tested on Intel PCH C246, the USB3 hub can be configured by grub. - -Issues: -* USB3 devices connected behind that hub are sometimes not detected. - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - grub-core/bus/usb/usbhub.c | 38 +++++++++++++++++++++++++++++++++----- - include/grub/usbdesc.h     |  1 + - include/grub/usbtrans.h    |  4 ++++ - 3 files changed, 38 insertions(+), 5 deletions(-) - -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index b4b3a1a61..e96505aa9 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -148,19 +148,32 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, -   return dev; - } -  -- -+static grub_usb_err_t -+grub_usb_set_hub_depth(grub_usb_device_t dev, grub_uint8_t depth) -+{ -+  return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT -+			            | GRUB_USB_REQTYPE_CLASS -+			            | GRUB_USB_REQTYPE_TARGET_DEV), -+			      GRUB_USB_HUB_REQ_SET_HUB_DEPTH, depth, -+			      0, 0, NULL); -+} -+ - static grub_usb_err_t - grub_usb_add_hub (grub_usb_device_t dev) - { -   struct grub_usb_usb_hubdesc hubdesc; -   grub_usb_err_t err; -+  grub_uint16_t req; -   int i; -  -+  req = (dev->speed == GRUB_USB_SPEED_SUPER) ? GRUB_USB_DESCRIPTOR_SS_HUB : -+    GRUB_USB_DESCRIPTOR_HUB; -+ -   err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - 	  		            | GRUB_USB_REQTYPE_CLASS - 			            | GRUB_USB_REQTYPE_TARGET_DEV), --                              GRUB_USB_REQ_GET_DESCRIPTOR, --			      (GRUB_USB_DESCRIPTOR_HUB << 8) | 0, -+			      GRUB_USB_REQ_GET_DESCRIPTOR, -+			      (req << 8) | 0, - 			      0, sizeof (hubdesc), (char *) &hubdesc); -   if (err) -     return err; -@@ -183,6 +196,19 @@ grub_usb_add_hub (grub_usb_device_t dev) -       return GRUB_USB_ERR_INTERNAL; -     } -  -+  if (dev->speed == GRUB_USB_SPEED_SUPER) -+    { -+      grub_uint8_t depth; -+      grub_uint32_t route; -+      /* Depth maximum value is 5, but root hubs doesn't count */ -+      for (depth = 0, route = dev->route; (route & 0xf) > 0; route >>= 4) -+	depth++; -+ -+      err = grub_usb_set_hub_depth(dev, depth); -+      if (err) -+        return err; -+    } -+ -   /* Power on all Hub ports.  */ -   for (i = 1; i <= hubdesc.portcnt; i++) -     { -@@ -637,7 +663,9 @@ poll_nonroot_hub (grub_usb_device_t dev) - 	      int split_hubaddr = 0; -  - 	      /* Determine the device speed.  */ --	      if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) -+	      if (dev->speed == GRUB_USB_SPEED_SUPER) -+	        speed = GRUB_USB_SPEED_SUPER; -+	      else if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) - 		speed = GRUB_USB_SPEED_LOW; - 	      else - 		{ -@@ -651,7 +679,7 @@ poll_nonroot_hub (grub_usb_device_t dev) - 	      grub_millisleep (10); -  -               /* Find correct values for SPLIT hubport and hubaddr */ --	      if (speed == GRUB_USB_SPEED_HIGH) -+	      if (speed == GRUB_USB_SPEED_HIGH || speed == GRUB_USB_SPEED_SUPER) - 	        { - 		  /* HIGH speed device needs not transaction translation */ - 		  split_hubport = 0; -diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h -index bb2ab2e27..1697aa465 100644 ---- a/include/grub/usbdesc.h -+++ b/include/grub/usbdesc.h -@@ -30,6 +30,7 @@ typedef enum { -   GRUB_USB_DESCRIPTOR_ENDPOINT, -   GRUB_USB_DESCRIPTOR_DEBUG = 10, -   GRUB_USB_DESCRIPTOR_HUB = 0x29, -+  GRUB_USB_DESCRIPTOR_SS_HUB = 0x2a, -   GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 - } grub_usb_descriptor_t; -  -diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h -index 039ebed65..d6c3f71dc 100644 ---- a/include/grub/usbtrans.h -+++ b/include/grub/usbtrans.h -@@ -110,6 +110,10 @@ enum -     GRUB_USB_REQ_SET_INTERFACE = 0x0B, -     GRUB_USB_REQ_SYNC_FRAME = 0x0C -   }; -+enum -+  { -+    GRUB_USB_HUB_REQ_SET_HUB_DEPTH = 0x0C, -+  }; -  - #define GRUB_USB_FEATURE_ENDP_HALT	0x00 - #define GRUB_USB_FEATURE_DEV_REMOTE_WU	0x01 ---  -2.39.2 - diff --git a/config/grub/patches/0005-xhci/0008-Fix-compilation-on-x86_64.patch b/config/grub/patches/0005-xhci/0008-Fix-compilation-on-x86_64.patch deleted file mode 100644 index af79c3d0..00000000 --- a/config/grub/patches/0005-xhci/0008-Fix-compilation-on-x86_64.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 871d768f8c5c960cb0d9761a9028b16882e1a7d3 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph <patrick.rudolph@9elements.com> -Date: Wed, 24 Feb 2021 08:25:41 +0100 -Subject: [PATCH 8/8] Fix compilation on x86_64 - -Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> ---- - grub-core/bus/usb/xhci.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c -index f4591ffb5..3495bb919 100644 ---- a/grub-core/bus/usb/xhci.c -+++ b/grub-core/bus/usb/xhci.c -@@ -184,7 +184,7 @@ enum -  *  then we can get it from a trb pointer (provided by evt ring). -  */ - #define XHCI_RING(_trb)	  \ --    ((struct grub_xhci_ring*)((grub_uint32_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) -+    ((struct grub_xhci_ring*)((grub_addr_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) -  - /* slot context */ - struct grub_xhci_slotctx { -@@ -495,6 +495,14 @@ grub_xhci_read8(volatile void *addr) { -   return (*((volatile grub_uint32_t *)addr)); - } -  -+static inline void * -+grub_xhci_read_etrb_ptr(volatile struct grub_xhci_trb *trb) { -+  grub_uint64_t tmp; -+  tmp = (grub_uint64_t)grub_xhci_read32(&trb->ptr_low); -+  tmp |= ((grub_uint64_t)grub_xhci_read32(&trb->ptr_high)) << 32; -+  return (void *)(grub_addr_t)tmp; -+} -+ - static inline grub_uint32_t - grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port) - { -@@ -664,7 +672,7 @@ static void xhci_process_events(struct grub_xhci *x) - 	    case ER_TRANSFER: - 	    case ER_COMMAND_COMPLETE: - 	      { --		struct grub_xhci_trb  *rtrb = (void*)grub_xhci_read32(&etrb->ptr_low); -+		struct grub_xhci_trb  *rtrb = grub_xhci_read_etrb_ptr(etrb); - 		struct grub_xhci_ring *ring = XHCI_RING(rtrb); - 		volatile struct grub_xhci_trb  *evt = &ring->evt; - 		grub_uint32_t eidx = rtrb - ring->ring + 1; -@@ -697,9 +705,9 @@ static void xhci_process_events(struct grub_xhci *x) - 	  } - 	grub_xhci_write32(&evts->nidx, nidx); - 	volatile struct grub_xhci_ir *ir = x->ir; --	grub_uint32_t erdp = (grub_uint32_t)(evts->ring + nidx); --	grub_xhci_write32(&ir->erdp_low, erdp); --	grub_xhci_write32(&ir->erdp_high, 0); -+	grub_uint64_t erdp = (grub_addr_t)(void *)(&evts->ring[nidx]); -+	grub_xhci_write32(&ir->erdp_low, erdp & 0xffffffff); -+	grub_xhci_write32(&ir->erdp_high, erdp >> 32); -     } - } -  -@@ -800,7 +808,7 @@ static void xhci_trb_queue(volatile struct grub_xhci_ring *ring, - 			   grub_uint32_t xferlen, grub_uint32_t flags) - { -   grub_dprintf("xhci", "%s: ring %p data %llx len %d flags 0x%x remain 0x%x\n", __func__, --      ring, data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); -+      ring, (unsigned long long)data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); -  -   if (xhci_ring_full(ring)) -     { -@@ -1907,7 +1915,7 @@ grub_xhci_setup_transfer (grub_usb_controller_t dev, -   if (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL) -   { -     volatile struct grub_usb_packet_setup *setupdata; --    setupdata = (void *)transfer->transactions[0].data; -+    setupdata = (void *)(grub_addr_t)transfer->transactions[0].data; -     grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request); -     grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length); -  -@@ -1974,7 +1982,7 @@ grub_xhci_setup_transfer (grub_usb_controller_t dev, - 	/* Assume the ring has enough free space for all TRBs */ - 	if (flags & TRB_TR_IDT && tr->size <= (int)sizeof(inline_data)) - 	  { --	    grub_memcpy(&inline_data, (void *)tr->data, tr->size); -+	    grub_memcpy(&inline_data, (void *)(grub_addr_t)tr->data, tr->size); - 	    xhci_trb_queue(reqs, inline_data, tr->size, flags); - 	  } - 	else ---  -2.39.2 - diff --git a/config/grub/patches/0006-nvme/0001-Add-native-NVMe-driver-based-on-SeaBIOS.patch b/config/grub/patches/0006-nvme/0001-Add-native-NVMe-driver-based-on-SeaBIOS.patch index b00611a0..4345ebae 100644 --- a/config/grub/patches/0006-nvme/0001-Add-native-NVMe-driver-based-on-SeaBIOS.patch +++ b/config/grub/patches/0006-nvme/0001-Add-native-NVMe-driver-based-on-SeaBIOS.patch @@ -1,7 +1,7 @@ -From ef9d61ae9ed490301adf9ee064a9fc1190069d81 Mon Sep 17 00:00:00 2001 +From 708c0092d44aec6409e0ecc1925cdbb3b76c6dfd Mon Sep 17 00:00:00 2001  From: Mate Kukri <km@mkukri.xyz>  Date: Mon, 20 May 2024 11:43:35 +0100 -Subject: Add native NVMe driver based on SeaBIOS +Subject: [PATCH 1/1] Add native NVMe driver based on SeaBIOS  Tested to successfully boot Debian on QEMU and OptiPlex 3050. @@ -18,23 +18,23 @@ Signed-off-by: Mate Kukri <km@mkukri.xyz>   create mode 100644 grub-core/disk/nvme.c  diff --git a/Makefile.am b/Makefile.am -index 65016f856..7bc0866ba 100644 +index 43635d5ff..2c86dbbf6 100644  --- a/Makefile.am  +++ b/Makefile.am  @@ -434,7 +434,7 @@ if COND_i386_coreboot   FS_PAYLOAD_MODULES ?= $(shell cat grub-core/fs.lst)   default_payload.elf: grub-mkstandalone grub-mkimage FORCE   	test -f $@ && rm $@ || true --	pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata xhci ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg -+	pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata nvme xhci ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg +-	pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg ++	pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata nvme ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg   endif   endif  diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index ea782666d..0f893369a 100644 +index 560c66447..d3bf9f1c5 100644  --- a/grub-core/Makefile.core.def  +++ b/grub-core/Makefile.core.def -@@ -2602,3 +2602,9 @@ module = { +@@ -2607,3 +2607,9 @@ module = {     efi = commands/bli.c;     enable = efi;   }; @@ -45,7 +45,7 @@ index ea782666d..0f893369a 100644  +  enable = pci;  +};  diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c -index 580c8d3b0..a2c766fbd 100644 +index 6806bff9c..fd68a513e 100644  --- a/grub-core/commands/nativedisk.c  +++ b/grub-core/commands/nativedisk.c  @@ -78,6 +78,7 @@ get_uuid (const char *name, char **uuid, int getnative) | 
