When 64-bit addressing is supported, the Linux EHCI driver programs the
segment register to zero. See ehci_run function:
https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c

The driver comment also notes that descriptor structures allocated from
the DMA pool use segment zero semantics.

Descriptor memory is allocated using the DMA API. The platform driver
configures a 64-bit DMA mask so memory can be allocated above 4GB.
See ehci_platform_probe function:
https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-platform.c

On AST2700 platforms, system DRAM is mapped above 4GB at 0x400000000.
As a result, descriptor addresses constructed directly from the guest
EHCI registers do not match the actual system address used by the
controller when fetching queue heads (QH) and queue element transfer
descriptors (qTD).

Add a ctrldssegment-default property so platforms can provide a
descriptor address offset when constructing descriptor addresses.
This allows systems where DRAM resides above 4GB to access EHCI
descriptors correctly.

The default value is zero, so existing machines are not affected.

Signed-off-by: Jamin Lin <[email protected]>
Reviewed-by: Cédric Le Goater <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
---
 hw/usb/hcd-ehci.h | 5 ++++-
 hw/usb/hcd-ehci.c | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 49176f3fd2..b5ac9c8670 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -268,6 +268,7 @@ struct EHCIState {
      */
     bool migrate_fetch_addr_64bit;
     bool caps_64bit_addr;
+    uint32_t ctrldssegment_default;
 
     /*
      *  EHCI spec version 1.0 Section 2.3
@@ -333,7 +334,9 @@ struct EHCIState {
     DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \
                      ehci.migrate_fetch_addr_64bit, true), \
     DEFINE_PROP_BOOL("caps-64bit-addr", _state, \
-                     ehci.caps_64bit_addr, false)
+                     ehci.caps_64bit_addr, false), \
+    DEFINE_PROP_UINT32("ctrldssegment-default", _state, \
+                       ehci.ctrldssegment_default, 0)
 
 extern const VMStateDescription vmstate_ehci;
 
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 9a80c74972..451a918e9f 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1162,6 +1162,7 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
                           "64-bit addressing capability is disabled\n");
             return;
         }
+        val |= s->ctrldssegment_default;
         break;
 
     case ASYNCLISTADDR:
-- 
2.43.0

Reply via email to