source: mainline/uspace/drv/bus/usb/xhci/hc.c@ 472235a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 472235a was 472235a, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

xhci: refactoring

Revise error paths, refactor some code.

  • Property mode set to 100644
File size: 16.7 KB
RevLine 
[5cbccd4]1/*
2 * Copyright (c) 2017 Ondrej Hlavaty
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbxhci
30 * @{
31 */
32/** @file
33 * @brief The host controller data bookkeeping.
34 */
35
36#include <errno.h>
[cb89430]37#include <str_error.h>
[5cbccd4]38#include <usb/debug.h>
[cb89430]39#include <usb/host/utils/malloc32.h>
[5cbccd4]40#include "debug.h"
41#include "hc.h"
[7bd99bf]42#include "rh.h"
[cb89430]43#include "hw_struct/trb.h"
[c9c0e41]44#include "commands.h"
[5cbccd4]45
[91ca111]46/**
47 * Default USB Speed ID mapping: Table 157
48 */
49#define PSI_TO_BPS(psie, psim) (((uint64_t) psim) << (10 * psie))
50#define PORT_SPEED(psie, psim) { \
51 .rx_bps = PSI_TO_BPS(psie, psim), \
52 .tx_bps = PSI_TO_BPS(psie, psim) \
53}
54static const xhci_port_speed_t ps_default_full = PORT_SPEED(2, 12);
55static const xhci_port_speed_t ps_default_low = PORT_SPEED(1, 1500);
56static const xhci_port_speed_t ps_default_high = PORT_SPEED(2, 480);
57static const xhci_port_speed_t ps_default_super = PORT_SPEED(3, 5);
58
59/**
60 * Walk the list of extended capabilities.
61 */
62static int hc_parse_ec(xhci_hc_t *hc)
63{
64 unsigned psic, major;
65
66 for (xhci_extcap_t *ec = hc->xecp; ec; ec = xhci_extcap_next(ec)) {
67 xhci_dump_extcap(ec);
68 switch (XHCI_REG_RD(ec, XHCI_EC_CAP_ID)) {
69 case XHCI_EC_USB_LEGACY:
70 assert(hc->legsup == NULL);
71 hc->legsup = (xhci_legsup_t *) ec;
72 break;
73 case XHCI_EC_SUPPORTED_PROTOCOL:
74 psic = XHCI_REG_RD(ec, XHCI_EC_SP_PSIC);
75 major = XHCI_REG_RD(ec, XHCI_EC_SP_MAJOR);
76
77 // "Implied" speed
78 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 */
[370a1c8]85
[472235a]86 unsigned ports_from = XHCI_REG_RD(ec, XHCI_EC_SP_CP_OFF);
87 unsigned ports_to = ports_from
[370a1c8]88 + XHCI_REG_RD(ec, XHCI_EC_SP_CP_COUNT) - 1;
89
[91ca111]90 if (major == 2) {
91 hc->speeds[1] = ps_default_full;
92 hc->speeds[2] = ps_default_low;
93 hc->speeds[3] = ps_default_high;
[370a1c8]94 hc->rh.usb2_port_start = ports_from;
95 hc->rh.usb2_port_end = ports_to;
[91ca111]96 } else if (major == 3) {
97 hc->speeds[4] = ps_default_super;
[370a1c8]98 hc->rh.usb3_port_start = ports_from;
99 hc->rh.usb3_port_end = ports_to;
[91ca111]100 } else {
101 return EINVAL;
102 }
103
104 usb_log_debug2("Implied speed of USB %u set up.", major);
105 } else {
106 for (unsigned i = 0; i < psic; i++) {
107 xhci_psi_t *psi = xhci_extcap_psi(ec, i);
108 unsigned sim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
109 unsigned psiv = XHCI_REG_RD(psi, XHCI_PSI_PSIV);
110 unsigned psie = XHCI_REG_RD(psi, XHCI_PSI_PSIE);
111 unsigned psim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
112
113 uint64_t bps = PSI_TO_BPS(psie, psim);
114
115 if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_RX)
116 hc->speeds[psiv].rx_bps = bps;
117 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);
120 }
121 }
122 }
123 }
124 }
125 return EOK;
126}
127
[e4d7363]128int hc_init_mmio(xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
129{
130 int err;
131
132 if (hw_res->mem_ranges.count != 1) {
133 usb_log_error("Unexpected MMIO area, bailing out.");
134 return EINVAL;
135 }
136
137 hc->mmio_range = hw_res->mem_ranges.ranges[0];
138
139 usb_log_debug("MMIO area at %p (size %zu), IRQ %d.\n",
140 RNGABSPTR(hc->mmio_range), RNGSZ(hc->mmio_range), hw_res->irqs.irqs[0]);
141
142 if (RNGSZ(hc->mmio_range) < sizeof(xhci_cap_regs_t))
143 return EOVERFLOW;
144
145 void *base;
146 if ((err = pio_enable_range(&hc->mmio_range, &base)))
147 return err;
148
[91ca111]149 hc->base = base;
[e4d7363]150 hc->cap_regs = (xhci_cap_regs_t *) base;
151 hc->op_regs = (xhci_op_regs_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
152 hc->rt_regs = (xhci_rt_regs_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
153 hc->db_arry = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
154
[91ca111]155 uintptr_t xec_offset = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_XECP) * sizeof(xhci_dword_t);
156 if (xec_offset > 0)
157 hc->xecp = (xhci_extcap_t *) (base + xec_offset);
158
[e4d7363]159 usb_log_debug2("Initialized MMIO reg areas:");
160 usb_log_debug2("\tCapability regs: %p", hc->cap_regs);
161 usb_log_debug2("\tOperational regs: %p", hc->op_regs);
162 usb_log_debug2("\tRuntime regs: %p", hc->rt_regs);
163 usb_log_debug2("\tDoorbell array base: %p", hc->db_arry);
164
165 xhci_dump_cap_regs(hc->cap_regs);
166
167 hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
168 hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
169
[91ca111]170 if ((err = hc_parse_ec(hc))) {
171 pio_disable(hc->base, RNGSZ(hc->mmio_range));
172 return err;
173 }
174
[e4d7363]175 return EOK;
176}
177
178int hc_init_memory(xhci_hc_t *hc)
179{
180 int err;
181
[73e5b62]182 hc->dcbaa = malloc32((1 + hc->max_slots) * sizeof(uint64_t));
[e4d7363]183 if (!hc->dcbaa)
184 return ENOMEM;
185
[decfc8d1]186 hc->dcbaa_virt = malloc32((1 + hc->max_slots) * sizeof(xhci_virt_device_ctx_t));
[73e5b62]187 if (!hc->dcbaa_virt) {
188 err = ENOMEM;
[e4d7363]189 goto err_dcbaa;
[73e5b62]190 }
191
192 if ((err = xhci_trb_ring_init(&hc->command_ring, hc)))
193 goto err_dcbaa_virt;
[e4d7363]194
195 if ((err = xhci_event_ring_init(&hc->event_ring, hc)))
196 goto err_cmd_ring;
197
[b19131c5]198 if ((err = xhci_scratchpad_alloc(hc)))
[5a9ae994]199 goto err_event_ring;
[e4d7363]200
[aee352c]201 if ((err = xhci_init_commands(hc)))
[ee28ae66]202 goto err_scratch;
[aee352c]203
[d32d51d]204 if ((err = xhci_rh_init(&hc->rh)))
[ee28ae66]205 goto err_cmd;
[d32d51d]206
[e4d7363]207 return EOK;
208
[ee28ae66]209err_cmd:
[d271f78]210 xhci_fini_commands(hc);
[ee28ae66]211err_scratch:
212 xhci_scratchpad_free(hc);
[5a9ae994]213err_event_ring:
[e4d7363]214 xhci_event_ring_fini(&hc->event_ring);
215err_cmd_ring:
216 xhci_trb_ring_fini(&hc->command_ring);
[73e5b62]217err_dcbaa_virt:
218 free32(hc->dcbaa_virt);
[e4d7363]219err_dcbaa:
220 free32(hc->dcbaa);
221 return err;
222}
223
[ab5a0830]224/*
225 * Pseudocode:
226 * ip = read(intr[0].iman)
227 * if (ip) {
228 * status = read(usbsts)
229 * assert status
230 * assert ip
231 * accept (passing status)
232 * }
233 * decline
234 */
235static const irq_cmd_t irq_commands[] = {
236 {
237 .cmd = CMD_PIO_READ_32,
238 .dstarg = 3,
239 .addr = NULL /* intr[0].iman */
240 },
241 {
242 .cmd = CMD_AND,
243 .srcarg = 3,
244 .dstarg = 4,
245 .value = 0 /* host2xhci(32, 1) */
246 },
247 {
248 .cmd = CMD_PREDICATE,
249 .srcarg = 4,
250 .value = 5
251 },
252 {
253 .cmd = CMD_PIO_READ_32,
254 .dstarg = 1,
255 .addr = NULL /* usbsts */
256 },
257 {
258 .cmd = CMD_AND,
259 .srcarg = 1,
260 .dstarg = 2,
261 .value = 0 /* host2xhci(32, XHCI_STATUS_ACK_MASK) */
262 },
263 {
264 .cmd = CMD_PIO_WRITE_A_32,
265 .srcarg = 2,
266 .addr = NULL /* usbsts */
267 },
268 {
269 .cmd = CMD_PIO_WRITE_A_32,
[efe9463]270 .srcarg = 3,
[ab5a0830]271 .addr = NULL /* intr[0].iman */
272 },
273 {
274 .cmd = CMD_ACCEPT
275 },
276 {
277 .cmd = CMD_DECLINE
278 }
279};
280
[e4d7363]281
[cb89430]282/**
283 * Generates code to accept interrupts. The xHCI is designed primarily for
284 * MSI/MSI-X, but we use PCI Interrupt Pin. In this mode, all the Interrupters
285 * (except 0) are disabled.
286 */
[e4d7363]287int hc_irq_code_gen(irq_code_t *code, xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
[cb89430]288{
289 assert(code);
290 assert(hw_res);
291
[e4d7363]292 if (hw_res->irqs.count != 1) {
[cb89430]293 usb_log_info("Unexpected HW resources to enable interrupts.");
294 return EINVAL;
295 }
296
297 code->ranges = malloc(sizeof(irq_pio_range_t));
298 if (code->ranges == NULL)
299 return ENOMEM;
300
301 code->cmds = malloc(sizeof(irq_commands));
302 if (code->cmds == NULL) {
303 free(code->ranges);
304 return ENOMEM;
305 }
306
307 code->rangecount = 1;
308 code->ranges[0] = (irq_pio_range_t) {
[91ca111]309 .base = RNGABS(hc->mmio_range),
310 .size = RNGSZ(hc->mmio_range),
[cb89430]311 };
312
313 code->cmdcount = ARRAY_SIZE(irq_commands);
314 memcpy(code->cmds, irq_commands, sizeof(irq_commands));
315
[91ca111]316 void *intr0_iman = RNGABSPTR(hc->mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
[ab5a0830]317 void *usbsts = RNGABSPTR(hc->mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH) + offsetof(xhci_op_regs_t, usbsts);
[cb89430]318 code->cmds[0].addr = intr0_iman;
319 code->cmds[1].value = host2xhci(32, 1);
[ab5a0830]320 code->cmds[3].addr = usbsts;
321 code->cmds[4].value = host2xhci(32, XHCI_STATUS_ACK_MASK);
322 code->cmds[5].addr = usbsts;
323 code->cmds[6].addr = intr0_iman;
[cb89430]324
325 return hw_res->irqs.irqs[0];
326}
327
[e4d7363]328int hc_claim(xhci_hc_t *hc, ddf_dev_t *dev)
[cb89430]329{
[91ca111]330 /* No legacy support capability, the controller is solely for us */
331 if (!hc->legsup)
332 return EOK;
333
[e6b0dba]334 /* Section 4.22.1 */
335 /* TODO: Test this with USB3-aware BIOS */
336 usb_log_debug2("LEGSUP: bios: %x, os: %x", hc->legsup->sem_bios, hc->legsup->sem_os);
337 XHCI_REG_WR(hc->legsup, XHCI_LEGSUP_SEM_OS, 1);
[4d28d86]338 for (int i = 0; i <= (XHCI_LEGSUP_BIOS_TIMEOUT_US / XHCI_LEGSUP_POLLING_DELAY_1MS); i++) {
[e6b0dba]339 usb_log_debug2("LEGSUP: elapsed: %i ms, bios: %x, os: %x", i,
340 XHCI_REG_RD(hc->legsup, XHCI_LEGSUP_SEM_BIOS),
341 XHCI_REG_RD(hc->legsup, XHCI_LEGSUP_SEM_OS));
342 if (XHCI_REG_RD(hc->legsup, XHCI_LEGSUP_SEM_BIOS) == 0) {
343 assert(XHCI_REG_RD(hc->legsup, XHCI_LEGSUP_SEM_OS) == 1);
344 return EOK;
345 }
[c9d905f]346 async_usleep(XHCI_LEGSUP_POLLING_DELAY_1MS);
[e6b0dba]347 }
348 usb_log_error("BIOS did not release XHCI legacy hold!\n");
349
[91ca111]350 return ENOTSUP;
[cb89430]351}
352
353static int hc_reset(xhci_hc_t *hc)
354{
355 /* Stop the HC: set R/S to 0 */
356 XHCI_REG_CLR(hc->op_regs, XHCI_OP_RS, 1);
357
358 /* Wait 16 ms until the HC is halted */
359 async_usleep(16000);
360 assert(XHCI_REG_RD(hc->op_regs, XHCI_OP_HCH));
361
362 /* Reset */
363 XHCI_REG_SET(hc->op_regs, XHCI_OP_HCRST, 1);
364
365 /* Wait until the reset is complete */
366 while (XHCI_REG_RD(hc->op_regs, XHCI_OP_HCRST))
367 async_usleep(1000);
368
369 return EOK;
370}
371
372/**
373 * Initialize the HC: section 4.2
374 */
[e4d7363]375int hc_start(xhci_hc_t *hc, bool irq)
[cb89430]376{
377 int err;
378
379 if ((err = hc_reset(hc)))
380 return err;
381
382 while (XHCI_REG_RD(hc->op_regs, XHCI_OP_CNR))
383 async_usleep(1000);
384
[37789b5f]385 uint64_t dcbaaptr = addr_to_phys(hc->dcbaa);
[cb89430]386 XHCI_REG_WR(hc->op_regs, XHCI_OP_DCBAAP_LO, LOWER32(dcbaaptr));
387 XHCI_REG_WR(hc->op_regs, XHCI_OP_DCBAAP_HI, UPPER32(dcbaaptr));
388 XHCI_REG_WR(hc->op_regs, XHCI_OP_MAX_SLOTS_EN, 0);
389
390 uint64_t crptr = xhci_trb_ring_get_dequeue_ptr(&hc->command_ring);
391 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_LO, LOWER32(crptr) >> 6);
392 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, UPPER32(crptr));
393
394 uint64_t erstptr = addr_to_phys(hc->event_ring.erst);
[12fba858]395 uint64_t erdp = hc->event_ring.dequeue_ptr;
[cb89430]396 xhci_interrupter_regs_t *intr0 = &hc->rt_regs->ir[0];
397 XHCI_REG_WR(intr0, XHCI_INTR_ERSTSZ, hc->event_ring.segment_count);
[12fba858]398 XHCI_REG_WR(intr0, XHCI_INTR_ERDP_LO, LOWER32(erdp));
399 XHCI_REG_WR(intr0, XHCI_INTR_ERDP_HI, UPPER32(erdp));
[cb89430]400 XHCI_REG_WR(intr0, XHCI_INTR_ERSTBA_LO, LOWER32(erstptr));
401 XHCI_REG_WR(intr0, XHCI_INTR_ERSTBA_HI, UPPER32(erstptr));
402
403 if (irq) {
404 XHCI_REG_SET(intr0, XHCI_INTR_IE, 1);
405 XHCI_REG_SET(hc->op_regs, XHCI_OP_INTE, 1);
406 }
407
408 XHCI_REG_SET(hc->op_regs, XHCI_OP_RS, 1);
409
410 return EOK;
411}
412
[ab5a0830]413/**
414 * Used only when polling. Shall supplement the irq_commands.
415 */
[e4d7363]416int hc_status(xhci_hc_t *hc, uint32_t *status)
[5cbccd4]417{
[ab5a0830]418 int ip = XHCI_REG_RD(hc->rt_regs->ir, XHCI_INTR_IP);
419 if (ip) {
420 *status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
421 XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
422 XHCI_REG_WR(hc->rt_regs->ir, XHCI_INTR_IP, 1);
423
424 /* interrupt handler expects status from irq_commands, which is
425 * in xhci order. */
426 *status = host2xhci(32, *status);
427 }
[62ba2cbe]428
[ab5a0830]429 usb_log_debug2("HC(%p): Polled status: %x", hc, *status);
[cb89430]430 return EOK;
431}
432
[e4d7363]433int hc_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch)
[5cbccd4]434{
[275f529]435 assert(batch);
436
[d32d51d]437 /* Check for root hub communication */
[17f24d9]438 if (batch->ep->address == xhci_rh_get_address(&hc->rh)) {
[d32d51d]439 usb_log_debug("XHCI root hub request.\n");
440 return xhci_rh_schedule(&hc->rh, batch);
441 }
442
[275f529]443 usb_log_debug2("EP(%d:%d) started %s transfer of size %lu.",
444 batch->ep->address, batch->ep->endpoint,
445 usb_str_transfer_type(batch->ep->transfer_type),
446 batch->buffer_size);
447
448 switch (batch->ep->transfer_type) {
449 case USB_TRANSFER_CONTROL:
450 /* TODO: Send setup stage TRB. */
451 /* TODO: Optionally, send data stage TRB followed by zero or
452 more normal TRB's. */
453 /* TODO: Send status stage TRB. */
454 /* TODO: Ring the appropriate doorbell. */
455 break;
456 case USB_TRANSFER_ISOCHRONOUS:
457 /* TODO: Implement me. */
458 break;
459 case USB_TRANSFER_BULK:
460 /* TODO: Implement me. */
461 break;
462 case USB_TRANSFER_INTERRUPT:
463 /* TODO: Implement me. */
464 break;
465 }
[e50bdd92]466
[d32d51d]467 return EOK;
[5cbccd4]468}
469
[472235a]470typedef int (*event_handler) (xhci_hc_t *, xhci_trb_t *trb);
471
472static event_handler event_handlers [] = {
473 [XHCI_TRB_TYPE_COMMAND_COMPLETION_EVENT] = &xhci_handle_command_completion,
474 [XHCI_TRB_TYPE_PORT_STATUS_CHANGE_EVENT] = &xhci_handle_port_status_change_event,
475};
476
477static int hc_handle_event(xhci_hc_t *hc, xhci_trb_t *trb, xhci_interrupter_regs_t *intr)
[7ee5408]478{
[472235a]479 unsigned type = TRB_TYPE(*trb);
480 if (type >= ARRAY_SIZE(event_handlers) || !event_handlers[type])
481 return ENOTSUP;
482
483 return event_handlers[type](hc, trb);
[7ee5408]484}
485
[cb89430]486static void hc_run_event_ring(xhci_hc_t *hc, xhci_event_ring_t *event_ring, xhci_interrupter_regs_t *intr)
[62ba2cbe]487{
[cb89430]488 int err;
[472235a]489 ssize_t size = 16;
490 xhci_trb_t *queue = malloc(sizeof(xhci_trb_t) * size);
491 if (!queue) {
492 usb_log_error("Not enough memory to run the event ring.");
493 return;
494 }
495
496 xhci_trb_t *head = queue;
497
498 while ((err = xhci_event_ring_dequeue(event_ring, head)) != ENOENT) {
499 if (err != EOK) {
[e50bdd92]500 usb_log_warning("Error while accessing event ring: %s", str_error(err));
501 break;
502 }
503
[472235a]504 usb_log_debug2("Dequeued trb from event ring: %s", xhci_trb_str_type(TRB_TYPE(*head)));
505 head++;
[adb4e683]506
507 /* Expand the array if needed. */
[472235a]508 if (head - queue >= size) {
[adb4e683]509 size *= 2;
[472235a]510 xhci_trb_t *new_queue = realloc(queue, size);
511 if (new_queue == NULL)
512 break; /* Will process only those TRBs we have memory for. */
[adb4e683]513
[472235a]514 head = new_queue + (head - queue);
[adb4e683]515 }
[cb89430]516 }
517
[adb4e683]518 /* Update the ERDP to make room in the ring. */
[472235a]519 usb_log_debug2("Copying from ring finished, updating ERDP.");
[a06fd64]520 hc->event_ring.dequeue_ptr = host2xhci(64, addr_to_phys(hc->event_ring.dequeue_trb));
[12fba858]521 uint64_t erdp = hc->event_ring.dequeue_ptr;
522 XHCI_REG_WR(intr, XHCI_INTR_ERDP_LO, LOWER32(erdp));
523 XHCI_REG_WR(intr, XHCI_INTR_ERDP_HI, UPPER32(erdp));
[a06fd64]524 XHCI_REG_SET(intr, XHCI_INTR_ERDP_EHB, 1);
[adb4e683]525
526 /* Handle all of the collected events if possible. */
[472235a]527 if (head == queue)
[adb4e683]528 usb_log_warning("No events to be handled!");
[472235a]529
530 for (xhci_trb_t *tail = queue; tail != head; tail++) {
531 if ((err = hc_handle_event(hc, tail, intr)) != EOK) {
532 usb_log_error("Failed to handle event: %s", str_error(err));
533 }
[adb4e683]534 }
535
[472235a]536 free(queue);
537 usb_log_debug2("Event ring run finished.");
[cb89430]538}
539
[e4d7363]540void hc_interrupt(xhci_hc_t *hc, uint32_t status)
[cb89430]541{
[ab5a0830]542 status = xhci2host(32, status);
[aee352c]543
[07c08ea]544 /* TODO: Figure out how root hub interrupts work. */
[8b415cc]545 if (status & XHCI_REG_MASK(XHCI_OP_PCD)) {
[07c08ea]546 usb_log_debug2("Root hub interrupt.");
547 xhci_rh_interrupt(&hc->rh);
[ab5a0830]548
549 status &= ~XHCI_REG_MASK(XHCI_OP_PCD);
[07c08ea]550 }
551
[cb89430]552 if (status & XHCI_REG_MASK(XHCI_OP_HSE)) {
553 usb_log_error("Host controller error occured. Bad things gonna happen...");
[ab5a0830]554 status &= ~XHCI_REG_MASK(XHCI_OP_HSE);
[cb89430]555 }
556
557 if (status & XHCI_REG_MASK(XHCI_OP_EINT)) {
[472235a]558 usb_log_debug2("Event interrupt, running the event ring.");
[ab5a0830]559 hc_run_event_ring(hc, &hc->event_ring, &hc->rt_regs->ir[0]);
560 status &= ~XHCI_REG_MASK(XHCI_OP_EINT);
[cb89430]561 }
[275f529]562
[cb89430]563 if (status & XHCI_REG_MASK(XHCI_OP_SRE)) {
564 usb_log_error("Save/Restore error occured. WTF, S/R mechanism not implemented!");
[ab5a0830]565 status &= ~XHCI_REG_MASK(XHCI_OP_SRE);
566 }
567
568 if (status) {
569 usb_log_error("Non-zero status after interrupt handling (%08x) - missing something?", status);
[cb89430]570 }
571}
572
[3256a6c]573static void hc_dcbaa_fini(xhci_hc_t *hc)
574{
[706a3e2]575 xhci_trb_ring_t* trb_ring;
[3256a6c]576 xhci_scratchpad_free(hc);
577
[5a9ae994]578 /* Idx 0 already deallocated by xhci_scratchpad_free. */
579 for (unsigned i = 1; i < hc->max_slots + 1; ++i) {
[decfc8d1]580 if (hc->dcbaa_virt[i].dev_ctx) {
581 free32(hc->dcbaa_virt[i].dev_ctx);
582 hc->dcbaa_virt[i].dev_ctx = NULL;
583 }
[706a3e2]584
[decfc8d1]585 for (unsigned i = 0; i < XHCI_EP_COUNT; ++i) {
586 trb_ring = hc->dcbaa_virt[i].trs[i];
587 if (trb_ring) {
588 hc->dcbaa_virt[i].trs[i] = NULL;
589 xhci_trb_ring_fini(trb_ring);
590 free32(trb_ring);
591 }
[3256a6c]592 }
593 }
594
595 free32(hc->dcbaa);
[73e5b62]596 free32(hc->dcbaa_virt);
[3256a6c]597}
598
[e4d7363]599void hc_fini(xhci_hc_t *hc)
[cb89430]600{
601 xhci_trb_ring_fini(&hc->command_ring);
602 xhci_event_ring_fini(&hc->event_ring);
[3256a6c]603 hc_dcbaa_fini(hc);
[c46c356]604 xhci_fini_commands(hc);
[d32d51d]605 xhci_rh_fini(&hc->rh);
[91ca111]606 pio_disable(hc->base, RNGSZ(hc->mmio_range));
[e4d7363]607 usb_log_info("HC(%p): Finalized.", hc);
[62ba2cbe]608}
609
[cb89430]610
[5cbccd4]611
612/**
613 * @}
614 */
Note: See TracBrowser for help on using the repository browser.