[xhci] Allow for non-PCI xHCI host controllers

Allow for the existence of xHCI host controllers where the underlying
hardware is not a PCI device.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-07-21 13:43:32 +01:00
parent eca97c2ee2
commit 6c42ea1275
2 changed files with 95 additions and 47 deletions

View File

@@ -35,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/usb.h> #include <ipxe/usb.h>
#include <ipxe/init.h> #include <ipxe/init.h>
#include <ipxe/profile.h> #include <ipxe/profile.h>
#include "xhci.h" #include <ipxe/xhci.h>
/** @file /** @file
* *
@@ -259,9 +259,8 @@ static struct profiler xhci_transfer_profiler __profiler =
* Initialise device * Initialise device
* *
* @v xhci xHCI 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 hcsparams1;
uint32_t hcsparams2; uint32_t hcsparams2;
uint32_t hccparams1; uint32_t hccparams1;
@@ -270,8 +269,11 @@ static void xhci_init ( struct xhci_device *xhci, void *regs ) {
size_t rtsoff; size_t rtsoff;
size_t dboff; size_t dboff;
/* Set device name */
xhci->name = xhci->dev->name;
/* Locate capability, operational, runtime, and doorbell registers */ /* Locate capability, operational, runtime, and doorbell registers */
xhci->cap = regs; xhci->cap = xhci->regs;
caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH ); caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH );
rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF ); rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF );
dboff = readl ( xhci->cap + XHCI_CAP_DBOFF ); dboff = readl ( xhci->cap + XHCI_CAP_DBOFF );
@@ -310,6 +312,10 @@ static void xhci_init ( struct xhci_device *xhci, void *regs ) {
assert ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 ); assert ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 );
DBGC2 ( xhci, "XHCI %s page size %zd bytes\n", DBGC2 ( xhci, "XHCI %s page size %zd bytes\n",
xhci->name, xhci->pagesize ); xhci->name, xhci->pagesize );
/* Configure DMA device */
if ( xhci->dma && xhci->addr64 )
dma_set_mask_64bit ( xhci->dma );
} }
/** /**
@@ -3264,7 +3270,7 @@ static int xhci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
/****************************************************************************** /******************************************************************************
* *
* PCI interface * Hardware-independent interface
* *
****************************************************************************** ******************************************************************************
*/ */
@@ -3303,6 +3309,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 * Fix Intel PCH-specific quirks
* *
@@ -3365,10 +3440,8 @@ static void xhci_pch_undo ( struct xhci_device *xhci, struct pci_device *pci ) {
*/ */
static int xhci_probe ( struct pci_device *pci ) { static int xhci_probe ( struct pci_device *pci ) {
struct xhci_device *xhci; struct xhci_device *xhci;
struct usb_port *port;
unsigned long bar_start; unsigned long bar_start;
size_t bar_size; size_t bar_size;
unsigned int i;
int rc; int rc;
/* Allocate and initialise structure */ /* Allocate and initialise structure */
@@ -3377,7 +3450,8 @@ static int xhci_probe ( struct pci_device *pci ) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_alloc; goto err_alloc;
} }
xhci->name = pci->dev.name; xhci->dev = &pci->dev;
xhci->dma = &pci->dma;
xhci->quirks = pci->id->driver_data; xhci->quirks = pci->id->driver_data;
/* Fix up PCI device */ /* Fix up PCI device */
@@ -3393,12 +3467,7 @@ static int xhci_probe ( struct pci_device *pci ) {
} }
/* Initialise xHCI device */ /* Initialise xHCI device */
xhci_init ( xhci, xhci->regs ); xhci_init ( xhci );
/* Configure DMA device */
xhci->dma = &pci->dma;
if ( xhci->addr64 )
dma_set_mask_64bit ( xhci->dma );
/* Initialise USB legacy support and claim ownership */ /* Initialise USB legacy support and claim ownership */
xhci_legacy_init ( xhci ); xhci_legacy_init ( xhci );
@@ -3408,39 +3477,15 @@ static int xhci_probe ( struct pci_device *pci ) {
if ( xhci->quirks & XHCI_PCH ) if ( xhci->quirks & XHCI_PCH )
xhci_pch_fix ( xhci, pci ); xhci_pch_fix ( xhci, pci );
/* Reset device */ /* Register xHCI device */
if ( ( rc = xhci_reset ( xhci ) ) != 0 ) if ( ( rc = xhci_register ( 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 )
goto err_register; goto err_register;
pci_set_drvdata ( pci, xhci ); pci_set_drvdata ( pci, xhci );
return 0; return 0;
unregister_usb_bus ( xhci->bus ); xhci_unregister ( xhci );
err_register: err_register:
free_usb_bus ( xhci->bus );
err_alloc_bus:
xhci_reset ( xhci );
err_reset:
if ( xhci->quirks & XHCI_PCH ) if ( xhci->quirks & XHCI_PCH )
xhci_pch_undo ( xhci, pci ); xhci_pch_undo ( xhci, pci );
xhci_legacy_release ( xhci ); xhci_legacy_release ( xhci );
@@ -3458,7 +3503,6 @@ static int xhci_probe ( struct pci_device *pci ) {
*/ */
static void xhci_remove ( struct pci_device *pci ) { static void xhci_remove ( struct pci_device *pci ) {
struct xhci_device *xhci = pci_get_drvdata ( pci ); struct xhci_device *xhci = pci_get_drvdata ( pci );
struct usb_bus *bus = xhci->bus;
uint16_t command; uint16_t command;
/* Some systems are observed to disable bus mastering on /* Some systems are observed to disable bus mastering on
@@ -3473,12 +3517,10 @@ static void xhci_remove ( struct pci_device *pci ) {
xhci_fail ( xhci ); xhci_fail ( xhci );
} }
/* Unregister and free USB bus */ /* Unregister xHCI controller */
unregister_usb_bus ( bus ); xhci_unregister ( xhci );
free_usb_bus ( bus );
/* Reset device and undo any PCH-specific fixes */ /* Undo any PCH-specific fixes */
xhci_reset ( xhci );
if ( xhci->quirks & XHCI_PCH ) if ( xhci->quirks & XHCI_PCH )
xhci_pch_undo ( xhci, pci ); xhci_pch_undo ( xhci, pci );

View File

@@ -1066,6 +1066,8 @@ struct xhci_scratchpad {
struct xhci_device { struct xhci_device {
/** Registers */ /** Registers */
void *regs; void *regs;
/** Underlying hardware device */
struct device *dev;
/** DMA device */ /** DMA device */
struct dma_device *dma; struct dma_device *dma;
/** Name */ /** Name */
@@ -1175,4 +1177,8 @@ struct xhci_endpoint {
struct xhci_trb_ring ring; struct xhci_trb_ring ring;
}; };
extern void xhci_init ( struct xhci_device *xhci );
extern int xhci_register ( struct xhci_device *xhci );
extern void xhci_unregister ( struct xhci_device *xhci );
#endif /* _IPXE_XHCI_H */ #endif /* _IPXE_XHCI_H */