Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/pci: implement reset_slot for hotplug slot

This is done by adding a zpci_hot_reset_device() call which does a low
level reset of the PCI function without changing its higher level
function state. This way it can be used while the zPCI function is bound
to a driver and with DMA tables being controlled either through the
IOMMU or DMA APIs which is prohibited when using zpci_disable_device()
as that drop existing DMA translations.

As this reset, unlike a normal FLR, also calls zpci_clear_irq() we need
to implement arch_restore_msi_irqs() and make sure we re-enable IRQs for
the PCI function if they were previously disabled.

Reviewed-by: Pierre Morel <pmorel@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Niklas Schnelle and committed by
Vasily Gorbik
da995d53 4fe20497

+93
+1
arch/s390/include/asm/pci.h
··· 210 210 void zpci_device_reserved(struct zpci_dev *zdev); 211 211 bool zpci_is_device_configured(struct zpci_dev *zdev); 212 212 213 + int zpci_hot_reset_device(struct zpci_dev *zdev); 213 214 int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64); 214 215 int zpci_unregister_ioat(struct zpci_dev *, u8); 215 216 void zpci_remove_reserved_devices(void);
+59
arch/s390/pci/pci.c
··· 724 724 } 725 725 726 726 /** 727 + * zpci_hot_reset_device - perform a reset of the given zPCI function 728 + * @zdev: the slot which should be reset 729 + * 730 + * Performs a low level reset of the zPCI function. The reset is low level in 731 + * the sense that the zPCI function can be reset without detaching it from the 732 + * common PCI subsystem. The reset may be performed while under control of 733 + * either DMA or IOMMU APIs in which case the existing DMA/IOMMU translation 734 + * table is reinstated at the end of the reset. 735 + * 736 + * After the reset the functions internal state is reset to an initial state 737 + * equivalent to its state during boot when first probing a driver. 738 + * Consequently after reset the PCI function requires re-initialization via the 739 + * common PCI code including re-enabling IRQs via pci_alloc_irq_vectors() 740 + * and enabling the function via e.g.pci_enablde_device_flags().The caller 741 + * must guard against concurrent reset attempts. 742 + * 743 + * In most cases this function should not be called directly but through 744 + * pci_reset_function() or pci_reset_bus() which handle the save/restore and 745 + * locking. 746 + * 747 + * Return: 0 on success and an error value otherwise 748 + */ 749 + int zpci_hot_reset_device(struct zpci_dev *zdev) 750 + { 751 + int rc; 752 + 753 + zpci_dbg(3, "rst fid:%x, fh:%x\n", zdev->fid, zdev->fh); 754 + if (zdev_enabled(zdev)) { 755 + /* Disables device access, DMAs and IRQs (reset state) */ 756 + rc = zpci_disable_device(zdev); 757 + /* 758 + * Due to a z/VM vs LPAR inconsistency in the error state the 759 + * FH may indicate an enabled device but disable says the 760 + * device is already disabled don't treat it as an error here. 761 + */ 762 + if (rc == -EINVAL) 763 + rc = 0; 764 + if (rc) 765 + return rc; 766 + } 767 + 768 + rc = zpci_enable_device(zdev); 769 + if (rc) 770 + return rc; 771 + 772 + if (zdev->dma_table) 773 + rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, 774 + (u64)zdev->dma_table); 775 + else 776 + rc = zpci_dma_init_device(zdev); 777 + if (rc) { 778 + zpci_disable_device(zdev); 779 + return rc; 780 + } 781 + 782 + return 0; 783 + } 784 + 785 + /** 727 786 * zpci_create_device() - Create a new zpci_dev and add it to the zbus 728 787 * @fid: Function ID of the device to be created 729 788 * @fh: Current Function Handle of the device to be created
+9
arch/s390/pci/pci_irq.c
··· 387 387 airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->msi_nr_irqs); 388 388 } 389 389 390 + void arch_restore_msi_irqs(struct pci_dev *pdev) 391 + { 392 + struct zpci_dev *zdev = to_zpci(pdev); 393 + 394 + if (!zdev->irqs_registered) 395 + zpci_set_irq(zdev); 396 + default_restore_msi_irqs(pdev); 397 + } 398 + 390 399 static struct airq_struct zpci_airq = { 391 400 .handler = zpci_floating_irq_handler, 392 401 .isc = PCI_ISC,
+24
drivers/pci/hotplug/s390_pci_hpc.c
··· 57 57 return zpci_deconfigure_device(zdev); 58 58 } 59 59 60 + static int reset_slot(struct hotplug_slot *hotplug_slot, bool probe) 61 + { 62 + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, 63 + hotplug_slot); 64 + 65 + if (zdev->state != ZPCI_FN_STATE_CONFIGURED) 66 + return -EIO; 67 + /* 68 + * We can't take the zdev->lock as reset_slot may be called during 69 + * probing and/or device removal which already happens under the 70 + * zdev->lock. Instead the user should use the higher level 71 + * pci_reset_function() or pci_bus_reset() which hold the PCI device 72 + * lock preventing concurrent removal. If not using these functions 73 + * holding the PCI device lock is required. 74 + */ 75 + 76 + /* As long as the function is configured we can reset */ 77 + if (probe) 78 + return 0; 79 + 80 + return zpci_hot_reset_device(zdev); 81 + } 82 + 60 83 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 61 84 { 62 85 struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, ··· 99 76 static const struct hotplug_slot_ops s390_hotplug_slot_ops = { 100 77 .enable_slot = enable_slot, 101 78 .disable_slot = disable_slot, 79 + .reset_slot = reset_slot, 102 80 .get_power_status = get_power_status, 103 81 .get_adapter_status = get_adapter_status, 104 82 };