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

Changeset 816335c in mainline


Ignore:
Timestamp:
2017-10-04T10:06:10Z (4 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master
Children:
c68c713c
Parents:
5c5c9407
Message:

xhci: port speed detected properly

The correct way to determine protocol supported on a port is to look at the Port Speed value in the port register, and use it as an index to the speeds defined in extended capabilities. Now we support non-contiguous ranges of ports, USB 3.1, and the detection would work even for non-USB protocols.

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

Legend:

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

    r5c5c9407 r816335c  
    288288                        ports_from = XHCI_REG_RD(ec, XHCI_EC_SP_CP_OFF);
    289289                        ports_to = ports_from + XHCI_REG_RD(ec, XHCI_EC_SP_CP_COUNT) - 1;
    290                         usb_log_debug("\tProtocol %4s%u.%u, ports %u-%u", name.str,
     290                        usb_log_debug("\tProtocol %.4s%u.%u, ports %u-%u", name.str,
    291291                            XHCI_REG_RD(ec, XHCI_EC_SP_MAJOR),
    292292                            XHCI_REG_RD(ec, XHCI_EC_SP_MINOR),
  • uspace/drv/bus/usb/xhci/hc.c

    r5c5c9407 r816335c  
    4848 */
    4949#define PSI_TO_BPS(psie, psim) (((uint64_t) psim) << (10 * psie))
    50 #define PORT_SPEED(psie, psim) { \
     50#define PORT_SPEED(mjr, psie, psim) { \
     51        .name = "USB ", \
     52        .major = mjr, \
     53        .minor = 0, \
    5154        .rx_bps = PSI_TO_BPS(psie, psim), \
    5255        .tx_bps = PSI_TO_BPS(psie, psim) \
    5356}
    54 static const xhci_port_speed_t ps_default_full  = PORT_SPEED(2, 12);
    55 static const xhci_port_speed_t ps_default_low   = PORT_SPEED(1, 1500);
    56 static const xhci_port_speed_t ps_default_high  = PORT_SPEED(2, 480);
    57 static const xhci_port_speed_t ps_default_super = PORT_SPEED(3, 5);
     57static const xhci_port_speed_t ps_default_full  = PORT_SPEED(2, 2, 12);
     58static const xhci_port_speed_t ps_default_low   = PORT_SPEED(2, 1, 1500);
     59static const xhci_port_speed_t ps_default_high  = PORT_SPEED(2, 2, 480);
     60static const xhci_port_speed_t ps_default_super = PORT_SPEED(3, 3, 5);
    5861
    5962/**
     
    6265static int hc_parse_ec(xhci_hc_t *hc)
    6366{
    64         unsigned psic, major;
     67        unsigned psic, major, minor;
     68        xhci_sp_name_t name;
     69
     70        xhci_port_speed_t *speeds = hc->rh.speeds;
    6571
    6672        for (xhci_extcap_t *ec = hc->xecp; ec; ec = xhci_extcap_next(ec)) {
     
    7480                        psic = XHCI_REG_RD(ec, XHCI_EC_SP_PSIC);
    7581                        major = XHCI_REG_RD(ec, XHCI_EC_SP_MAJOR);
     82                        minor = XHCI_REG_RD(ec, XHCI_EC_SP_MINOR);
     83                        name.packed = host2uint32_t_le(XHCI_REG_RD(ec, XHCI_EC_SP_NAME));
     84
     85                        if (name.packed != xhci_name_usb.packed) {
     86                                /**
     87                                 * The detection of such protocol would work,
     88                                 * but the rest of the implementation is made
     89                                 * for the USB protocol only.
     90                                 */
     91                                usb_log_error("Unknown protocol %.4s.", name.str);
     92                                return ENOTSUP;
     93                        }
    7694
    7795                        // "Implied" speed
    7896                        if (psic == 0) {
    79                                 /*
    80                                  * According to section 7.2.2.1.2, only USB 2.0
    81                                  * and USB 3.0 can have psic == 0. So we
    82                                  * blindly assume the name == "USB " and minor
    83                                  * == 0.
    84                                  */
    85 
    86                                 unsigned ports_from = XHCI_REG_RD(ec, XHCI_EC_SP_CP_OFF);
    87                                 unsigned ports_to = ports_from
    88                                         + XHCI_REG_RD(ec, XHCI_EC_SP_CP_COUNT) - 1;
     97                                assert(minor == 0);
    8998
    9099                                if (major == 2) {
    91                                         hc->speeds[1] = ps_default_full;
    92                                         hc->speeds[2] = ps_default_low;
    93                                         hc->speeds[3] = ps_default_high;
    94                                         hc->rh.usb2_port_start = ports_from;
    95                                         hc->rh.usb2_port_end = ports_to;
     100                                        speeds[1] = ps_default_full;
     101                                        speeds[2] = ps_default_low;
     102                                        speeds[3] = ps_default_high;
    96103                                } else if (major == 3) {
    97                                         hc->speeds[4] = ps_default_super;
    98                                         hc->rh.usb3_port_start = ports_from;
    99                                         hc->rh.usb3_port_end = ports_to;
     104                                        speeds[4] = ps_default_super;
    100105                                } else {
    101106                                        return EINVAL;
    102107                                }
    103108
    104                                 usb_log_debug2("Implied speed of USB %u set up.", major);
     109                                usb_log_debug2("Implied speed of USB %u.0 set up.", major);
    105110                        } else {
    106111                                for (unsigned i = 0; i < psic; i++) {
     
    111116                                        unsigned psim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
    112117
     118                                        speeds[psiv].major = major;
     119                                        speeds[psiv].minor = minor;
     120                                        str_ncpy(speeds[psiv].name, 4, name.str, 4);
     121
    113122                                        uint64_t bps = PSI_TO_BPS(psie, psim);
    114123
    115124                                        if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_RX)
    116                                                 hc->speeds[psiv].rx_bps = bps;
     125                                                speeds[psiv].rx_bps = bps;
    117126                                        if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_TX) {
    118                                                 hc->speeds[psiv].tx_bps = bps;
    119                                                 usb_log_debug2("Speed %u set up for bps %" PRIu64 " / %" PRIu64 ".", psiv, hc->speeds[psiv].rx_bps, hc->speeds[psiv].tx_bps);
     127                                                speeds[psiv].tx_bps = bps;
     128                                                usb_log_debug2("Speed %u set up for bps %" PRIu64 " / %" PRIu64 ".", psiv, speeds[psiv].rx_bps, speeds[psiv].tx_bps);
    120129                                        }
    121130                                }
     
    202211                goto err_scratch;
    203212
    204         if ((err = xhci_rh_init(&hc->rh, hc->op_regs)))
     213        if ((err = xhci_rh_init(&hc->rh, hc)))
    205214                goto err_cmd;
    206215
  • uspace/drv/bus/usb/xhci/hc.h

    r5c5c9407 r816335c  
    4949} xhci_virt_device_ctx_t;
    5050
    51 /**
    52  * xHCI lets the controller define speeds of ports it controls.
    53  */
    54 typedef struct xhci_port_speed {
    55         uint64_t rx_bps, tx_bps;
    56 } xhci_port_speed_t;
    57 
    5851typedef struct xhci_hc {
    5952        /* MMIO range */
     
    8073
    8174        /* Cached capabilities */
    82         xhci_port_speed_t speeds [16];
    8375        unsigned max_slots;
    8476        bool ac64;
  • uspace/drv/bus/usb/xhci/hw_struct/regs.h

    r5c5c9407 r816335c  
    241241         * 15:14 - PIC
    242242         *          27  26  25  24  23  22  21  20  19  18  17  16
    243     * 27:16 - WOE WDE WCE CAS CEC PLC PRC OCC WRC PEC CSC LWS
     243        * 27:16 - WOE WDE WCE CAS CEC PLC PRC OCC WRC PEC CSC LWS
    244244         *    30 - DR
    245245         *    31 - WPR
     
    546546} xhci_sp_name_t;
    547547
     548static const xhci_sp_name_t xhci_name_usb = {
     549    .str = "USB "
     550};
     551
    548552static inline xhci_extcap_t *xhci_extcap_next(const xhci_extcap_t *cur)
    549553{
  • uspace/drv/bus/usb/xhci/rh.c

    r5c5c9407 r816335c  
    5151static usbvirt_device_ops_t ops;
    5252
    53 int xhci_rh_init(xhci_rh_t *rh, xhci_op_regs_t *op_regs)
     53int xhci_rh_init(xhci_rh_t *rh, xhci_hc_t *hc)
    5454{
    5555        assert(rh);
    56         rh->op_regs = op_regs;
     56        assert(hc);
     57
     58        rh->hc = hc;
    5759
    5860        usb_hub_descriptor_header_t *header = &rh->hub_descriptor.header;
     
    172174{
    173175        uint8_t link_state = XHCI_REG_RD(regs, XHCI_PORT_PLS);
    174         // FIXME: do we have a better way to detect if this is usb2 or usb3 device?
    175         if (xhci_is_usb3_port(&hc->rh, port_id)) {
     176        const xhci_port_speed_t *speed = xhci_get_port_speed(&hc->rh, port_id);
     177
     178        usb_log_info("Detected new %.4s%u.%u device on port %u.", speed->name, speed->major, speed->minor, port_id);
     179
     180        if (speed->major == 3) {
    176181                if(link_state == 0) {
    177182                        /* USB3 is automatically advanced to enabled. */
    178                         uint8_t port_speed = XHCI_REG_RD(regs, XHCI_PORT_PS);
    179                         usb_log_debug("Detected new device on port %u, port speed id %u.", port_id, port_speed);
    180 
    181183                        return alloc_dev(hc, port_id, 0);
    182184                }
     
    237239
    238240        return EOK;
     241}
     242
     243const xhci_port_speed_t *xhci_get_port_speed(xhci_rh_t *rh, uint8_t port)
     244{
     245        xhci_port_regs_t *port_regs = &rh->hc->op_regs->portrs[port - 1];
     246
     247        unsigned psiv = XHCI_REG_RD(port_regs, XHCI_PORT_PS);
     248        return &rh->speeds[psiv];
    239249}
    240250
     
    343353
    344354        /* The index is 1-based. */
    345         xhci_port_regs_t* regs = &hub->op_regs->portrs[setup_packet->index - 1];
     355        xhci_port_regs_t* regs = &hub->hc->op_regs->portrs[setup_packet->index - 1];
    346356
    347357        const uint32_t status = uint32_host2usb(
  • uspace/drv/bus/usb/xhci/rh.h

    r5c5c9407 r816335c  
    3939#include <usb/host/usb_transfer_batch.h>
    4040#include <usbvirt/virthub_base.h>
     41#include "hw_struct/regs.h"
     42
     43typedef struct xhci_hc xhci_hc_t;
    4144
    4245enum {
     
    4447};
    4548
     49/**
     50 * xHCI lets the controller define speeds of ports it controls.
     51 */
     52typedef struct xhci_port_speed {
     53        char name [4];
     54        uint8_t major, minor;
     55        uint64_t rx_bps, tx_bps;
     56} xhci_port_speed_t;
     57
    4658/* XHCI root hub instance */
    4759typedef struct {
    4860        /** Virtual hub instance */
    4961        virthub_base_t base;
    50         /** XHCI operational registers */
    51         xhci_op_regs_t *op_regs;
     62
     63        /** Host controller */
     64        xhci_hc_t *hc;
     65
     66        /** Port speeds reported from HC */
     67        xhci_port_speed_t speeds [16];
     68
    5269        /** USB hub descriptor describing the XHCI root hub */
    5370        struct {
     
    5774        /** Interrupt transfer waiting for an actual interrupt to occur */
    5875        usb_transfer_batch_t *unfinished_interrupt_transfer;
    59 
    60         uint8_t usb2_port_start;
    61         uint8_t usb2_port_end;
    62         uint8_t usb3_port_start;
    63         uint8_t usb3_port_end;
    6476} xhci_rh_t;
    6577
    66 int xhci_rh_init(xhci_rh_t *, xhci_op_regs_t *);
     78int xhci_rh_init(xhci_rh_t *, xhci_hc_t *);
    6779int xhci_rh_fini(xhci_rh_t *);
     80const xhci_port_speed_t *xhci_get_port_speed(xhci_rh_t *, uint8_t);
    6881int xhci_handle_port_status_change_event(xhci_hc_t *, xhci_trb_t *);
    6982int xhci_get_hub_port(xhci_trb_t *);
     
    8497}
    8598
    86 static inline bool xhci_is_usb3_port(xhci_rh_t* rh, uint8_t port) {
    87         return port >= rh->usb3_port_start && port <= rh->usb3_port_end;
     99static inline bool xhci_is_usb3_port(xhci_rh_t* rh, uint8_t port)
     100{
     101        return xhci_get_port_speed(rh, port)->major == 3;
    88102}
    89 
    90103#endif
    91104
Note: See TracChangeset for help on using the changeset viewer.