From c91590ccfdb9ea3db5c25153c01cf1f61bb7081b Mon Sep 17 00:00:00 2001 From: YanLiang Date: Tue, 22 May 2018 19:41:12 +0800 Subject: [PATCH] DM USB: xHCI: refine xHCI extended capability related functions. Every platform should have their own xHCI specific extended capabilities, but the current xHCI DM is not scalable for them. This patch refines related logic to make it scalable. Current code only support 4 registers(4*32) as basic extended capabilites. Base on this new implementation, the mmio range from excapoff to regsend will cover real excap size according to the cap parameter. Change-Id: Ic55a4494e090ec255939cdb8f32950e3c8a66082 Signed-off-by: Liang Yang Reviewed-by: Xiaoguang Wu Reviewed-by: Yu Wang Reviewed-by: Kevin Tian --- devicemodel/hw/pci/xhci.c | 136 ++++++++++++++++++++++------------ devicemodel/include/xhci.h | 16 ++++ devicemodel/include/xhcireg.h | 11 +++ 3 files changed, 115 insertions(+), 48 deletions(-) mode change 100644 => 100755 devicemodel/hw/pci/xhci.c mode change 100644 => 100755 devicemodel/include/xhci.h mode change 100644 => 100755 devicemodel/include/xhcireg.h diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c old mode 100644 new mode 100755 index 13bc6572a..534088475 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -211,6 +211,51 @@ struct pci_xhci_rtsregs { uint32_t event_pcs; /* producer cycle state flag */ }; +struct pci_xhci_excap_ptr { + uint8_t cap_id; + uint8_t cap_ptr; +} __attribute__((packed)); + +struct pci_xhci_excap_prot { + struct pci_xhci_excap_ptr excap_ptr; + uint8_t rev_min; + uint8_t rev_maj; + char string[4]; + uint8_t port_off; + uint8_t port_cnt; + uint16_t psic_prot_def; + uint32_t reserve; +} __attribute__((packed)); + +struct pci_xhci_excap { + uint32_t start; + uint32_t end; + void *data; +}; + +static DEFINE_EXCP_PROT(u2_prot, + 0x08, + 2, + XHCI_MAX_DEVS/2 + 1, + XHCI_MAX_DEVS/2); +static DEFINE_EXCP_PROT(u3_prot, + 0x14, + 3, + 1, + XHCI_MAX_DEVS/2); + +/* + * default xhci extended capabilities + * excap start excap end register value + * 0x8000 0x8010 0x02000802 + * 0x8020 0x8030 0x03001402 + */ +struct pci_xhci_excap excap_group_dft[] = { + {0x8000, 0x8010, &excap_u2_prot}, + {0x8020, 0x8030, &excap_u3_prot}, + {EXCAP_GROUP_END, EXCAP_GROUP_END, EXCAP_GROUP_NULL} +}; + struct pci_xhci_vdev; /* @@ -245,6 +290,7 @@ struct pci_xhci_vdev { uint32_t rtsoff; /* runtime register space offset */ uint32_t hccparams2; /* capability parameters 2 */ + uint32_t excapoff; /* ext-capability registers offset */ uint32_t regsend; /* end of configuration registers */ struct pci_xhci_opregs opregs; @@ -255,6 +301,7 @@ struct pci_xhci_vdev { struct pci_xhci_dev_emu **slots; /* slots assigned from 1 */ int ndevices; + void *excap_ptr; int usb2_port_start; int usb3_port_start; uint8_t *native_assign_ports[USB_NATIVE_NUM_BUS]; @@ -2683,7 +2730,7 @@ pci_xhci_write(struct vmctx *ctx, pci_xhci_hostop_write(xdev, offset, value); else if (offset < xdev->rtsoff) pci_xhci_dbregs_write(xdev, offset, value); - else if (offset < xdev->regsend) + else if (offset < xdev->excapoff) pci_xhci_rtsregs_write(xdev, offset, value); else UPRINTF(LWRN, "write invalid offset %ld\r\n", offset); @@ -2838,48 +2885,33 @@ pci_xhci_rtsregs_read(struct pci_xhci_vdev *xdev, uint64_t offset) } static uint64_t -pci_xhci_xecp_read(struct pci_xhci_vdev *xdev, uint64_t offset) +pci_xhci_excap_read(struct pci_xhci_vdev *xdev, uint64_t offset) { - uint32_t value; + uint32_t value = 0; + uint32_t off = offset; + struct pci_xhci_excap *excap; - offset -= xdev->regsend; - value = 0; + assert(xdev); - switch (offset) { - case 0: - /* rev major | rev minor | next-cap | cap-id */ - value = (0x02 << 24) | (4 << 8) | XHCI_ID_PROTOCOLS; - break; - case 4: - /* name string = "USB" */ - value = 0x20425355; - break; - case 8: - /* psic | proto-defined | compat # | compat offset */ - value = ((XHCI_MAX_DEVS/2) << 8) | xdev->usb2_port_start; - break; - case 12: - break; - case 16: - /* rev major | rev minor | next-cap | cap-id */ - value = (0x03 << 24) | XHCI_ID_PROTOCOLS; - break; - case 20: - /* name string = "USB" */ - value = 0x20425355; - break; - case 24: - /* psic | proto-defined | compat # | compat offset */ - value = ((XHCI_MAX_DEVS/2) << 8) | xdev->usb3_port_start; - break; - case 28: - break; - default: - UPRINTF(LDBG, "xecp invalid offset 0x%lx\r\n", offset); - break; + excap = xdev->excap_ptr; + + while (excap && excap->start != EXCAP_GROUP_END) { + if (off >= excap->start && off < excap->end) + break; + excap++; } - UPRINTF(LDBG, "xecp read offset 0x%lx -> 0x%x\r\n", offset, value); + if (!excap || excap->start == EXCAP_GROUP_END) { + UPRINTF(LWRN, "extended capability 0x%lx can't be found\r\n", + offset); + return value; + } + + if (excap->start != EXCAP_GROUP_END) { + off -= excap->start; + memcpy(&value, (uint32_t *)excap->data + off / 4, + sizeof(uint32_t)); + } return value; } @@ -2906,10 +2938,10 @@ pci_xhci_read(struct vmctx *ctx, value = pci_xhci_hostop_read(xdev, offset); else if (offset < xdev->rtsoff) value = pci_xhci_dbregs_read(xdev, offset); - else if (offset < xdev->regsend) + else if (offset < xdev->excapoff) value = pci_xhci_rtsregs_read(xdev, offset); - else if (offset < (xdev->regsend + 4*32)) - value = pci_xhci_xecp_read(xdev, offset); + else if (offset < xdev->regsend) + value = pci_xhci_excap_read(xdev, offset); else { value = 0; UPRINTF(LDBG, "read invalid offset %ld\r\n", offset); @@ -3327,6 +3359,7 @@ static int pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) { struct pci_xhci_vdev *xdev; + struct pci_xhci_excap *excap; int error; if (xhci_in_use) { @@ -3348,6 +3381,8 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) xdev->usb2_port_start = (XHCI_MAX_DEVS/2) + 1; xdev->usb3_port_start = 1; + xdev->excap_ptr = excap_group_dft; + /* discover devices */ error = pci_xhci_parse_opts(xdev, opts); if (error < 0) @@ -3398,14 +3433,19 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) pci_xhci_reset(xdev); - /* only 1 intrpter */ - xdev->regsend = xdev->rtsoff + 0x20 + 32; + excap = xdev->excap_ptr; + xdev->excapoff = excap->start; + + while (excap && excap->start != EXCAP_GROUP_END) + excap++; + + xdev->regsend = (excap - 1)->end; /* * Set extended capabilities pointer to be after regsend; - * value of xecp field is 32-bit offset. + * value of excap field is 32-bit offset. */ - xdev->hccparams1 |= XHCI_SET_HCCP1_XECP(xdev->regsend/4); + xdev->hccparams1 |= XHCI_SET_HCCP1_XECP(XHCI_EXCAP_PTR); pci_set_cfgdata16(dev, PCIR_DEVICE, 0x1E31); pci_set_cfgdata16(dev, PCIR_VENDOR, 0x8086); @@ -3416,9 +3456,9 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) pci_emul_add_msicap(dev, 1); - /* regsend + xecp registers */ - pci_emul_alloc_bar(dev, 0, PCIBAR_MEM32, xdev->regsend + 4*32); - UPRINTF(LDBG, "pci_emu_alloc: %d\r\n", xdev->regsend + 4*32); + /* regsend registers */ + pci_emul_alloc_bar(dev, 0, PCIBAR_MEM32, xdev->regsend); + UPRINTF(LDBG, "pci_emu_alloc: %d\r\n", xdev->regsend); pci_lintr_request(dev); diff --git a/devicemodel/include/xhci.h b/devicemodel/include/xhci.h old mode 100644 new mode 100755 index f0366ffaa..547583555 --- a/devicemodel/include/xhci.h +++ b/devicemodel/include/xhci.h @@ -86,6 +86,22 @@ enum { #define XHCI_TD_ALIGN 64 /* bytes */ #define XHCI_PAGE_SIZE 4096 /* bytes */ +/* xHCI extended capability supported protocol fileds */ +#define DEFINE_EXCP_PROT(name, next_ptr, revmaj, portoff, portcnt) \ + struct pci_xhci_excap_prot excap_##name = { \ + { \ + .cap_id = XHCI_ID_PROTOCOLS, \ + .cap_ptr = next_ptr \ + }, \ + .rev_min = 0x00, \ + .rev_maj = revmaj, \ + .string = "USB"#revmaj, \ + .port_off = portoff, \ + .port_cnt = portcnt, \ + .psic_prot_def = 0x00, \ + .reserve = 0x00 \ +} + struct xhci_slot_ctx { volatile uint32_t dwSctx0; #define XHCI_SCTX_0_ROUTE_SET(x) ((x) & 0xFFFFF) diff --git a/devicemodel/include/xhcireg.h b/devicemodel/include/xhcireg.h old mode 100644 new mode 100755 index f2b31c784..bd872c2cd --- a/devicemodel/include/xhcireg.h +++ b/devicemodel/include/xhcireg.h @@ -228,6 +228,17 @@ #define XHCI_ID_MSG_IRQ 0x0005 #define XHCI_ID_USB_LOCAL_MEM 0x0006 +/* + * xHCI extended capability pointer in HCCPARAMS1. + * The excap offset is calculated by left shift 2 + * bits which equals 0x8000 + */ +#define XHCI_EXCAP_PTR 0x2000 + +/* xHCI extended capability group end marker */ +#define EXCAP_GROUP_END 0xFFFF +#define EXCAP_GROUP_NULL NULL + /* XHCI register R/W wrappers */ #define XREAD1(sc, what, a) \ bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \