Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 497b9a7

Browse files
committed
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()
2 parents 1522b53 + 1e56310 commit 497b9a7

File tree

6 files changed

+59
-22
lines changed

6 files changed

+59
-22
lines changed

arch/s390/include/asm/pci_insn.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
#define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40
1717
#define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44
1818

19-
/* Load/Store return codes */
20-
#define ZPCI_PCI_LS_OK 0
21-
#define ZPCI_PCI_LS_ERR 1
22-
#define ZPCI_PCI_LS_BUSY 2
23-
#define ZPCI_PCI_LS_INVAL_HANDLE 3
19+
/* PCI instruction condition codes */
20+
#define ZPCI_CC_OK 0
21+
#define ZPCI_CC_ERR 1
22+
#define ZPCI_CC_BUSY 2
23+
#define ZPCI_CC_INVAL_HANDLE 3
2424

2525
/* Load/Store address space identifiers */
2626
#define ZPCI_PCIAS_MEMIO_0 0

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ struct gcr3_tbl_info {
555555
};
556556

557557
struct amd_io_pgtable {
558+
seqcount_t seqcount; /* Protects root/mode update */
558559
struct io_pgtable pgtbl;
559560
int mode;
560561
u64 *root;

drivers/iommu/amd/init.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,12 +1455,12 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
14551455
PCI_FUNC(e->devid));
14561456

