From bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 Mon Sep 17 00:00:00 2001 From: RajithaY Date: Tue, 25 Apr 2017 03:31:15 -0700 Subject: 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 --- qemu/roms/seabios/src/hw/usb-xhci.c | 1161 ----------------------------------- 1 file changed, 1161 deletions(-) delete mode 100644 qemu/roms/seabios/src/hw/usb-xhci.c (limited to 'qemu/roms/seabios/src/hw/usb-xhci.c') 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 -// Copyright (C) 2014 Kevin O'Connor -// -// 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; -} -- cgit 1.2.3-korg