mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
Revert "iommu/amd_iommu: Use CONFIG_DMA_DIRECT_OPS=y and dma_direct_{alloc,free}()"
This reverts commitb468620f2a
. It turns out that this broke drm on AMD platforms. Quoting Gabriel C: "I can confirm revertingb468620f2a
fixes that issue for me. The GPU is working fine with SME enabled. Now with working GPU :) I can also confirm performance is back to normal without doing any other workarounds" Christan König analyzed it partially: "As far as I analyzed it we now get an -ENOMEM from dma_alloc_attrs() in drivers/gpu/drm/ttm/ttm_page_alloc_dma.c when IOMMU is enabled" and Christoph Hellwig responded: "I think the prime issue is that dma_direct_alloc respects the dma mask. Which we don't need if actually using the iommu. This would be mostly harmless exept for the the SEV bit high in the address that makes the checks fail. For now I'd say revert this commit for 4.17/4.18-rc and I'll look into addressing these issues properly" Reported-and-bisected-by: Gabriel C <nix.or.die@gmail.com> Acked-by: Christoph Hellwig <hch@lst.de> Cc: Christian König <christian.koenig@amd.com> Cc: Michel Dänzer <michel.daenzer@amd.com> Cc: Joerg Roedel <jroedel@suse.de> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: stable@kernel.org # v4.17 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
f7cca14bce
commit
e16c4790de
@ -107,7 +107,6 @@ config IOMMU_PGTABLES_L2
|
||||
# AMD IOMMU support
|
||||
config AMD_IOMMU
|
||||
bool "AMD IOMMU support"
|
||||
select DMA_DIRECT_OPS
|
||||
select SWIOTLB
|
||||
select PCI_MSI
|
||||
select PCI_ATS
|
||||
|
@ -2596,32 +2596,51 @@ static void *alloc_coherent(struct device *dev, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
u64 dma_mask = dev->coherent_dma_mask;
|
||||
struct protection_domain *domain = get_domain(dev);
|
||||
bool is_direct = false;
|
||||
void *virt_addr;
|
||||
struct protection_domain *domain;
|
||||
struct dma_ops_domain *dma_dom;
|
||||
struct page *page;
|
||||
|
||||
if (IS_ERR(domain)) {
|
||||
if (PTR_ERR(domain) != -EINVAL)
|
||||
domain = get_domain(dev);
|
||||
if (PTR_ERR(domain) == -EINVAL) {
|
||||
page = alloc_pages(flag, get_order(size));
|
||||
*dma_addr = page_to_phys(page);
|
||||
return page_address(page);
|
||||
} else if (IS_ERR(domain))
|
||||
return NULL;
|
||||
|
||||
dma_dom = to_dma_ops_domain(domain);
|
||||
size = PAGE_ALIGN(size);
|
||||
dma_mask = dev->coherent_dma_mask;
|
||||
flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
|
||||
flag |= __GFP_ZERO;
|
||||
|
||||
page = alloc_pages(flag | __GFP_NOWARN, get_order(size));
|
||||
if (!page) {
|
||||
if (!gfpflags_allow_blocking(flag))
|
||||
return NULL;
|
||||
is_direct = true;
|
||||
}
|
||||
|
||||
virt_addr = dma_direct_alloc(dev, size, dma_addr, flag, attrs);
|
||||
if (!virt_addr || is_direct)
|
||||
return virt_addr;
|
||||
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
|
||||
get_order(size), flag);
|
||||
if (!page)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!dma_mask)
|
||||
dma_mask = *dev->dma_mask;
|
||||
|
||||
*dma_addr = __map_single(dev, to_dma_ops_domain(domain),
|
||||
virt_to_phys(virt_addr), PAGE_ALIGN(size),
|
||||
DMA_BIDIRECTIONAL, dma_mask);
|
||||
*dma_addr = __map_single(dev, dma_dom, page_to_phys(page),
|
||||
size, DMA_BIDIRECTIONAL, dma_mask);
|
||||
|
||||
if (*dma_addr == AMD_IOMMU_MAPPING_ERROR)
|
||||
goto out_free;
|
||||
return virt_addr;
|
||||
|
||||
return page_address(page);
|
||||
|
||||
out_free:
|
||||
dma_direct_free(dev, size, virt_addr, *dma_addr, attrs);
|
||||
|
||||
if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
|
||||
__free_pages(page, get_order(size));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2632,17 +2651,24 @@ static void free_coherent(struct device *dev, size_t size,
|
||||
void *virt_addr, dma_addr_t dma_addr,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct protection_domain *domain = get_domain(dev);
|
||||
struct protection_domain *domain;
|
||||
struct dma_ops_domain *dma_dom;
|
||||
struct page *page;
|
||||
|
||||
page = virt_to_page(virt_addr);
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (!IS_ERR(domain)) {
|
||||
struct dma_ops_domain *dma_dom = to_dma_ops_domain(domain);
|
||||
domain = get_domain(dev);
|
||||
if (IS_ERR(domain))
|
||||
goto free_mem;
|
||||
|
||||
__unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL);
|
||||
}
|
||||
dma_dom = to_dma_ops_domain(domain);
|
||||
|
||||
dma_direct_free(dev, size, virt_addr, dma_addr, attrs);
|
||||
__unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL);
|
||||
|
||||
free_mem:
|
||||
if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
|
||||
__free_pages(page, get_order(size));
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user