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

Changeset d2c3dcd in mainline


Ignore:
Timestamp:
2018-01-15T20:48:54Z (2 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
master
Children:
c4e84ed6
Parents:
309d9865
git-author:
Ondřej Hlavatý <aearsis@…> (2018-01-15 20:45:08)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-01-15 20:48:54)
Message:

xhci commands: wait if the ring is full

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

Legend:

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

    r309d9865 rd2c3dcd  
    168168}
    169169
     170static void cr_set_state(xhci_cmd_ring_t *cr, xhci_cr_state_t state)
     171{
     172        assert(fibril_mutex_is_locked(&cr->guard));
     173
     174        cr->state = state;
     175        if (state == XHCI_CR_STATE_OPEN
     176            || state == XHCI_CR_STATE_CLOSED)
     177                fibril_condvar_broadcast(&cr->state_cv);
     178}
     179
     180static int wait_for_ring_open(xhci_cmd_ring_t *cr)
     181{
     182        assert(fibril_mutex_is_locked(&cr->guard));
     183
     184        while (true) {
     185                switch (cr->state) {
     186                case XHCI_CR_STATE_CHANGING:
     187                case XHCI_CR_STATE_FULL:
     188                        fibril_condvar_wait(&cr->state_cv, &cr->guard);
     189                        break;
     190                case XHCI_CR_STATE_OPEN:
     191                        return EOK;
     192                case XHCI_CR_STATE_CLOSED:
     193                        return ENAK;
     194                }
     195        }
     196}
     197
    170198/**
    171199 * Enqueue a command on the TRB ring. Ring the doorbell to initiate processing.
     
    179207        fibril_mutex_lock(&cr->guard);
    180208
    181         while (cr->state == XHCI_CR_STATE_CHANGING)
    182                 fibril_condvar_wait(&cr->state_cv, &cr->guard);
    183 
    184         if (cr->state != XHCI_CR_STATE_OPEN) {
     209        if (wait_for_ring_open(cr)) {
    185210                fibril_mutex_unlock(&cr->guard);
    186211                return ENAK;
     
    191216        list_append(&cmd->_header.link, &cr->cmd_list);
    192217
    193         xhci_trb_ring_enqueue(&cr->trb_ring, &cmd->_header.trb, &cmd->_header.trb_phys);
    194         hc_ring_doorbell(hc, 0, 0);
     218        int err = EOK;
     219        while (err == EOK) {
     220                err = xhci_trb_ring_enqueue(&cr->trb_ring,
     221                    &cmd->_header.trb, &cmd->_header.trb_phys);
     222                if (err != EAGAIN)
     223                        break;
     224
     225                cr_set_state(cr, XHCI_CR_STATE_FULL);
     226                err = wait_for_ring_open(cr);
     227        }
     228
     229        if (err == EOK)
     230                hc_ring_doorbell(hc, 0, 0);
    195231
    196232        fibril_mutex_unlock(&cr->guard);
    197233
    198         return EOK;
     234        return err;
    199235}
    200236
     
    210246
    211247        // Prevent others from starting CR again.
    212         cr->state = XHCI_CR_STATE_CLOSED;
    213         fibril_condvar_broadcast(&cr->state_cv);
     248        cr_set_state(cr, XHCI_CR_STATE_CLOSED);
    214249
    215250        XHCI_REG_SET(hc->op_regs, XHCI_OP_CS, 1);
     
    299334
    300335        int code = TRB_GET_CODE(*trb);
    301         const uint64_t phys = TRB_GET_PHYS(*trb);
    302 
    303         xhci_trb_ring_update_dequeue(&cr->trb_ring, phys);
    304336
    305337        if (code == XHCI_TRBC_COMMAND_RING_STOPPED) {
     
    316348                return EOK;
    317349        }
     350
     351        const uint64_t phys = TRB_GET_PHYS(*trb);
     352        xhci_trb_ring_update_dequeue(&cr->trb_ring, phys);
     353
     354        if (cr->state == XHCI_CR_STATE_FULL)
     355                cr_set_state(cr, XHCI_CR_STATE_OPEN);
    318356
    319357        xhci_cmd_t *command = find_command(hc, phys);
     
    592630        fibril_mutex_lock(&cr->guard);
    593631
    594         if (cr->state != XHCI_CR_STATE_OPEN) {
    595                 // The CR is either stopped, or different fibril is already
    596                 // restarting it.
    597                 usb_log_debug2("Command ring already being stopped.");
     632        if (cr->state == XHCI_CR_STATE_CLOSED) {
     633                fibril_mutex_unlock(&cr->guard);
     634                return ENAK;
     635        }
     636
     637        if (cr->state == XHCI_CR_STATE_CHANGING) {
    598638                fibril_mutex_unlock(&cr->guard);
    599639                return EOK;
     
    602642        usb_log_error("Timeout while waiting for command: aborting current command.");
    603643
    604         cr->state = XHCI_CR_STATE_CHANGING;
    605         fibril_condvar_broadcast(&cr->state_cv);
     644        cr_set_state(cr, XHCI_CR_STATE_CHANGING);
    606645
    607646        abort_command_ring(hc);
     
    616655                usb_log_error("Command didn't abort.");
    617656
    618                 cr->state = XHCI_CR_STATE_CLOSED;
    619                 fibril_condvar_broadcast(&cr->state_cv);
     657                cr_set_state(cr, XHCI_CR_STATE_CLOSED);
    620658
    621659                // TODO: Reset HC completely.
     
    626664        }
    627665
     666        cr_set_state(cr, XHCI_CR_STATE_OPEN);
     667
     668        fibril_mutex_unlock(&cr->guard);
     669
    628670        usb_log_error("Command ring stopped. Starting again.");
    629671        hc_ring_doorbell(hc, 0, 0);
    630672
    631         cr->state = XHCI_CR_STATE_OPEN;
    632         fibril_condvar_broadcast(&cr->state_cv);
    633 
    634         fibril_mutex_unlock(&cr->guard);
    635673        return EOK;
    636674}
  • uspace/drv/bus/usb/xhci/commands.h

    r309d9865 rd2c3dcd  
    7373        XHCI_CR_STATE_OPEN,             /**< Commands are enqueued normally. */
    7474        XHCI_CR_STATE_CHANGING,         /**< Commands wait until state changes. */
    75 } xhci_cr_state;
     75        XHCI_CR_STATE_FULL,             /**< Commands wait until something completes. */
     76} xhci_cr_state_t;
    7677
    7778typedef struct xhci_command_ring {
     
    8182        list_t cmd_list;
    8283
    83         xhci_cr_state state;            /**< Whether commands are allowed to be
     84        xhci_cr_state_t state;          /**< Whether commands are allowed to be
    8485                                             added. */
    8586        fibril_condvar_t state_cv;      /**< For waiting on CR state change. */
Note: See TracChangeset for help on using the changeset viewer.