From 6d7eae8c4a4415d6da3000487bb67e2dee44e110 Mon Sep 17 00:00:00 2001 From: kettenis Date: Fri, 9 Jan 2015 20:17:05 +0000 Subject: [PATCH] Properly unwind from a failure in usbd_dma_contig_alloc(). Calling bus_dmamap_unload(9) on a map that failed to load is a bad idea and causes panics on some architectures (such as sparc64). ok mpi@ --- sys/dev/usb/xhci.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index f79f4b48144..1e605e83bae 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xhci.c,v 1.52 2015/01/05 12:38:16 mpi Exp $ */ +/* $OpenBSD: xhci.c,v 1.53 2015/01/09 20:17:05 kettenis Exp $ */ /* * Copyright (c) 2014 Martin Pieuchot @@ -224,22 +224,22 @@ usbd_dma_contig_alloc(struct usbd_bus *bus, struct usbd_dma_info *dma, error = bus_dmamap_create(dma->tag, size, 1, size, boundary, BUS_DMA_NOWAIT, &dma->map); if (error != 0) - goto fail; + return (error);; error = bus_dmamem_alloc(dma->tag, size, alignment, boundary, &dma->seg, 1, &dma->nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO); if (error != 0) - goto fail; + goto destroy; error = bus_dmamem_map(dma->tag, &dma->seg, 1, size, &dma->vaddr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); if (error != 0) - goto fail; + goto free; error = bus_dmamap_load_raw(dma->tag, dma->map, &dma->seg, 1, size, BUS_DMA_NOWAIT); if (error != 0) - goto fail; + goto unmap; bus_dmamap_sync(dma->tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE); @@ -249,7 +249,12 @@ usbd_dma_contig_alloc(struct usbd_bus *bus, struct usbd_dma_info *dma, return (0); -fail: usbd_dma_contig_free(bus, dma); +unmap: + bus_dmamem_unmap(dma->tag, dma->vaddr, size); +free: + bus_dmamem_free(dma->tag, &dma->seg, 1); +destroy: + bus_dmamap_destroy(dma->tag, dma->map); return (error); } @@ -257,14 +262,11 @@ void usbd_dma_contig_free(struct usbd_bus *bus, struct usbd_dma_info *dma) { if (dma->map != NULL) { - if (dma->vaddr != NULL) { - bus_dmamap_sync(bus->dmatag, dma->map, 0, dma->size, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(bus->dmatag, dma->map); - bus_dmamem_unmap(bus->dmatag, dma->vaddr, dma->size); - bus_dmamem_free(bus->dmatag, &dma->seg, 1); - dma->vaddr = NULL; - } + bus_dmamap_sync(bus->dmatag, dma->map, 0, dma->size, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(bus->dmatag, dma->map); + bus_dmamem_unmap(bus->dmatag, dma->vaddr, dma->size); + bus_dmamem_free(bus->dmatag, &dma->seg, 1); bus_dmamap_destroy(bus->dmatag, dma->map); dma->map = NULL; } -- 2.20.1