summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src/hw/usb-xhci.c
diff options
context:
space:
mode:
authorRajithaY <rajithax.yerrumsetty@intel.com>2017-04-25 03:31:15 -0700
committerRajitha Yerrumchetty <rajithax.yerrumsetty@intel.com>2017-05-22 06:48:08 +0000
commitbb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch)
treeca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/seabios/src/hw/usb-xhci.c
parenta14b48d18a9ed03ec191cf16b162206998a895ce (diff)
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to kvmfornfv repo and make use of the updated latest qemu for the execution of all testcase Change-Id: I1280af507a857675c7f81d30c95255635667bdd7 Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/seabios/src/hw/usb-xhci.c')
-rw-r--r--qemu/roms/seabios/src/hw/usb-xhci.c1161
1 files changed, 0 insertions, 1161 deletions
diff --git a/qemu/roms/seabios/src/hw/usb-xhci.c b/qemu/roms/seabios/src/hw/usb-xhci.c
deleted file mode 100644
index 654febaad..000000000
--- a/qemu/roms/seabios/src/hw/usb-xhci.c
+++ /dev/null
@@ -1,1161 +0,0 @@
-// Code for handling XHCI "Super speed" USB controllers.
-//
-// Copyright (C) 2013 Gerd Hoffmann <kraxel@redhat.com>
-// Copyright (C) 2014 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "config.h" // CONFIG_*
-#include "malloc.h" // memalign_low
-#include "memmap.h" // PAGE_SIZE
-#include "output.h" // dprintf
-#include "pci.h" // pci_bdf_to_bus
-#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_XHCI
-#include "pci_regs.h" // PCI_BASE_ADDRESS_0
-#include "string.h" // memcpy
-#include "usb.h" // struct usb_s
-#include "usb-xhci.h" // struct ehci_qh
-#include "util.h" // timer_calc
-#include "x86.h" // readl
-
-// --------------------------------------------------------------
-// configuration
-
-#define XHCI_RING_ITEMS 16
-#define XHCI_RING_SIZE (XHCI_RING_ITEMS*sizeof(struct xhci_trb))
-
-/*
- * xhci_ring structs are allocated with XHCI_RING_SIZE alignment,
- * then we can get it from a trb pointer (provided by evt ring).
- */
-#define XHCI_RING(_trb) \
- ((struct xhci_ring*)((u32)(_trb) & ~(XHCI_RING_SIZE-1)))
-
-// --------------------------------------------------------------
-// bit definitions
-
-#define XHCI_CMD_RS (1<<0)
-#define XHCI_CMD_HCRST (1<<1)
-#define XHCI_CMD_INTE (1<<2)
-#define XHCI_CMD_HSEE (1<<3)
-#define XHCI_CMD_LHCRST (1<<7)
-#define XHCI_CMD_CSS (1<<8)
-#define XHCI_CMD_CRS (1<<9)
-#define XHCI_CMD_EWE (1<<10)
-#define XHCI_CMD_EU3S (1<<11)
-
-#define XHCI_STS_HCH (1<<0)
-#define XHCI_STS_HSE (1<<2)
-#define XHCI_STS_EINT (1<<3)
-#define XHCI_STS_PCD (1<<4)
-#define XHCI_STS_SSS (1<<8)
-#define XHCI_STS_RSS (1<<9)
-#define XHCI_STS_SRE (1<<10)
-#define XHCI_STS_CNR (1<<11)
-#define XHCI_STS_HCE (1<<12)
-
-#define XHCI_PORTSC_CCS (1<<0)
-#define XHCI_PORTSC_PED (1<<1)
-#define XHCI_PORTSC_OCA (1<<3)
-#define XHCI_PORTSC_PR (1<<4)
-#define XHCI_PORTSC_PLS_SHIFT 5
-#define XHCI_PORTSC_PLS_MASK 0xf
-#define XHCI_PORTSC_PP (1<<9)
-#define XHCI_PORTSC_SPEED_SHIFT 10
-#define XHCI_PORTSC_SPEED_MASK 0xf
-#define XHCI_PORTSC_SPEED_FULL (1<<10)
-#define XHCI_PORTSC_SPEED_LOW (2<<10)
-#define XHCI_PORTSC_SPEED_HIGH (3<<10)
-#define XHCI_PORTSC_SPEED_SUPER (4<<10)
-#define XHCI_PORTSC_PIC_SHIFT 14
-#define XHCI_PORTSC_PIC_MASK 0x3
-#define XHCI_PORTSC_LWS (1<<16)
-#define XHCI_PORTSC_CSC (1<<17)
-#define XHCI_PORTSC_PEC (1<<18)
-#define XHCI_PORTSC_WRC (1<<19)
-#define XHCI_PORTSC_OCC (1<<20)
-#define XHCI_PORTSC_PRC (1<<21)
-#define XHCI_PORTSC_PLC (1<<22)
-#define XHCI_PORTSC_CEC (1<<23)
-#define XHCI_PORTSC_CAS (1<<24)
-#define XHCI_PORTSC_WCE (1<<25)
-#define XHCI_PORTSC_WDE (1<<26)
-#define XHCI_PORTSC_WOE (1<<27)
-#define XHCI_PORTSC_DR (1<<30)
-#define XHCI_PORTSC_WPR (1<<31)
-
-#define TRB_C (1<<0)
-#define TRB_TYPE_SHIFT 10
-#define TRB_TYPE_MASK 0x3f
-#define TRB_TYPE(t) (((t) >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
-
-#define TRB_EV_ED (1<<2)
-
-#define TRB_TR_ENT (1<<1)
-#define TRB_TR_ISP (1<<2)
-#define TRB_TR_NS (1<<3)
-#define TRB_TR_CH (1<<4)
-#define TRB_TR_IOC (1<<5)
-#define TRB_TR_IDT (1<<6)
-#define TRB_TR_TBC_SHIFT 7
-#define TRB_TR_TBC_MASK 0x3
-#define TRB_TR_BEI (1<<9)
-#define TRB_TR_TLBPC_SHIFT 16
-#define TRB_TR_TLBPC_MASK 0xf
-#define TRB_TR_FRAMEID_SHIFT 20
-#define TRB_TR_FRAMEID_MASK 0x7ff
-#define TRB_TR_SIA (1<<31)
-
-#define TRB_TR_DIR (1<<16)
-
-#define TRB_CR_SLOTID_SHIFT 24
-#define TRB_CR_SLOTID_MASK 0xff
-#define TRB_CR_EPID_SHIFT 16
-#define TRB_CR_EPID_MASK 0x1f
-
-#define TRB_CR_BSR (1<<9)
-#define TRB_CR_DC (1<<9)
-
-#define TRB_LK_TC (1<<1)
-
-#define TRB_INTR_SHIFT 22
-#define TRB_INTR_MASK 0x3ff
-#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
-
-typedef enum TRBType {
- TRB_RESERVED = 0,
- TR_NORMAL,
- TR_SETUP,
- TR_DATA,
- TR_STATUS,
- TR_ISOCH,
- TR_LINK,
- TR_EVDATA,
- TR_NOOP,
- CR_ENABLE_SLOT,
- CR_DISABLE_SLOT,
- CR_ADDRESS_DEVICE,
- CR_CONFIGURE_ENDPOINT,
- CR_EVALUATE_CONTEXT,
- CR_RESET_ENDPOINT,
- CR_STOP_ENDPOINT,
- CR_SET_TR_DEQUEUE,
- CR_RESET_DEVICE,
- CR_FORCE_EVENT,
- CR_NEGOTIATE_BW,
- CR_SET_LATENCY_TOLERANCE,
- CR_GET_PORT_BANDWIDTH,
- CR_FORCE_HEADER,
- CR_NOOP,
- ER_TRANSFER = 32,
- ER_COMMAND_COMPLETE,
- ER_PORT_STATUS_CHANGE,
- ER_BANDWIDTH_REQUEST,
- ER_DOORBELL,
- ER_HOST_CONTROLLER,
- ER_DEVICE_NOTIFICATION,
- ER_MFINDEX_WRAP,
-} TRBType;
-
-typedef enum TRBCCode {
- CC_INVALID = 0,
- CC_SUCCESS,
- CC_DATA_BUFFER_ERROR,
- CC_BABBLE_DETECTED,
- CC_USB_TRANSACTION_ERROR,
- CC_TRB_ERROR,
- CC_STALL_ERROR,
- CC_RESOURCE_ERROR,
- CC_BANDWIDTH_ERROR,
- CC_NO_SLOTS_ERROR,
- CC_INVALID_STREAM_TYPE_ERROR,
- CC_SLOT_NOT_ENABLED_ERROR,
- CC_EP_NOT_ENABLED_ERROR,
- CC_SHORT_PACKET,
- CC_RING_UNDERRUN,
- CC_RING_OVERRUN,
- CC_VF_ER_FULL,
- CC_PARAMETER_ERROR,
- CC_BANDWIDTH_OVERRUN,
- CC_CONTEXT_STATE_ERROR,
- CC_NO_PING_RESPONSE_ERROR,
- CC_EVENT_RING_FULL_ERROR,
- CC_INCOMPATIBLE_DEVICE_ERROR,
- CC_MISSED_SERVICE_ERROR,
- CC_COMMAND_RING_STOPPED,
- CC_COMMAND_ABORTED,
- CC_STOPPED,
- CC_STOPPED_LENGTH_INVALID,
- CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
- CC_ISOCH_BUFFER_OVERRUN = 31,
- CC_EVENT_LOST_ERROR,
- CC_UNDEFINED_ERROR,
- CC_INVALID_STREAM_ID_ERROR,
- CC_SECONDARY_BANDWIDTH_ERROR,
- CC_SPLIT_TRANSACTION_ERROR
-} TRBCCode;
-
-enum {
- PLS_U0 = 0,
- PLS_U1 = 1,
- PLS_U2 = 2,
- PLS_U3 = 3,
- PLS_DISABLED = 4,
- PLS_RX_DETECT = 5,
- PLS_INACTIVE = 6,
- PLS_POLLING = 7,
- PLS_RECOVERY = 8,
- PLS_HOT_RESET = 9,
- PLS_COMPILANCE_MODE = 10,
- PLS_TEST_MODE = 11,
- PLS_RESUME = 15,
-};
-
-#define xhci_get_field(data, field) \
- (((data) >> field##_SHIFT) & field##_MASK)
-
-// --------------------------------------------------------------
-// state structs
-
-struct xhci_ring {
- struct xhci_trb ring[XHCI_RING_ITEMS];
- struct xhci_trb evt;
- u32 eidx;
- u32 nidx;
- u32 cs;
- struct mutex_s lock;
-};
-
-struct usb_xhci_s {
- struct usb_s usb;
-
- /* devinfo */
- u32 baseaddr;
- u32 xcap;
- u32 ports;
- u32 slots;
- u8 context64;
-
- /* xhci registers */
- struct xhci_caps *caps;
- struct xhci_op *op;
- struct xhci_pr *pr;
- struct xhci_ir *ir;
- struct xhci_db *db;
-
- /* xhci data structures */
- struct xhci_devlist *devs;
- struct xhci_ring *cmds;
- struct xhci_ring *evts;
- struct xhci_er_seg *eseg;
-};
-
-struct xhci_pipe {
- struct xhci_ring reqs;
-
- struct usb_pipe pipe;
- u32 slotid;
- u32 epid;
- void *buf;
- int bufused;
-};
-
-// --------------------------------------------------------------
-// tables
-
-static const char *speed_name[16] = {
- [ 0 ] = " - ",
- [ 1 ] = "Full",
- [ 2 ] = "Low",
- [ 3 ] = "High",
- [ 4 ] = "Super",
-};
-
-static const int speed_from_xhci[16] = {
- [ 0 ] = -1,
- [ 1 ] = USB_FULLSPEED,
- [ 2 ] = USB_LOWSPEED,
- [ 3 ] = USB_HIGHSPEED,
- [ 4 ] = USB_SUPERSPEED,
- [ 5 ... 15 ] = -1,
-};
-
-static const int speed_to_xhci[] = {
- [ USB_FULLSPEED ] = 1,
- [ USB_LOWSPEED ] = 2,
- [ USB_HIGHSPEED ] = 3,
- [ USB_SUPERSPEED ] = 4,
-};
-
-static const int eptype_to_xhci_in[] = {
- [ USB_ENDPOINT_XFER_CONTROL] = 4,
- [ USB_ENDPOINT_XFER_ISOC ] = 5,
- [ USB_ENDPOINT_XFER_BULK ] = 6,
- [ USB_ENDPOINT_XFER_INT ] = 7,
-};
-
-static const int eptype_to_xhci_out[] = {
- [ USB_ENDPOINT_XFER_CONTROL] = 4,
- [ USB_ENDPOINT_XFER_ISOC ] = 1,
- [ USB_ENDPOINT_XFER_BULK ] = 2,
- [ USB_ENDPOINT_XFER_INT ] = 3,
-};
-
-static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout)
-{
- u32 end = timer_calc(timeout);
-
- while ((readl(reg) & mask) != value) {
- if (timer_check(end)) {
- warn_timeout();
- return -1;
- }
- yield();
- }
- return 0;
-}
-
-
-/****************************************************************
- * Root hub
- ****************************************************************/
-
-#define XHCI_TIME_POSTPOWER 20
-
-// Check if device attached to port
-static void
-xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc)
-{
- u32 pls = xhci_get_field(portsc, XHCI_PORTSC_PLS);
- u32 speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED);
-
- dprintf(loglevel, "%s port #%d: 0x%08x,%s%s pls %d, speed %d [%s]\n",
- prefix, port + 1, portsc,
- (portsc & XHCI_PORTSC_PP) ? " powered," : "",
- (portsc & XHCI_PORTSC_PED) ? " enabled," : "",
- pls, speed, speed_name[speed]);
-}
-
-static int
-xhci_hub_detect(struct usbhub_s *hub, u32 port)
-{
- struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
- u32 portsc = readl(&xhci->pr[port].portsc);
- return (portsc & XHCI_PORTSC_CCS) ? 1 : 0;
-}
-
-// Reset device on port
-static int
-xhci_hub_reset(struct usbhub_s *hub, u32 port)
-{
- struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
- u32 portsc = readl(&xhci->pr[port].portsc);
- if (!(portsc & XHCI_PORTSC_CCS))
- // Device no longer connected?!
- return -1;
-
- switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) {
- case PLS_U0:
- // A USB3 port - controller automatically performs reset
- break;
- case PLS_POLLING:
- // A USB2 port - perform device reset
- xhci_print_port_state(3, __func__, port, portsc);
- writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
- break;
- default:
- return -1;
- }
-
- // Wait for device to complete reset and be enabled
- u32 end = timer_calc(100);
- for (;;) {
- portsc = readl(&xhci->pr[port].portsc);
- if (!(portsc & XHCI_PORTSC_CCS))
- // Device disconnected during reset
- return -1;
- if (portsc & XHCI_PORTSC_PED)
- // Reset complete
- break;
- if (timer_check(end)) {
- warn_timeout();
- return -1;
- }
- yield();
- }
-
- int rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
- xhci_print_port_state(1, "XHCI", port, portsc);
- return rc;
-}
-
-static void
-xhci_hub_disconnect(struct usbhub_s *hub, u32 port)
-{
- // XXX - should turn the port power off.
-}
-
-static struct usbhub_op_s xhci_hub_ops = {
- .detect = xhci_hub_detect,
- .reset = xhci_hub_reset,
- .disconnect = xhci_hub_disconnect,
-};
-
-// Find any devices connected to the root hub.
-static int
-xhci_check_ports(struct usb_xhci_s *xhci)
-{
- // Wait for port power to stabilize.
- msleep(XHCI_TIME_POSTPOWER);
-
- struct usbhub_s hub;
- memset(&hub, 0, sizeof(hub));
- hub.cntl = &xhci->usb;
- hub.portcount = xhci->ports;
- hub.op = &xhci_hub_ops;
- usb_enumerate(&hub);
- return hub.devcount;
-}
-
-
-/****************************************************************
- * Setup
- ****************************************************************/
-
-static void
-xhci_free_pipes(struct usb_xhci_s *xhci)
-{
- // XXX - should walk list of pipes and free unused pipes.
-}
-
-static void
-configure_xhci(void *data)
-{
- struct usb_xhci_s *xhci = data;
- u32 reg;
-
- xhci->devs = memalign_high(64, sizeof(*xhci->devs) * (xhci->slots + 1));
- xhci->eseg = memalign_high(64, sizeof(*xhci->eseg));
- xhci->cmds = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->cmds));
- xhci->evts = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->evts));
- if (!xhci->devs || !xhci->cmds || !xhci->evts || !xhci->eseg) {
- warn_noalloc();
- goto fail;
- }
- memset(xhci->devs, 0, sizeof(*xhci->devs) * (xhci->slots + 1));
- memset(xhci->cmds, 0, sizeof(*xhci->cmds));
- memset(xhci->evts, 0, sizeof(*xhci->evts));
- memset(xhci->eseg, 0, sizeof(*xhci->eseg));
-
- reg = readl(&xhci->op->usbcmd);
- if (reg & XHCI_CMD_RS) {
- reg &= ~XHCI_CMD_RS;
- writel(&xhci->op->usbcmd, reg);
- if (wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32) != 0)
- goto fail;
- }
-
- dprintf(3, "%s: resetting\n", __func__);
- writel(&xhci->op->usbcmd, XHCI_CMD_HCRST);
- if (wait_bit(&xhci->op->usbcmd, XHCI_CMD_HCRST, 0, 100) != 0)
- goto fail;
- if (wait_bit(&xhci->op->usbsts, XHCI_STS_CNR, 0, 100) != 0)
- goto fail;
-
- writel(&xhci->op->config, xhci->slots);
- writel(&xhci->op->dcbaap_low, (u32)xhci->devs);
- writel(&xhci->op->dcbaap_high, 0);
- writel(&xhci->op->crcr_low, (u32)xhci->cmds | 1);
- writel(&xhci->op->crcr_high, 0);
- xhci->cmds->cs = 1;
-
- xhci->eseg->ptr_low = (u32)xhci->evts;
- xhci->eseg->ptr_high = 0;
- xhci->eseg->size = XHCI_RING_ITEMS;
- writel(&xhci->ir->erstsz, 1);
- writel(&xhci->ir->erdp_low, (u32)xhci->evts);
- writel(&xhci->ir->erdp_high, 0);
- writel(&xhci->ir->erstba_low, (u32)xhci->eseg);
- writel(&xhci->ir->erstba_high, 0);
- xhci->evts->cs = 1;
-
- reg = readl(&xhci->caps->hcsparams2);
- u32 spb = (reg >> 21 & 0x1f) << 5 | reg >> 27;
- if (spb) {
- dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb);
- u64 *spba = memalign_high(64, sizeof(*spba) * spb);
- void *pad = memalign_high(PAGE_SIZE, PAGE_SIZE * spb);
- if (!spba || !pad) {
- warn_noalloc();
- free(spba);
- free(pad);
- goto fail;
- }
- int i;
- for (i = 0; i < spb; i++)
- spba[i] = (u32)pad + (i * PAGE_SIZE);
- xhci->devs[0].ptr_low = (u32)spba;
- xhci->devs[0].ptr_high = 0;
- }
-
- reg = readl(&xhci->op->usbcmd);
- reg |= XHCI_CMD_RS;
- writel(&xhci->op->usbcmd, reg);
-
- // Find devices
- int count = xhci_check_ports(xhci);
- xhci_free_pipes(xhci);
- if (count)
- // Success
- return;
-
- // No devices found - shutdown and free controller.
- dprintf(1, "XHCI no devices found\n");
- reg = readl(&xhci->op->usbcmd);
- reg &= ~XHCI_CMD_RS;
- writel(&xhci->op->usbcmd, reg);
- wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32);
-
-fail:
- free(xhci->eseg);
- free(xhci->evts);
- free(xhci->cmds);
- free(xhci->devs);
- free(xhci);
-}
-
-static void
-xhci_controller_setup(struct pci_device *pci)
-{
- struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci));
- if (!xhci) {
- warn_noalloc();
- return;
- }
- memset(xhci, 0, sizeof(*xhci));
-
- wait_preempt(); // Avoid pci_config_readl when preempting
- xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
- & PCI_BASE_ADDRESS_MEM_MASK;
- xhci->caps = (void*)(xhci->baseaddr);
- xhci->op = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength));
- xhci->pr = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength) + 0x400);
- xhci->db = (void*)(xhci->baseaddr + readl(&xhci->caps->dboff));
- xhci->ir = (void*)(xhci->baseaddr + readl(&xhci->caps->rtsoff) + 0x20);
-
- u32 hcs1 = readl(&xhci->caps->hcsparams1);
- u32 hcc = readl(&xhci->caps->hccparams);
- xhci->ports = (hcs1 >> 24) & 0xff;
- xhci->slots = hcs1 & 0xff;
- xhci->xcap = ((hcc >> 16) & 0xffff) << 2;
- xhci->context64 = (hcc & 0x04) ? 1 : 0;
-
- xhci->usb.pci = pci;
- xhci->usb.type = USB_TYPE_XHCI;
-
- dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots"
- ", %d byte contexts\n"
- , pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)
- , pci_bdf_to_fn(pci->bdf), xhci->caps
- , xhci->ports, xhci->slots, xhci->context64 ? 64 : 32);
-
- if (xhci->xcap) {
- u32 off, addr = xhci->baseaddr + xhci->xcap;
- do {
- struct xhci_xcap *xcap = (void*)addr;
- u32 ports, name, cap = readl(&xcap->cap);
- switch (cap & 0xff) {
- case 0x02:
- name = readl(&xcap->data[0]);
- ports = readl(&xcap->data[1]);
- dprintf(1, "XHCI protocol %c%c%c%c %x.%02x"
- ", %d ports (offset %d), def %x\n"
- , (name >> 0) & 0xff
- , (name >> 8) & 0xff
- , (name >> 16) & 0xff
- , (name >> 24) & 0xff
- , (cap >> 24) & 0xff
- , (cap >> 16) & 0xff
- , (ports >> 8) & 0xff
- , (ports >> 0) & 0xff
- , ports >> 16);
- break;
- default:
- dprintf(1, "XHCI extcap 0x%x @ %x\n", cap & 0xff, addr);
- break;
- }
- off = (cap >> 8) & 0xff;
- addr += off << 2;
- } while (off > 0);
- }
-
- u32 pagesize = readl(&xhci->op->pagesize);
- if (PAGE_SIZE != (pagesize<<12)) {
- dprintf(1, "XHCI driver does not support page size code %d\n"
- , pagesize<<12);
- free(xhci);
- return;
- }
-
- pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
-
- run_thread(configure_xhci, xhci);
-}
-
-void
-xhci_setup(void)
-{
- if (! CONFIG_USB_XHCI)
- return;
- struct pci_device *pci;
- foreachpci(pci) {
- if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_XHCI)
- xhci_controller_setup(pci);
- }
-}
-
-
-/****************************************************************
- * End point communication
- ****************************************************************/
-
-static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value)
-{
- struct xhci_db *db = xhci->db;
- void *addr = &db[slotid].doorbell;
- writel(addr, value);
-}
-
-static void xhci_process_events(struct usb_xhci_s *xhci)
-{
- struct xhci_ring *evts = xhci->evts;
-
- for (;;) {
- /* check for event */
- u32 nidx = evts->nidx;
- u32 cs = evts->cs;
- struct xhci_trb *etrb = evts->ring + nidx;
- u32 control = etrb->control;
- if ((control & TRB_C) != (cs ? 1 : 0))
- return;
-
- /* process event */
- u32 evt_type = TRB_TYPE(control);
- u32 evt_cc = (etrb->status >> 24) & 0xff;
- switch (evt_type) {
- case ER_TRANSFER:
- case ER_COMMAND_COMPLETE:
- {
- struct xhci_trb *rtrb = (void*)etrb->ptr_low;
- struct xhci_ring *ring = XHCI_RING(rtrb);
- struct xhci_trb *evt = &ring->evt;
- u32 eidx = rtrb - ring->ring + 1;
- dprintf(5, "%s: ring %p [trb %p, evt %p, type %d, eidx %d, cc %d]\n",
- __func__, ring, rtrb, evt, evt_type, eidx, evt_cc);
- memcpy(evt, etrb, sizeof(*etrb));
- ring->eidx = eidx;
- break;
- }
- case ER_PORT_STATUS_CHANGE:
- {
- u32 portid = (etrb->ptr_low >> 24) & 0xff;
- dprintf(3, "%s: status change port #%d\n",
- __func__, portid);
- break;
- }
- default:
- dprintf(1, "%s: unknown event, type %d, cc %d\n",
- __func__, evt_type, evt_cc);
- break;
- }
-
- /* move ring index, notify xhci */
- nidx++;
- if (nidx == XHCI_RING_ITEMS) {
- nidx = 0;
- cs = cs ? 0 : 1;
- evts->cs = cs;
- }
- evts->nidx = nidx;
- struct xhci_ir *ir = xhci->ir;
- u32 erdp = (u32)(evts->ring + nidx);
- writel(&ir->erdp_low, erdp);
- writel(&ir->erdp_high, 0);
- }
-}
-
-static int xhci_ring_busy(struct xhci_ring *ring)
-{
- u32 eidx = ring->eidx;
- u32 nidx = ring->nidx;
- return (eidx != nidx);
-}
-
-static int xhci_event_wait(struct usb_xhci_s *xhci,
- struct xhci_ring *ring,
- u32 timeout)
-{
- u32 end = timer_calc(timeout);
-
- for (;;) {
- xhci_process_events(xhci);
- if (!xhci_ring_busy(ring)) {
- u32 status = ring->evt.status;
- return (status >> 24) & 0xff;
- }
- if (timer_check(end)) {
- warn_timeout();
- return -1;
- }
- yield();
- }
-}
-
-static void xhci_trb_queue(struct xhci_ring *ring,
- struct xhci_trb *trb)
-{
- u32 nidx = ring->nidx;
- u32 cs = ring->cs;
- struct xhci_trb *dst;
- u32 control;
-
- if (nidx == XHCI_RING_ITEMS-1) {
- dst = ring->ring + nidx;
- control = (TR_LINK << 10); // trb type
- control |= TRB_LK_TC;
- control |= (cs ? TRB_C : 0);
- dst->ptr_low = (u32)&ring[0];
- dst->ptr_high = 0;
- dst->status = 0;
- dst->control = control;
- nidx = 0;
- cs = cs ? 0 : 1;
- ring->nidx = nidx;
- ring->cs = cs;
-
- dprintf(5, "%s: ring %p [linked]\n", __func__, ring);
- }
-
- dst = ring->ring + nidx;
- control = trb->control | (cs ? TRB_C : 0);
-
- dst->ptr_low = trb->ptr_low;
- dst->ptr_high = trb->ptr_high;
- dst->status = trb->status;
- dst->control = control;
- nidx++;
- ring->nidx = nidx;
-
- dprintf(5, "%s: ring %p [nidx %d, len %d]\n",
- __func__, ring, nidx,
- trb->status & 0xffff);
-}
-
-static int xhci_cmd_submit(struct usb_xhci_s *xhci,
- struct xhci_trb *cmd)
-{
- int rc;
-
- mutex_lock(&xhci->cmds->lock);
- xhci_trb_queue(xhci->cmds, cmd);
- xhci_doorbell(xhci, 0, 0);
- rc = xhci_event_wait(xhci, xhci->cmds, 1000);
- mutex_unlock(&xhci->cmds->lock);
- return rc;
-}
-
-static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci)
-{
- struct xhci_trb cmd = {
- .ptr_low = 0,
- .ptr_high = 0,
- .status = 0,
- .control = (CR_ENABLE_SLOT << 10)
- };
- dprintf(3, "%s:\n", __func__);
- int cc = xhci_cmd_submit(xhci, &cmd);
- if (cc != CC_SUCCESS)
- return -1;
- return (xhci->cmds->evt.control >> 24) & 0xff;
-}
-
-#if 0
-static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid)
-{
- struct xhci_trb cmd = {
- .ptr_low = 0,
- .ptr_high = 0,
- .status = 0,
- .control = (slotid << 24) | (CR_DISABLE_SLOT << 10)
- };
- dprintf(3, "%s: slotid %d\n", __func__, slotid);
- return xhci_cmd_submit(xhci, &cmd);
-}
-#endif
-
-static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid
- , struct xhci_inctx *inctx)
-{
- struct xhci_trb cmd = {
- .ptr_low = (u32)inctx,
- .ptr_high = 0,
- .status = 0,
- .control = (slotid << 24) | (CR_ADDRESS_DEVICE << 10)
- };
- dprintf(3, "%s: slotid %d\n", __func__, slotid);
- return xhci_cmd_submit(xhci, &cmd);
-}
-
-static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid
- , struct xhci_inctx *inctx)
-{
- struct xhci_trb cmd = {
- .ptr_low = (u32)inctx,
- .ptr_high = 0,
- .status = 0,
- .control = (slotid << 24) | (CR_CONFIGURE_ENDPOINT << 10)
- };
- dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
- slotid, inctx->add, inctx->del);
- return xhci_cmd_submit(xhci, &cmd);
-}
-
-static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid
- , struct xhci_inctx *inctx)
-{
- struct xhci_trb cmd = {
- .ptr_low = (u32)inctx,
- .ptr_high = 0,
- .status = 0,
- .control = (slotid << 24) | (CR_EVALUATE_CONTEXT << 10)
- };
- dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
- slotid, inctx->add, inctx->del);
- return xhci_cmd_submit(xhci, &cmd);
-}
-
-static struct xhci_inctx *
-xhci_alloc_inctx(struct usbdevice_s *usbdev, int maxepid)
-{
- struct usb_xhci_s *xhci = container_of(
- usbdev->hub->cntl, struct usb_xhci_s, usb);
- int size = (sizeof(struct xhci_inctx) * 33) << xhci->context64;
- struct xhci_inctx *in = memalign_tmphigh(2048 << xhci->context64, size);
- if (!in) {
- warn_noalloc();
- return NULL;
- }
- memset(in, 0, size);
-
- struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
- slot->ctx[0] |= maxepid << 27; // context entries
- slot->ctx[0] |= speed_to_xhci[usbdev->speed] << 20;
-
- // Set high-speed hub flags.
- struct usbdevice_s *hubdev = usbdev->hub->usbdev;
- if (hubdev) {
- if (usbdev->speed == USB_LOWSPEED || usbdev->speed == USB_FULLSPEED) {
- struct xhci_pipe *hpipe = container_of(
- hubdev->defpipe, struct xhci_pipe, pipe);
- if (hubdev->speed == USB_HIGHSPEED) {
- slot->ctx[2] |= hpipe->slotid;
- slot->ctx[2] |= (usbdev->port+1) << 8;
- } else {
- struct xhci_slotctx *hslot = (void*)xhci->devs[hpipe->slotid].ptr_low;
- slot->ctx[2] = hslot->ctx[2];
- }
- }
- u32 route = 0;
- while (usbdev->hub->usbdev) {
- route <<= 4;
- route |= (usbdev->port+1) & 0xf;
- usbdev = usbdev->hub->usbdev;
- }
- slot->ctx[0] |= route;
- }
-
- slot->ctx[1] |= (usbdev->port+1) << 16;
-
- return in;
-}
-
-static int xhci_config_hub(struct usbhub_s *hub)
-{
- struct usb_xhci_s *xhci = container_of(
- hub->cntl, struct usb_xhci_s, usb);
- struct xhci_pipe *pipe = container_of(
- hub->usbdev->defpipe, struct xhci_pipe, pipe);
- struct xhci_slotctx *hdslot = (void*)xhci->devs[pipe->slotid].ptr_low;
- if ((hdslot->ctx[3] >> 27) == 3)
- // Already configured
- return 0;
- struct xhci_inctx *in = xhci_alloc_inctx(hub->usbdev, 1);
- if (!in)
- return -1;
- in->add = 0x01;
- struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
- slot->ctx[0] |= 1 << 26;
- slot->ctx[1] |= hub->portcount << 24;
-
- int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in);
- free(in);
- if (cc != CC_SUCCESS) {
- dprintf(1, "%s: configure hub: failed (cc %d)\n", __func__, cc);
- return -1;
- }
- return 0;
-}
-
-static struct usb_pipe *
-xhci_alloc_pipe(struct usbdevice_s *usbdev
- , struct usb_endpoint_descriptor *epdesc)
-{
- u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
- struct usb_xhci_s *xhci = container_of(
- usbdev->hub->cntl, struct usb_xhci_s, usb);
- struct xhci_pipe *pipe;
- u32 epid;
-
- if (epdesc->bEndpointAddress == 0) {
- epid = 1;
- } else {
- epid = (epdesc->bEndpointAddress & 0x0f) * 2;
- epid += (epdesc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
- }
-
- if (eptype == USB_ENDPOINT_XFER_CONTROL)
- pipe = memalign_high(XHCI_RING_SIZE, sizeof(*pipe));
- else
- pipe = memalign_low(XHCI_RING_SIZE, sizeof(*pipe));
- if (!pipe) {
- warn_noalloc();
- return NULL;
- }
- memset(pipe, 0, sizeof(*pipe));
-
- usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
- pipe->epid = epid;
- pipe->reqs.cs = 1;
- if (eptype == USB_ENDPOINT_XFER_INT) {
- pipe->buf = malloc_high(pipe->pipe.maxpacket);
- if (!pipe->buf) {
- warn_noalloc();
- free(pipe);
- return NULL;
- }
- }
-
- // Allocate input context and initialize endpoint info.
- struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid);
- if (!in)
- goto fail;
- in->add = 0x01 | (1 << epid);
- struct xhci_epctx *ep = (void*)&in[(pipe->epid+1) << xhci->context64];
- if (eptype == USB_ENDPOINT_XFER_INT)
- ep->ctx[0] = (usb_get_period(usbdev, epdesc) + 3) << 16;
- ep->ctx[1] |= eptype << 3;
- if (epdesc->bEndpointAddress & USB_DIR_IN
- || eptype == USB_ENDPOINT_XFER_CONTROL)
- ep->ctx[1] |= 1 << 5;
- ep->ctx[1] |= pipe->pipe.maxpacket << 16;
- ep->deq_low = (u32)&pipe->reqs.ring[0];
- ep->deq_low |= 1; // dcs
- ep->length = pipe->pipe.maxpacket;
-
- dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
- usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
- if (pipe->epid == 1) {
- if (usbdev->hub->usbdev) {
- // Make sure parent hub is configured.
- int ret = xhci_config_hub(usbdev->hub);
- if (ret)
- goto fail;
- }
- // Enable slot.
- u32 size = (sizeof(struct xhci_slotctx) * 32) << xhci->context64;
- struct xhci_slotctx *dev = memalign_high(1024 << xhci->context64, size);
- if (!dev) {
- warn_noalloc();
- goto fail;
- }
- int slotid = xhci_cmd_enable_slot(xhci);
- if (slotid < 0) {
- dprintf(1, "%s: enable slot: failed\n", __func__);
- free(dev);
- goto fail;
- }
- dprintf(3, "%s: enable slot: got slotid %d\n", __func__, slotid);
- memset(dev, 0, size);
- pipe->slotid = usbdev->slotid = slotid;
- xhci->devs[slotid].ptr_low = (u32)dev;
- xhci->devs[slotid].ptr_high = 0;
-
- // Send set_address command.
- int cc = xhci_cmd_address_device(xhci, slotid, in);
- if (cc != CC_SUCCESS) {
- dprintf(1, "%s: address device: failed (cc %d)\n", __func__, cc);
- goto fail;
- }
- } else {
- pipe->slotid = usbdev->slotid;
- // Send configure command.
- int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in);
- if (cc != CC_SUCCESS) {
- dprintf(1, "%s: configure endpoint: failed (cc %d)\n", __func__, cc);
- goto fail;
- }
- }
- free(in);
- return &pipe->pipe;
-
-fail:
- free(pipe->buf);
- free(pipe);
- free(in);
- return NULL;
-}
-
-struct usb_pipe *
-xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
- , struct usb_endpoint_descriptor *epdesc)
-{
- if (!CONFIG_USB_XHCI)
- return NULL;
- if (!epdesc) {
- usb_add_freelist(upipe);
- return NULL;
- }
- if (!upipe)
- return xhci_alloc_pipe(usbdev, epdesc);
- u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
- int oldmaxpacket = upipe->maxpacket;
- usb_desc2pipe(upipe, usbdev, epdesc);
- struct xhci_pipe *pipe = container_of(upipe, struct xhci_pipe, pipe);
- struct usb_xhci_s *xhci = container_of(
- pipe->pipe.cntl, struct usb_xhci_s, usb);
- dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
- usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
- if (eptype != USB_ENDPOINT_XFER_CONTROL || upipe->maxpacket == oldmaxpacket)
- return upipe;
-
- // maxpacket has changed on control endpoint - update controller.
- dprintf(1, "%s: reconf ctl endpoint pkt size: %d -> %d\n",
- __func__, oldmaxpacket, pipe->pipe.maxpacket);
- struct xhci_inctx *in = xhci_alloc_inctx(usbdev, 1);
- if (!in)
- return upipe;
- in->add = (1 << 1);
- struct xhci_epctx *ep = (void*)&in[2 << xhci->context64];
- ep->ctx[1] |= (pipe->pipe.maxpacket << 16);
- int cc = xhci_cmd_evaluate_context(xhci, pipe->slotid, in);
- if (cc != CC_SUCCESS) {
- dprintf(1, "%s: reconf ctl endpoint: failed (cc %d)\n",
- __func__, cc);
- }
- free(in);
-
- return upipe;
-}
-
-static void xhci_xfer_queue(struct xhci_pipe *pipe,
- void *data, int datalen, u32 flags)
-{
- struct xhci_trb trb;
- memset(&trb, 0, sizeof(trb));
- if (flags & TRB_TR_IDT)
- memcpy(&trb.ptr_low, data, datalen);
- else
- trb.ptr_low = (u32)data;
- trb.status = datalen;
- trb.control = flags;
- xhci_trb_queue(&pipe->reqs, &trb);
-}
-
-static void xhci_xfer_kick(struct xhci_pipe *pipe)
-{
- struct usb_xhci_s *xhci = container_of(
- pipe->pipe.cntl, struct usb_xhci_s, usb);
- u32 slotid = pipe->slotid;
- u32 epid = pipe->epid;
-
- dprintf(5, "%s: ring %p, slotid %d, epid %d\n",
- __func__, &pipe->reqs, slotid, epid);
- xhci_doorbell(xhci, slotid, epid);
-}
-
-static void xhci_xfer_normal(struct xhci_pipe *pipe,
- void *data, int datalen)
-{
- xhci_xfer_queue(pipe, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
- xhci_xfer_kick(pipe);
-}
-
-int
-xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
- , void *data, int datalen)
-{
- if (!CONFIG_USB_XHCI)
- return -1;
- struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe);
- struct usb_xhci_s *xhci = container_of(
- pipe->pipe.cntl, struct usb_xhci_s, usb);
-
- if (cmd) {
- const struct usb_ctrlrequest *req = cmd;
- if (req->bRequest == USB_REQ_SET_ADDRESS)
- // Set address command sent during xhci_alloc_pipe.
- return 0;
-
- xhci_xfer_queue(pipe, (void*)req, USB_CONTROL_SETUP_SIZE
- , (TR_SETUP << 10) | TRB_TR_IDT
- | ((datalen ? (dir ? 3 : 2) : 0) << 16));
- if (datalen)
- xhci_xfer_queue(pipe, data, datalen, (TR_DATA << 10)
- | ((dir ? 1 : 0) << 16));
- xhci_xfer_queue(pipe, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
- | ((dir ? 0 : 1) << 16));
- xhci_xfer_kick(pipe);
- } else {
- xhci_xfer_normal(pipe, data, datalen);
- }
-
- int cc = xhci_event_wait(xhci, &pipe->reqs, usb_xfer_time(p, datalen));
- if (cc != CC_SUCCESS) {
- dprintf(1, "%s: xfer failed (cc %d)\n", __func__, cc);
- return -1;
- }
-
- return 0;
-}
-
-int VISIBLE32FLAT
-xhci_poll_intr(struct usb_pipe *p, void *data)
-{
- if (!CONFIG_USB_XHCI)
- return -1;
-
- struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe);
- struct usb_xhci_s *xhci = container_of(
- pipe->pipe.cntl, struct usb_xhci_s, usb);
- u32 len = pipe->pipe.maxpacket;
- void *buf = pipe->buf;
- int bufused = pipe->bufused;
-
- if (!bufused) {
- xhci_xfer_normal(pipe, buf, len);
- bufused = 1;
- pipe->bufused = bufused;
- return -1;
- }
-
- xhci_process_events(xhci);
- if (xhci_ring_busy(&pipe->reqs))
- return -1;
- dprintf(5, "%s: st %x ct %x [ %p <= %p / %d ]\n", __func__,
- pipe->reqs.evt.status,
- pipe->reqs.evt.control,
- data, buf, len);
- memcpy(data, buf, len);
- xhci_xfer_normal(pipe, buf, len);
- return 0;
-}