Changeset ab5a0830 in mainline


Ignore:
Timestamp:
2017-09-27T15:04:39Z (7 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
548c123
Parents:
6da6039
Message:

Handle interrupts correctly

Now, irq_commands asserts all flags in usbsts, then asserts IP, and passes
usbsts as status to the handler. The previous weird behavior was becouse
status_hook is only called when in polling mode, which we didn't notice.

File:
1 edited

Legend:

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

    r6da6039 rab5a0830  
    4444#include "commands.h"
    4545
    46 static const irq_cmd_t irq_commands[] = {
    47         {
    48                 .cmd = CMD_PIO_READ_32,
    49                 .dstarg = 1,
    50                 .addr = NULL
    51         },
    52         {
    53                 .cmd = CMD_AND,
    54                 .srcarg = 1,
    55                 .dstarg = 2,
    56                 .value = 0
    57         },
    58         {
    59                 .cmd = CMD_PREDICATE,
    60                 .srcarg = 2,
    61                 .value = 2
    62         },
    63         {
    64                 .cmd = CMD_PIO_WRITE_A_32,
    65                 .srcarg = 1,
    66                 .addr = NULL
    67         },
    68         {
    69                 .cmd = CMD_ACCEPT
    70         }
    71 };
    72 
    7346/**
    7447 * Default USB Speed ID mapping: Table 157
     
    240213}
    241214
     215/*
     216 * Pseudocode:
     217 *      ip = read(intr[0].iman)
     218 *      if (ip) {
     219 *              status = read(usbsts)
     220 *              assert status
     221 *              assert ip
     222 *              accept (passing status)
     223 *      }
     224 *      decline
     225 */
     226static const irq_cmd_t irq_commands[] = {
     227        {
     228                .cmd = CMD_PIO_READ_32,
     229                .dstarg = 3,
     230                .addr = NULL    /* intr[0].iman */
     231        },
     232        {
     233                .cmd = CMD_AND,
     234                .srcarg = 3,
     235                .dstarg = 4,
     236                .value = 0      /* host2xhci(32, 1) */
     237        },
     238        {
     239                .cmd = CMD_PREDICATE,
     240                .srcarg = 4,
     241                .value = 5
     242        },
     243        {
     244                .cmd = CMD_PIO_READ_32,
     245                .dstarg = 1,
     246                .addr = NULL    /* usbsts */
     247        },
     248        {
     249                .cmd = CMD_AND,
     250                .srcarg = 1,
     251                .dstarg = 2,
     252                .value = 0      /* host2xhci(32, XHCI_STATUS_ACK_MASK) */
     253        },
     254        {
     255                .cmd = CMD_PIO_WRITE_A_32,
     256                .srcarg = 2,
     257                .addr = NULL    /* usbsts */
     258        },
     259        {
     260                .cmd = CMD_PIO_WRITE_A_32,
     261                .srcarg = 4,
     262                .addr = NULL    /* intr[0].iman */
     263        },
     264        {
     265                .cmd = CMD_ACCEPT
     266        },
     267        {
     268                .cmd = CMD_DECLINE
     269        }
     270};
     271
    242272
    243273/**
     
    276306
    277307        void *intr0_iman = RNGABSPTR(hc->mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
     308        void *usbsts = RNGABSPTR(hc->mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH) + offsetof(xhci_op_regs_t, usbsts);
    278309        code->cmds[0].addr = intr0_iman;
    279         code->cmds[3].addr = intr0_iman;
    280310        code->cmds[1].value = host2xhci(32, 1);
     311        code->cmds[3].addr = usbsts;
     312        code->cmds[4].value = host2xhci(32, XHCI_STATUS_ACK_MASK);
     313        code->cmds[5].addr = usbsts;
     314        code->cmds[6].addr = intr0_iman;
    281315
    282316        return hw_res->irqs.irqs[0];
     
    356390}
    357391
     392/**
     393 * Used only when polling. Shall supplement the irq_commands.
     394 */
    358395int hc_status(xhci_hc_t *hc, uint32_t *status)
    359396{
    360         *status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
    361         XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
    362 
    363         usb_log_debug2("HC(%p): Read status: %x", hc, *status);
     397        int ip = XHCI_REG_RD(hc->rt_regs->ir, XHCI_INTR_IP);
     398        if (ip) {
     399                *status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
     400                XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
     401                XHCI_REG_WR(hc->rt_regs->ir, XHCI_INTR_IP, 1);
     402
     403                /* interrupt handler expects status from irq_commands, which is
     404                 * in xhci order. */
     405                *status = host2xhci(32, *status);
     406        }
     407
     408        usb_log_debug2("HC(%p): Polled status: %x", hc, *status);
    364409        return EOK;
    365410}
     
    460505void hc_interrupt(xhci_hc_t *hc, uint32_t status)
    461506{
    462         /**
    463          * TODO: This is a temporary workaround, when an event interrupt
    464          *       happens, status has the value of 3, which is equal to
    465          *       XHCI_REG_SHIFT(XHCI_OP_EINT), intstead to the correct
    466          *       XHCI_REG_MASK(XHCI_OP_EINT), which has the value of 8 (1 << 3).
    467          *       This is how e.g. FreeBSD does it.
    468          */
    469         status = hc->op_regs->usbsts;
     507        status = xhci2host(32, status);
    470508
    471509        /* TODO: Figure out how root hub interrupts work. */
     
    473511                usb_log_debug2("Root hub interrupt.");
    474512                xhci_rh_interrupt(&hc->rh);
     513
     514                status &= ~XHCI_REG_MASK(XHCI_OP_PCD);
    475515        }
    476516
    477517        if (status & XHCI_REG_MASK(XHCI_OP_HSE)) {
    478518                usb_log_error("Host controller error occured. Bad things gonna happen...");
     519                status &= ~XHCI_REG_MASK(XHCI_OP_HSE);
    479520        }
    480521
    481522        if (status & XHCI_REG_MASK(XHCI_OP_EINT)) {
    482523                usb_log_debug2("Event interrupt.");
    483 
    484                 xhci_interrupter_regs_t *intr0 = &hc->rt_regs->ir[0];
    485 
    486                 /**
    487                  * EINT has to be cleared before IP, but we also need to
    488                  * handle the event before clearing EINT.
    489                  */
    490                 uint32_t ip = XHCI_REG_RD(intr0, XHCI_INTR_IP);
    491 
    492                 if (ip | 1) { // TODO: IP is being cleared right after it is set by the xHC.
    493                         hc_run_event_ring(hc, &hc->event_ring, intr0);
    494                 }
    495 
    496                 XHCI_REG_SET(hc->op_regs, XHCI_OP_EINT, 1);
    497 
    498                 if (ip) {
    499                         XHCI_REG_SET(intr0, XHCI_INTR_IP, 1);
    500                 }
    501         }
    502 
    503         if (status & XHCI_REG_MASK(XHCI_OP_PCD)) {
    504                 usb_log_error("Port change detected. Not implemented yet!");
     524                hc_run_event_ring(hc, &hc->event_ring, &hc->rt_regs->ir[0]);
     525                status &= ~XHCI_REG_MASK(XHCI_OP_EINT);
    505526        }
    506527
    507528        if (status & XHCI_REG_MASK(XHCI_OP_SRE)) {
    508529                usb_log_error("Save/Restore error occured. WTF, S/R mechanism not implemented!");
     530                status &= ~XHCI_REG_MASK(XHCI_OP_SRE);
     531        }
     532
     533        if (status) {
     534                usb_log_error("Non-zero status after interrupt handling (%08x) - missing something?", status);
    509535        }
    510536}
Note: See TracChangeset for help on using the changeset viewer.