Changeset 47e9494 in mainline


Ignore:
Timestamp:
2018-01-16T18:02:46Z (6 years ago)
Author:
Salmelu <salmelu@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
eeca8a6
Parents:
7d1dd2b
Message:

xhci: stub for streams support

Location:
uspace
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/Makefile

    r7d1dd2b r47e9494  
    4343        rh.c \
    4444        scratchpad.c \
     45        streams.c \
    4546        transfers.c \
    4647        trb_ring.c
  • uspace/drv/bus/usb/xhci/endpoint.c

    r7d1dd2b r47e9494  
    4444#include "commands.h"
    4545#include "endpoint.h"
     46#include "streams.h"
    4647
    4748static int alloc_transfer_ds(xhci_endpoint_t *);
     
    131132 * @return EP_TYPE_[CONTROL|ISOCH|BULK|INTERRUPT]_[IN|OUT]
    132133 */
    133 static int xhci_endpoint_type(xhci_endpoint_t *ep)
     134int xhci_endpoint_type(xhci_endpoint_t *ep)
    134135{
    135136        const bool in = ep->base.direction == USB_DIRECTION_IN;
     
    153154
    154155        return EP_TYPE_INVALID;
    155 }
    156 
    157 /**
    158  * Test whether an XHCI endpoint uses streams.
    159  * @param[in] xhci_ep XHCI endpoint to query.
    160  *
    161  * @return True if the endpoint uses streams.
    162  */
    163 static bool endpoint_using_streams(xhci_endpoint_t *xhci_ep)
    164 {
    165         return xhci_ep->primary_stream_ctx_array != NULL;
    166 }
    167 
    168 // static bool primary_stream_ctx_has_secondary_array(xhci_stream_ctx_t *primary_ctx) {
    169 //      /* Section 6.2.4.1, SCT values */
    170 //      return XHCI_STREAM_SCT(*primary_ctx) >= 2;
    171 // }
    172 //
    173 // static size_t secondary_stream_ctx_array_size(xhci_stream_ctx_t *primary_ctx) {
    174 //      if (XHCI_STREAM_SCT(*primary_ctx) < 2) return 0;
    175 //      return 2 << XHCI_STREAM_SCT(*primary_ctx);
    176 // }
    177 
    178 /** Initialize primary streams of XHCI bulk endpoint.
    179  * @param[in] hc Host controller of the endpoint.
    180  * @param[in] xhci_epi XHCI bulk endpoint to use.
    181  * @param[in] count Number of primary streams to initialize.
    182  */
    183 static void initialize_primary_streams(xhci_hc_t *hc, xhci_endpoint_t *xhci_ep, unsigned count) {
    184         for (size_t index = 0; index < count; ++index) {
    185                 xhci_stream_ctx_t *ctx = &xhci_ep->primary_stream_ctx_array[index];
    186                 xhci_trb_ring_t *ring = &xhci_ep->primary_stream_rings[index];
    187 
    188                 /* Init and register TRB ring for every primary stream */
    189                 xhci_trb_ring_init(ring); // FIXME: Not checking error code?
    190                 XHCI_STREAM_DEQ_PTR_SET(*ctx, ring->dequeue);
    191 
    192                 /* Set to linear stream array */
    193                 XHCI_STREAM_SCT_SET(*ctx, 1);
    194         }
    195 }
    196 
    197 /** Configure XHCI bulk endpoint's stream context.
    198  * @param[in] xhci_ep Associated XHCI bulk endpoint.
    199  * @param[in] ctx Endpoint context to configure.
    200  * @param[in] pstreams The value of MaxPStreams.
    201  */
    202 static void setup_stream_context(xhci_endpoint_t *xhci_ep, xhci_ep_ctx_t *ctx, unsigned pstreams) {
    203         XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(xhci_ep));
    204         XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, xhci_ep->base.max_packet_size);
    205         XHCI_EP_MAX_BURST_SIZE_SET(*ctx, xhci_ep->max_burst - 1);
    206         XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
    207 
    208         XHCI_EP_MAX_P_STREAMS_SET(*ctx, pstreams);
    209         XHCI_EP_TR_DPTR_SET(*ctx, xhci_ep->primary_stream_ctx_dma.phys);
    210         // TODO: set HID?
    211         XHCI_EP_LSA_SET(*ctx, 1);
    212 }
    213 
    214 /** TODO document this
    215  */
    216 int xhci_endpoint_request_streams(xhci_hc_t *hc, xhci_device_t *dev, xhci_endpoint_t *xhci_ep, unsigned count) {
    217         if (xhci_ep->base.transfer_type != USB_TRANSFER_BULK
    218                 || dev->base.speed != USB_SPEED_SUPER) {
    219                 usb_log_error("Streams are only supported by superspeed bulk endpoints.");
    220                 return EINVAL;
    221         }
    222 
    223         if (xhci_ep->max_streams == 1) {
    224                 usb_log_error("Streams are not supported by endpoint " XHCI_EP_FMT, XHCI_EP_ARGS(*xhci_ep));
    225                 return EINVAL;
    226         }
    227 
    228         uint8_t max_psa_size = 2 << XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_PSA_SIZE);
    229         if (count > max_psa_size) {
    230                 // FIXME: We don't support secondary stream arrays yet, so we just give up for this
    231                 return ENOTSUP;
    232         }
    233 
    234         if (count > xhci_ep->max_streams) {
    235                 usb_log_error("Endpoint " XHCI_EP_FMT " supports only %" PRIu32 " streams.",
    236                         XHCI_EP_ARGS(*xhci_ep), xhci_ep->max_streams);
    237                 return EINVAL;
    238         }
    239 
    240         if (count <= 1024) {
    241                 usb_log_debug2("Allocating primary stream context array of size %u for endpoint " XHCI_EP_FMT,
    242                         count, XHCI_EP_ARGS(*xhci_ep));
    243                 if ((dma_buffer_alloc(&xhci_ep->primary_stream_ctx_dma, count * sizeof(xhci_stream_ctx_t))))
    244                         return ENOMEM;
    245                 xhci_ep->primary_stream_ctx_array = xhci_ep->primary_stream_ctx_dma.virt;
    246 
    247                 xhci_ep->primary_stream_rings = calloc(count, sizeof(xhci_trb_ring_t));
    248                 if (!xhci_ep->primary_stream_rings) {
    249                         dma_buffer_free(&xhci_ep->primary_stream_ctx_dma);
    250                         return ENOMEM;
    251                 }
    252 
    253                 // FIXME: count should be rounded to nearest power of 2 for xHC, workaround for now
    254                 count = 1024;
    255                 // FIXME: pstreams are "log2(count) - 1"
    256                 const size_t pstreams = 9;
    257                 xhci_ep->primary_stream_ctx_array_size = count;
    258 
    259                 memset(xhci_ep->primary_stream_ctx_array, 0, count * sizeof(xhci_stream_ctx_t));
    260                 initialize_primary_streams(hc, xhci_ep, count);
    261 
    262                 xhci_ep_ctx_t ep_ctx;
    263                 setup_stream_context(xhci_ep, &ep_ctx, pstreams);
    264                 return hc_add_endpoint(hc, dev->slot_id, xhci_endpoint_index(xhci_ep), &ep_ctx);
    265         }
    266         // FIXME: Complex stuff not supported yet
    267         return ENOTSUP;
    268156}
    269157
     
    300188static void free_transfer_ds(xhci_endpoint_t *xhci_ep)
    301189{
    302         if (endpoint_using_streams(xhci_ep)) {
    303                 usb_log_debug2("Freeing primary stream context array of endpoint " XHCI_EP_FMT, XHCI_EP_ARGS(*xhci_ep));
    304 
    305                 // maybe check if LSA, then skip?
    306                 // for (size_t index = 0; index < primary_stream_ctx_array_size(xhci_ep); ++index) {
    307                 //      xhci_stream_ctx_t *primary_ctx = xhci_ep->primary_stream_ctx_array + index;
    308                 //      if (primary_stream_ctx_has_secondary_array(primary_ctx)) {
    309                 //              // uintptr_t phys = XHCI_STREAM_DEQ_PTR(*primary_ctx);
    310                 //              /* size_t size = */ secondary_stream_ctx_array_size(primary_ctx);
    311                 //              // TODO: somehow map the address to virtual and free the secondary array
    312                 //      }
    313                 // }
    314                 for (size_t index = 0; index < xhci_ep->primary_stream_ctx_array_size; ++index) {
    315                         // FIXME: Get the trb ring associated with stream [index] and fini it
    316                 }
    317                 dma_buffer_free(&xhci_ep->primary_stream_ctx_dma);
     190        if (xhci_ep->primary_stream_data_size) {
     191                xhci_stream_free_ds(xhci_ep);
    318192        } else {
    319193                usb_log_debug2("Freeing main transfer ring of endpoint " XHCI_EP_FMT, XHCI_EP_ARGS(*xhci_ep));
    320 
    321194                xhci_trb_ring_fini(&xhci_ep->ring);
    322195        }
  • uspace/drv/bus/usb/xhci/endpoint.h

    r7d1dd2b r47e9494  
    5151typedef struct xhci_device xhci_device_t;
    5252typedef struct xhci_endpoint xhci_endpoint_t;
     53typedef struct xhci_stream_data xhci_stream_data_t;
    5354typedef struct xhci_bus xhci_bus_t;
    5455
     
    7172        xhci_trb_ring_t ring;
    7273
    73         /** Primary stream context array (or NULL if endpoint doesn't use streams). */
     74        /** Primary stream context data array (or NULL if endpoint doesn't use streams). */
     75        xhci_stream_data_t *primary_stream_data_array;
     76
     77        /** Primary stream context array - allocated for xHC hardware. */
    7478        xhci_stream_ctx_t *primary_stream_ctx_array;
    7579        dma_buffer_t primary_stream_ctx_dma;
    7680
    77         /** Primary stream ring array (or NULL if endpoint doesn't use streams). */
    78         xhci_trb_ring_t *primary_stream_rings;
    79 
    80         /** Size of the allocated primary stream context array (and ring array). */
    81         uint16_t primary_stream_ctx_array_size;
     81        /** Size of the allocated primary stream data array (and context array). */
     82        uint16_t primary_stream_data_size;
    8283
    8384        /* Maximum number of primary streams (0 - 2^16). */
     
    129130#define XHCI_DEV_ARGS(dev)               ddf_fun_get_name((dev).base.fun), (dev).slot_id
    130131
     132int xhci_endpoint_type(xhci_endpoint_t *ep);
     133
    131134int xhci_endpoint_init(xhci_endpoint_t *, device_t *, const usb_endpoint_descriptors_t *);
    132135void xhci_endpoint_fini(xhci_endpoint_t *);
    133 
    134 int xhci_endpoint_request_streams(xhci_hc_t *, xhci_device_t *, xhci_endpoint_t *, unsigned);
    135136
    136137uint8_t xhci_endpoint_dci(xhci_endpoint_t *);
  • uspace/drv/bus/usb/xhci/hw_struct/context.h

    r7d1dd2b r47e9494  
    167167#define XHCI_STREAM_DCS(ctx)       XHCI_QWORD_EXTRACT((ctx).data[0],  0, 0)
    168168#define XHCI_STREAM_SCT(ctx)       XHCI_QWORD_EXTRACT((ctx).data[0],  3, 1)
    169 #define XHCI_STREAM_DEQ_PTR(ctx)   XHCI_QWORD_EXTRACT((ctx).data[0], 63, 4)
     169#define XHCI_STREAM_DEQ_PTR(ctx)   (XHCI_QWORD_EXTRACT((ctx).data[0], 63, 4) << 4)
    170170#define XHCI_STREAM_EDTLA(ctx)     XHCI_QWORD_EXTRACT((ctx).data[1], 24, 0)
    171171
  • uspace/drv/bus/usb/xhci/hw_struct/trb.h

    r7d1dd2b r47e9494  
    102102#define TRB_LINK_TC(trb)        XHCI_DWORD_EXTRACT((trb).control, 1, 1)
    103103#define TRB_IOC(trb)            XHCI_DWORD_EXTRACT((trb).control, 5, 5)
     104#define TRB_EVENT_DATA(trb)             XHCI_DWORD_EXTRACT((trb).control, 2, 2)
    104105
    105106#define TRB_TRANSFER_LENGTH(trb)        XHCI_DWORD_EXTRACT((trb).status, 23, 0)
  • uspace/drv/bus/usb/xhci/transfers.c

    r7d1dd2b r47e9494  
    3939#include "hc.h"
    4040#include "hw_struct/trb.h"
     41#include "streams.h"
    4142#include "transfers.h"
    4243#include "trb_ring.h"
     
    121122static xhci_trb_ring_t *get_ring(xhci_hc_t *hc, xhci_transfer_t *transfer)
    122123{
    123         return &xhci_endpoint_get(transfer->batch.ep)->ring;
     124        xhci_endpoint_t *ep = xhci_endpoint_get(transfer->batch.ep);
     125        if (ep->primary_stream_data_size == 0) return &ep->ring;
     126        uint32_t stream_id = transfer->batch.target.stream;
     127
     128        xhci_stream_data_t *stream_data = xhci_get_stream_ctx_data(ep, stream_id);
     129        if (stream_data == NULL) {
     130                usb_log_warning("No transfer ring was found for stream %u.", stream_id);
     131                return NULL;
     132        }
     133
     134        return &stream_data->ring;
    124135}
    125136
     
    202213        // data size (sent for OUT, or buffer size)
    203214        TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    204         // FIXME: TD size 4.11.2.4
    205         TRB_CTRL_SET_TD_SIZE(trb, 1);
    206 
    207         // we want an interrupt after this td is done
    208         TRB_CTRL_SET_IOC(trb, 1);
    209 
    210         TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
    211 
    212         xhci_trb_ring_t* ring = get_ring(hc, transfer);
    213 
    214         return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     215
     216        /* The stream-enabled endpoints need to chain ED trb */
     217        xhci_endpoint_t *ep = xhci_endpoint_get(transfer->batch.ep);
     218        if (!ep->primary_stream_data_size) {
     219                // FIXME: TD size 4.11.2.4
     220                TRB_CTRL_SET_TD_SIZE(trb, 1);
     221
     222                // we want an interrupt after this td is done
     223                TRB_CTRL_SET_IOC(trb, 1);
     224                TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
     225
     226                xhci_trb_ring_t* ring = get_ring(hc, transfer);
     227                return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     228        }
     229        else {
     230                TRB_CTRL_SET_TD_SIZE(trb, 2);
     231                TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
     232                TRB_CTRL_SET_CHAIN(trb, 1);
     233                TRB_CTRL_SET_ENT(trb, 1);
     234
     235                xhci_trb_ring_t* ring = get_ring(hc, transfer);
     236                int err = xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     237
     238                if (err) {
     239                        return err;
     240                }
     241
     242                xhci_trb_clean(&trb);
     243                trb.parameter = host2xhci(64, (uintptr_t) transfer);
     244                TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_EVENT_DATA);
     245                TRB_CTRL_SET_IOC(trb, 1);
     246
     247                return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     248        }
    215249}
    216250
     
    267301        xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
    268302
    269         xhci_trb_ring_update_dequeue(&ep->ring, addr);
    270 
    271         if (ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS) {
    272                 isoch_handle_transfer_event(hc, ep, trb);
    273                 endpoint_del_ref(&ep->base);
    274                 return EOK;
    275         }
    276 
    277         fibril_mutex_lock(&ep->base.guard);
    278         usb_transfer_batch_t *batch = ep->base.active_batch;
    279         if (!batch) {
     303        usb_transfer_batch_t *batch;
     304        xhci_transfer_t *transfer;
     305
     306        if (TRB_EVENT_DATA(*trb)) {
     307                assert(ep->base.transfer_type != USB_TRANSFER_ISOCHRONOUS);
     308                /* We are received transfer pointer instead - work with that */
     309                transfer = (xhci_transfer_t *) addr;
     310                xhci_trb_ring_t * ring = get_ring(hc, transfer);
     311                xhci_trb_ring_update_dequeue(ring, transfer->interrupt_trb_phys);
     312                batch = &transfer->batch;
     313
     314                fibril_mutex_lock(&ep->base.guard);
     315                endpoint_deactivate_locked(&ep->base);
    280316                fibril_mutex_unlock(&ep->base.guard);
    281                 endpoint_del_ref(&ep->base);
    282                 return ENOENT;
     317        }
     318        else {
     319                xhci_trb_ring_update_dequeue(&ep->ring, addr);
     320
     321                if (ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS) {
     322                        isoch_handle_transfer_event(hc, ep, trb);
     323                        endpoint_del_ref(&ep->base);
     324                        return EOK;
     325                }
     326
     327                fibril_mutex_lock(&ep->base.guard);
     328                batch = ep->base.active_batch;
     329                if (!batch) {
     330                        fibril_mutex_unlock(&ep->base.guard);
     331                        endpoint_del_ref(&ep->base);
     332                        return ENOENT;
     333                }
     334
     335                transfer = xhci_transfer_from_batch(batch);
     336
     337                endpoint_deactivate_locked(&ep->base);
     338                fibril_mutex_unlock(&ep->base.guard);
    283339        }
    284340
     
    296352        }
    297353
    298         endpoint_deactivate_locked(&ep->base);
    299         fibril_mutex_unlock(&ep->base.guard);
    300 
    301         xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
    302 
    303354        if (batch->dir == USB_DIRECTION_IN) {
    304355                assert(batch->buffer);
     
    370421
    371422        const uint8_t slot_id = xhci_dev->slot_id;
    372         const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
     423        /* EP Doorbells start at 1 */
     424        const uint8_t target = (xhci_endpoint_index(xhci_ep) + 1) | (batch->target.stream << 16);
    373425        hc_ring_doorbell(hc, slot_id, target);
    374426        return EOK;
  • uspace/lib/drv/include/usb_iface.h

    r7d1dd2b r47e9494  
    8989                usb_address_t address;
    9090                usb_endpoint_t endpoint;
     91                uint32_t stream;
    9192        } __attribute__((packed));
    92         uint32_t packed;
     93        uint64_t packed;
    9394} usb_target_t;
    9495
Note: See TracChangeset for help on using the changeset viewer.