diff options
| author | Simon Rettberg | 2022-05-11 10:41:01 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2022-05-11 10:41:01 +0200 |
| commit | a12e3c379cf2e5946c7316259ef46736cdd5f222 (patch) | |
| tree | 49638dad528a4490e293ea4a0f87e39ce862a75b /src/drivers | |
| parent | Local UEFI disk boot support (diff) | |
| parent | [cloud] Allow aws-import script to run on Python 3.6 (diff) | |
| download | ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.tar.gz ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.tar.xz ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.zip | |
Merge branch 'master' into openslx
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/bus/pci.c | 5 | ||||
| -rw-r--r-- | src/drivers/bus/virtio-pci.c | 45 | ||||
| -rw-r--r-- | src/drivers/bus/virtio-ring.c | 4 | ||||
| -rw-r--r-- | src/drivers/net/efi/nii.c | 2 | ||||
| -rw-r--r-- | src/drivers/net/efi/snpnet.c | 18 | ||||
| -rw-r--r-- | src/drivers/net/intelx.c | 1 | ||||
| -rw-r--r-- | src/drivers/net/virtio-net.c | 36 | ||||
| -rw-r--r-- | src/drivers/usb/usbkbd.c | 27 | ||||
| -rw-r--r-- | src/drivers/usb/usbkbd.h | 1 | ||||
| -rw-r--r-- | src/drivers/usb/xhci.c | 73 | ||||
| -rw-r--r-- | src/drivers/usb/xhci.h | 2 |
11 files changed, 175 insertions, 39 deletions
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 1b7350c8b..5891e42ff 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -121,6 +121,11 @@ static void pci_read_bases ( struct pci_device *pci ) { unsigned long bar; int reg; + /* Clear any existing base addresses */ + pci->ioaddr = 0; + pci->membase = 0; + + /* Get first memory and I/O BAR addresses */ for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) { bar = pci_bar ( pci, reg ); if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) { diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c index 5d2d62750..8b34c7277 100644 --- a/src/drivers/bus/virtio-pci.c +++ b/src/drivers/bus/virtio-pci.c @@ -17,37 +17,47 @@ #include "ipxe/io.h" #include "ipxe/iomap.h" #include "ipxe/pci.h" +#include "ipxe/dma.h" #include "ipxe/reboot.h" #include "ipxe/virtio-pci.h" #include "ipxe/virtio-ring.h" -static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num) +static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num, size_t header_size) { - size_t queue_size = PAGE_MASK + vring_size(num); + size_t ring_size = PAGE_MASK + vring_size(num); size_t vdata_size = num * sizeof(void *); + size_t queue_size = ring_size + vdata_size + header_size; - vq->queue = zalloc(queue_size + vdata_size); + vq->queue = dma_alloc(vq->dma, &vq->map, queue_size, queue_size); if (!vq->queue) { return -ENOMEM; } + memset ( vq->queue, 0, queue_size ); + vq->queue_size = queue_size; + /* vdata immediately follows the ring */ - vq->vdata = (void **)(vq->queue + queue_size); + vq->vdata = (void **)(vq->queue + ring_size); + + /* empty header immediately follows vdata */ + vq->empty_header = (struct virtio_net_hdr_modern *)(vq->queue + ring_size + vdata_size); return 0; } void vp_free_vq(struct vring_virtqueue *vq) { - if (vq->queue) { - free(vq->queue); + if (vq->queue && vq->queue_size) { + dma_free(&vq->map, vq->queue, vq->queue_size); vq->queue = NULL; vq->vdata = NULL; + vq->queue_size = 0; } } int vp_find_vq(unsigned int ioaddr, int queue_index, - struct vring_virtqueue *vq) + struct vring_virtqueue *vq, struct dma_device *dma_dev, + size_t header_size) { struct vring * vr = &vq->vring; u16 num; @@ -73,9 +83,10 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, } vq->queue_index = queue_index; + vq->dma = dma_dev; /* initialize the queue */ - rc = vp_alloc_vq(vq, num); + rc = vp_alloc_vq(vq, num, header_size); if (rc) { DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n"); return rc; @@ -87,8 +98,7 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, * NOTE: vr->desc is initialized by vring_init() */ - outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, - ioaddr + VIRTIO_PCI_QUEUE_PFN); + outl(dma(&vq->map, vr->desc) >> PAGE_SHIFT, ioaddr + VIRTIO_PCI_QUEUE_PFN); return num; } @@ -348,7 +358,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev, } int vpm_find_vqs(struct virtio_pci_modern_device *vdev, - unsigned nvqs, struct vring_virtqueue *vqs) + unsigned nvqs, struct vring_virtqueue *vqs, + struct dma_device *dma_dev, size_t header_size) { unsigned i; struct vring_virtqueue *vq; @@ -392,11 +403,12 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev, vq = &vqs[i]; vq->queue_index = i; + vq->dma = dma_dev; /* get offset of notification word for this vq */ off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off)); - err = vp_alloc_vq(vq, size); + err = vp_alloc_vq(vq, size, header_size); if (err) { DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev); return err; @@ -406,13 +418,16 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev, /* activate the queue */ vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size)); - vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.desc), + vpm_iowrite64(vdev, &vdev->common, + dma(&vq->map, vq->vring.desc), COMMON_OFFSET(queue_desc_lo), COMMON_OFFSET(queue_desc_hi)); - vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.avail), + vpm_iowrite64(vdev, &vdev->common, + dma(&vq->map, vq->vring.avail), COMMON_OFFSET(queue_avail_lo), COMMON_OFFSET(queue_avail_hi)); - vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.used), + vpm_iowrite64(vdev, &vdev->common, + dma(&vq->map, vq->vring.used), COMMON_OFFSET(queue_used_lo), COMMON_OFFSET(queue_used_hi)); diff --git a/src/drivers/bus/virtio-ring.c b/src/drivers/bus/virtio-ring.c index 98e787e16..e448c3488 100644 --- a/src/drivers/bus/virtio-ring.c +++ b/src/drivers/bus/virtio-ring.c @@ -98,7 +98,7 @@ void vring_add_buf(struct vring_virtqueue *vq, for (i = head; out; i = vr->desc[i].next, out--) { vr->desc[i].flags = VRING_DESC_F_NEXT; - vr->desc[i].addr = (u64)virt_to_phys(list->addr); + vr->desc[i].addr = list->addr; vr->desc[i].len = list->length; prev = i; list++; @@ -106,7 +106,7 @@ void vring_add_buf(struct vring_virtqueue *vq, for ( ; in; i = vr->desc[i].next, in--) { vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; - vr->desc[i].addr = (u64)virt_to_phys(list->addr); + vr->desc[i].addr = list->addr; vr->desc[i].len = list->length; prev = i; list++; diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index b9f34650e..833462e77 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -576,7 +576,7 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb, cdb.IFnum = nii->nii->IfNum; /* Raise task priority level */ - tpl = bs->RaiseTPL ( TPL_CALLBACK ); + tpl = bs->RaiseTPL ( efi_internal_tpl ); /* Issue command */ DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n", diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index fb5240277..69ec6f5e5 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -164,6 +164,10 @@ static int snpnet_transmit ( struct net_device *netdev, EFI_STATUS efirc; int rc; + /* Do nothing if shutdown is in progress */ + if ( efi_shutdown_in_progress ) + return -ECANCELED; + /* Defer the packet if there is already a transmission in progress */ if ( snp->txbuf ) { netdev_tx_defer ( netdev, iobuf ); @@ -283,6 +287,10 @@ static void snpnet_poll_rx ( struct net_device *netdev ) { */ static void snpnet_poll ( struct net_device *netdev ) { + /* Do nothing if shutdown is in progress */ + if ( efi_shutdown_in_progress ) + return; + /* Process any TX completions */ snpnet_poll_tx ( netdev ); @@ -426,8 +434,9 @@ static void snpnet_close ( struct net_device *netdev ) { EFI_STATUS efirc; int rc; - /* Shut down NIC */ - if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) { + /* Shut down NIC (unless whole system shutdown is in progress) */ + if ( ( ! efi_shutdown_in_progress ) && + ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); DBGC ( snp, "SNP %s could not shut down: %s\n", netdev->name, strerror ( rc ) ); @@ -589,8 +598,9 @@ void snpnet_stop ( struct efi_device *efidev ) { /* Unregister network device */ unregister_netdev ( netdev ); - /* Stop SNP protocol */ - if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) { + /* Stop SNP protocol (unless whole system shutdown is in progress) */ + if ( ( ! efi_shutdown_in_progress ) && + ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); DBGC ( device, "SNP %s could not stop: %s\n", efi_handle_name ( device ), strerror ( rc ) ); diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index ccf6b0648..f4dad8859 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -481,6 +481,7 @@ static struct pci_device_id intelx_nics[] = { PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ), PCI_ROM ( 0x8086, 0x15c8, "x553t", "X553/X557-AT", 0 ), PCI_ROM ( 0x8086, 0x15ce, "x553-sfp", "X553 (SFP+)", 0 ), + PCI_ROM ( 0x8086, 0x15e4, "x553a", "X553", 0 ), PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ), }; diff --git a/src/drivers/net/virtio-net.c b/src/drivers/net/virtio-net.c index 78ec9ac4e..0c4541924 100644 --- a/src/drivers/net/virtio-net.c +++ b/src/drivers/net/virtio-net.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> #include <ipxe/pci.h> +#include <ipxe/dma.h> #include <ipxe/if_ether.h> #include <ipxe/ethernet.h> #include <ipxe/virtio-pci.h> @@ -99,8 +100,9 @@ struct virtnet_nic { /** Pending rx packet count */ unsigned int rx_num_iobufs; - /** Virtio net dummy packet headers */ - struct virtio_net_hdr_modern empty_header[QUEUE_NB]; + /** DMA device */ + struct dma_device *dma; + }; /** Add an iobuf to a virtqueue @@ -115,7 +117,7 @@ static void virtnet_enqueue_iob ( struct net_device *netdev, int vq_idx, struct io_buffer *iobuf ) { struct virtnet_nic *virtnet = netdev->priv; struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx]; - struct virtio_net_hdr_modern *header = &virtnet->empty_header[vq_idx]; + struct virtio_net_hdr_modern *header = vq->empty_header; unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0; unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2; size_t header_len = ( virtnet->virtio_version ? @@ -132,11 +134,11 @@ static void virtnet_enqueue_iob ( struct net_device *netdev, * to header->flags for received packets. Work around * this by using separate RX and TX headers. */ - .addr = ( char* ) header, + .addr = dma ( &vq->map, header ), .length = header_len, }, { - .addr = ( char* ) iobuf->data, + .addr = iob_dma ( iobuf ), .length = iob_len ( iobuf ), }, }; @@ -161,7 +163,7 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) { struct io_buffer *iobuf; /* Try to allocate a buffer, stop for now if out of memory */ - iobuf = alloc_iob ( len ); + iobuf = alloc_rx_iob ( len, virtnet->dma ); if ( ! iobuf ) break; @@ -215,7 +217,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) { /* Initialize rx/tx virtqueues */ for ( i = 0; i < QUEUE_NB; i++ ) { - if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) { + if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i], virtnet->dma, + sizeof ( struct virtio_net_hdr_modern ) ) == -1 ) { DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n", virtnet, i ); virtnet_free_virtqueues ( netdev ); @@ -280,7 +283,8 @@ static int virtnet_open_modern ( struct net_device *netdev ) { } /* Initialize rx/tx virtqueues */ - if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) { + if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue, + virtnet->dma, sizeof ( struct virtio_net_hdr_modern ) ) ) { DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n", virtnet ); virtnet_free_virtqueues ( netdev ); @@ -335,7 +339,7 @@ static void virtnet_close ( struct net_device *netdev ) { /* Free rx iobufs */ list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) { - free_iob ( iobuf ); + free_rx_iob ( iobuf ); } INIT_LIST_HEAD ( &virtnet->rx_iobufs ); virtnet->rx_num_iobufs = 0; @@ -478,6 +482,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { /* Enable PCI bus master and reset NIC */ adjust_pci_device ( pci ); + + /* Configure DMA */ + virtnet->dma = &pci->dma; + dma_set_mask_64bit ( virtnet->dma ); + netdev->dma = virtnet->dma; + vp_reset ( ioaddr ); /* Load MAC address and MTU */ @@ -506,7 +516,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { return 0; unregister_netdev ( netdev ); - err_register_netdev: +err_register_netdev: vp_reset ( ioaddr ); netdev_nullify ( netdev ); netdev_put ( netdev ); @@ -586,6 +596,11 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) { /* Enable the PCI device */ adjust_pci_device ( pci ); + /* Configure DMA */ + virtnet->dma = &pci->dma; + dma_set_mask_64bit ( virtnet->dma ); + netdev->dma = virtnet->dma; + /* Reset the device and set initial status bits */ vpm_reset ( &virtnet->vdev ); vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE ); @@ -633,7 +648,6 @@ err_mac_address: vpm_reset ( &virtnet->vdev ); netdev_nullify ( netdev ); netdev_put ( netdev ); - virtio_pci_unmap_capability ( &virtnet->vdev.device ); err_map_device: virtio_pci_unmap_capability ( &virtnet->vdev.isr ); diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index a8ab6ab76..b284e584f 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -25,10 +25,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <errno.h> #include <assert.h> #include <ipxe/console.h> #include <ipxe/keys.h> +#include <ipxe/keymap.h> #include <ipxe/usb.h> #include "usbkbd.h" @@ -69,10 +71,7 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, } else if ( keycode <= USBKBD_KEY_Z ) { /* Alphabetic keys */ key = ( keycode - USBKBD_KEY_A + 'a' ); - if ( modifiers & USBKBD_CTRL ) { - key -= ( 'a' - CTRL_A ); - } else if ( ( modifiers & USBKBD_SHIFT ) || - ( leds & USBKBD_LED_CAPS_LOCK ) ) { + if ( modifiers & USBKBD_SHIFT ) { key -= ( 'a' - 'A' ); } } else if ( keycode <= USBKBD_KEY_0 ) { @@ -118,10 +117,30 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, }; key = keypad[ keycode - USBKBD_KEY_PAD_1 ]; }; + } else if ( keycode == USBKBD_KEY_NON_US ) { + /* Non-US \ and | */ + key = ( ( modifiers & USBKBD_SHIFT ) ? + ( KEYMAP_PSEUDO | '|' ) : ( KEYMAP_PSEUDO | '\\' ) ); } else { key = 0; } + /* Remap key if applicable */ + if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) || + ( keycode == USBKBD_KEY_NON_US ) ) { + + /* Apply modifiers */ + if ( modifiers & USBKBD_CTRL ) + key |= KEYMAP_CTRL; + if ( modifiers & USBKBD_ALT_RIGHT ) + key |= KEYMAP_ALTGR; + if ( leds & USBKBD_LED_CAPS_LOCK ) + key |= KEYMAP_CAPSLOCK; + + /* Remap key */ + key = key_remap ( key ); + } + return key; } diff --git a/src/drivers/usb/usbkbd.h b/src/drivers/usb/usbkbd.h index cedebfe71..1a3fea1ba 100644 --- a/src/drivers/usb/usbkbd.h +++ b/src/drivers/usb/usbkbd.h @@ -75,6 +75,7 @@ enum usb_keycode { USBKBD_KEY_PAD_ENTER = 0x58, USBKBD_KEY_PAD_1 = 0x59, USBKBD_KEY_PAD_DOT = 0x63, + USBKBD_KEY_NON_US = 0x64, }; /** USB keyboard LEDs */ diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index cc48af033..3247ee69c 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1165,6 +1165,31 @@ static int xhci_reset ( struct xhci_device *xhci ) { return -ETIMEDOUT; } +/** + * Mark xHCI device as permanently failed + * + * @v xhci xHCI device + * @ret rc Return status code + */ +static int xhci_fail ( struct xhci_device *xhci ) { + size_t len; + int rc; + + /* Mark command mechanism as permanently failed */ + xhci->failed = 1; + + /* Reset device */ + if ( ( rc = xhci_reset ( xhci ) ) != 0 ) + return rc; + + /* Discard DCBAA entries since DCBAAP has been cleared */ + assert ( xhci->dcbaa.context != NULL ); + len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); + memset ( xhci->dcbaa.context, 0, len ); + + return 0; +} + /****************************************************************************** * * Transfer request blocks @@ -1720,6 +1745,10 @@ static void xhci_event_poll ( struct xhci_device *xhci ) { unsigned int consumed; unsigned int type; + /* Do nothing if device has permanently failed */ + if ( xhci->failed ) + return; + /* Poll for events */ profile_start ( &xhci_event_profiler ); for ( consumed = 0 ; ; consumed++ ) { @@ -1778,6 +1807,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) { */ static void xhci_abort ( struct xhci_device *xhci ) { physaddr_t crp; + uint32_t crcr; /* Abort the command */ DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name ); @@ -1786,8 +1816,18 @@ static void xhci_abort ( struct xhci_device *xhci ) { /* Allow time for command to abort */ mdelay ( XHCI_COMMAND_ABORT_DELAY_MS ); - /* Sanity check */ - assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 ); + /* Check for failure to abort */ + crcr = readl ( xhci->op + XHCI_OP_CRCR ); + if ( crcr & XHCI_CRCR_CRR ) { + + /* Device has failed to abort a command and is almost + * certainly beyond repair. Reset device, abandoning + * all state, and mark device as failed to avoid + * delays on any future command attempts. + */ + DBGC ( xhci, "XHCI %s failed to abort command\n", xhci->name ); + xhci_fail ( xhci ); + } /* Consume (and ignore) any final command status */ xhci_event_poll ( xhci ); @@ -1813,6 +1853,12 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { unsigned int i; int rc; + /* Immediately fail all commands if command mechanism has failed */ + if ( xhci->failed ) { + rc = -EPIPE; + goto err_failed; + } + /* Sanity check */ if ( xhci->pending ) { DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name ); @@ -1863,6 +1909,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { err_enqueue: xhci->pending = NULL; err_pending: + err_failed: return rc; } @@ -3412,14 +3459,36 @@ 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 + * Thunderbolt controllers before we get a chance to shut + * down. Detect this and avoid attempting any DMA operations, + * which are guaranteed to fail and may end up spuriously + * completing after the operating system kernel starts up. + */ + pci_read_config_word ( pci, PCI_COMMAND, &command ); + if ( ! ( command & PCI_COMMAND_MASTER ) ) { + DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name ); + xhci_fail ( xhci ); + } + /* Unregister and free USB bus */ unregister_usb_bus ( bus ); free_usb_bus ( bus ); + + /* Reset device and undo any PCH-specific fixes */ xhci_reset ( xhci ); if ( xhci->quirks & XHCI_PCH ) xhci_pch_undo ( xhci, pci ); + + /* Release ownership back to BIOS */ xhci_legacy_release ( xhci ); + + /* Unmap registers */ iounmap ( xhci->regs ); + + /* Free device */ free ( xhci ); } diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index 6e02d70e0..a3c8888af 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -1115,6 +1115,8 @@ struct xhci_device { 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; |
