[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 02/10] xue: reset XHCI ports when initializing dbc
Reset ports, to force host system to re-enumerate devices. Otheriwse it will require the cable to be re-plugged, or will wait in the "configuring" state indefinitely. Trick and code copied from Linux: drivers/usb/early/xhci-dbc.c:xdbc_start()->xdbc_reset_debug_port() Signed-off-by: Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx> --- xen/drivers/char/xue.c | 70 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+) diff --git a/xen/drivers/char/xue.c b/xen/drivers/char/xue.c index e95dd09d39a8..a9ba25d9d07e 100644 --- a/xen/drivers/char/xue.c +++ b/xen/drivers/char/xue.c @@ -60,6 +60,10 @@ ((1UL << XUE_PSC_CSC) | (1UL << XUE_PSC_PRC) | (1UL << XUE_PSC_PLC) | \ (1UL << XUE_PSC_CEC)) +#define XUE_XHC_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) +#define PORT_RESET (1 << 4) +#define PORT_CONNECT (1 << 0) + #define xue_debug(...) printk("xue debug: " __VA_ARGS__) #define xue_alert(...) printk("xue alert: " __VA_ARGS__) #define xue_error(...) printk("xue error: " __VA_ARGS__) @@ -604,6 +608,68 @@ static void xue_init_strings(struct xue *xue, uint32_t *info) info[8] = (4 << 24) | (30 << 16) | (8 << 8) | 6; } +static void xue_do_reset_debug_port(struct xue *xue, u32 id, u32 count) +{ + uint32_t *ops_reg; + uint32_t *portsc; + u32 val, cap_length; + int i; + + cap_length = (*(uint32_t*)xue->xhc_mmio) & 0xff; + ops_reg = xue->xhc_mmio + cap_length; + + id--; + for ( i = id; i < (id + count); i++ ) + { + portsc = ops_reg + 0x100 + i * 0x4; + val = *portsc; + if ( !(val & PORT_CONNECT) ) + *portsc = val | PORT_RESET; + } +} + + +static void xue_reset_debug_port(struct xue *xue) +{ + u32 val, port_offset, port_count; + uint32_t *xcap; + uint32_t next; + uint32_t id; + uint8_t *mmio = (uint8_t *)xue->xhc_mmio; + uint32_t *hccp1 = (uint32_t *)(mmio + 0x10); + const uint32_t PROTOCOL_ID = 0x2; + + /** + * Paranoid check against a zero value. The spec mandates that + * at least one "supported protocol" capability must be implemented, + * so this should always be false. + */ + if ( (*hccp1 & 0xFFFF0000) == 0 ) + return; + + xcap = (uint32_t *)(mmio + (((*hccp1 & 0xFFFF0000) >> 16) << 2)); + next = (*xcap & 0xFF00) >> 8; + id = *xcap & 0xFF; + + /* Look for "supported protocol" capability, major revision 3 */ + for ( ; next; xcap += next, id = *xcap & 0xFF, next = (*xcap & 0xFF00) >> 8) + { + if ( id != PROTOCOL_ID && next ) + continue; + + if ( XUE_XHC_EXT_PORT_MAJOR(*xcap) != 0x3 ) + continue; + + /* extract ports offset and count from the capability structure */ + val = *(xcap + 2); + port_offset = val & 0xff; + port_count = (val >> 8) & 0xff; + + /* and reset them all */ + xue_do_reset_debug_port(xue, port_offset, port_count); + } +} + static void xue_dump(struct xue *xue) { struct xue_dbc_reg *r = xue->dbc_reg; @@ -639,6 +705,10 @@ static void xue_enable_dbc(struct xue *xue) while ( (reg->ctrl & (1UL << XUE_CTRL_DCE)) == 0 ) xue_sys_pause(); + /* reset ports on initial open, to force re-enumerating by the host */ + if ( !xue->open ) + xue_reset_debug_port(xue); + wmb(); reg->portsc |= (1UL << XUE_PSC_PED); wmb(); -- git-series 0.9.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |