Skip to content

Commit 59bbf59

Browse files
niklas88joergroedel
authored andcommitted
iommu/s390: Make attach succeed even if the device is in error state
If a zPCI device is in the error state while switching IOMMU domains zpci_register_ioat() will fail and we would end up with the device not attached to any domain. In this state since zdev->dma_table == NULL a reset via zpci_hot_reset_device() would wrongfully re-initialize the device for DMA API usage using zpci_dma_init_device(). As automatic recovery is currently disabled while attached to an IOMMU domain this only affects slot resets triggered through other means but will affect automatic recovery once we switch to using dma-iommu. Additionally with that switch common code expects attaching to the default domain to always work so zpci_register_ioat() should only fail if there is no chance to recover anyway, e.g. if the device has been unplugged. Improve the robustness of attach by specifically looking at the status returned by zpci_mod_fc() to determine if the device is unavailable and in this case simply ignore the error. Once the device is reset zpci_hot_reset_device() will then correctly set the domain's DMA translation tables. Signed-off-by: Niklas Schnelle <[email protected]> Reviewed-by: Matthew Rosato <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent f3cc4f8 commit 59bbf59

File tree

5 files changed

+20
-11
lines changed

5 files changed

+20
-11
lines changed

arch/s390/include/asm/pci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ void zpci_device_reserved(struct zpci_dev *zdev);
221221
bool zpci_is_device_configured(struct zpci_dev *zdev);
222222

223223
int zpci_hot_reset_device(struct zpci_dev *zdev);
224-
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
224+
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64, u8 *);
225225
int zpci_unregister_ioat(struct zpci_dev *, u8);
226226
void zpci_remove_reserved_devices(void);
227227
void zpci_update_fh(struct zpci_dev *zdev, u32 fh);

arch/s390/kvm/pci.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
434434
static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
435435
{
436436
struct zpci_dev *zdev = opaque;
437+
u8 status;
437438
int rc;
438439

439440
if (!zdev)
@@ -486,7 +487,7 @@ static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
486487

487488
/* Re-register the IOMMU that was already created */
488489
rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
489-
virt_to_phys(zdev->dma_table));
490+
virt_to_phys(zdev->dma_table), &status);
490491
if (rc)
491492
goto clear_gisa;
492493

@@ -516,6 +517,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
516517
{
517518
struct zpci_dev *zdev = opaque;
518519
struct kvm *kvm;
520+
u8 status;
519521

520522
if (!zdev)
521523
return;
@@ -554,7 +556,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
554556

555557
/* Re-register the IOMMU that was already created */
556558
zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
557-
virt_to_phys(zdev->dma_table));
559+
virt_to_phys(zdev->dma_table), &status);
558560

559561
out:
560562
spin_lock(&kvm->arch.kzdev_list_lock);

arch/s390/pci/pci.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,20 +116,20 @@ EXPORT_SYMBOL_GPL(pci_proc_domain);
116116

117117
/* Modify PCI: Register I/O address translation parameters */
118118
int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
119-
u64 base, u64 limit, u64 iota)
119+
u64 base, u64 limit, u64 iota, u8 *status)
120120
{
121121
u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_REG_IOAT);
122122
struct zpci_fib fib = {0};
123-
u8 cc, status;
123+
u8 cc;
124124

125125
WARN_ON_ONCE(iota & 0x3fff);
126126
fib.pba = base;
127127
fib.pal = limit;
128128
fib.iota = iota | ZPCI_IOTA_RTTO_FLAG;
129129
fib.gd = zdev->gisa;
130-
cc = zpci_mod_fc(req, &fib, &status);
130+
cc = zpci_mod_fc(req, &fib, status);
131131
if (cc)
132-
zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status);
132+
zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, *status);
133133
return cc;
134134
}
135135
EXPORT_SYMBOL_GPL(zpci_register_ioat);
@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(zpci_disable_device);
764764
*/
765765
int zpci_hot_reset_device(struct zpci_dev *zdev)
766766
{
767+
u8 status;
767768
int rc;
768769

769770
zpci_dbg(3, "rst fid:%x, fh:%x\n", zdev->fid, zdev->fh);
@@ -787,7 +788,7 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
787788

788789
if (zdev->dma_table)
789790
rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
790-
virt_to_phys(zdev->dma_table));
791+
virt_to_phys(zdev->dma_table), &status);
791792
else
792793
rc = zpci_dma_init_device(zdev);
793794
if (rc) {

arch/s390/pci/pci_dma.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
547547

548548
int zpci_dma_init_device(struct zpci_dev *zdev)
549549
{
550+
u8 status;
550551
int rc;
551552

552553
/*
@@ -598,7 +599,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
598599

599600
}
600601
if (zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
601-
virt_to_phys(zdev->dma_table))) {
602+
virt_to_phys(zdev->dma_table), &status)) {
602603
rc = -EIO;
603604
goto free_bitmap;
604605
}

drivers/iommu/s390-iommu.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
9898
struct s390_domain *s390_domain = to_s390_domain(domain);
9999
struct zpci_dev *zdev = to_zpci_dev(dev);
100100
unsigned long flags;
101+
u8 status;
101102
int cc;
102103

103104
if (!zdev)
@@ -113,8 +114,12 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
113114
zpci_dma_exit_device(zdev);
114115

115116
cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
116-
virt_to_phys(s390_domain->dma_table));
117-
if (cc)
117+
virt_to_phys(s390_domain->dma_table), &status);
118+
/*
119+
* If the device is undergoing error recovery the reset code
120+
* will re-establish the new domain.
121+
*/
122+
if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
118123
return -EIO;
119124
zdev->dma_table = s390_domain->dma_table;
120125

0 commit comments

Comments
 (0)