diff options
Diffstat (limited to 'src/drivers/usb')
| -rw-r--r-- | src/drivers/usb/dwusb.c | 131 | ||||
| -rw-r--r-- | src/drivers/usb/dwusb.h | 23 | ||||
| -rw-r--r-- | src/drivers/usb/ehci.c | 1 | ||||
| -rw-r--r-- | src/drivers/usb/ehci.h | 1 | ||||
| -rw-r--r-- | src/drivers/usb/uhci.c | 1 | ||||
| -rw-r--r-- | src/drivers/usb/uhci.h | 1 | ||||
| -rw-r--r-- | src/drivers/usb/usbblk.c | 12 | ||||
| -rw-r--r-- | src/drivers/usb/usbblk.h | 1 | ||||
| -rw-r--r-- | src/drivers/usb/usbhub.c | 1 | ||||
| -rw-r--r-- | src/drivers/usb/usbhub.h | 1 | ||||
| -rw-r--r-- | src/drivers/usb/usbio.c | 148 | ||||
| -rw-r--r-- | src/drivers/usb/usbnet.c | 1 | ||||
| -rw-r--r-- | src/drivers/usb/xhci.c | 149 | ||||
| -rw-r--r-- | src/drivers/usb/xhci.h | 1179 |
14 files changed, 313 insertions, 1337 deletions
diff --git a/src/drivers/usb/dwusb.c b/src/drivers/usb/dwusb.c new file mode 100644 index 000000000..1bae2ce74 --- /dev/null +++ b/src/drivers/usb/dwusb.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ipxe/timer.h> +#include <ipxe/devtree.h> +#include <ipxe/fdt.h> +#include "dwusb.h" + +/** @file + * + * Synopsys DesignWare USB3 host controller driver + * + */ + +/** + * Probe devicetree device + * + * @v dt Devicetree device + * @v offset Starting node offset + * @ret rc Return status code + */ +static int dwusb_probe ( struct dt_device *dt, unsigned int offset ) { + struct xhci_device *xhci; + uint32_t gctl; + int rc; + + /* Allocate and initialise structure */ + xhci = zalloc ( sizeof ( *xhci ) ); + if ( ! xhci ) { + rc = -ENOMEM; + goto err_alloc; + } + xhci->dev = &dt->dev; + xhci->dma = &dt->dma; + + /* Map registers */ + xhci->regs = dt_ioremap ( dt, offset, 0, 0 ); + if ( ! xhci->regs ) { + rc = -ENODEV; + goto err_ioremap; + } + + /* Reset via global core control register */ + gctl = readl ( xhci->regs + DWUSB_GCTL ); + writel ( ( gctl | DWUSB_GCTL_RESET ), ( xhci->regs + DWUSB_GCTL ) ); + mdelay ( 100 ); + writel ( gctl, ( xhci->regs + DWUSB_GCTL ) ); + + /* Configure as a host controller */ + gctl &= ~DWUSB_GCTL_PRTDIR_MASK; + gctl |= DWUSB_GCTL_PRTDIR_HOST; + writel ( gctl, ( xhci->regs + DWUSB_GCTL ) ); + + /* Initialise xHCI device */ + xhci_init ( xhci ); + + /* Register xHCI device */ + if ( ( rc = xhci_register ( xhci ) ) != 0 ) { + DBGC ( xhci, "XHCI %s could not register: %s\n", + xhci->name, strerror ( rc ) ); + goto err_register; + } + + dt_set_drvdata ( dt, xhci ); + return 0; + + xhci_unregister ( xhci ); + err_register: + iounmap ( xhci->regs ); + err_ioremap: + free ( xhci ); + err_alloc: + return rc; +} + +/** + * Remove devicetree device + * + * @v dt Devicetree device + */ +static void dwusb_remove ( struct dt_device *dt ) { + struct xhci_device *xhci = dt_get_drvdata ( dt ); + + /* Unregister xHCI device */ + xhci_unregister ( xhci ); + + /* Unmap registers */ + iounmap ( xhci->regs ); + + /* Free device */ + free ( xhci ); +} + +/** DesignWare USB3 compatible model identifiers */ +static const char * dwusb_ids[] = { + "snps,dwc3", +}; + +/** DesignWare USB3 devicetree driver */ +struct dt_driver dwusb_driver __dt_driver = { + .name = "dwusb", + .ids = dwusb_ids, + .id_count = ( sizeof ( dwusb_ids ) / sizeof ( dwusb_ids[0] ) ), + .probe = dwusb_probe, + .remove = dwusb_remove, +}; diff --git a/src/drivers/usb/dwusb.h b/src/drivers/usb/dwusb.h new file mode 100644 index 000000000..523f7ba81 --- /dev/null +++ b/src/drivers/usb/dwusb.h @@ -0,0 +1,23 @@ +#ifndef _DWUSB_H +#define _DWUSB_H + +/** @file + * + * Synopsys DesignWare USB3 host controller driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/xhci.h> + +/** Global core control register */ +#define DWUSB_GCTL 0xc110 +#define DWUSB_GCTL_PRTDIR( x ) ( (x) << 12 ) /**< Port direction */ +#define DWUSB_GCTL_PRTDIR_HOST \ + DWUSB_GCTL_PRTDIR ( 1 ) /**< Operate as a host */ +#define DWUSB_GCTL_PRTDIR_MASK \ + DWUSB_GCTL_PRTDIR ( 3 ) /**< Port direction mask */ +#define DWUSB_GCTL_RESET 0x00000800 /**< Core soft reset */ + +#endif /* _DWUSB_H */ diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c index 77022a47d..9f9d94175 100644 --- a/src/drivers/usb/ehci.c +++ b/src/drivers/usb/ehci.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdlib.h> #include <unistd.h> diff --git a/src/drivers/usb/ehci.h b/src/drivers/usb/ehci.h index 42e282e92..a0166bc63 100644 --- a/src/drivers/usb/ehci.h +++ b/src/drivers/usb/ehci.h @@ -8,6 +8,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <ipxe/pci.h> #include <ipxe/usb.h> diff --git a/src/drivers/usb/uhci.c b/src/drivers/usb/uhci.c index 47474bdc7..2c70a11bd 100644 --- a/src/drivers/usb/uhci.c +++ b/src/drivers/usb/uhci.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <strings.h> #include <unistd.h> diff --git a/src/drivers/usb/uhci.h b/src/drivers/usb/uhci.h index ba4c28f7e..629f6ae3b 100644 --- a/src/drivers/usb/uhci.h +++ b/src/drivers/usb/uhci.h @@ -8,6 +8,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <assert.h> #include <ipxe/pci.h> diff --git a/src/drivers/usb/usbblk.c b/src/drivers/usb/usbblk.c index 5a086d3f8..b42c70645 100644 --- a/src/drivers/usb/usbblk.c +++ b/src/drivers/usb/usbblk.c @@ -22,9 +22,11 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdint.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include <ipxe/usb.h> #include <ipxe/scsi.h> @@ -205,7 +207,7 @@ static int usbblk_out_data ( struct usbblk_device *usbblk ) { /* Calculate length */ assert ( cmd->tag ); - assert ( cmd->scsi.data_out != UNULL ); + assert ( cmd->scsi.data_out != NULL ); assert ( cmd->offset < cmd->scsi.data_out_len ); len = ( cmd->scsi.data_out_len - cmd->offset ); if ( len > USBBLK_MAX_LEN ) @@ -220,8 +222,8 @@ static int usbblk_out_data ( struct usbblk_device *usbblk ) { } /* Populate I/O buffer */ - copy_from_user ( iob_put ( iobuf, len ), cmd->scsi.data_out, - cmd->offset, len ); + memcpy ( iob_put ( iobuf, len ), + ( cmd->scsi.data_out + cmd->offset ), len ); /* Send data */ if ( ( rc = usb_stream ( &usbblk->out, iobuf, 0 ) ) != 0 ) { @@ -332,12 +334,12 @@ static int usbblk_in_data ( struct usbblk_device *usbblk, const void *data, /* Sanity checks */ assert ( cmd->tag ); - assert ( cmd->scsi.data_in != UNULL ); + assert ( cmd->scsi.data_in != NULL ); assert ( cmd->offset <= cmd->scsi.data_in_len ); assert ( len <= ( cmd->scsi.data_in_len - cmd->offset ) ); /* Store data */ - copy_to_user ( cmd->scsi.data_in, cmd->offset, data, len ); + memcpy ( ( cmd->scsi.data_in + cmd->offset ), data, len ); cmd->offset += len; return 0; diff --git a/src/drivers/usb/usbblk.h b/src/drivers/usb/usbblk.h index 65d0705e3..1fa0ebad8 100644 --- a/src/drivers/usb/usbblk.h +++ b/src/drivers/usb/usbblk.h @@ -8,6 +8,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdint.h> #include <ipxe/usb.h> diff --git a/src/drivers/usb/usbhub.c b/src/drivers/usb/usbhub.c index 28d6cb33d..1d7b03e77 100644 --- a/src/drivers/usb/usbhub.c +++ b/src/drivers/usb/usbhub.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdlib.h> #include <string.h> diff --git a/src/drivers/usb/usbhub.h b/src/drivers/usb/usbhub.h index a5f123acc..9768b81a9 100644 --- a/src/drivers/usb/usbhub.h +++ b/src/drivers/usb/usbhub.h @@ -8,6 +8,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <ipxe/usb.h> #include <ipxe/list.h> diff --git a/src/drivers/usb/usbio.c b/src/drivers/usb/usbio.c index 278b43cd3..97860a281 100644 --- a/src/drivers/usb/usbio.c +++ b/src/drivers/usb/usbio.c @@ -187,10 +187,6 @@ static int usbio_open ( struct usbio_device *usbio, unsigned int interface ) { EFI_DEVICE_PATH_PROTOCOL *path; EFI_DEVICE_PATH_PROTOCOL *end; USB_DEVICE_PATH *usbpath; - union { - void *interface; - EFI_USB_IO_PROTOCOL *io; - } u; EFI_STATUS efirc; int rc; @@ -229,13 +225,9 @@ static int usbio_open ( struct usbio_device *usbio, unsigned int interface ) { } /* Open USB I/O protocol on this handle */ - if ( ( efirc = bs->OpenProtocol ( intf->handle, - &efi_usb_io_protocol_guid, - &u.interface, efi_image_handle, - intf->handle, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open_by_driver ( intf->handle, + &efi_usb_io_protocol_guid, + &intf->io ) ) != 0 ) { DBGC ( usbio, "USBIO %s cannot open ", efi_handle_name ( handle ) ); DBGC ( usbio, "%s: %s\n", @@ -244,7 +236,6 @@ static int usbio_open ( struct usbio_device *usbio, unsigned int interface ) { &efi_usb_io_protocol_guid ); return rc; } - intf->io = u.io; /* Increment usage count */ intf->count++; @@ -259,7 +250,6 @@ static int usbio_open ( struct usbio_device *usbio, unsigned int interface ) { * @v interface Interface number */ static void usbio_close ( struct usbio_device *usbio, unsigned int interface ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct usbio_interface *intf = &usbio->interface[interface]; /* Sanity checks */ @@ -274,8 +264,7 @@ static void usbio_close ( struct usbio_device *usbio, unsigned int interface ) { return; /* Close USB I/O protocol */ - bs->CloseProtocol ( intf->handle, &efi_usb_io_protocol_guid, - efi_image_handle, intf->handle ); + efi_close_by_driver ( intf->handle, &efi_usb_io_protocol_guid ); } /****************************************************************************** @@ -1297,49 +1286,40 @@ static struct usb_host_operations usbio_operations = { * @ret rc Return status code */ static int usbio_supported ( EFI_HANDLE handle ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_USB_DEVICE_DESCRIPTOR device; EFI_USB_INTERFACE_DESCRIPTOR interface; struct usb_function_descriptor desc; struct usb_driver *driver; struct usb_device_id *id; - union { - void *interface; - EFI_USB_IO_PROTOCOL *io; - } usb; + EFI_USB_IO_PROTOCOL *io; EFI_STATUS efirc; int rc; /* Get protocol */ - if ( ( efirc = bs->OpenProtocol ( handle, &efi_usb_io_protocol_guid, - &usb.interface, efi_image_handle, - handle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open ( handle, &efi_usb_io_protocol_guid, + &io ) ) != 0 ) { DBGCP ( handle, "USB %s is not a USB device\n", efi_handle_name ( handle ) ); - goto err_open_protocol; + return rc; } /* Get device descriptor */ - if ( ( efirc = usb.io->UsbGetDeviceDescriptor ( usb.io, - &device ) ) != 0 ) { + if ( ( efirc = io->UsbGetDeviceDescriptor ( io, &device ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( handle, "USB %s could not get device descriptor: " "%s\n", efi_handle_name ( handle ), strerror ( rc ) ); - goto err_get_device_descriptor; + return rc; } memset ( &desc, 0, sizeof ( desc ) ); desc.vendor = device.IdVendor; desc.product = device.IdProduct; /* Get interface descriptor */ - if ( ( efirc = usb.io->UsbGetInterfaceDescriptor ( usb.io, - &interface ) ) !=0){ + if ( ( efirc = io->UsbGetInterfaceDescriptor ( io, &interface ) ) != 0){ rc = -EEFI ( efirc ); DBGC ( handle, "USB %s could not get interface descriptor: " "%s\n", efi_handle_name ( handle ), strerror ( rc ) ); - goto err_get_interface_descriptor; + return rc; } desc.class.class.class = interface.InterfaceClass; desc.class.class.subclass = interface.InterfaceSubClass; @@ -1347,21 +1327,10 @@ static int usbio_supported ( EFI_HANDLE handle ) { /* Look for a driver for this interface */ driver = usb_find_driver ( &desc, &id ); - if ( ! driver ) { - rc = -ENOTSUP; - goto err_unsupported; - } - - /* Success */ - rc = 0; + if ( ! driver ) + return -ENOTSUP; - err_unsupported: - err_get_interface_descriptor: - err_get_device_descriptor: - bs->CloseProtocol ( handle, &efi_usb_io_protocol_guid, - efi_image_handle, handle ); - err_open_protocol: - return rc; + return 0; } /** @@ -1477,39 +1446,27 @@ static int usbio_config ( struct usbio_device *usbio ) { * @ret rc Return status code */ static int usbio_path ( struct usbio_device *usbio ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE handle = usbio->handle; EFI_DEVICE_PATH_PROTOCOL *path; EFI_DEVICE_PATH_PROTOCOL *end; USB_DEVICE_PATH *usbpath; - union { - void *interface; - EFI_DEVICE_PATH_PROTOCOL *path; - } u; size_t len; - EFI_STATUS efirc; int rc; /* Open device path protocol */ - if ( ( efirc = bs->OpenProtocol ( handle, - &efi_device_path_protocol_guid, - &u.interface, efi_image_handle, - handle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open ( handle, &efi_device_path_protocol_guid, + &path ) ) != 0 ) { DBGC ( usbio, "USBIO %s cannot open device path protocol: " "%s\n", efi_handle_name ( handle ), strerror ( rc ) ); - goto err_open_protocol; + return rc; } - path = u.interface; /* Locate end of device path and sanity check */ len = efi_path_len ( path ); if ( len < sizeof ( *usbpath ) ) { DBGC ( usbio, "USBIO %s underlength device path\n", efi_handle_name ( handle ) ); - rc = -EINVAL; - goto err_underlength; + return -EINVAL; } usbpath = ( ( ( void * ) path ) + len - sizeof ( *usbpath ) ); if ( ! ( ( usbpath->Header.Type == MESSAGING_DEVICE_PATH ) && @@ -1517,34 +1474,18 @@ static int usbio_path ( struct usbio_device *usbio ) { DBGC ( usbio, "USBIO %s not a USB device path: ", efi_handle_name ( handle ) ); DBGC ( usbio, "%s\n", efi_devpath_text ( path ) ); - rc = -EINVAL; - goto err_non_usb; + return -EINVAL; } /* Allocate copy of device path */ usbio->path = malloc ( len + sizeof ( *end ) ); - if ( ! usbio->path ) { - rc = -ENOMEM; - goto err_alloc; - } + if ( ! usbio->path ) + return -ENOMEM; memcpy ( usbio->path, path, ( len + sizeof ( *end ) ) ); usbio->usbpath = ( ( ( void * ) usbio->path ) + len - sizeof ( *usbpath ) ); - /* Close protocol */ - bs->CloseProtocol ( handle, &efi_device_path_protocol_guid, - efi_image_handle, handle ); - return 0; - - free ( usbio->path ); - err_alloc: - err_non_usb: - err_underlength: - bs->CloseProtocol ( handle, &efi_device_path_protocol_guid, - efi_image_handle, handle ); - err_open_protocol: - return rc; } /** @@ -1602,21 +1543,35 @@ static int usbio_interfaces ( struct usbio_device *usbio ) { } /** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int usbio_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_usb_io_protocol_guid; + int rc; + + /* Exclude existing USB I/O protocol drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "USBIO %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** * Attach driver to device * * @v efidev EFI device * @ret rc Return status code */ static int usbio_start ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE handle = efidev->device; struct usbio_device *usbio; struct usb_port *port; - union { - void *interface; - EFI_USB_IO_PROTOCOL *io; - } u; - EFI_STATUS efirc; int rc; /* Allocate and initialise structure */ @@ -1630,18 +1585,13 @@ static int usbio_start ( struct efi_device *efidev ) { INIT_LIST_HEAD ( &usbio->endpoints ); /* Open USB I/O protocol */ - if ( ( efirc = bs->OpenProtocol ( handle, &efi_usb_io_protocol_guid, - &u.interface, efi_image_handle, - handle, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open_by_driver ( handle, &efi_usb_io_protocol_guid, + &usbio->io ) ) != 0 ) { DBGC ( usbio, "USBIO %s cannot open USB I/O protocol: %s\n", efi_handle_name ( handle ), strerror ( rc ) ); DBGC_EFI_OPENERS ( usbio, handle, &efi_usb_io_protocol_guid ); goto err_open_usbio; } - usbio->io = u.io; /* Describe generic device */ efi_device_info ( handle, "USB", &usbio->dev ); @@ -1692,8 +1642,7 @@ static int usbio_start ( struct efi_device *efidev ) { free ( usbio->config ); err_config: list_del ( &usbio->dev.siblings ); - bs->CloseProtocol ( handle, &efi_usb_io_protocol_guid, - efi_image_handle, handle ); + efi_close_by_driver ( handle, &efi_usb_io_protocol_guid ); err_open_usbio: free ( usbio ); err_alloc: @@ -1706,7 +1655,6 @@ static int usbio_start ( struct efi_device *efidev ) { * @v efidev EFI device */ static void usbio_stop ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE handle = efidev->device; struct usbio_device *usbio = efidev_get_drvdata ( efidev ); @@ -1716,15 +1664,15 @@ static void usbio_stop ( struct efi_device *efidev ) { free ( usbio->path ); free ( usbio->config ); list_del ( &usbio->dev.siblings ); - bs->CloseProtocol ( handle, &efi_usb_io_protocol_guid, - efi_image_handle, handle ); + efi_close_by_driver ( handle, &efi_usb_io_protocol_guid ); free ( usbio ); } /** EFI USB I/O driver */ -struct efi_driver usbio_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver usbio_driver __efi_driver ( EFI_DRIVER_HARDWARE ) = { .name = "USBIO", .supported = usbio_supported, + .exclude = usbio_exclude, .start = usbio_start, .stop = usbio_stop, }; diff --git a/src/drivers/usb/usbnet.c b/src/drivers/usb/usbnet.c index 0fac00b56..e773ab882 100644 --- a/src/drivers/usb/usbnet.c +++ b/src/drivers/usb/usbnet.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <string.h> #include <errno.h> diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 3247ee69c..f812ed338 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdlib.h> #include <stdio.h> @@ -35,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/usb.h> #include <ipxe/init.h> #include <ipxe/profile.h> -#include "xhci.h" +#include <ipxe/xhci.h> /** @file * @@ -259,9 +260,8 @@ static struct profiler xhci_transfer_profiler __profiler = * Initialise device * * @v xhci xHCI device - * @v regs MMIO registers */ -static void xhci_init ( struct xhci_device *xhci, void *regs ) { +void xhci_init ( struct xhci_device *xhci ) { uint32_t hcsparams1; uint32_t hcsparams2; uint32_t hccparams1; @@ -270,8 +270,11 @@ static void xhci_init ( struct xhci_device *xhci, void *regs ) { size_t rtsoff; size_t dboff; + /* Set device name */ + xhci->name = xhci->dev->name; + /* Locate capability, operational, runtime, and doorbell registers */ - xhci->cap = regs; + xhci->cap = xhci->regs; caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH ); rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF ); dboff = readl ( xhci->cap + XHCI_CAP_DBOFF ); @@ -310,6 +313,10 @@ static void xhci_init ( struct xhci_device *xhci, void *regs ) { assert ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 ); DBGC2 ( xhci, "XHCI %s page size %zd bytes\n", xhci->name, xhci->pagesize ); + + /* Configure DMA device */ + if ( xhci->dma && xhci->addr64 ) + dma_set_mask_64bit ( xhci->dma ); } /** @@ -1000,7 +1007,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { rc = -ENOMEM; goto err_alloc; } - memset_user ( scratch->buffer, 0, 0, buffer_len ); + memset ( scratch->buffer, 0, buffer_len ); /* Allocate scratchpad array */ array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); @@ -1014,8 +1021,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { } /* Populate scratchpad array */ - addr = dma_phys ( &scratch->buffer_map, - user_to_phys ( scratch->buffer, 0 ) ); + addr = dma ( &scratch->buffer_map, scratch->buffer ); for ( i = 0 ; i < scratch->count ; i++ ) { scratch->array[i] = cpu_to_le64 ( addr ); addr += xhci->pagesize; @@ -1027,8 +1033,8 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { scratch->array ) ); DBGC2 ( xhci, "XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n", - xhci->name, user_to_phys ( scratch->buffer, 0 ), - user_to_phys ( scratch->buffer, buffer_len ), + xhci->name, virt_to_phys ( scratch->buffer ), + ( virt_to_phys ( scratch->buffer ) + buffer_len ), virt_to_phys ( scratch->array ), ( virt_to_phys ( scratch->array ) + array_len ) ); return 0; @@ -2771,6 +2777,7 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, */ static int xhci_device_open ( struct usb_device *usb ) { struct xhci_device *xhci = usb_bus_get_hostdata ( usb->port->hub->bus ); + struct usb_port *root_port = usb_root_hub_port ( usb ); struct usb_port *tt = usb_transaction_translator ( usb ); struct xhci_slot *slot; struct xhci_slot *tt_slot; @@ -2780,7 +2787,7 @@ static int xhci_device_open ( struct usb_device *usb ) { int rc; /* Determine applicable slot type */ - type = xhci_port_slot_type ( xhci, usb->port->address ); + type = xhci_port_slot_type ( xhci, root_port->address ); if ( type < 0 ) { rc = type; DBGC ( xhci, "XHCI %s-%d has no slot type\n", @@ -3264,7 +3271,7 @@ static int xhci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port, /****************************************************************************** * - * PCI interface + * Hardware-independent interface * ****************************************************************************** */ @@ -3304,6 +3311,75 @@ static struct usb_host_operations xhci_operations = { }; /** + * Register xHCI controller + * + * @v xhci xHCI device + * @ret rc Return status code + */ +int xhci_register ( struct xhci_device *xhci ) { + struct usb_port *port; + unsigned int i; + int rc; + + /* Reset device */ + if ( ( rc = xhci_reset ( xhci ) ) != 0 ) + goto err_reset; + + /* Allocate USB bus */ + xhci->bus = alloc_usb_bus ( xhci->dev, xhci->ports, XHCI_MTU, + &xhci_operations ); + if ( ! xhci->bus ) { + rc = -ENOMEM; + goto err_alloc_bus; + } + usb_bus_set_hostdata ( xhci->bus, xhci ); + usb_hub_set_drvdata ( xhci->bus->hub, xhci ); + + /* Set port protocols */ + for ( i = 1 ; i <= xhci->ports ; i++ ) { + port = usb_port ( xhci->bus->hub, i ); + port->protocol = xhci_port_protocol ( xhci, i ); + } + + /* Register USB bus */ + if ( ( rc = register_usb_bus ( xhci->bus ) ) != 0 ) + goto err_register; + + return 0; + + unregister_usb_bus ( xhci->bus ); + err_register: + free_usb_bus ( xhci->bus ); + err_alloc_bus: + xhci_reset ( xhci ); + err_reset: + return rc; +} + +/** + * Unregister xHCI controller + * + * @v xhci xHCI device + */ +void xhci_unregister ( struct xhci_device *xhci ) { + struct usb_bus *bus = xhci->bus; + + /* Unregister and free USB bus */ + unregister_usb_bus ( bus ); + free_usb_bus ( bus ); + + /* Reset device */ + xhci_reset ( xhci ); +} + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** * Fix Intel PCH-specific quirks * * @v xhci xHCI device @@ -3365,10 +3441,8 @@ static void xhci_pch_undo ( struct xhci_device *xhci, struct pci_device *pci ) { */ static int xhci_probe ( struct pci_device *pci ) { struct xhci_device *xhci; - struct usb_port *port; unsigned long bar_start; size_t bar_size; - unsigned int i; int rc; /* Allocate and initialise structure */ @@ -3377,7 +3451,8 @@ static int xhci_probe ( struct pci_device *pci ) { rc = -ENOMEM; goto err_alloc; } - xhci->name = pci->dev.name; + xhci->dev = &pci->dev; + xhci->dma = &pci->dma; xhci->quirks = pci->id->driver_data; /* Fix up PCI device */ @@ -3393,12 +3468,7 @@ static int xhci_probe ( struct pci_device *pci ) { } /* Initialise xHCI device */ - xhci_init ( xhci, xhci->regs ); - - /* Configure DMA device */ - xhci->dma = &pci->dma; - if ( xhci->addr64 ) - dma_set_mask_64bit ( xhci->dma ); + xhci_init ( xhci ); /* Initialise USB legacy support and claim ownership */ xhci_legacy_init ( xhci ); @@ -3408,39 +3478,15 @@ static int xhci_probe ( struct pci_device *pci ) { if ( xhci->quirks & XHCI_PCH ) xhci_pch_fix ( xhci, pci ); - /* Reset device */ - if ( ( rc = xhci_reset ( xhci ) ) != 0 ) - goto err_reset; - - /* Allocate USB bus */ - xhci->bus = alloc_usb_bus ( &pci->dev, xhci->ports, XHCI_MTU, - &xhci_operations ); - if ( ! xhci->bus ) { - rc = -ENOMEM; - goto err_alloc_bus; - } - usb_bus_set_hostdata ( xhci->bus, xhci ); - usb_hub_set_drvdata ( xhci->bus->hub, xhci ); - - /* Set port protocols */ - for ( i = 1 ; i <= xhci->ports ; i++ ) { - port = usb_port ( xhci->bus->hub, i ); - port->protocol = xhci_port_protocol ( xhci, i ); - } - - /* Register USB bus */ - if ( ( rc = register_usb_bus ( xhci->bus ) ) != 0 ) + /* Register xHCI device */ + if ( ( rc = xhci_register ( xhci ) ) != 0 ) goto err_register; pci_set_drvdata ( pci, xhci ); return 0; - unregister_usb_bus ( xhci->bus ); + xhci_unregister ( xhci ); err_register: - free_usb_bus ( xhci->bus ); - err_alloc_bus: - xhci_reset ( xhci ); - err_reset: if ( xhci->quirks & XHCI_PCH ) xhci_pch_undo ( xhci, pci ); xhci_legacy_release ( xhci ); @@ -3458,7 +3504,6 @@ static int xhci_probe ( struct pci_device *pci ) { */ static void xhci_remove ( struct pci_device *pci ) { struct xhci_device *xhci = pci_get_drvdata ( pci ); - struct usb_bus *bus = xhci->bus; uint16_t command; /* Some systems are observed to disable bus mastering on @@ -3473,12 +3518,10 @@ static void xhci_remove ( struct pci_device *pci ) { xhci_fail ( xhci ); } - /* Unregister and free USB bus */ - unregister_usb_bus ( bus ); - free_usb_bus ( bus ); + /* Unregister xHCI controller */ + xhci_unregister ( xhci ); - /* Reset device and undo any PCH-specific fixes */ - xhci_reset ( xhci ); + /* Undo any PCH-specific fixes */ if ( xhci->quirks & XHCI_PCH ) xhci_pch_undo ( xhci, pci ); diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h deleted file mode 100644 index a3c8888af..000000000 --- a/src/drivers/usb/xhci.h +++ /dev/null @@ -1,1179 +0,0 @@ -#ifndef _IPXE_XHCI_H -#define _IPXE_XHCI_H - -/** @file - * - * USB eXtensible Host Controller Interface (xHCI) driver - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <assert.h> -#include <ipxe/pci.h> -#include <ipxe/uaccess.h> -#include <ipxe/usb.h> - -/** Minimum alignment required for data structures - * - * With the exception of the scratchpad buffer pages (which are - * page-aligned), data structures used by xHCI generally require from - * 16 to 64 byte alignment and must not cross an (xHCI) page boundary. - * We simplify this requirement by aligning each structure on its own - * size, with a minimum of a 64 byte alignment. - */ -#define XHCI_MIN_ALIGN 64 - -/** Maximum transfer size */ -#define XHCI_MTU 65536 - -/** xHCI PCI BAR */ -#define XHCI_BAR PCI_BASE_ADDRESS_0 - -/** Capability register length */ -#define XHCI_CAP_CAPLENGTH 0x00 - -/** Host controller interface version number */ -#define XHCI_CAP_HCIVERSION 0x02 - -/** Structural parameters 1 */ -#define XHCI_CAP_HCSPARAMS1 0x04 - -/** Number of device slots */ -#define XHCI_HCSPARAMS1_SLOTS(params) ( ( (params) >> 0 ) & 0xff ) - -/** Number of interrupters */ -#define XHCI_HCSPARAMS1_INTRS(params) ( ( (params) >> 8 ) & 0x3ff ) - -/** Number of ports */ -#define XHCI_HCSPARAMS1_PORTS(params) ( ( (params) >> 24 ) & 0xff ) - -/** Structural parameters 2 */ -#define XHCI_CAP_HCSPARAMS2 0x08 - -/** Number of page-sized scratchpad buffers */ -#define XHCI_HCSPARAMS2_SCRATCHPADS(params) \ - ( ( ( (params) >> 16 ) & 0x3e0 ) | ( ( (params) >> 27 ) & 0x1f ) ) - -/** Capability parameters */ -#define XHCI_CAP_HCCPARAMS1 0x10 - -/** 64-bit addressing capability */ -#define XHCI_HCCPARAMS1_ADDR64(params) ( ( (params) >> 0 ) & 0x1 ) - -/** Context size shift */ -#define XHCI_HCCPARAMS1_CSZ_SHIFT(params) ( 5 + ( ( (params) >> 2 ) & 0x1 ) ) - -/** xHCI extended capabilities pointer */ -#define XHCI_HCCPARAMS1_XECP(params) ( ( ( (params) >> 16 ) & 0xffff ) << 2 ) - -/** Doorbell offset */ -#define XHCI_CAP_DBOFF 0x14 - -/** Runtime register space offset */ -#define XHCI_CAP_RTSOFF 0x18 - -/** xHCI extended capability ID */ -#define XHCI_XECP_ID(xecp) ( ( (xecp) >> 0 ) & 0xff ) - -/** Next xHCI extended capability pointer */ -#define XHCI_XECP_NEXT(xecp) ( ( ( (xecp) >> 8 ) & 0xff ) << 2 ) - -/** USB legacy support extended capability */ -#define XHCI_XECP_ID_LEGACY 1 - -/** USB legacy support BIOS owned semaphore */ -#define XHCI_USBLEGSUP_BIOS 0x02 - -/** USB legacy support BIOS ownership flag */ -#define XHCI_USBLEGSUP_BIOS_OWNED 0x01 - -/** USB legacy support OS owned semaphore */ -#define XHCI_USBLEGSUP_OS 0x03 - -/** USB legacy support OS ownership flag */ -#define XHCI_USBLEGSUP_OS_OWNED 0x01 - -/** USB legacy support control/status */ -#define XHCI_USBLEGSUP_CTLSTS 0x04 - -/** Supported protocol extended capability */ -#define XHCI_XECP_ID_SUPPORTED 2 - -/** Supported protocol revision */ -#define XHCI_SUPPORTED_REVISION 0x00 - -/** Supported protocol minor revision */ -#define XHCI_SUPPORTED_REVISION_VER(revision) ( ( (revision) >> 16 ) & 0xffff ) - -/** Supported protocol name */ -#define XHCI_SUPPORTED_NAME 0x04 - -/** Supported protocol ports */ -#define XHCI_SUPPORTED_PORTS 0x08 - -/** Supported protocol port offset */ -#define XHCI_SUPPORTED_PORTS_OFFSET(ports) ( ( (ports) >> 0 ) & 0xff ) - -/** Supported protocol port count */ -#define XHCI_SUPPORTED_PORTS_COUNT(ports) ( ( (ports) >> 8 ) & 0xff ) - -/** Supported protocol PSI count */ -#define XHCI_SUPPORTED_PORTS_PSIC(ports) ( ( (ports) >> 28 ) & 0x0f ) - -/** Supported protocol slot */ -#define XHCI_SUPPORTED_SLOT 0x0c - -/** Supported protocol slot type */ -#define XHCI_SUPPORTED_SLOT_TYPE(slot) ( ( (slot) >> 0 ) & 0x1f ) - -/** Supported protocol PSI */ -#define XHCI_SUPPORTED_PSI(index) ( 0x10 + ( (index) * 4 ) ) - -/** Supported protocol PSI value */ -#define XHCI_SUPPORTED_PSI_VALUE(psi) ( ( (psi) >> 0 ) & 0x0f ) - -/** Supported protocol PSI mantissa */ -#define XHCI_SUPPORTED_PSI_MANTISSA(psi) ( ( (psi) >> 16 ) & 0xffff ) - -/** Supported protocol PSI exponent */ -#define XHCI_SUPPORTED_PSI_EXPONENT(psi) ( ( (psi) >> 4 ) & 0x03 ) - -/** Default PSI values */ -enum xhci_default_psi_value { - /** Full speed (12Mbps) */ - XHCI_SPEED_FULL = 1, - /** Low speed (1.5Mbps) */ - XHCI_SPEED_LOW = 2, - /** High speed (480Mbps) */ - XHCI_SPEED_HIGH = 3, - /** Super speed */ - XHCI_SPEED_SUPER = 4, -}; - -/** USB command register */ -#define XHCI_OP_USBCMD 0x00 - -/** Run/stop */ -#define XHCI_USBCMD_RUN 0x00000001UL - -/** Host controller reset */ -#define XHCI_USBCMD_HCRST 0x00000002UL - -/** USB status register */ -#define XHCI_OP_USBSTS 0x04 - -/** Host controller halted */ -#define XHCI_USBSTS_HCH 0x00000001UL - -/** Page size register */ -#define XHCI_OP_PAGESIZE 0x08 - -/** Page size */ -#define XHCI_PAGESIZE(pagesize) ( (pagesize) << 12 ) - -/** Device notifcation control register */ -#define XHCI_OP_DNCTRL 0x14 - -/** Command ring control register */ -#define XHCI_OP_CRCR 0x18 - -/** Command ring cycle state */ -#define XHCI_CRCR_RCS 0x00000001UL - -/** Command abort */ -#define XHCI_CRCR_CA 0x00000004UL - -/** Command ring running */ -#define XHCI_CRCR_CRR 0x00000008UL - -/** Device context base address array pointer */ -#define XHCI_OP_DCBAAP 0x30 - -/** Configure register */ -#define XHCI_OP_CONFIG 0x38 - -/** Maximum device slots enabled */ -#define XHCI_CONFIG_MAX_SLOTS_EN(slots) ( (slots) << 0 ) - -/** Maximum device slots enabled mask */ -#define XHCI_CONFIG_MAX_SLOTS_EN_MASK \ - XHCI_CONFIG_MAX_SLOTS_EN ( 0xff ) - -/** Port status and control register */ -#define XHCI_OP_PORTSC(port) ( 0x400 - 0x10 + ( (port) << 4 ) ) - -/** Current connect status */ -#define XHCI_PORTSC_CCS 0x00000001UL - -/** Port enabled */ -#define XHCI_PORTSC_PED 0x00000002UL - -/** Port reset */ -#define XHCI_PORTSC_PR 0x00000010UL - -/** Port link state */ -#define XHCI_PORTSC_PLS(pls) ( (pls) << 5 ) - -/** Disabled port link state */ -#define XHCI_PORTSC_PLS_DISABLED XHCI_PORTSC_PLS ( 4 ) - -/** RxDetect port link state */ -#define XHCI_PORTSC_PLS_RXDETECT XHCI_PORTSC_PLS ( 5 ) - -/** Port link state mask */ -#define XHCI_PORTSC_PLS_MASK XHCI_PORTSC_PLS ( 0xf ) - -/** Port power */ -#define XHCI_PORTSC_PP 0x00000200UL - -/** Time to delay after enabling power to a port */ -#define XHCI_PORT_POWER_DELAY_MS 20 - -/** Port speed ID value */ -#define XHCI_PORTSC_PSIV(portsc) ( ( (portsc) >> 10 ) & 0xf ) - -/** Port indicator control */ -#define XHCI_PORTSC_PIC(indicators) ( (indicators) << 14 ) - -/** Port indicator control mask */ -#define XHCI_PORTSC_PIC_MASK XHCI_PORTSC_PIC ( 3 ) - -/** Port link state write strobe */ -#define XHCI_PORTSC_LWS 0x00010000UL - -/** Time to delay after writing the port link state */ -#define XHCI_LINK_STATE_DELAY_MS 100 - -/** Connect status change */ -#define XHCI_PORTSC_CSC 0x00020000UL - -/** Port enabled/disabled change */ -#define XHCI_PORTSC_PEC 0x00040000UL - -/** Warm port reset change */ -#define XHCI_PORTSC_WRC 0x00080000UL - -/** Over-current change */ -#define XHCI_PORTSC_OCC 0x00100000UL - -/** Port reset change */ -#define XHCI_PORTSC_PRC 0x00200000UL - -/** Port link state change */ -#define XHCI_PORTSC_PLC 0x00400000UL - -/** Port config error change */ -#define XHCI_PORTSC_CEC 0x00800000UL - -/** Port status change mask */ -#define XHCI_PORTSC_CHANGE \ - ( XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_WRC | \ - XHCI_PORTSC_OCC | XHCI_PORTSC_PRC | XHCI_PORTSC_PLC | \ - XHCI_PORTSC_CEC ) - -/** Port status and control bits which should be preserved - * - * The port status and control register is a horrendous mix of - * differing semantics. Some bits are written to only when a separate - * write strobe bit is set. Some bits should be preserved when - * modifying other bits. Some bits will be cleared if written back as - * a one. Most excitingly, the "port enabled" bit has the semantics - * that 1=enabled, 0=disabled, yet writing a 1 will disable the port. - */ -#define XHCI_PORTSC_PRESERVE ( XHCI_PORTSC_PP | XHCI_PORTSC_PIC_MASK ) - -/** Port power management status and control register */ -#define XHCI_OP_PORTPMSC(port) ( 0x404 - 0x10 + ( (port) << 4 ) ) - -/** Port link info register */ -#define XHCI_OP_PORTLI(port) ( 0x408 - 0x10 + ( (port) << 4 ) ) - -/** Port hardware link power management control register */ -#define XHCI_OP_PORTHLPMC(port) ( 0x40c - 0x10 + ( (port) << 4 ) ) - -/** Event ring segment table size register */ -#define XHCI_RUN_ERSTSZ(intr) ( 0x28 + ( (intr) << 5 ) ) - -/** Event ring segment table base address register */ -#define XHCI_RUN_ERSTBA(intr) ( 0x30 + ( (intr) << 5 ) ) - -/** Event ring dequeue pointer register */ -#define XHCI_RUN_ERDP(intr) ( 0x38 + ( (intr) << 5 ) ) - -/** A transfer request block template */ -struct xhci_trb_template { - /** Parameter */ - uint64_t parameter; - /** Status */ - uint32_t status; - /** Control */ - uint32_t control; -}; - -/** A transfer request block */ -struct xhci_trb_common { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** Transfer request block cycle bit flag */ -#define XHCI_TRB_C 0x01 - -/** Transfer request block toggle cycle bit flag */ -#define XHCI_TRB_TC 0x02 - -/** Transfer request block chain flag */ -#define XHCI_TRB_CH 0x10 - -/** Transfer request block interrupt on completion flag */ -#define XHCI_TRB_IOC 0x20 - -/** Transfer request block immediate data flag */ -#define XHCI_TRB_IDT 0x40 - -/** Transfer request block type */ -#define XHCI_TRB_TYPE(type) ( (type) << 2 ) - -/** Transfer request block type mask */ -#define XHCI_TRB_TYPE_MASK XHCI_TRB_TYPE ( 0x3f ) - -/** A normal transfer request block */ -struct xhci_trb_normal { - /** Data buffer */ - uint64_t data; - /** Length */ - uint32_t len; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved; -} __attribute__ (( packed )); - -/** A normal transfer request block */ -#define XHCI_TRB_NORMAL XHCI_TRB_TYPE ( 1 ) - -/** Construct TD size field */ -#define XHCI_TD_SIZE(remaining) \ - ( ( ( (remaining) <= 0xf ) ? remaining : 0xf ) << 17 ) - -/** A setup stage transfer request block */ -struct xhci_trb_setup { - /** Setup packet */ - struct usb_setup_packet packet; - /** Length */ - uint32_t len; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Transfer direction */ - uint8_t direction; - /** Reserved */ - uint8_t reserved; -} __attribute__ (( packed )); - -/** A setup stage transfer request block */ -#define XHCI_TRB_SETUP XHCI_TRB_TYPE ( 2 ) - -/** Setup stage input data direction */ -#define XHCI_SETUP_IN 3 - -/** Setup stage output data direction */ -#define XHCI_SETUP_OUT 2 - -/** A data stage transfer request block */ -struct xhci_trb_data { - /** Data buffer */ - uint64_t data; - /** Length */ - uint32_t len; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Transfer direction */ - uint8_t direction; - /** Reserved */ - uint8_t reserved; -} __attribute__ (( packed )); - -/** A data stage transfer request block */ -#define XHCI_TRB_DATA XHCI_TRB_TYPE ( 3 ) - -/** Input data direction */ -#define XHCI_DATA_IN 0x01 - -/** Output data direction */ -#define XHCI_DATA_OUT 0x00 - -/** A status stage transfer request block */ -struct xhci_trb_status { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Direction */ - uint8_t direction; - /** Reserved */ - uint8_t reserved_c; -} __attribute__ (( packed )); - -/** A status stage transfer request block */ -#define XHCI_TRB_STATUS XHCI_TRB_TYPE ( 4 ) - -/** Input status direction */ -#define XHCI_STATUS_IN 0x01 - -/** Output status direction */ -#define XHCI_STATUS_OUT 0x00 - -/** A link transfer request block */ -struct xhci_trb_link { - /** Next ring segment */ - uint64_t next; - /** Reserved */ - uint32_t reserved_a; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** A link transfer request block */ -#define XHCI_TRB_LINK XHCI_TRB_TYPE ( 6 ) - -/** A no-op transfer request block */ -#define XHCI_TRB_NOP XHCI_TRB_TYPE ( 8 ) - -/** An enable slot transfer request block */ -struct xhci_trb_enable_slot { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Slot type */ - uint8_t slot; - /** Reserved */ - uint8_t reserved_c; -} __attribute__ (( packed )); - -/** An enable slot transfer request block */ -#define XHCI_TRB_ENABLE_SLOT XHCI_TRB_TYPE ( 9 ) - -/** A disable slot transfer request block */ -struct xhci_trb_disable_slot { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint8_t reserved_c; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A disable slot transfer request block */ -#define XHCI_TRB_DISABLE_SLOT XHCI_TRB_TYPE ( 10 ) - -/** A context transfer request block */ -struct xhci_trb_context { - /** Input context */ - uint64_t input; - /** Reserved */ - uint32_t reserved_a; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint8_t reserved_b; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** An address device transfer request block */ -#define XHCI_TRB_ADDRESS_DEVICE XHCI_TRB_TYPE ( 11 ) - -/** A configure endpoint transfer request block */ -#define XHCI_TRB_CONFIGURE_ENDPOINT XHCI_TRB_TYPE ( 12 ) - -/** An evaluate context transfer request block */ -#define XHCI_TRB_EVALUATE_CONTEXT XHCI_TRB_TYPE ( 13 ) - -/** A reset endpoint transfer request block */ -struct xhci_trb_reset_endpoint { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A reset endpoint transfer request block */ -#define XHCI_TRB_RESET_ENDPOINT XHCI_TRB_TYPE ( 14 ) - -/** A stop endpoint transfer request block */ -struct xhci_trb_stop_endpoint { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A stop endpoint transfer request block */ -#define XHCI_TRB_STOP_ENDPOINT XHCI_TRB_TYPE ( 15 ) - -/** A set transfer ring dequeue pointer transfer request block */ -struct xhci_trb_set_tr_dequeue_pointer { - /** Dequeue pointer */ - uint64_t dequeue; - /** Reserved */ - uint32_t reserved; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A set transfer ring dequeue pointer transfer request block */ -#define XHCI_TRB_SET_TR_DEQUEUE_POINTER XHCI_TRB_TYPE ( 16 ) - -/** A no-op command transfer request block */ -#define XHCI_TRB_NOP_CMD XHCI_TRB_TYPE ( 23 ) - -/** A transfer event transfer request block */ -struct xhci_trb_transfer { - /** Transfer TRB pointer */ - uint64_t transfer; - /** Residual transfer length */ - uint16_t residual; - /** Reserved */ - uint8_t reserved; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A transfer event transfer request block */ -#define XHCI_TRB_TRANSFER XHCI_TRB_TYPE ( 32 ) - -/** A command completion event transfer request block */ -struct xhci_trb_complete { - /** Command TRB pointer */ - uint64_t command; - /** Parameter */ - uint8_t parameter[3]; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Virtual function ID */ - uint8_t vf; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A command completion event transfer request block */ -#define XHCI_TRB_COMPLETE XHCI_TRB_TYPE ( 33 ) - -/** xHCI completion codes */ -enum xhci_completion_code { - /** Success */ - XHCI_CMPLT_SUCCESS = 1, - /** Short packet */ - XHCI_CMPLT_SHORT = 13, - /** Command ring stopped */ - XHCI_CMPLT_CMD_STOPPED = 24, -}; - -/** A port status change transfer request block */ -struct xhci_trb_port_status { - /** Reserved */ - uint8_t reserved_a[3]; - /** Port ID */ - uint8_t port; - /** Reserved */ - uint8_t reserved_b[7]; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** A port status change transfer request block */ -#define XHCI_TRB_PORT_STATUS XHCI_TRB_TYPE ( 34 ) - -/** A port status change transfer request block */ -struct xhci_trb_host_controller { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint8_t reserved_b[3]; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** A port status change transfer request block */ -#define XHCI_TRB_HOST_CONTROLLER XHCI_TRB_TYPE ( 37 ) - -/** A transfer request block */ -union xhci_trb { - /** Template */ - struct xhci_trb_template template; - /** Common fields */ - struct xhci_trb_common common; - /** Normal TRB */ - struct xhci_trb_normal normal; - /** Setup stage TRB */ - struct xhci_trb_setup setup; - /** Data stage TRB */ - struct xhci_trb_data data; - /** Status stage TRB */ - struct xhci_trb_status status; - /** Link TRB */ - struct xhci_trb_link link; - /** Enable slot TRB */ - struct xhci_trb_enable_slot enable; - /** Disable slot TRB */ - struct xhci_trb_disable_slot disable; - /** Input context TRB */ - struct xhci_trb_context context; - /** Reset endpoint TRB */ - struct xhci_trb_reset_endpoint reset; - /** Stop endpoint TRB */ - struct xhci_trb_stop_endpoint stop; - /** Set transfer ring dequeue pointer TRB */ - struct xhci_trb_set_tr_dequeue_pointer dequeue; - /** Transfer event */ - struct xhci_trb_transfer transfer; - /** Command completion event */ - struct xhci_trb_complete complete; - /** Port status changed event */ - struct xhci_trb_port_status port; - /** Host controller event */ - struct xhci_trb_host_controller host; -} __attribute__ (( packed )); - -/** An input control context */ -struct xhci_control_context { - /** Drop context flags */ - uint32_t drop; - /** Add context flags */ - uint32_t add; - /** Reserved */ - uint32_t reserved_a[5]; - /** Configuration value */ - uint8_t config; - /** Interface number */ - uint8_t intf; - /** Alternate setting */ - uint8_t alt; - /** Reserved */ - uint8_t reserved_b; -} __attribute__ (( packed )); - -/** A slot context */ -struct xhci_slot_context { - /** Device info */ - uint32_t info; - /** Maximum exit latency */ - uint16_t latency; - /** Root hub port number */ - uint8_t port; - /** Number of downstream ports */ - uint8_t ports; - /** TT hub slot ID */ - uint8_t tt_id; - /** TT port number */ - uint8_t tt_port; - /** Interrupter target */ - uint16_t intr; - /** USB address */ - uint8_t address; - /** Reserved */ - uint16_t reserved_a; - /** Slot state */ - uint8_t state; - /** Reserved */ - uint32_t reserved_b[4]; -} __attribute__ (( packed )); - -/** Construct slot context device info */ -#define XHCI_SLOT_INFO( entries, hub, speed, route ) \ - ( ( (entries) << 27 ) | ( (hub) << 26 ) | ( (speed) << 20 ) | (route) ) - -/** An endpoint context */ -struct xhci_endpoint_context { - /** Endpoint state */ - uint8_t state; - /** Stream configuration */ - uint8_t stream; - /** Polling interval */ - uint8_t interval; - /** Max ESIT payload high */ - uint8_t esit_high; - /** Endpoint type */ - uint8_t type; - /** Maximum burst size */ - uint8_t burst; - /** Maximum packet size */ - uint16_t mtu; - /** Transfer ring dequeue pointer */ - uint64_t dequeue; - /** Average TRB length */ - uint16_t trb_len; - /** Max ESIT payload low */ - uint16_t esit_low; - /** Reserved */ - uint32_t reserved[3]; -} __attribute__ (( packed )); - -/** Endpoint states */ -enum xhci_endpoint_state { - /** Endpoint is disabled */ - XHCI_ENDPOINT_DISABLED = 0, - /** Endpoint is running */ - XHCI_ENDPOINT_RUNNING = 1, - /** Endpoint is halted due to a USB Halt condition */ - XHCI_ENDPOINT_HALTED = 2, - /** Endpoint is stopped */ - XHCI_ENDPOINT_STOPPED = 3, - /** Endpoint is halted due to a TRB error */ - XHCI_ENDPOINT_ERROR = 4, -}; - -/** Endpoint state mask */ -#define XHCI_ENDPOINT_STATE_MASK 0x07 - -/** Endpoint type */ -#define XHCI_EP_TYPE(type) ( (type) << 3 ) - -/** Control endpoint type */ -#define XHCI_EP_TYPE_CONTROL XHCI_EP_TYPE ( 4 ) - -/** Input endpoint type */ -#define XHCI_EP_TYPE_IN XHCI_EP_TYPE ( 4 ) - -/** Periodic endpoint type */ -#define XHCI_EP_TYPE_PERIODIC XHCI_EP_TYPE ( 1 ) - -/** Endpoint dequeue cycle state */ -#define XHCI_EP_DCS 0x00000001UL - -/** Control endpoint average TRB length */ -#define XHCI_EP0_TRB_LEN 8 - -/** An event ring segment */ -struct xhci_event_ring_segment { - /** Base address */ - uint64_t base; - /** Number of TRBs */ - uint32_t count; - /** Reserved */ - uint32_t reserved; -} __attribute__ (( packed )); - -/** A transfer request block command/transfer ring */ -struct xhci_trb_ring { - /** Producer counter */ - unsigned int prod; - /** Consumer counter */ - unsigned int cons; - /** Ring size (log2) */ - unsigned int shift; - /** Ring counter mask */ - unsigned int mask; - - /** I/O buffers */ - struct io_buffer **iobuf; - - /** Transfer request blocks */ - union xhci_trb *trb; - /** Length of transfer request blocks */ - size_t len; - /** DMA mapping */ - struct dma_mapping map; - /** Link TRB (if applicable) */ - struct xhci_trb_link *link; - - /** Doorbell register */ - void *db; - /** Doorbell register value */ - uint32_t dbval; -}; - -/** An event ring */ -struct xhci_event_ring { - /** Consumer counter */ - unsigned int cons; - /** Event ring segment table */ - struct xhci_event_ring_segment *segment; - /** Event ring segment table DMA mapping */ - struct dma_mapping segment_map; - /** Transfer request blocks */ - union xhci_trb *trb; - /** Transfer request blocks DMA mapping */ - struct dma_mapping trb_map; -}; - -/** - * Calculate doorbell register value - * - * @v target Doorbell target - * @v stream Doorbell stream ID - * @ret dbval Doorbell register value - */ -#define XHCI_DBVAL( target, stream ) ( (target) | ( (stream) << 16 ) ) - -/** - * Calculate space used in TRB ring - * - * @v ring TRB ring - * @ret fill Number of entries used - */ -static inline __attribute__ (( always_inline )) unsigned int -xhci_ring_fill ( struct xhci_trb_ring *ring ) { - - return ( ring->prod - ring->cons ); -} - -/** - * Calculate space remaining in TRB ring - * - * @v ring TRB ring - * @ret remaining Number of entries remaining - * - * xHCI does not allow us to completely fill a ring; there must be at - * least one free entry (excluding the Link TRB). - */ -static inline __attribute__ (( always_inline )) unsigned int -xhci_ring_remaining ( struct xhci_trb_ring *ring ) { - unsigned int fill = xhci_ring_fill ( ring ); - - /* We choose to utilise rings with ( 2^n + 1 ) entries, with - * the final entry being a Link TRB. The maximum fill level - * is therefore - * - * ( ( 2^n + 1 ) - 1 (Link TRB) - 1 (one slot always empty) - * == ( 2^n - 1 ) - * - * which is therefore equal to the ring mask. - */ - assert ( fill <= ring->mask ); - return ( ring->mask - fill ); -} - -/** - * Calculate physical address of most recently consumed TRB - * - * @v ring TRB ring - * @ret trb TRB physical address - */ -static inline __attribute__ (( always_inline )) physaddr_t -xhci_ring_consumed ( struct xhci_trb_ring *ring ) { - unsigned int index = ( ( ring->cons - 1 ) & ring->mask ); - - return virt_to_phys ( &ring->trb[index] ); -} - -/** Slot context index */ -#define XHCI_CTX_SLOT 0 - -/** Calculate context index from USB endpoint address */ -#define XHCI_CTX(address) \ - ( (address) ? ( ( ( (address) & 0x0f ) << 1 ) | \ - ( ( (address) & 0x80 ) >> 7 ) ) : 1 ) - -/** Endpoint zero context index */ -#define XHCI_CTX_EP0 XHCI_CTX ( 0x00 ) - -/** End of contexts */ -#define XHCI_CTX_END 32 - -/** Device context index */ -#define XHCI_DCI(ctx) ( (ctx) + 0 ) - -/** Input context index */ -#define XHCI_ICI(ctx) ( (ctx) + 1 ) - -/** Number of TRBs (excluding Link TRB) in the command ring - * - * This is a policy decision. - */ -#define XHCI_CMD_TRBS_LOG2 2 - -/** Number of TRBs in the event ring - * - * This is a policy decision. - */ -#define XHCI_EVENT_TRBS_LOG2 6 - -/** Number of TRBs in a transfer ring - * - * This is a policy decision. - */ -#define XHCI_TRANSFER_TRBS_LOG2 6 - -/** Maximum time to wait for BIOS to release ownership - * - * This is a policy decision. - */ -#define XHCI_USBLEGSUP_MAX_WAIT_MS 100 - -/** Maximum time to wait for host controller to stop - * - * This is a policy decision. - */ -#define XHCI_STOP_MAX_WAIT_MS 100 - -/** Maximum time to wait for reset to complete - * - * This is a policy decision. - */ -#define XHCI_RESET_MAX_WAIT_MS 500 - -/** Maximum time to wait for a command to complete - * - * The "address device" command involves waiting for a response to a - * USB control transaction, and so we must wait for up to the 5000ms - * that USB allows for devices to respond to control transactions. - */ -#define XHCI_COMMAND_MAX_WAIT_MS USB_CONTROL_MAX_WAIT_MS - -/** Time to delay after aborting a command - * - * This is a policy decision - */ -#define XHCI_COMMAND_ABORT_DELAY_MS 500 - -/** Maximum time to wait for a port reset to complete - * - * This is a policy decision. - */ -#define XHCI_PORT_RESET_MAX_WAIT_MS 500 - -/** Intel PCH quirk */ -struct xhci_pch { - /** USB2 port routing register original value */ - uint32_t xusb2pr; - /** USB3 port SuperSpeed enable register original value */ - uint32_t usb3pssen; -}; - -/** Intel PCH quirk flag */ -#define XHCI_PCH 0x0001 - -/** Intel PCH USB2 port routing register */ -#define XHCI_PCH_XUSB2PR 0xd0 - -/** Intel PCH USB2 port routing mask register */ -#define XHCI_PCH_XUSB2PRM 0xd4 - -/** Intel PCH SuperSpeed enable register */ -#define XHCI_PCH_USB3PSSEN 0xd8 - -/** Intel PCH USB3 port routing mask register */ -#define XHCI_PCH_USB3PRM 0xdc - -/** Invalid protocol speed ID values quirk */ -#define XHCI_BAD_PSIV 0x0002 - -/** Device context base address array */ -struct xhci_dcbaa { - /** Context base addresses */ - uint64_t *context; - /** DMA mapping */ - struct dma_mapping map; -}; - -/** Scratchpad buffer */ -struct xhci_scratchpad { - /** Number of page-sized scratchpad buffers */ - unsigned int count; - /** Scratchpad buffer area */ - userptr_t buffer; - /** Buffer DMA mapping */ - struct dma_mapping buffer_map; - /** Scratchpad array */ - uint64_t *array; - /** Array DMA mapping */ - struct dma_mapping array_map; -}; - -/** An xHCI device */ -struct xhci_device { - /** Registers */ - void *regs; - /** DMA device */ - struct dma_device *dma; - /** Name */ - const char *name; - /** Quirks */ - unsigned int quirks; - - /** Capability registers */ - void *cap; - /** Operational registers */ - void *op; - /** Runtime registers */ - void *run; - /** Doorbell registers */ - void *db; - - /** Number of device slots */ - unsigned int slots; - /** Number of interrupters */ - unsigned int intrs; - /** Number of ports */ - unsigned int ports; - - /** 64-bit addressing capability */ - int addr64; - /** Context size shift */ - unsigned int csz_shift; - /** xHCI extended capabilities offset */ - unsigned int xecp; - - /** Page size */ - size_t pagesize; - - /** USB legacy support capability (if present and enabled) */ - unsigned int legacy; - - /** Device context base address array */ - struct xhci_dcbaa dcbaa; - - /** Scratchpad buffer */ - struct xhci_scratchpad scratch; - - /** Command ring */ - struct xhci_trb_ring command; - /** Event ring */ - struct xhci_event_ring event; - /** Current command (if any) */ - union xhci_trb *pending; - /** Command mechanism has permanently failed */ - int failed; - - /** Device slots, indexed by slot ID */ - struct xhci_slot **slot; - - /** USB bus */ - struct usb_bus *bus; - - /** Intel PCH quirk */ - struct xhci_pch pch; -}; - -/** An xHCI device slot */ -struct xhci_slot { - /** xHCI device */ - struct xhci_device *xhci; - /** USB device */ - struct usb_device *usb; - /** Slot ID */ - unsigned int id; - /** Slot context */ - struct xhci_slot_context *context; - /** DMA mapping */ - struct dma_mapping map; - /** Route string */ - unsigned int route; - /** Root hub port number */ - unsigned int port; - /** Protocol speed ID */ - unsigned int psiv; - /** Number of ports (if this device is a hub) */ - unsigned int ports; - /** Transaction translator slot ID */ - unsigned int tt_id; - /** Transaction translator port */ - unsigned int tt_port; - /** Endpoints, indexed by context ID */ - struct xhci_endpoint *endpoint[XHCI_CTX_END]; -}; - -/** An xHCI endpoint */ -struct xhci_endpoint { - /** xHCI device */ - struct xhci_device *xhci; - /** xHCI slot */ - struct xhci_slot *slot; - /** USB endpoint */ - struct usb_endpoint *ep; - /** Context index */ - unsigned int ctx; - /** Endpoint type */ - unsigned int type; - /** Endpoint interval */ - unsigned int interval; - /** Endpoint context */ - struct xhci_endpoint_context *context; - /** Transfer ring */ - struct xhci_trb_ring ring; -}; - -#endif /* _IPXE_XHCI_H */ |
