diff options
Diffstat (limited to 'src/drivers/usb/xhci.c')
| -rw-r--r-- | src/drivers/usb/xhci.c | 149 |
1 files changed, 96 insertions, 53 deletions
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 ); |
