Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 9b56e528 in mainline


Ignore:
Timestamp:
2018-01-13T15:13:44Z (4 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master
Children:
36fb6d7
Parents:
37b13175
git-author:
Ondřej Hlavatý <aearsis@…> (2018-01-13 15:11:45)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-01-13 15:13:44)
Message:

xhci rh: better not disable port on any event

The result of a long debugging is that PED bit is RW1C, which means
that enabled port disables itself when asserting events.

Location:
uspace/drv/bus/usb/xhci
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/debug.c

    r37b13175 r9b56e528  
    127127        DUMP_REG(port, XHCI_PORT_DR);
    128128        DUMP_REG(port, XHCI_PORT_WPR);
     129        DUMP_REG(port, XHCI_PORT_USB3_U1TO);
     130        DUMP_REG(port, XHCI_PORT_USB3_U2TO);
     131        DUMP_REG(port, XHCI_PORT_USB3_FLPMA);
     132        DUMP_REG(port, XHCI_PORT_USB3_LEC);
     133        DUMP_REG(port, XHCI_PORT_USB3_RLC);
     134        DUMP_REG(port, XHCI_PORT_USB3_TLC);
     135        DUMP_REG(port, XHCI_PORT_USB2_L1S);
     136        DUMP_REG(port, XHCI_PORT_USB2_RWE);
     137        DUMP_REG(port, XHCI_PORT_USB2_BESL);
     138        DUMP_REG(port, XHCI_PORT_USB2_L1DS);
     139        DUMP_REG(port, XHCI_PORT_USB2_HLE);
     140        DUMP_REG(port, XHCI_PORT_USB2_TM);
     141        DUMP_REG(port, XHCI_PORT_USB2_HIRDM);
     142        DUMP_REG(port, XHCI_PORT_USB2_L1TO);
     143        DUMP_REG(port, XHCI_PORT_USB2_BESLD);
    129144}
    130145
  • uspace/drv/bus/usb/xhci/hw_struct/regs.h

    r37b13175 r9b56e528  
    300300#define XHCI_PORT_WDE           portsc, 32,  FLAG, 26
    301301#define XHCI_PORT_WOE           portsc, 32,  FLAG, 27
    302 #define XHCI_PORT_DR            portsc, 32,  FLAG, 28
    303 #define XHCI_PORT_WPR           portsc, 32,  FLAG, 29
     302#define XHCI_PORT_DR            portsc, 32,  FLAG, 30
     303#define XHCI_PORT_WPR           portsc, 32,  FLAG, 31
    304304
    305305#define XHCI_PORT_USB3_U1TO   portpmsc, 32, RANGE,  7,  0
     
    316316#define XHCI_PORT_USB2_HLE    portpmsc, 32,  FLAG, 16
    317317#define XHCI_PORT_USB2_TM     portpmsc, 32, RANGE, 31, 28
    318 #define XHCI_PORT_USB2_HIRDM porthlmpc, 32, RANGE,  1,  0
    319 #define XHCI_PORT_USB2_L1TO  porthlmpc, 32, RANGE,  9,  2
    320 #define XHCI_PORT_USB2_BESLD porthlmpc, 32, RANGE, 13, 10
     318#define XHCI_PORT_USB2_HIRDM porthlpmc, 32, RANGE,  1,  0
     319#define XHCI_PORT_USB2_L1TO  porthlpmc, 32, RANGE,  9,  2
     320#define XHCI_PORT_USB2_BESLD porthlpmc, 32, RANGE, 13, 10
    321321
    322322/**
  • uspace/drv/bus/usb/xhci/rh.c

    r37b13175 r9b56e528  
    5252
    5353/* This mask only lists registers, which imply port change. */
    54 static const uint32_t port_change_mask =
     54static const uint32_t port_events_mask =
    5555        XHCI_REG_MASK(XHCI_PORT_CSC) |
    5656        XHCI_REG_MASK(XHCI_PORT_PEC) |
     
    162162        int err;
    163163        assert(rh);
    164 
    165164        assert(rh->devices_by_port[port_id - 1] == NULL);
     165
     166        if (!XHCI_REG_RD(&rh->hc->op_regs->portrs[port_id - 1], XHCI_PORT_PED)) {
     167                usb_log_error("Cannot setup RH device: port is disabled.");
     168                return EIO;
     169        }
    166170
    167171        device_t *dev = hcd_ddf_fun_create(&rh->hc->base);
     
    322326        xhci_port_regs_t * const regs = &rh->hc->op_regs->portrs[port_id - 1];
    323327
    324         uint32_t events = XHCI_REG_RD_FIELD(&regs->portsc, 32) & port_change_mask;
     328        uint32_t events = XHCI_REG_RD_FIELD(&regs->portsc, 32) & port_events_mask;
    325329
    326330        while (events) {
    327                 XHCI_REG_SET_FIELD(&regs->portsc, events, 32);
     331                /*
     332                 * The PED bit in xHCI has RW1C semantics, which means that
     333                 * writing 1 to it will disable the port. Which means all
     334                 * standard mechanisms of register handling fails here.
     335                 */
     336                uint32_t portsc = XHCI_REG_RD_FIELD(&regs->portsc, 32);
     337                portsc &= ~(port_events_mask | XHCI_REG_MASK(XHCI_PORT_PED)); // Clear events + PED
     338                portsc |= events; // Add back events to assert them
     339                XHCI_REG_WR_FIELD(&regs->portsc, portsc, 32);
    328340
    329341                if (events & XHCI_REG_MASK(XHCI_PORT_CSC)) {
     
    346358               
    347359                /* Make sure that PSCEG is 0 before exiting the loop. */
    348                 events = XHCI_REG_RD_FIELD(&regs->portsc, 32) & port_change_mask;
     360                events = XHCI_REG_RD_FIELD(&regs->portsc, 32) & port_events_mask;
    349361        }
    350362
Note: See TracChangeset for help on using the changeset viewer.