Changeset 9b56e528 in mainline for uspace/drv/bus/usb/xhci/rh.c


Ignore:
Timestamp:
2018-01-13T15:13:44Z (6 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.