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

Changeset 889146e in mainline


Ignore:
Timestamp:
2017-12-10T21:49:12Z (4 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master
Children:
53db806
Parents:
6ef407b
git-author:
Ondřej Hlavatý <aearsis@…> (2017-12-10 21:43:47)
git-committer:
Ondřej Hlavatý <aearsis@…> (2017-12-10 21:49:12)
Message:

xhci: commands shall not just timeout

Previous behavior was breaking semantic: if a command was successful,
but just took too long to complete, we returned an error, and the caller
had no way to know if the command's effect has taken place.

This commit implements command aborting. The wait_for_command now cannot
just timeout - instead it aborts currently running (probably blocked)
command, and then gets back to waiting. So now, if command_sync returns
an error, it means the command was really unsuccessful.

If aborting the command takes too long, we should reset the whole HC.
This is not yet implemented.

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

Legend:

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

    r6ef407b r889146e  
    6464/* Control functions */
    6565
     66static xhci_cmd_ring_t *get_cmd_ring(xhci_hc_t *hc)
     67{
     68        assert(hc);
     69        return &hc->cr;
     70}
     71
    6672int xhci_init_commands(xhci_hc_t *hc)
    6773{
    68         assert(hc);
    69 
    70         list_initialize(&hc->commands);
    71 
    72         fibril_mutex_initialize(&hc->commands_mtx);
     74        xhci_cmd_ring_t *cr = get_cmd_ring(hc);
     75        int err;
     76
     77        if ((err = xhci_trb_ring_init(&cr->trb_ring)))
     78                return err;
     79
     80        fibril_mutex_initialize(&cr->guard);
     81        fibril_condvar_initialize(&cr->state_cv);
     82        fibril_condvar_initialize(&cr->stopped_cv);
     83
     84        list_initialize(&cr->cmd_list);
     85
     86        cr->state = XHCI_CR_STATE_OPEN;
    7387
    7488        return EOK;
     
    7791void xhci_fini_commands(xhci_hc_t *hc)
    7892{
    79         // Note: Untested.
     93        xhci_stop_command_ring(hc);
    8094        assert(hc);
    8195}
     
    91105
    92106        cmd->_header.cmd = type;
    93         cmd->_header.timeout = XHCI_DEFAULT_TIMEOUT;
    94107}
    95108
     
    106119}
    107120
    108 static inline xhci_cmd_t *get_command(xhci_hc_t *hc, uint64_t phys)
    109 {
    110         fibril_mutex_lock(&hc->commands_mtx);
    111 
    112         link_t *cmd_link = list_first(&hc->commands);
     121/** Call with guard locked. */
     122static inline xhci_cmd_t *find_command(xhci_hc_t *hc, uint64_t phys)
     123{
     124        xhci_cmd_ring_t *cr = get_cmd_ring(hc);
     125        assert(fibril_mutex_is_locked(&cr->guard));
     126
     127        link_t *cmd_link = list_first(&cr->cmd_list);
    113128
    114129        while (cmd_link != NULL) {
     
    118133                        break;
    119134
    120                 cmd_link = list_next(cmd_link, &hc->commands);
    121         }
    122 
    123         if (cmd_link != NULL) {
    124                 list_remove(cmd_link);
    125                 fibril_mutex_unlock(&hc->commands_mtx);
    126 
    127                 return list_get_instance(cmd_link, xhci_cmd_t, _header.link);
    128         }
    129 
    130         fibril_mutex_unlock(&hc->commands_mtx);
    131         return NULL;
     135                cmd_link = list_next(cmd_link, &cr->cmd_list);
     136        }
     137
     138        return cmd_link ? list_get_instance(cmd_link, xhci_cmd_t, _header.link)
     139                : NULL;
    132140}
    133141
    134142static inline int enqueue_command(xhci_hc_t *hc, xhci_cmd_t *cmd, unsigned doorbell, unsigned target)
    135143{
    136         assert(hc);
    137         assert(cmd);
    138 
    139         fibril_mutex_lock(&hc->commands_mtx);
    140         list_append(&cmd->_header.link, &hc->commands);
    141         fibril_mutex_unlock(&hc->commands_mtx);
    142 
    143         xhci_trb_ring_enqueue(&hc->command_ring, &cmd->_header.trb, &cmd->_header.trb_phys);
    144         hc_ring_doorbell(hc, doorbell, target);
    145 
    146         usb_log_debug2("HC(%p): Sent command:", hc);
     144        xhci_cmd_ring_t *cr = get_cmd_ring(hc);
     145        assert(cmd);
     146
     147        fibril_mutex_lock(&cr->guard);
     148
     149        while (cr->state == XHCI_CR_STATE_CHANGING)
     150                fibril_condvar_wait(&cr->state_cv, &cr->guard);
     151
     152        if (cr->state != XHCI_CR_STATE_OPEN) {
     153                fibril_mutex_unlock(&cr->guard);
     154                return ENAK;
     155        }
     156
     157        usb_log_debug2("HC(%p): Sending command:", hc);
    147158        xhci_dump_trb(&cmd->_header.trb);
    148159
     160        list_append(&cmd->_header.link, &cr->cmd_list);
     161
     162        xhci_trb_ring_enqueue(&cr->trb_ring, &cmd->_header.trb, &cmd->_header.trb_phys);
     163        hc_ring_doorbell(hc, 0, 0);
     164
     165        fibril_mutex_unlock(&cr->guard);
     166
    149167        return EOK;
    150168}
     
    152170void xhci_stop_command_ring(xhci_hc_t *hc)
    153171{
    154         assert(hc);
     172        xhci_cmd_ring_t *cr = get_cmd_ring(hc);
     173
     174        fibril_mutex_lock(&cr->guard);
     175
     176        // Prevent others from starting CR again.
     177        cr->state = XHCI_CR_STATE_CLOSED;
     178        fibril_condvar_broadcast(&cr->state_cv);
    155179
    156180        XHCI_REG_SET(hc->op_regs, XHCI_OP_CS, 1);
    157 
    158         /**
    159          * Note: There is a bug in qemu that checks CS only when CRCR_HI
    160          *       is written, this (and the read/write in abort) ensures
    161          *       the command rings stops.
    162          */
    163         XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, XHCI_REG_RD(hc->op_regs, XHCI_OP_CRCR_HI));
    164 }
    165 
    166 void xhci_abort_command_ring(xhci_hc_t *hc)
    167 {
    168         assert(hc);
    169 
     181        XHCI_REG_SET(hc->op_regs, XHCI_OP_CRCR_HI, 0); // Some systems (incl. QEMU) require 64-bit write
     182
     183        while (XHCI_REG_RD(hc->op_regs, XHCI_OP_CRR))
     184                fibril_condvar_wait(&cr->stopped_cv, &cr->guard);
     185
     186        fibril_mutex_unlock(&cr->guard);
     187}
     188
     189static void abort_command_ring(xhci_hc_t *hc)
     190{
    170191        XHCI_REG_WR(hc->op_regs, XHCI_OP_CA, 1);
    171         XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, XHCI_REG_RD(hc->op_regs, XHCI_OP_CRCR_HI));
    172 }
    173 
    174 void xhci_start_command_ring(xhci_hc_t *hc)
    175 {
    176         assert(hc);
    177 
    178         XHCI_REG_WR(hc->op_regs, XHCI_OP_CRR, 1);
    179         hc_ring_doorbell(hc, 0, 0);
     192        XHCI_REG_SET(hc->op_regs, XHCI_OP_CRCR_HI, 0); // Some systems (incl. QEMU) require 64-bit write
    180193}
    181194
     
    233246int xhci_handle_command_completion(xhci_hc_t *hc, xhci_trb_t *trb)
    234247{
    235         // TODO: Update dequeue ptrs.
    236         assert(hc);
     248        xhci_cmd_ring_t *cr = get_cmd_ring(hc);
    237249        assert(trb);
    238250
    239251        usb_log_debug2("HC(%p) Command completed.", hc);
    240252
    241         int code;
    242         uint64_t phys;
    243         xhci_cmd_t *command;
    244 
    245         code = TRB_GET_CODE(*trb);
    246         phys = TRB_GET_PHYS(*trb);;
    247         command = get_command(hc, phys);
     253        fibril_mutex_lock(&cr->guard);
     254
     255        int code = TRB_GET_CODE(*trb);
     256        const uint64_t phys = TRB_GET_PHYS(*trb);
     257
     258        xhci_trb_ring_update_dequeue(&cr->trb_ring, phys);
     259
     260        if (code == XHCI_TRBC_COMMAND_RING_STOPPED) {
     261                /* This can either mean that the ring is being stopped, or
     262                 * a command was aborted. In either way, wake threads waiting
     263                 * on stopped_cv.
     264                 *
     265                 * Note that we need to hold mutex, because we must be sure the
     266                 * requesting thread is waiting inside the CV.
     267                 */
     268                fibril_condvar_broadcast(&cr->stopped_cv);
     269                fibril_mutex_unlock(&cr->guard);
     270                return EOK;
     271        }
     272
     273        xhci_cmd_t *command = find_command(hc, phys);
    248274        if (command == NULL) {
    249                 // TODO: STOP & ABORT may not have command structs in the list!
    250                 usb_log_warning("No command struct for this completion event found.");
     275                usb_log_error("No command struct for this completion event found.");
    251276
    252277                if (code != XHCI_TRBC_SUCCESS)
     
    255280                return EOK;
    256281        }
     282
     283        list_remove(&command->_header.link);
    257284
    258285        /* Semantics of NO_OP_CMD is that success is marked as a TRB error. */
     
    272299        switch (TRB_TYPE(command->_header.trb)) {
    273300        case XHCI_TRB_TYPE_NO_OP_CMD:
    274                 break;
    275301        case XHCI_TRB_TYPE_ENABLE_SLOT_CMD:
    276                 break;
    277302        case XHCI_TRB_TYPE_DISABLE_SLOT_CMD:
    278                 break;
    279303        case XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD:
    280                 break;
    281304        case XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD:
    282                 break;
    283305        case XHCI_TRB_TYPE_EVALUATE_CONTEXT_CMD:
    284                 break;
    285306        case XHCI_TRB_TYPE_RESET_ENDPOINT_CMD:
    286307                break;
     
    294315        default:
    295316                usb_log_debug2("Unsupported command trb: %s", xhci_trb_str_type(TRB_TYPE(command->_header.trb)));
    296 
    297                 command->_header.completed = true;
    298317                return ENAK;
    299318        }
     319
     320        fibril_mutex_unlock(&cr->guard);
    300321
    301322        fibril_mutex_lock(&command->_header.completed_mtx);
     
    533554};
    534555
    535 static int wait_for_cmd_completion(xhci_cmd_t *cmd)
     556static int try_abort_current_command(xhci_hc_t *hc)
     557{
     558        xhci_cmd_ring_t *cr = get_cmd_ring(hc);
     559
     560        fibril_mutex_lock(&cr->guard);
     561
     562        if (cr->state != XHCI_CR_STATE_OPEN) {
     563                // The CR is either stopped, or different fibril is already
     564                // restarting it.
     565                fibril_mutex_unlock(&cr->guard);
     566                return EOK;
     567        }
     568
     569        usb_log_error("HC(%p): Timeout while waiting for command: aborting current command.", hc);
     570
     571        cr->state = XHCI_CR_STATE_CHANGING;
     572        fibril_condvar_broadcast(&cr->state_cv);
     573
     574        abort_command_ring(hc);
     575
     576        fibril_condvar_wait_timeout(&cr->stopped_cv, &cr->guard, XHCI_CR_ABORT_TIMEOUT);
     577
     578        if (XHCI_REG_RD(hc->op_regs, XHCI_OP_CRR)) {
     579                /* 4.6.1.2, implementation note
     580                 * Assume there are larger problems with HC and
     581                 * reset it.
     582                 */
     583                usb_log_error("HC(%p): Command didn't abort.", hc);
     584
     585                cr->state = XHCI_CR_STATE_CLOSED;
     586                fibril_condvar_broadcast(&cr->state_cv);
     587
     588                // TODO: Reset HC completely.
     589                // Don't forget to somehow complete all commands with error.
     590
     591                fibril_mutex_unlock(&cr->guard);
     592                return ENAK;
     593        }
     594
     595        usb_log_error("HC(%p): Command ring stopped. Starting again.", hc);
     596        hc_ring_doorbell(hc, 0, 0);
     597
     598        cr->state = XHCI_CR_STATE_OPEN;
     599        fibril_condvar_broadcast(&cr->state_cv);
     600
     601        fibril_mutex_unlock(&cr->guard);
     602        return EOK;
     603}
     604
     605static int wait_for_cmd_completion(xhci_hc_t *hc, xhci_cmd_t *cmd)
    536606{
    537607        int rv = EOK;
     
    539609        fibril_mutex_lock(&cmd->_header.completed_mtx);
    540610        while (!cmd->_header.completed) {
    541                 usb_log_debug2("Waiting for event completion: going to sleep.");
    542                 rv = fibril_condvar_wait_timeout(&cmd->_header.completed_cv, &cmd->_header.completed_mtx, cmd->_header.timeout);
    543 
    544                 usb_log_debug2("Waiting for event completion: woken: %s", str_error(rv));
    545                 if (rv == ETIMEOUT) {
    546                         break;
     611
     612                rv = fibril_condvar_wait_timeout(&cmd->_header.completed_cv, &cmd->_header.completed_mtx, XHCI_COMMAND_TIMEOUT);
     613
     614                /* The waiting timed out. Current command (not necessarily
     615                 * ours) is probably blocked.
     616                 */
     617                if (!cmd->_header.completed && rv == ETIMEOUT) {
     618                        fibril_mutex_unlock(&cmd->_header.completed_mtx);
     619
     620                        rv = try_abort_current_command(hc);
     621                        if (rv)
     622                                return rv;
     623
     624                        fibril_mutex_lock(&cmd->_header.completed_mtx);
    547625                }
    548626        }
     
    572650        }
    573651
    574         if ((err = wait_for_cmd_completion(cmd))) {
    575                 /* Timeout expired or command failed. */
     652        if ((err = wait_for_cmd_completion(hc, cmd))) {
     653                /* Command failed. */
    576654                return err;
    577655        }
  • uspace/drv/bus/usb/xhci/commands.h

    r6ef407b r889146e  
    4242#include <usb/host/dma_buffer.h>
    4343#include "hw_struct/trb.h"
     44#include "trb_ring.h"
    4445
    45 #define XHCI_DEFAULT_TIMEOUT       1000000
    46 #define XHCI_BLOCK_INDEFINITELY    0
     46#define XHCI_COMMAND_TIMEOUT       10000
     47#define XHCI_CR_ABORT_TIMEOUT       5000
    4748
    4849typedef struct xhci_hc xhci_hc_t;
     
    6869} xhci_cmd_type_t;
    6970
     71typedef enum {
     72        XHCI_CR_STATE_CLOSED,           /**< Commands are rejected with ENAK. */
     73        XHCI_CR_STATE_OPEN,             /**< Commands are enqueued normally. */
     74        XHCI_CR_STATE_CHANGING,         /**< Commands wait until state changes. */
     75} xhci_cr_state;
     76
     77typedef struct xhci_command_ring {
     78        xhci_trb_ring_t trb_ring;
     79
     80        fibril_mutex_t guard;           /**< Guard access to this structure. */
     81        list_t cmd_list;
     82
     83        xhci_cr_state state;            /**< Whether commands are allowed to be
     84                                             added. */
     85        fibril_condvar_t state_cv;      /**< For waiting on CR state change. */
     86
     87        fibril_condvar_t stopped_cv;    /**< For waiting on CR stopped event. */
     88} xhci_cmd_ring_t;
     89
    7090typedef struct xhci_command {
    7191        /** Internal fields used for bookkeeping. Need not worry about these. */
     
    7494
    7595                xhci_cmd_type_t cmd;
    76                 suseconds_t timeout;
    7796
    7897                xhci_trb_t trb;
     
    130149        fibril_condvar_initialize(&cmd._header.completed_cv);
    131150
    132         if (!cmd._header.timeout) {
    133                 cmd._header.timeout = XHCI_DEFAULT_TIMEOUT;
    134         }
    135 
    136151        /* Issue the command */
    137152        const int err = xhci_cmd_sync(hc, &cmd);
  • uspace/drv/bus/usb/xhci/hc.c

    r6ef407b r889146e  
    4444#include "hw_struct/context.h"
    4545#include "endpoint.h"
    46 #include "commands.h"
    4746#include "transfers.h"
    4847#include "trb_ring.h"
     
    204203        hc->dcbaa = hc->dcbaa_dma.virt;
    205204
    206         if ((err = xhci_trb_ring_init(&hc->command_ring)))
     205        if ((err = xhci_event_ring_init(&hc->event_ring)))
    207206                goto err_dcbaa;
    208 
    209         if ((err = xhci_event_ring_init(&hc->event_ring)))
    210                 goto err_cmd_ring;
    211207
    212208        if ((err = xhci_scratchpad_alloc(hc)))
     
    233229err_event_ring:
    234230        xhci_event_ring_fini(&hc->event_ring);
    235 err_cmd_ring:
    236         xhci_trb_ring_fini(&hc->command_ring);
    237231err_dcbaa:
    238232        hc->dcbaa = NULL;
     
    399393                return err;
    400394
     395        // FIXME: Waiting forever.
    401396        while (XHCI_REG_RD(hc->op_regs, XHCI_OP_CNR))
    402397                async_usleep(1000);
     
    407402        XHCI_REG_WR(hc->op_regs, XHCI_OP_MAX_SLOTS_EN, 0);
    408403
    409         uint64_t crptr = xhci_trb_ring_get_dequeue_ptr(&hc->command_ring);
     404        uint64_t crptr = xhci_trb_ring_get_dequeue_ptr(&hc->cr.trb_ring);
    410405        XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_LO, LOWER32(crptr) >> 6);
    411406        XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, UPPER32(crptr));
     
    578573{
    579574        xhci_bus_fini(&hc->bus);
    580         xhci_trb_ring_fini(&hc->command_ring);
    581575        xhci_event_ring_fini(&hc->event_ring);
    582576        hc_dcbaa_fini(hc);
  • uspace/drv/bus/usb/xhci/hc.h

    r6ef407b r889146e  
    4545
    4646#include "rh.h"
     47#include "commands.h"
    4748#include "bus.h"
     49
     50typedef struct xhci_command xhci_cmd_t;
    4851
    4952typedef struct xhci_hc {
     
    6164
    6265        /* Structures in allocated memory */
    63         xhci_trb_ring_t command_ring;
    6466        xhci_event_ring_t event_ring;
    6567        uint64_t *dcbaa;
     
    6769        dma_buffer_t scratchpad_array;
    6870        dma_buffer_t *scratchpad_buffers;
     71
     72        /* Command ring management */
     73        xhci_cmd_ring_t cr;
    6974
    7075        /* Root hub emulation */
     
    8186        xhci_port_speed_t speeds [16];
    8287        uint8_t speed_to_psiv [USB_SPEED_MAX];
    83 
    84         /* Command list */
    85         list_t commands;
    86         fibril_mutex_t commands_mtx;
    8788
    8889        /* TODO: Hack. Figure out a better way. */
  • uspace/drv/bus/usb/xhci/trb_ring.h

    r6ef407b r889146e  
    9191 * pointer inside the ring. Otherwise, the ring will soon show up as full.
    9292 */
    93 void xhci_trb_ring_update_dequeue(xhci_trb_ring_t *, uintptr_t);
     93static inline void xhci_trb_ring_update_dequeue(xhci_trb_ring_t *ring, uintptr_t phys) {}
    9494uintptr_t xhci_trb_ring_get_dequeue_ptr(xhci_trb_ring_t *);
    9595
Note: See TracChangeset for help on using the changeset viewer.