summaryrefslogtreecommitdiff
path: root/payloads/libpayload/drivers/usb/xhci.c
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@google.com>2020-03-17 19:32:14 -0700
committerPatrick Georgi <pgeorgi@google.com>2020-04-14 09:47:22 +0000
commit287cf6c7d101d98cdbba8926651d87945534b7d9 (patch)
treed584740b961638cd4c052eef3ed1c1d283400dc6 /payloads/libpayload/drivers/usb/xhci.c
parentbc885c194c0175b7a3ac9442cf9c82a0fa28ac2a (diff)
downloadcoreboot-287cf6c7d101d98cdbba8926651d87945534b7d9.tar.xz
lp/drivers/usb: Work around QEMU XHCI register issue
The QEMU XHCI controller does not support byte/word reads from the capability register and it expects dword reads only. In order to make this work move the access of the capability register fields to use macros instead of a packed struct bitfield. This issue was filed upstream: https://bugs.launchpad.net/qemu/+bug/1693050 The original fix attempt in 2012 was not effective: https://github.com/qemu/qemu/commit/6ee021d41078844df60a3a466e3829a3e82776f3 With this change the controller is detected properly by the libpayload USB drivers. Change-Id: I048ed14921a4c9c0620c10b315b42476b6e5c512 Signed-off-by: Duncan Laurie <dlaurie@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/39838 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de> Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Diffstat (limited to 'payloads/libpayload/drivers/usb/xhci.c')
-rw-r--r--payloads/libpayload/drivers/usb/xhci.c41
1 files changed, 23 insertions, 18 deletions
diff --git a/payloads/libpayload/drivers/usb/xhci.c b/payloads/libpayload/drivers/usb/xhci.c
index 0a69c5137b..2f61f8658a 100644
--- a/payloads/libpayload/drivers/usb/xhci.c
+++ b/payloads/libpayload/drivers/usb/xhci.c
@@ -185,26 +185,27 @@ xhci_init (unsigned long physical_bar)
goto _free_xhci;
}
- xhci->capreg = phys_to_virt(physical_bar);
- xhci->opreg = ((void *)xhci->capreg) + xhci->capreg->caplength;
- xhci->hcrreg = ((void *)xhci->capreg) + xhci->capreg->rtsoff;
- xhci->dbreg = ((void *)xhci->capreg) + xhci->capreg->dboff;
+ memcpy(&xhci->capreg, phys_to_virt(physical_bar), sizeof(xhci->capreg));
+ xhci->opreg = phys_to_virt(physical_bar) + CAP_GET(CAPLEN, xhci->capreg);
+ xhci->hcrreg = phys_to_virt(physical_bar) + xhci->capreg.rtsoff;
+ xhci->dbreg = phys_to_virt(physical_bar) + xhci->capreg.dboff;
+
xhci_debug("regbase: 0x%"PRIx32"\n", physical_bar);
- xhci_debug("caplen: 0x%"PRIx32"\n", xhci->capreg->caplength);
- xhci_debug("rtsoff: 0x%"PRIx32"\n", xhci->capreg->rtsoff);
- xhci_debug("dboff: 0x%"PRIx32"\n", xhci->capreg->dboff);
+ xhci_debug("caplen: 0x%"PRIx32"\n", CAP_GET(CAPLEN, xhci->capreg));
+ xhci_debug("rtsoff: 0x%"PRIx32"\n", xhci->capreg.rtsoff);
+ xhci_debug("dboff: 0x%"PRIx32"\n", xhci->capreg.dboff);
xhci_debug("hciversion: %"PRIx8".%"PRIx8"\n",
- xhci->capreg->hciver_hi, xhci->capreg->hciver_lo);
- if ((xhci->capreg->hciversion < 0x96) ||
- (xhci->capreg->hciversion > 0x110)) {
+ CAP_GET(CAPVER_HI, xhci->capreg), CAP_GET(CAPVER_LO, xhci->capreg));
+ if ((CAP_GET(CAPVER, xhci->capreg) < 0x96) ||
+ (CAP_GET(CAPVER, xhci->capreg) > 0x110)) {
xhci_debug("Unsupported xHCI version\n");
goto _free_xhci;
}
xhci_debug("context size: %dB\n", CTXSIZE(xhci));
- xhci_debug("maxslots: 0x%02lx\n", xhci->capreg->MaxSlots);
- xhci_debug("maxports: 0x%02lx\n", xhci->capreg->MaxPorts);
+ xhci_debug("maxslots: 0x%02lx\n", CAP_GET(MAXSLOTS, xhci->capreg));
+ xhci_debug("maxports: 0x%02lx\n", CAP_GET(MAXPORTS, xhci->capreg));
const unsigned pagesize = xhci->opreg->pagesize << 12;
xhci_debug("pagesize: 0x%04x\n", pagesize);
@@ -213,7 +214,8 @@ xhci_init (unsigned long physical_bar)
* structures at first and can still chicken out easily if we run out
* of memory.
*/
- xhci->max_slots_en = xhci->capreg->MaxSlots & CONFIG_LP_MASK_MaxSlotsEn;
+ xhci->max_slots_en = CAP_GET(MAXSLOTS, xhci->capreg) &
+ CONFIG_LP_MASK_MaxSlotsEn;
xhci->dcbaa = xhci_align(64, (xhci->max_slots_en + 1) * sizeof(u64));
xhci->dev = malloc((xhci->max_slots_en + 1) * sizeof(*xhci->dev));
if (!xhci->dcbaa || !xhci->dev) {
@@ -227,8 +229,9 @@ xhci_init (unsigned long physical_bar)
* Let dcbaa[0] point to another array of pointers, sp_ptrs.
* The pointers therein point to scratchpad buffers (pages).
*/
- const size_t max_sp_bufs = xhci->capreg->Max_Scratchpad_Bufs_Hi << 5 |
- xhci->capreg->Max_Scratchpad_Bufs_Lo;
+ const size_t max_sp_bufs =
+ CAP_GET(MAX_SCRATCH_BUFS_HI, xhci->capreg) << 5 |
+ CAP_GET(MAX_SCRATCH_BUFS_LO, xhci->capreg);
xhci_debug("max scratchpad bufs: 0x%zx\n", max_sp_bufs);
if (max_sp_bufs) {
const size_t sp_ptrs_size = max_sp_bufs * sizeof(u64);
@@ -376,7 +379,8 @@ xhci_reinit (hci_t *controller)
xhci_debug("event ring @%p (0x%08x)\n",
xhci->er.ring, virt_to_phys(xhci->er.ring));
xhci_debug("ERST Max: 0x%lx -> 0x%lx entries\n",
- xhci->capreg->ERST_Max, 1 << xhci->capreg->ERST_Max);
+ CAP_GET(ERST_MAX, xhci->capreg),
+ 1 << CAP_GET(ERST_MAX, xhci->capreg));
memset((void*)xhci->ev_ring_table, 0x00, sizeof(erst_entry_t));
xhci->ev_ring_table[0].seg_base_lo = virt_to_phys(xhci->er.ring);
xhci->ev_ring_table[0].seg_base_hi = 0;
@@ -432,8 +436,9 @@ xhci_shutdown(hci_t *const controller)
#endif
if (xhci->sp_ptrs) {
- size_t max_sp_bufs = xhci->capreg->Max_Scratchpad_Bufs_Hi << 5 |
- xhci->capreg->Max_Scratchpad_Bufs_Lo;
+ const size_t max_sp_bufs =
+ CAP_GET(MAX_SCRATCH_BUFS_HI, xhci->capreg) << 5 |
+ CAP_GET(MAX_SCRATCH_BUFS_LO, xhci->capreg);
for (i = 0; i < max_sp_bufs; ++i) {
if (xhci->sp_ptrs[i])
free(phys_to_virt(xhci->sp_ptrs[i]));