drivers/usbhost: Read xHCI registers at the required access width.

xHCI requires aligned accesses of each register's own size, and a
controller may ignore narrower ones; QEMU's does.  volatile does not pin
the access width: GCC 16.1.0 at -Os narrows a 32-bit load feeding a
single bit test into a byte load, so polling USBSTS for HCH never
observes the halted state.

Launder each register value through a register with an empty asm, on
loads and stores both, so the access is the width the source specifies.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
This commit is contained in:
Justin Hammond
2026-08-17 10:10:47 -03:00
committed by Alan C. Assis
parent eaaba5e0a1
commit 24132be56e
+38 -8
View File
@@ -519,6 +519,12 @@ static struct pci_driver_s g_pci_xhci_drv =
* Private Functions
****************************************************************************/
/* xHCI requires aligned accesses of each register's own size, and
* narrower ones may be ignored. volatile does not pin the access width,
* so every accessor below launders the value through a register with an
* empty asm, on loads and stores both, to force the full-width access.
*/
/****************************************************************************
* Name: xhci_capa_getreg
*
@@ -530,8 +536,11 @@ static struct pci_driver_s g_pci_xhci_drv =
static uint32_t xhci_capa_getreg(FAR struct usbhost_xhci_s *priv,
unsigned int offset)
{
uintptr_t addr = priv->capa_base + offset;
return *((FAR volatile uint32_t *)addr);
uintptr_t addr = priv->capa_base + offset;
uint32_t regval = *((FAR volatile uint32_t *)addr);
__asm__ __volatile__("" : "+r"(regval));
return regval;
}
/****************************************************************************
@@ -545,8 +554,11 @@ static uint32_t xhci_capa_getreg(FAR struct usbhost_xhci_s *priv,
static uint8_t xhci_capa_getreg_1b(FAR struct usbhost_xhci_s *priv,
unsigned int offset)
{
uintptr_t addr = priv->capa_base + offset;
return *((FAR volatile uint8_t *)addr);
uintptr_t addr = priv->capa_base + offset;
uint8_t regval = *((FAR volatile uint8_t *)addr);
__asm__ __volatile__("" : "+r"(regval));
return regval;
}
/****************************************************************************
@@ -562,6 +574,8 @@ static void xhci_capa_putreg_1b(FAR struct usbhost_xhci_s *priv,
uint8_t value)
{
uintptr_t addr = priv->capa_base + offset;
__asm__ __volatile__("" : "+r"(value));
*((FAR volatile uint8_t *)addr) = value;
}
@@ -576,8 +590,11 @@ static void xhci_capa_putreg_1b(FAR struct usbhost_xhci_s *priv,
static uint32_t xhci_oper_getreg(FAR struct usbhost_xhci_s *priv,
unsigned int offset)
{
uintptr_t addr = priv->oper_base + offset;
return *((FAR volatile uint32_t *)addr);
uintptr_t addr = priv->oper_base + offset;
uint32_t regval = *((FAR volatile uint32_t *)addr);
__asm__ __volatile__("" : "+r"(regval));
return regval;
}
/****************************************************************************
@@ -593,6 +610,8 @@ static void xhci_oper_putreg(FAR struct usbhost_xhci_s *priv,
uint32_t value)
{
uintptr_t addr = priv->oper_base + offset;
__asm__ __volatile__("" : "+r"(value));
*((FAR volatile uint32_t *)addr) = value;
}
@@ -609,6 +628,8 @@ static void xhci_oper_putreg_8b(FAR struct usbhost_xhci_s *priv,
uint64_t value)
{
uintptr_t addr = priv->oper_base + offset;
__asm__ __volatile__("" : "+r"(value));
*((FAR volatile uint64_t *)addr) = value;
}
@@ -623,8 +644,11 @@ static void xhci_oper_putreg_8b(FAR struct usbhost_xhci_s *priv,
static uint32_t xhci_runt_getreg(FAR struct usbhost_xhci_s *priv,
unsigned int offset)
{
uintptr_t addr = priv->runt_base + offset;
return *((FAR volatile uint32_t *)addr);
uintptr_t addr = priv->runt_base + offset;
uint32_t regval = *((FAR volatile uint32_t *)addr);
__asm__ __volatile__("" : "+r"(regval));
return regval;
}
/****************************************************************************
@@ -640,6 +664,8 @@ static void xhci_runt_putreg(FAR struct usbhost_xhci_s *priv,
uint32_t value)
{
uintptr_t addr = priv->runt_base + offset;
__asm__ __volatile__("" : "+r"(value));
*((FAR volatile uint32_t *)addr) = value;
}
@@ -656,6 +682,8 @@ static void xhci_runt_putreg_8b(FAR struct usbhost_xhci_s *priv,
uint64_t value)
{
uintptr_t addr = priv->runt_base + offset;
__asm__ __volatile__("" : "+r"(value));
*((FAR volatile uint64_t *)addr) = value;
}
@@ -672,6 +700,8 @@ static void xhci_door_putreg(FAR struct usbhost_xhci_s *priv,
uint32_t value)
{
uintptr_t addr = priv->door_base + offset;
__asm__ __volatile__("" : "+r"(value));
*((FAR volatile uint32_t *)addr) = value;
}