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

Changeset 91ca111 in mainline


Ignore:
Timestamp:
2017-06-23T11:18:50Z (3 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
master
Children:
51b2693
Parents:
e4d7363
Message:

xhci: extended capability handling

Currently, only detection of legacy support and parsing of protocol speeds is
implemented.

Location:
uspace
Files:
6 edited

Legend:

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

    re4d7363 r91ca111  
    3535
    3636#include <inttypes.h>
     37#include <byteorder.h>
    3738#include <usb/debug.h>
    3839
     
    6061 * Dumps all capability registers.
    6162 */
    62 void xhci_dump_cap_regs(xhci_cap_regs_t *cap)
     63void xhci_dump_cap_regs(const xhci_cap_regs_t *cap)
    6364{
    6465        usb_log_debug2("Capabilities:");
     
    99100}
    100101
    101 void xhci_dump_port(xhci_port_regs_t *port)
     102void xhci_dump_port(const xhci_port_regs_t *port)
    102103{
    103104        DUMP_REG(port, XHCI_PORT_CCS);
     
    124125}
    125126
    126 void xhci_dump_state(xhci_hc_t *hc)
     127void xhci_dump_state(const xhci_hc_t *hc)
    127128{
    128129        usb_log_debug2("Operational registers:");
     
    171172}
    172173
    173 void xhci_dump_ports(xhci_hc_t *hc)
     174void xhci_dump_ports(const xhci_hc_t *hc)
    174175{
    175176        const size_t num_ports = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_PORTS);
     
    230231}
    231232
    232 void xhci_dump_trb(xhci_trb_t *trb)
     233void xhci_dump_trb(const xhci_trb_t *trb)
    233234{
    234235        usb_log_debug2("TRB(%p): type %s, cycle %u", trb, xhci_trb_str_type(TRB_TYPE(*trb)), TRB_CYCLE(*trb));
     236}
     237
     238static const char *ec_ids [] = {
     239        [0] = "<empty>",
     240#define EC(t) [XHCI_EC_##t] = #t
     241        EC(USB_LEGACY),
     242        EC(SUPPORTED_PROTOCOL),
     243        EC(EXTENDED_POWER_MANAGEMENT),
     244        EC(IOV),
     245        EC(MSI),
     246        EC(LOCALMEM),
     247        EC(DEBUG),
     248        EC(MSIX),
     249#undef EC
     250        [XHCI_EC_MAX] = NULL
     251};
     252
     253const char *xhci_ec_str_id(unsigned id)
     254{
     255        static char buf [20];
     256
     257        if (id < XHCI_EC_MAX && ec_ids[id] != NULL)
     258                return ec_ids[id];
     259
     260        snprintf(buf, sizeof(buf), "<unknown (%u)>", id);
     261        return buf;
     262}
     263
     264static void xhci_dump_psi(const xhci_psi_t *psi)
     265{
     266        static const char speed_exp [] = " KMG";
     267        static const char *psi_types [] = { "", " rsvd", " RX", " TX" };
     268       
     269        usb_log_debug("Speed %u%s: %5u %cb/s, %s",
     270            XHCI_REG_RD(psi, XHCI_PSI_PSIV),
     271            psi_types[XHCI_REG_RD(psi, XHCI_PSI_PLT)],
     272            XHCI_REG_RD(psi, XHCI_PSI_PSIM),
     273            speed_exp[XHCI_REG_RD(psi, XHCI_PSI_PSIE)],
     274            XHCI_REG_RD(psi, XHCI_PSI_PFD) ? "full-duplex" : "");
     275}
     276
     277void xhci_dump_extcap(const xhci_extcap_t *ec)
     278{
     279        xhci_sp_name_t name;
     280        unsigned ports_from, ports_to;
     281
     282        unsigned id = XHCI_REG_RD(ec, XHCI_EC_CAP_ID);
     283        usb_log_debug("Extended capability %s", xhci_ec_str_id(id));
     284
     285        switch (id) {
     286                case XHCI_EC_SUPPORTED_PROTOCOL:
     287                        name.packed = host2uint32_t_le(XHCI_REG_RD(ec, XHCI_EC_SP_NAME));
     288                        ports_from = XHCI_REG_RD(ec, XHCI_EC_SP_CP_OFF);
     289                        ports_to = ports_from + XHCI_REG_RD(ec, XHCI_EC_SP_CP_OFF) - 1;
     290                        usb_log_debug("\tProtocol %4s%u.%u, ports %u-%u", name.str,
     291                            XHCI_REG_RD(ec, XHCI_EC_SP_MAJOR),
     292                            XHCI_REG_RD(ec, XHCI_EC_SP_MINOR),
     293                            ports_from, ports_to);
     294
     295                        unsigned psic = XHCI_REG_RD(ec, XHCI_EC_SP_PSIC);
     296                        for (unsigned i = 0; i < psic; i++)
     297                                xhci_dump_psi(xhci_extcap_psi(ec, i));
     298                        break;
     299        }
    235300}
    236301
  • uspace/drv/bus/usb/xhci/debug.h

    re4d7363 r91ca111  
    3737#define XHCI_DEBUG_H
    3838
     39/**
     40 * As the debug header is likely to be included in every file, avoid including
     41 * all headers of xhci to support "include what you use".
     42 */
    3943struct xhci_hc;
    4044struct xhci_cap_regs;
    4145struct xhci_port_regs;
    4246struct xhci_trb;
     47struct xhci_extcap;
    4348
    4449void xhci_dump_cap_regs(const struct xhci_cap_regs *);
    45 void xhci_dump_port(struct xhci_port_regs *);
    46 void xhci_dump_state(struct xhci_hc *);
    47 void xhci_dump_ports(struct xhci_hc *);
     50void xhci_dump_port(const struct xhci_port_regs *);
     51void xhci_dump_state(const struct xhci_hc *);
     52void xhci_dump_ports(const struct xhci_hc *);
    4853
    4954const char *xhci_trb_str_type(unsigned);
    50 void xhci_dump_trb(struct xhci_trb *trb);
     55void xhci_dump_trb(const struct xhci_trb *trb);
     56
     57const char *xhci_ec_str_id(unsigned);
     58void xhci_dump_extcap(const struct xhci_extcap *);
    5159
    5260#endif
  • uspace/drv/bus/usb/xhci/hc.c

    re4d7363 r91ca111  
    6969};
    7070
     71/**
     72 * Default USB Speed ID mapping: Table 157
     73 */
     74#define PSI_TO_BPS(psie, psim) (((uint64_t) psim) << (10 * psie))
     75#define PORT_SPEED(psie, psim) { \
     76        .rx_bps = PSI_TO_BPS(psie, psim), \
     77        .tx_bps = PSI_TO_BPS(psie, psim) \
     78}
     79static const xhci_port_speed_t ps_default_full  = PORT_SPEED(2, 12);
     80static const xhci_port_speed_t ps_default_low   = PORT_SPEED(1, 1500);
     81static const xhci_port_speed_t ps_default_high  = PORT_SPEED(2, 480);
     82static const xhci_port_speed_t ps_default_super = PORT_SPEED(3, 5);
     83
     84/**
     85 * Walk the list of extended capabilities.
     86 */
     87static int hc_parse_ec(xhci_hc_t *hc)
     88{
     89        unsigned psic, major;
     90
     91        for (xhci_extcap_t *ec = hc->xecp; ec; ec = xhci_extcap_next(ec)) {
     92                xhci_dump_extcap(ec);
     93                switch (XHCI_REG_RD(ec, XHCI_EC_CAP_ID)) {
     94                case XHCI_EC_USB_LEGACY:
     95                        assert(hc->legsup == NULL);
     96                        hc->legsup = (xhci_legsup_t *) ec;
     97                        break;
     98                case XHCI_EC_SUPPORTED_PROTOCOL:
     99                        psic = XHCI_REG_RD(ec, XHCI_EC_SP_PSIC);
     100                        major = XHCI_REG_RD(ec, XHCI_EC_SP_MAJOR);
     101
     102                        // "Implied" speed
     103                        if (psic == 0) {
     104                                /*
     105                                 * According to section 7.2.2.1.2, only USB 2.0
     106                                 * and USB 3.0 can have psic == 0. So we
     107                                 * blindly assume the name == "USB " and minor
     108                                 * == 0.
     109                                 */
     110                                if (major == 2) {
     111                                        hc->speeds[1] = ps_default_full;
     112                                        hc->speeds[2] = ps_default_low;
     113                                        hc->speeds[3] = ps_default_high;
     114                                } else if (major == 3) {
     115                                        hc->speeds[4] = ps_default_super;
     116                                } else {
     117                                        return EINVAL;
     118                                }
     119
     120                                usb_log_debug2("Implied speed of USB %u set up.", major);
     121                        } else {
     122                                for (unsigned i = 0; i < psic; i++) {
     123                                        xhci_psi_t *psi = xhci_extcap_psi(ec, i);
     124                                        unsigned sim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
     125                                        unsigned psiv = XHCI_REG_RD(psi, XHCI_PSI_PSIV);
     126                                        unsigned psie = XHCI_REG_RD(psi, XHCI_PSI_PSIE);
     127                                        unsigned psim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
     128
     129                                        uint64_t bps = PSI_TO_BPS(psie, psim);
     130
     131                                        if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_RX)
     132                                                hc->speeds[psiv].rx_bps = bps;
     133                                        if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_TX) {
     134                                                hc->speeds[psiv].tx_bps = bps;
     135                                                usb_log_debug2("Speed %u set up for bps %" PRIu64 " / %" PRIu64 ".", psiv, hc->speeds[psiv].rx_bps, hc->speeds[psiv].tx_bps);
     136                                        }
     137                                }
     138                        }
     139                }
     140        }
     141        return EOK;
     142}
     143
    71144int hc_init_mmio(xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
    72145{
     
    90163                return err;
    91164
     165        hc->base = base;
    92166        hc->cap_regs = (xhci_cap_regs_t *)  base;
    93167        hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
    94168        hc->rt_regs  = (xhci_rt_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
    95169        hc->db_arry  = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
     170
     171        uintptr_t xec_offset = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_XECP) * sizeof(xhci_dword_t);
     172        if (xec_offset > 0)
     173                hc->xecp = (xhci_extcap_t *) (base + xec_offset);
    96174
    97175        usb_log_debug2("Initialized MMIO reg areas:");
     
    105183        hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
    106184        hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
     185
     186        if ((err = hc_parse_ec(hc))) {
     187                pio_disable(hc->base, RNGSZ(hc->mmio_range));
     188                return err;
     189        }
    107190
    108191        return EOK;
     
    151234        }
    152235
    153         addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
    154 
    155236        code->ranges = malloc(sizeof(irq_pio_range_t));
    156237        if (code->ranges == NULL)
     
    165246        code->rangecount = 1;
    166247        code->ranges[0] = (irq_pio_range_t) {
    167             .base = RNGABS(mmio_range),
    168             .size = RNGSZ(mmio_range),
     248            .base = RNGABS(hc->mmio_range),
     249            .size = RNGSZ(hc->mmio_range),
    169250        };
    170251
     
    172253        memcpy(code->cmds, irq_commands, sizeof(irq_commands));
    173254
    174         void *intr0_iman = RNGABSPTR(mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
     255        void *intr0_iman = RNGABSPTR(hc->mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
    175256        code->cmds[0].addr = intr0_iman;
    176257        code->cmds[3].addr = intr0_iman;
     
    182263int hc_claim(xhci_hc_t *hc, ddf_dev_t *dev)
    183264{
    184         // TODO: impl
    185         return EOK;
     265        /* No legacy support capability, the controller is solely for us */
     266        if (!hc->legsup)
     267                return EOK;
     268
     269        /*
     270         * TODO: Implement handoff from BIOS, section 4.22.1
     271         * QEMU does not support this, so we have to test on real HW.
     272         */
     273        return ENOTSUP;
    186274}
    187275
     
    346434        xhci_trb_ring_fini(&hc->command_ring);
    347435        xhci_event_ring_fini(&hc->event_ring);
     436        pio_disable(hc->base, RNGSZ(hc->mmio_range));
    348437        usb_log_info("HC(%p): Finalized.", hc);
    349438}
  • uspace/drv/bus/usb/xhci/hc.h

    re4d7363 r91ca111  
    3939#include "trb_ring.h"
    4040
     41/**
     42 * xHCI lets the controller define speeds of ports it controls.
     43 */
     44typedef struct xhci_port_speed {
     45        uint64_t rx_bps, tx_bps;
     46} xhci_port_speed_t;
     47
    4148typedef struct xhci_hc {
     49        /* MMIO range */
     50        addr_range_t mmio_range;
     51        void *base;
     52
     53        /* Mapped register sets */
    4254        xhci_cap_regs_t *cap_regs;
    4355        xhci_op_regs_t *op_regs;
    4456        xhci_rt_regs_t *rt_regs;
    4557        xhci_doorbell_t *db_arry;
     58        xhci_extcap_t *xecp;            /**< First extended capability */
     59        xhci_legsup_t *legsup;          /**< Legacy support capability */
    4660
    47         addr_range_t mmio_range;
    48 
     61        /* Structures in allocated memory */
    4962        xhci_trb_ring_t command_ring;
    5063        xhci_event_ring_t event_ring;
    51 
    5264        xhci_device_ctx_t *dcbaa;
    5365
     66        /* Cached capabilities */
     67        xhci_port_speed_t speeds [16];
    5468        unsigned max_slots;
    5569        bool ac64;
    56 
    5770} xhci_hc_t;
    5871
  • uspace/drv/bus/usb/xhci/hw_struct/regs.h

    re4d7363 r91ca111  
    483483typedef ioport32_t xhci_doorbell_t;
    484484
     485enum xhci_plt {
     486        XHCI_PSI_PLT_SYMM,
     487        XHCI_PSI_PLT_RSVD,
     488        XHCI_PSI_PLT_RX,
     489        XHCI_PSI_PLT_TX
     490};
     491
     492/**
     493 * Protocol speed ID: section 7.2.1
     494 */
     495typedef struct xhci_psi {
     496        xhci_dword_t psi;
     497} xhci_psi_t;
     498
     499#define XHCI_PSI_PSIV    psi, 32, RANGE,  3,  0
     500#define XHCI_PSI_PSIE    psi, 32, RANGE,  5,  4
     501#define XHCI_PSI_PLT     psi, 32, RANGE,  7,  6
     502#define XHCI_PSI_PFD     psi, 32,  FLAG,  8
     503#define XHCI_PSI_PSIM    psi, 32, RANGE, 31, 16
     504
     505enum xhci_extcap_type {
     506        XHCI_EC_RESERVED = 0,
     507        XHCI_EC_USB_LEGACY,
     508        XHCI_EC_SUPPORTED_PROTOCOL,
     509        XHCI_EC_EXTENDED_POWER_MANAGEMENT,
     510        XHCI_EC_IOV,
     511        XHCI_EC_MSI,
     512        XHCI_EC_LOCALMEM,
     513        XHCI_EC_DEBUG = 10,
     514        XHCI_EC_MSIX = 17,
     515        XHCI_EC_MAX = 255
     516};
     517
     518/**
     519 * xHCI Extended Capability: section 7
     520 */
     521typedef struct xhci_extcap {
     522        xhci_dword_t header;
     523        xhci_dword_t cap_specific[];
     524} xhci_extcap_t;
     525
     526#define XHCI_EC_CAP_ID                           header, 32, RANGE,  7,  0
     527#define XHCI_EC_SIZE                             header, 32, RANGE, 15,  8
     528
     529/* Supported protocol */
     530#define XHCI_EC_SP_MINOR                         header, 32, RANGE, 23, 16
     531#define XHCI_EC_SP_MAJOR                         header, 32, RANGE, 31, 24
     532#define XHCI_EC_SP_NAME                 cap_specific[0], 32, FIELD
     533#define XHCI_EC_SP_CP_OFF               cap_specific[1], 32, RANGE,  7,  0
     534#define XHCI_EC_SP_CP_COUNT             cap_specific[1], 32, RANGE, 15,  8
     535#define XHCI_EC_SP_PSIC                 cap_specific[1], 32, RANGE, 31, 28
     536#define XHCI_EC_SP_SLOT_TYPE            cap_specific[2], 32, RANGE,  4,  0
     537
     538typedef union {
     539        char str [4];
     540        uint32_t packed;
     541} xhci_sp_name_t;
     542
     543static inline xhci_extcap_t *xhci_extcap_next(const xhci_extcap_t *cur)
     544{
     545        unsigned dword_offset = XHCI_REG_RD(cur, XHCI_EC_SIZE);
     546        if (!dword_offset)
     547                return NULL;
     548        return (xhci_extcap_t *) (((xhci_dword_t *) cur) + dword_offset);
     549}
     550
     551static inline xhci_psi_t *xhci_extcap_psi(const xhci_extcap_t *ec, unsigned psid)
     552{
     553        assert(XHCI_REG_RD(ec, XHCI_EC_CAP_ID) == XHCI_EC_SUPPORTED_PROTOCOL);
     554        assert(XHCI_REG_RD(ec, XHCI_EC_SP_PSIC) > psid);
     555
     556        unsigned dword_offset = 4 + psid;
     557        return (xhci_psi_t *) (((xhci_dword_t *) ec) + dword_offset);
     558}
     559
     560/**
     561 * USB Legacy Support: section 7.1
     562 *
     563 * Legacy support have an exception from dword-access, because it needs to be
     564 * byte-accessed.
     565 */
     566typedef struct xhci_extcap_legsup {
     567        ioport8_t cap_id;
     568        ioport8_t size;                 /**< Next Capability Pointer */
     569        ioport8_t sem_bios;
     570        ioport8_t sem_os;
     571
     572        xhci_dword_t usblegctlsts;      /**< USB Legacy Support Control/Status - RW for BIOS, RO for OS */
     573} xhci_legsup_t;
     574
     575#define XHCI_LEGSUP_SEM_BIOS    sem_bios, 8, FLAG, 0
     576#define XHCI_LEGSUP_SEM_OS      sem_os, 8, FLAG, 0
     577
    485578#endif
    486579/**
  • uspace/lib/usb/include/usb/usb.h

    re4d7363 r91ca111  
    8080        /** USB 2.0 high speed (480Mbits/s). */
    8181        USB_SPEED_HIGH,
    82         /** USB 3.0 super speed (480Mbits/s). */
     82        /** USB 3.0 super speed (5Gbits/s). */
    8383        USB_SPEED_SUPER,
    8484        /** Psuedo-speed serving as a boundary. */
Note: See TracChangeset for help on using the changeset viewer.