Skip to content

Commit 09b473a

Browse files
tiwaigregkh
authored andcommitted
ALSA: usb: qcom: Fix false-positive address space check
[ Upstream commit 44499ec ] The sanity check previously added to uaudio_transfer_buffer_setup() assumed the allocated buffer being linear-mapped. But the buffer allocated via usb_alloc_coherent() isn't always so, rather to be used with (SG-)DMA API. This leaded to a false-positive warning and the driver failed to work. Actually uaudio_transfer_buffer_setup() deals only with the DMA-API addresses for MEM_XFER_BUF type, while other callers of uaudio_iommu_map() are with pages with physical addresses for MEM_EVENT_RING and MEM_XFER_RING types. So this patch splits the mapping helper function to two different ones, uaudio_iommu_map() for the DMA pages and uaudio_iommu_map_pa() for the latter, in order to handle mapping differently for each type. Along with it, the unnecessary address check that caused probe error is dropped, too. Fixes: 3335a1b ("ALSA: qc_audio_offload: try to reduce address space confusion") Suggested-by: Arnd Bergmann <[email protected]> Acked-by: Arnd Bergmann <[email protected]> Reported-and-tested-by: Luca Weiss <[email protected]> Closes: https://lore.kernel.org/[email protected] Signed-off-by: Takashi Iwai <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent b45cabf commit 09b473a

File tree

1 file changed

+48
-44
lines changed

1 file changed

+48
-44
lines changed

sound/usb/qcom/qc_audio_offload.c

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -538,38 +538,33 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long iova,
538538
umap_size, iova, mapped_iova_size);
539539
}
540540

541+
static int uaudio_iommu_map_prot(bool dma_coherent)
542+
{
543+
int prot = IOMMU_READ | IOMMU_WRITE;
544+
545+
if (dma_coherent)
546+
prot |= IOMMU_CACHE;
547+
return prot;
548+
}
549+
541550
/**
542-
* uaudio_iommu_map() - maps iommu memory for adsp
551+
* uaudio_iommu_map_pa() - maps iommu memory for adsp
543552
* @mtype: ring type
544553
* @dma_coherent: dma coherent
545554
* @pa: physical address for ring/buffer
546555
* @size: size of memory region
547-
* @sgt: sg table for memory region
548556
*
549557
* Maps the XHCI related resources to a memory region that is assigned to be
550558
* used by the adsp. This will be mapped to the domain, which is created by
551559
* the ASoC USB backend driver.
552560
*
553561
*/
554-
static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent,
555-
phys_addr_t pa, size_t size,
556-
struct sg_table *sgt)
562+
static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent,
563+
phys_addr_t pa, size_t size)
557564
{
558-
struct scatterlist *sg;
559565
unsigned long iova = 0;
560-
size_t total_len = 0;
561-
unsigned long iova_sg;
562-
phys_addr_t pa_sg;
563566
bool map = true;
564-
size_t sg_len;
565-
int prot;
566-
int ret;
567-
int i;
568-
569-
prot = IOMMU_READ | IOMMU_WRITE;
570-
571-
if (dma_coherent)
572-
prot |= IOMMU_CACHE;
567+
int prot = uaudio_iommu_map_prot(dma_coherent);
573568

574569
switch (mtype) {
575570
case MEM_EVENT_RING:
@@ -583,20 +578,41 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent,
583578
&uaudio_qdev->xfer_ring_iova_size,
584579
&uaudio_qdev->xfer_ring_list, size);
585580
break;
586-
case MEM_XFER_BUF:
587-
iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova,
588-
&uaudio_qdev->xfer_buf_iova_size,
589-
&uaudio_qdev->xfer_buf_list, size);
590-
break;
591581
default:
592582
dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype);
593583
}
594584

595585
if (!iova || !map)
596-
goto done;
586+
return 0;
587+
588+
iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL);
597589

598-
if (!sgt)
599-
goto skip_sgt_map;
590+
return iova;
591+
}
592+
593+
static unsigned long uaudio_iommu_map_xfer_buf(bool dma_coherent, size_t size,
594+
struct sg_table *sgt)
595+
{
596+
struct scatterlist *sg;
597+
unsigned long iova = 0;
598+
size_t total_len = 0;
599+
unsigned long iova_sg;
600+
phys_addr_t pa_sg;
601+
size_t sg_len;
602+
int prot = uaudio_iommu_map_prot(dma_coherent);
603+
int ret;
604+
int i;
605+
606+
prot = IOMMU_READ | IOMMU_WRITE;
607+
608+
if (dma_coherent)
609+
prot |= IOMMU_CACHE;
610+
611+
iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova,
612+
&uaudio_qdev->xfer_buf_iova_size,
613+
&uaudio_qdev->xfer_buf_list, size);
614+
if (!iova)
615+
goto done;
600616

601617
iova_sg = iova;
602618
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,
618634
uaudio_iommu_unmap(MEM_XFER_BUF, iova, size, total_len);
619635
iova = 0;
620636
}
621-
return iova;
622-
623-
skip_sgt_map:
624-
iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL);
625-
626637
done:
627638
return iova;
628639
}
@@ -1020,7 +1031,6 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs,
10201031
struct sg_table xfer_buf_sgt;
10211032
dma_addr_t xfer_buf_dma;
10221033
void *xfer_buf;
1023-
phys_addr_t xfer_buf_pa;
10241034
u32 len = xfer_buf_len;
10251035
bool dma_coherent;
10261036
dma_addr_t xfer_buf_dma_sysdev;
@@ -1051,18 +1061,12 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs,
10511061
if (!xfer_buf)
10521062
return -ENOMEM;
10531063

1054-
/* Remapping is not possible if xfer_buf is outside of linear map */
1055-
xfer_buf_pa = virt_to_phys(xfer_buf);
1056-
if (WARN_ON(!page_is_ram(PFN_DOWN(xfer_buf_pa)))) {
1057-
ret = -ENXIO;
1058-
goto unmap_sync;
1059-
}
10601064
dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf,
10611065
xfer_buf_dma, len);
10621066

10631067
/* map the physical buffer into sysdev as well */
1064-
xfer_buf_dma_sysdev = uaudio_iommu_map(MEM_XFER_BUF, dma_coherent,
1065-
xfer_buf_pa, len, &xfer_buf_sgt);
1068+
xfer_buf_dma_sysdev = uaudio_iommu_map_xfer_buf(dma_coherent,
1069+
len, &xfer_buf_sgt);
10661070
if (!xfer_buf_dma_sysdev) {
10671071
ret = -ENOMEM;
10681072
goto unmap_sync;
@@ -1143,8 +1147,8 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs,
11431147
sg_free_table(sgt);
11441148

11451149
/* data transfer ring */
1146-
iova = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_pa,
1147-
PAGE_SIZE, NULL);
1150+
iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa,
1151+
PAGE_SIZE);
11481152
if (!iova) {
11491153
ret = -ENOMEM;
11501154
goto clear_pa;
@@ -1207,8 +1211,8 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs,
12071211
mem_info->dma = sg_dma_address(sgt->sgl);
12081212
sg_free_table(sgt);
12091213

1210-
iova = uaudio_iommu_map(MEM_EVENT_RING, dma_coherent, er_pa,
1211-
PAGE_SIZE, NULL);
1214+
iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa,
1215+
PAGE_SIZE);
12121216
if (!iova) {
12131217
ret = -ENOMEM;
12141218
goto clear_pa;

0 commit comments

Comments
 (0)