diff options
Diffstat (limited to 'sound/usb/qcom/qc_audio_offload.c')
-rw-r--r-- | sound/usb/qcom/qc_audio_offload.c | 176 |
1 files changed, 76 insertions, 100 deletions
diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c index a25c5a531690..cfb30a195364 100644 --- a/sound/usb/qcom/qc_audio_offload.c +++ b/sound/usb/qcom/qc_audio_offload.c @@ -538,38 +538,33 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long iova, umap_size, iova, mapped_iova_size); } +static int uaudio_iommu_map_prot(bool dma_coherent) +{ + int prot = IOMMU_READ | IOMMU_WRITE; + + if (dma_coherent) + prot |= IOMMU_CACHE; + return prot; +} + /** - * uaudio_iommu_map() - maps iommu memory for adsp + * uaudio_iommu_map_pa() - maps iommu memory for adsp * @mtype: ring type * @dma_coherent: dma coherent * @pa: physical address for ring/buffer * @size: size of memory region - * @sgt: sg table for memory region * * Maps the XHCI related resources to a memory region that is assigned to be * used by the adsp. This will be mapped to the domain, which is created by * the ASoC USB backend driver. * */ -static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, - phys_addr_t pa, size_t size, - struct sg_table *sgt) +static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent, + phys_addr_t pa, size_t size) { - struct scatterlist *sg; unsigned long iova = 0; - size_t total_len = 0; - unsigned long iova_sg; - phys_addr_t pa_sg; bool map = true; - size_t sg_len; - int prot; - int ret; - int i; - - prot = IOMMU_READ | IOMMU_WRITE; - - if (dma_coherent) - prot |= IOMMU_CACHE; + int prot = uaudio_iommu_map_prot(dma_coherent); switch (mtype) { case MEM_EVENT_RING: @@ -583,20 +578,41 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, &uaudio_qdev->xfer_ring_iova_size, &uaudio_qdev->xfer_ring_list, size); break; - case MEM_XFER_BUF: - iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, - &uaudio_qdev->xfer_buf_iova_size, - &uaudio_qdev->xfer_buf_list, size); - break; default: dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype); } if (!iova || !map) - goto done; + return 0; - if (!sgt) - goto skip_sgt_map; + iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL); + + return iova; +} + +static unsigned long uaudio_iommu_map_xfer_buf(bool dma_coherent, size_t size, + struct sg_table *sgt) +{ + struct scatterlist *sg; + unsigned long iova = 0; + size_t total_len = 0; + unsigned long iova_sg; + phys_addr_t pa_sg; + size_t sg_len; + int prot = uaudio_iommu_map_prot(dma_coherent); + int ret; + int i; + + prot = IOMMU_READ | IOMMU_WRITE; + + if (dma_coherent) + prot |= IOMMU_CACHE; + + iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, + &uaudio_qdev->xfer_buf_iova_size, + &uaudio_qdev->xfer_buf_list, size); + if (!iova) + goto done; iova_sg = iova; for_each_sg(sgt->sgl, sg, sgt->nents, i) { @@ -618,11 +634,6 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, uaudio_iommu_unmap(MEM_XFER_BUF, iova, size, total_len); iova = 0; } - return iova; - -skip_sgt_map: - iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL); - done: return iova; } @@ -744,7 +755,7 @@ static void qmi_stop_session(void) int if_idx; int idx; - mutex_lock(&qdev_mutex); + guard(mutex)(&qdev_mutex); /* find all active intf for set alt 0 and cleanup usb audio dev */ for (idx = 0; idx < SNDRV_CARDS; idx++) { if (!atomic_read(&uadev[idx].in_use)) @@ -780,11 +791,9 @@ static void qmi_stop_session(void) disable_audio_stream(subs); } atomic_set(&uadev[idx].in_use, 0); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); uaudio_dev_cleanup(&uadev[idx]); - mutex_unlock(&chip->mutex); } - mutex_unlock(&qdev_mutex); } /** @@ -810,8 +819,8 @@ static int uaudio_sideband_notifier(struct usb_interface *intf, chip = usb_get_intfdata(intf); - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); dev = &uadev[chip->card->number]; @@ -825,9 +834,6 @@ static int uaudio_sideband_notifier(struct usb_interface *intf, } } - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); - return 0; } @@ -961,21 +967,21 @@ static int enable_audio_stream(struct snd_usb_substream *subs, goto put_suspend; if (!atomic_read(&chip->shutdown)) { - ret = snd_usb_lock_shutdown(chip); - if (ret < 0) + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) { + ret = pm.err; goto detach_ep; + } if (subs->sync_endpoint) { ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (ret < 0) - goto unlock; + goto detach_ep; } ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (ret < 0) - goto unlock; - - snd_usb_unlock_shutdown(chip); + goto detach_ep; dev_dbg(uaudio_qdev->data->dev, "selected %s iface:%d altsetting:%d datainterval:%dus\n", @@ -989,9 +995,6 @@ static int enable_audio_stream(struct snd_usb_substream *subs, return 0; -unlock: - snd_usb_unlock_shutdown(chip); - detach_ep: snd_usb_hw_free(subs); @@ -1020,7 +1023,6 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs, struct sg_table xfer_buf_sgt; dma_addr_t xfer_buf_dma; void *xfer_buf; - phys_addr_t xfer_buf_pa; u32 len = xfer_buf_len; bool dma_coherent; dma_addr_t xfer_buf_dma_sysdev; @@ -1051,18 +1053,12 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs, if (!xfer_buf) return -ENOMEM; - /* Remapping is not possible if xfer_buf is outside of linear map */ - xfer_buf_pa = virt_to_phys(xfer_buf); - if (WARN_ON(!page_is_ram(PFN_DOWN(xfer_buf_pa)))) { - ret = -ENXIO; - goto unmap_sync; - } dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, xfer_buf_dma, len); /* map the physical buffer into sysdev as well */ - xfer_buf_dma_sysdev = uaudio_iommu_map(MEM_XFER_BUF, dma_coherent, - xfer_buf_pa, len, &xfer_buf_sgt); + xfer_buf_dma_sysdev = uaudio_iommu_map_xfer_buf(dma_coherent, + len, &xfer_buf_sgt); if (!xfer_buf_dma_sysdev) { ret = -ENOMEM; goto unmap_sync; @@ -1143,8 +1139,8 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs, sg_free_table(sgt); /* data transfer ring */ - iova = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_pa, - PAGE_SIZE, NULL); + iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa, + PAGE_SIZE); if (!iova) { ret = -ENOMEM; goto clear_pa; @@ -1207,8 +1203,8 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs, mem_info->dma = sg_dma_address(sgt->sgl); sg_free_table(sgt); - iova = uaudio_iommu_map(MEM_EVENT_RING, dma_coherent, er_pa, - PAGE_SIZE, NULL); + iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa, + PAGE_SIZE); if (!iova) { ret = -ENOMEM; goto clear_pa; @@ -1580,17 +1576,15 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, goto response; } - mutex_lock(&chip->mutex); - if (req_msg->enable) { - if (info_idx < 0 || chip->system_suspend || subs->opened) { - ret = -EBUSY; - mutex_unlock(&chip->mutex); - - goto response; + scoped_guard(mutex, &chip->mutex) { + if (req_msg->enable) { + if (info_idx < 0 || chip->system_suspend || subs->opened) { + ret = -EBUSY; + goto response; + } + subs->opened = 1; } - subs->opened = 1; } - mutex_unlock(&chip->mutex); if (req_msg->service_interval_valid) { ret = get_data_interval_from_si(subs, @@ -1613,9 +1607,8 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, ret = prepare_qmi_response(subs, req_msg, &resp, info_idx); if (ret < 0) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); subs->opened = 0; - mutex_unlock(&chip->mutex); } } else { info = &uadev[pcm_card_num].info[info_idx]; @@ -1646,14 +1639,13 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, } disable_audio_stream(subs); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); subs->opened = 0; - mutex_unlock(&chip->mutex); } response: if (!req_msg->enable && ret != -EINVAL && ret != -ENODEV) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (info_idx >= 0) { info = &uadev[pcm_card_num].info[info_idx]; uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, @@ -1662,7 +1654,6 @@ response: if (atomic_read(&uadev[pcm_card_num].in_use)) kref_put(&uadev[pcm_card_num].kref, uaudio_dev_release); - mutex_unlock(&chip->mutex); } mutex_unlock(&qdev_mutex); @@ -1765,12 +1756,12 @@ static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) !usb_qmi_get_pcm_num(chip, 0)) return; - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); if (!uadev[chip->card->number].chip) { sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); if (!sdev) - goto exit; + return; sb = xhci_sideband_register(intf, XHCI_SIDEBAND_VENDOR, uaudio_sideband_notifier); @@ -1809,9 +1800,6 @@ static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) snd_soc_usb_connect(uaudio_qdev->auxdev->dev.parent, sdev); } - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); - return; unreg_xhci: @@ -1821,9 +1809,6 @@ free_sdev: kfree(sdev); uadev[chip->card->number].sdev = NULL; uadev[chip->card->number].chip = NULL; -exit: - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); } /** @@ -1859,16 +1844,13 @@ static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) if (card_num >= SNDRV_CARDS) return; - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); dev = &uadev[card_num]; /* Device has already been cleaned up, or never populated */ - if (!dev->chip) { - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); + if (!dev->chip) return; - } /* cleaned up already */ if (!dev->udev) @@ -1889,9 +1871,6 @@ done: kfree(dev->sdev); dev->sdev = NULL; } - mutex_unlock(&chip->mutex); - - mutex_unlock(&qdev_mutex); } /** @@ -1916,13 +1895,10 @@ static void qc_usb_audio_offload_suspend(struct usb_interface *intf, if (card_num >= SNDRV_CARDS) return; - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); uaudio_send_disconnect_ind(chip); - - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); } static struct snd_usb_platform_ops offload_ops = { |