X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2Fipxe%2Fsrc%2Fdrivers%2Fusb%2Fuhci.h;fp=qemu%2Froms%2Fipxe%2Fsrc%2Fdrivers%2Fusb%2Fuhci.h;h=ba4c28f7e2efd0f6137881637b457d3029235716;hb=437fd90c0250dee670290f9b714253671a990160;hp=0000000000000000000000000000000000000000;hpb=5bbd6fe9b8bab2a93e548c5a53b032d1939eec05;p=kvmfornfv.git diff --git a/qemu/roms/ipxe/src/drivers/usb/uhci.h b/qemu/roms/ipxe/src/drivers/usb/uhci.h new file mode 100644 index 000000000..ba4c28f7e --- /dev/null +++ b/qemu/roms/ipxe/src/drivers/usb/uhci.h @@ -0,0 +1,350 @@ +#ifndef _IPXE_UHCI_H +#define _IPXE_UHCI_H + +/** @file + * + * USB Universal Host Controller Interface (UHCI) driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** Minimum alignment required for data structures + * + * With the exception of the frame list (which is page-aligned), data + * structures used by UHCI generally require 16-byte alignment. + */ +#define UHCI_ALIGN 16 + +/** Number of ports */ +#define UHCI_PORTS 2 + +/** Maximum transfer size */ +#define UHCI_MTU 1280 + +/** I/O BAR size */ +#define UHCI_BAR_SIZE 0x14 + +/** USB command register */ +#define UHCI_USBCMD 0x00 + +/** Max packet is 64 bytes */ +#define UHCI_USBCMD_MAX64 0x0080 + +/** Host controller reset */ +#define UHCI_USBCMD_HCRESET 0x0002 + +/** Run/stop */ +#define UHCI_USBCMD_RUN 0x0001 + +/** USB status register */ +#define UHCI_USBSTS 0x02 + +/** Host controller halted */ +#define UHCI_USBSTS_HCHALTED 0x0020 + +/** USB interrupt */ +#define UHCI_USBSTS_USBINT 0x0001 + +/** Frame list base address register */ +#define UHCI_FLBASEADD 0x08 + +/** Port status and control register */ +#define UHCI_PORTSC(port) ( 0x0e + ( (port) << 1 ) ) + +/** Port reset */ +#define UHCI_PORTSC_PR 0x0200 + +/** Low-speed device attached */ +#define UHCI_PORTSC_LS 0x0100 + +/** Port enabled/disabled change */ +#define UHCI_PORTSC_PEC 0x0008 + +/** Port enabled */ +#define UHCI_PORTSC_PED 0x0004 + +/** Connect status change */ +#define UHCI_PORTSC_CSC 0x0002 + +/** Current connect status */ +#define UHCI_PORTSC_CCS 0x0001 + +/** Port status change mask */ +#define UHCI_PORTSC_CHANGE ( UHCI_PORTSC_CSC | UHCI_PORTSC_PEC ) + +/** Depth-first processing */ +#define UHCI_LINK_DEPTH_FIRST 0x00000004UL + +/** Queue head type */ +#define UHCI_LINK_TYPE_QH 0x00000002UL + +/** List terminator */ +#define UHCI_LINK_TERMINATE 0x00000001UL + +/** Number of frames in frame list */ +#define UHCI_FRAMES 1024 + +/** A frame list */ +struct uhci_frame_list { + /** Link pointer */ + uint32_t link[UHCI_FRAMES]; +} __attribute__ (( packed )); + +/** A transfer descriptor */ +struct uhci_transfer_descriptor { + /** Link pointer */ + uint32_t link; + /** Actual length */ + uint16_t actual; + /** Status */ + uint8_t status; + /** Flags */ + uint8_t flags; + /** Control */ + uint32_t control; + /** Buffer pointer */ + uint32_t data; +} __attribute__ (( packed )); + +/** Length mask */ +#define UHCI_LEN_MASK 0x7ff + +/** Actual length */ +#define UHCI_ACTUAL_LEN( actual ) ( ( (actual) + 1 ) & UHCI_LEN_MASK ) + +/** Active */ +#define UHCI_STATUS_ACTIVE 0x80 + +/** Stalled */ +#define UHCI_STATUS_STALLED 0x40 + +/** Data buffer error */ +#define UHCI_STATUS_BUFFER 0x20 + +/** Babble detected */ +#define UHCI_STATUS_BABBLE 0x10 + +/** NAK received */ +#define UHCI_STATUS_NAK 0x08 + +/** CRC/timeout error */ +#define UHCI_STATUS_CRC_TIMEOUT 0x04 + +/** Bitstuff error */ +#define UHCI_STATUS_BITSTUFF 0x02 + +/** Short packet detect */ +#define UHCI_FL_SPD 0x20 + +/** Error counter */ +#define UHCI_FL_CERR( count ) ( (count) << 3 ) + +/** Error counter maximum value */ +#define UHCI_FL_CERR_MAX UHCI_FL_CERR ( 3 ) + +/** Low speed device */ +#define UHCI_FL_LS 0x04 + +/** Interrupt on completion */ +#define UHCI_FL_IOC 0x01 + +/** Packet ID */ +#define UHCI_CONTROL_PID( pid ) ( (pid) << 0 ) + +/** Packet ID mask */ +#define UHCI_CONTROL_PID_MASK UHCI_CONTROL_PID ( 0xff ) + +/** Device address */ +#define UHCI_CONTROL_DEVICE( address ) ( (address) << 8 ) + +/** Endpoint address */ +#define UHCI_CONTROL_ENDPOINT( address ) ( (address) << 15 ) + +/** Data toggle */ +#define UHCI_CONTROL_TOGGLE ( 1 << 19 ) + +/** Data length */ +#define UHCI_CONTROL_LEN( len ) ( ( ( (len) - 1 ) & UHCI_LEN_MASK ) << 21 ) + +/** Check for data packet + * + * This check is based on the fact that only USB_PID_SETUP has bit 2 + * set. + */ +#define UHCI_DATA_PACKET( control ) ( ! ( control & 0x04 ) ) + +/** Check for short packet */ +#define UHCI_SHORT_PACKET( control, actual ) \ + ( ( ( (control) >> 21 ) ^ (actual) ) & UHCI_LEN_MASK ) + +/** USB legacy support register (in PCI configuration space) */ +#define UHCI_USBLEGSUP 0xc0 + +/** USB legacy support default value */ +#define UHCI_USBLEGSUP_DEFAULT 0x2000 + +/** A queue head */ +struct uhci_queue_head { + /** Horizontal link pointer */ + uint32_t link; + /** Current transfer descriptor */ + uint32_t current; +} __attribute__ (( packed )); + +/** A single UHCI transfer + * + * UHCI hardware is extremely simple, and requires software to build + * the entire packet schedule (including manually handling all of the + * data toggles). The hardware requires at least 16 bytes of transfer + * descriptors per 64 bytes of transmitted/received data. We allocate + * the transfer descriptors at the time that the transfer is enqueued, + * to avoid the need to allocate unreasonably large blocks when the + * endpoint is opened. + */ +struct uhci_transfer { + /** Producer counter */ + unsigned int prod; + /** Consumer counter */ + unsigned int cons; + /** Completed data length */ + size_t len; + + /** Transfer descriptors */ + struct uhci_transfer_descriptor *desc; + + /** I/O buffer */ + struct io_buffer *iobuf; +}; + +/** Number of transfer descriptors in a ring + * + * This is a policy decision. + */ +#define UHCI_RING_COUNT 16 + +/** A transfer ring */ +struct uhci_ring { + /** Producer counter */ + unsigned int prod; + /** Consumer counter */ + unsigned int cons; + + /** Maximum packet length */ + size_t mtu; + /** Base flags + * + * This incorporates the CERR and LS bits + */ + uint8_t flags; + /** Base control word + * + * This incorporates the device address, the endpoint address, + * and the data toggle for the next descriptor to be enqueued. + */ + uint32_t control; + + /** Transfers */ + struct uhci_transfer *xfer[UHCI_RING_COUNT]; + /** End of transfer ring (if non-empty) */ + struct uhci_transfer *end; + + /** Queue head */ + struct uhci_queue_head *head; +}; + +/** + * Calculate space used in transfer ring + * + * @v ring Transfer ring + * @ret fill Number of entries used + */ +static inline __attribute__ (( always_inline )) unsigned int +uhci_ring_fill ( struct uhci_ring *ring ) { + unsigned int fill; + + fill = ( ring->prod - ring->cons ); + assert ( fill <= UHCI_RING_COUNT ); + return fill; +} + +/** + * Calculate space remaining in transfer ring + * + * @v ring Transfer ring + * @ret remaining Number of entries remaining + */ +static inline __attribute__ (( always_inline )) unsigned int +uhci_ring_remaining ( struct uhci_ring *ring ) { + unsigned int fill = uhci_ring_fill ( ring ); + + return ( UHCI_RING_COUNT - fill ); +} + +/** Maximum time to wait for host controller to stop + * + * This is a policy decision. + */ +#define UHCI_STOP_MAX_WAIT_MS 100 + +/** Maximum time to wait for reset to complete + * + * This is a policy decision. + */ +#define UHCI_RESET_MAX_WAIT_MS 500 + +/** Maximum time to wait for a port to be enabled + * + * This is a policy decision. + */ +#define UHCI_PORT_ENABLE_MAX_WAIT_MS 500 + +/** A UHCI device */ +struct uhci_device { + /** Registers */ + unsigned long regs; + /** Name */ + const char *name; + + /** EHCI companion controller bus:dev.fn address (if any) */ + unsigned int companion; + + /** Asynchronous queue head */ + struct uhci_queue_head *head; + /** Frame list */ + struct uhci_frame_list *frame; + + /** List of all endpoints */ + struct list_head endpoints; + /** Asynchronous schedule */ + struct list_head async; + /** Periodic schedule + * + * Listed in decreasing order of endpoint interval. + */ + struct list_head periodic; + + /** USB bus */ + struct usb_bus *bus; +}; + +/** A UHCI endpoint */ +struct uhci_endpoint { + /** UHCI device */ + struct uhci_device *uhci; + /** USB endpoint */ + struct usb_endpoint *ep; + /** List of all endpoints */ + struct list_head list; + /** Endpoint schedule */ + struct list_head schedule; + + /** Transfer ring */ + struct uhci_ring ring; +}; + +#endif /* _IPXE_UHCI_H */