14571457
devid = e->devid;
1458-
for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
1459-
if (alias)
1458+
if (alias) {
1459+
for (dev_i = devid_start; dev_i <= devid; ++dev_i)
14601460
pci_seg->alias_table[dev_i] = devid_to;
1461+
set_dev_entry_from_acpi(iommu, devid_to, flags, ext_flags);
14611462
}
14621463
set_dev_entry_from_acpi_range(iommu, devid_start, devid, flags, ext_flags);
1463-
set_dev_entry_from_acpi(iommu, devid_to, flags, ext_flags);
14641464
break;
14651465
case IVHD_DEV_SPECIAL: {
14661466
u8 handle, type;
@@ -3067,7 +3067,8 @@ static int __init early_amd_iommu_init(void)
30673067

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

30733074
/*

drivers/iommu/amd/io_pgtable.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/slab.h>
1818
#include <linux/types.h>
1919
#include <linux/dma-mapping.h>
20+
#include <linux/seqlock.h>
2021

2122
#include <asm/barrier.h>
2223

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

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

134+
write_seqcount_begin(&pgtable->seqcount);
133135
pgtable->root = pte;
134136
pgtable->mode += 1;
137+
write_seqcount_end(&pgtable->seqcount);
138+
135139
amd_iommu_update_and_flush_device_table(domain);
136140

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

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

172177

173-
level = pgtable->mode - 1;
174-
pte = &pgtable->root[PM_LEVEL_INDEX(level, address)];
178+
do {
179+
seqcount = read_seqcount_begin(&pgtable->seqcount);
180+
181+
level = pgtable->mode - 1;
182+
pte = &pgtable->root[PM_LEVEL_INDEX(level, address)];
183+
} while (read_seqcount_retry(&pgtable->seqcount, seqcount));
184+
185+
175186
address = PAGE_SIZE_ALIGN(address, page_size);
176187
end_lvl = PAGE_SIZE_LEVEL(page_size);
177188

@@ -249,15 +260,20 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
249260
unsigned long *page_size)
250261
{
251262
int level;
263+
unsigned int seqcount;
252264
u64 *pte;
253265

254266
*page_size = 0;
255267

256268
if (address > PM_LEVEL_SIZE(pgtable->mode))
257269
return NULL;
258270

259-
level = pgtable->mode - 1;
260-
pte = &pgtable->root[PM_LEVEL_INDEX(level, address)];
271+
do {
272+
seqcount = read_seqcount_begin(&pgtable->seqcount);
273+
level = pgtable->mode - 1;
274+
pte = &pgtable->root[PM_LEVEL_INDEX(level, address)];
275+
} while (read_seqcount_retry(&pgtable->seqcount, seqcount));
276+
261277
*page_size = PTE_LEVEL_PAGE_SIZE(level);
262278

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

545562
cfg->pgsize_bitmap = amd_iommu_pgsize_bitmap;
546563
cfg->ias = IOMMU_IN_ADDR_BIT_SIZE;

drivers/iommu/intel/iommu.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,10 @@ static void switch_to_super_page(struct dmar_domain *domain,
15751575
unsigned long lvl_pages = lvl_to_nr_pages(level);
15761576
struct dma_pte *pte = NULL;
15771577

1578+
if (WARN_ON(!IS_ALIGNED(start_pfn, lvl_pages) ||
1579+
!IS_ALIGNED(end_pfn + 1, lvl_pages)))
1580+
return;
1581+
15781582
while (start_pfn <= end_pfn) {
15791583
if (!pte)
15801584
pte = pfn_to_dma_pte(domain, start_pfn, &level,
@@ -1650,7 +1654,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
16501654
unsigned long pages_to_remove;
16511655

16521656
pteval |= DMA_PTE_LARGE_PAGE;
1653-
pages_to_remove = min_t(unsigned long, nr_pages,
1657+
pages_to_remove = min_t(unsigned long,
1658+
round_down(nr_pages, lvl_pages),
16541659
nr_pte_to_next_page(pte) * lvl_pages);
16551660
end_pfn = iov_pfn + pages_to_remove - 1;
16561661
switch_to_super_page(domain, iov_pfn, end_pfn, largepage_lvl);

drivers/iommu/s390-iommu.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,23 @@ static u64 get_iota_region_flag(struct s390_domain *domain)
612612
}
613613
}
614614

615+
static bool reg_ioat_propagate_error(int cc, u8 status)
616+
{
617+
/*
618+
* If the device is in the error state the reset routine
619+
* will register the IOAT of the newly set domain on re-enable
620+
*/
621+
if (cc == ZPCI_CC_ERR && status == ZPCI_PCI_ST_FUNC_NOT_AVAIL)
622+
return false;
623+
/*
624+
* If the device was removed treat registration as success
625+
* and let the subsequent error event trigger tear down.
626+
*/
627+
if (cc == ZPCI_CC_INVAL_HANDLE)
628+
return false;
629+
return cc != ZPCI_CC_OK;
630+
}
631+
615632
static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev,
616633
struct iommu_domain *domain, u8 *status)
617634
{
@@ -696,7 +713,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
696713

697714
/* If we fail now DMA remains blocked via blocking domain */
698715
cc = s390_iommu_domain_reg_ioat(zdev, domain, &status);
699-
if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
716+
if (reg_ioat_propagate_error(cc, status))
700717
return -EIO;
701718
zdev->dma_table = s390_domain->dma_table;
702719
zdev_s390_domain_update(zdev, domain);
@@ -1032,7 +1049,8 @@ struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev)
10321049

10331050
lockdep_assert_held(&zdev->dom_lock);
10341051

1035-
if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED)
1052+
if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED ||
1053+
zdev->s390_domain->type == IOMMU_DOMAIN_IDENTITY)
10361054
return NULL;
10371055

10381056
s390_domain = to_s390_domain(zdev->s390_domain);
@@ -1123,12 +1141,7 @@ static int s390_attach_dev_identity(struct iommu_domain *domain,
11231141

11241142
/* If we fail now DMA remains blocked via blocking domain */
11251143
cc = s390_iommu_domain_reg_ioat(zdev, domain, &status);
1126-
1127-
/*
1128-
* If the device is undergoing error recovery the reset code
1129-
* will re-establish the new domain.
1130-
*/
1131-
if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
1144+
if (reg_ioat_propagate_error(cc, status))
11321145
return -EIO;
11331146

11341147
zdev_s390_domain_update(zdev, domain);

0 commit comments

Comments
 (0)