Commit 497b9a7b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'iommu-fixes-v6.17-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux

Pull iommu fixes from Joerg Roedel:

 - Fixes for memory leak and memory corruption bugs on S390 and AMD-Vi

 - Race condition fix in AMD-Vi page table code and S390 device attach
   code

 - Intel VT-d: Fix alignment checks in __domain_mapping()

 - AMD-Vi: Fix potentially incorrect DTE settings when device has
   aliases

* tag 'iommu-fixes-v6.17-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux:
  iommu/amd/pgtbl: Fix possible race while increase page table level
  iommu/amd: Fix alias device DTE setting
  iommu/s390: Make attach succeed when the device was surprise removed
  iommu/vt-d: Fix __domain_mapping()'s usage of switch_to_super_page()
  iommu/s390: Fix memory corruption when using identity domain
  iommu/amd: Fix ivrs_base memleak in early_amd_iommu_init()
parents 1522b530 1e56310b
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -16,11 +16,11 @@
#define ZPCI_PCI_ST_FUNC_NOT_AVAIL		40
#define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE		44

/* Load/Store return codes */
#define ZPCI_PCI_LS_OK				0
#define ZPCI_PCI_LS_ERR				1
#define ZPCI_PCI_LS_BUSY			2
#define ZPCI_PCI_LS_INVAL_HANDLE		3
/* PCI instruction condition codes */
#define ZPCI_CC_OK				0
#define ZPCI_CC_ERR				1
#define ZPCI_CC_BUSY				2
#define ZPCI_CC_INVAL_HANDLE			3

/* Load/Store address space identifiers */
#define ZPCI_PCIAS_MEMIO_0			0
+1 −0
Original line number Diff line number Diff line
@@ -555,6 +555,7 @@ struct gcr3_tbl_info {
};

struct amd_io_pgtable {
	seqcount_t		seqcount;	/* Protects root/mode update */
	struct io_pgtable	pgtbl;
	int			mode;
	u64			*root;
+5 −4
Original line number Diff line number Diff line
@@ -1455,12 +1455,12 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
				    PCI_FUNC(e->devid));

			devid = e->devid;
			for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
				if (alias)
			if (alias) {
				for (dev_i = devid_start; dev_i <= devid; ++dev_i)
					pci_seg->alias_table[dev_i] = devid_to;
				set_dev_entry_from_acpi(iommu, devid_to, flags, ext_flags);
			}
			set_dev_entry_from_acpi_range(iommu, devid_start, devid, flags, ext_flags);
			set_dev_entry_from_acpi(iommu, devid_to, flags, ext_flags);
			break;
		case IVHD_DEV_SPECIAL: {
			u8 handle, type;
@@ -3067,7 +3067,8 @@ static int __init early_amd_iommu_init(void)

	if (!boot_cpu_has(X86_FEATURE_CX16)) {
		pr_err("Failed to initialize. The CMPXCHG16B feature is required.\n");
		return -EINVAL;
		ret = -EINVAL;
		goto out;
	}

	/*
+21 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/seqlock.h>

#include <asm/barrier.h>

@@ -130,8 +131,11 @@ static bool increase_address_space(struct amd_io_pgtable *pgtable,

	*pte = PM_LEVEL_PDE(pgtable->mode, iommu_virt_to_phys(pgtable->root));

	write_seqcount_begin(&pgtable->seqcount);
	pgtable->root  = pte;
	pgtable->mode += 1;
	write_seqcount_end(&pgtable->seqcount);

	amd_iommu_update_and_flush_device_table(domain);

	pte = NULL;
@@ -153,6 +157,7 @@ static u64 *alloc_pte(struct amd_io_pgtable *pgtable,
{
	unsigned long last_addr = address + (page_size - 1);
	struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg;
	unsigned int seqcount;
	int level, end_lvl;
	u64 *pte, *page;

@@ -170,8 +175,14 @@ static u64 *alloc_pte(struct amd_io_pgtable *pgtable,
	}


	do {
		seqcount = read_seqcount_begin(&pgtable->seqcount);

		level   = pgtable->mode - 1;
		pte     = &pgtable->root[PM_LEVEL_INDEX(level, address)];
	} while (read_seqcount_retry(&pgtable->seqcount, seqcount));


	address = PAGE_SIZE_ALIGN(address, page_size);
	end_lvl = PAGE_SIZE_LEVEL(page_size);

@@ -249,6 +260,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
		      unsigned long *page_size)
{
	int level;
	unsigned int seqcount;
	u64 *pte;

	*page_size = 0;
@@ -256,8 +268,12 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
	if (address > PM_LEVEL_SIZE(pgtable->mode))
		return NULL;

	do {
		seqcount = read_seqcount_begin(&pgtable->seqcount);
		level	   =  pgtable->mode - 1;
		pte	   = &pgtable->root[PM_LEVEL_INDEX(level, address)];
	} while (read_seqcount_retry(&pgtable->seqcount, seqcount));

	*page_size =  PTE_LEVEL_PAGE_SIZE(level);

	while (level > 0) {
@@ -541,6 +557,7 @@ static struct io_pgtable *v1_alloc_pgtable(struct io_pgtable_cfg *cfg, void *coo
	if (!pgtable->root)
		return NULL;
	pgtable->mode = PAGE_MODE_3_LEVEL;
	seqcount_init(&pgtable->seqcount);

	cfg->pgsize_bitmap  = amd_iommu_pgsize_bitmap;
	cfg->ias            = IOMMU_IN_ADDR_BIT_SIZE;
+6 −1
Original line number Diff line number Diff line
@@ -1575,6 +1575,10 @@ static void switch_to_super_page(struct dmar_domain *domain,
	unsigned long lvl_pages = lvl_to_nr_pages(level);
	struct dma_pte *pte = NULL;

	if (WARN_ON(!IS_ALIGNED(start_pfn, lvl_pages) ||
		    !IS_ALIGNED(end_pfn + 1, lvl_pages)))
		return;

	while (start_pfn <= end_pfn) {
		if (!pte)
			pte = pfn_to_dma_pte(domain, start_pfn, &level,
@@ -1650,7 +1654,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
				unsigned long pages_to_remove;

				pteval |= DMA_PTE_LARGE_PAGE;
				pages_to_remove = min_t(unsigned long, nr_pages,
				pages_to_remove = min_t(unsigned long,
							round_down(nr_pages, lvl_pages),
							nr_pte_to_next_page(pte) * lvl_pages);
				end_pfn = iov_pfn + pages_to_remove - 1;
				switch_to_super_page(domain, iov_pfn, end_pfn, largepage_lvl);
Loading