Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 711d5779 authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by Jesse Barnes
Browse files

PCI: expose function reset capability in sysfs



Some devices allow an individual function to be reset without affecting
other functions in the same device: that's what pci_reset_function does.
For devices that have this support, expose reset attribite in sysfs.

This is useful e.g. for virtualization, where a qemu userspace
process wants to reset the device when the guest is reset,
to emulate machine reboot as closely as possible.

Acked-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 5228a828
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -84,6 +84,16 @@ Description:
		from this part of the device tree.
		Depends on CONFIG_HOTPLUG.

What:		/sys/bus/pci/devices/.../reset
Date:		July 2009
Contact:	Michael S. Tsirkin <mst@redhat.com>
Description:
		Some devices allow an individual function to be reset
		without affecting other functions in the same device.
		For devices that have this support, a file named reset
		will be present in sysfs.  Writing 1 to this file
		will perform reset.

What:		/sys/bus/pci/devices/.../vpd
Date:		February 2008
Contact:	Ben Hutchings <bhutchings@solarflare.com>
+37 −0
Original line number Diff line number Diff line
@@ -916,6 +916,24 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
	return 0;
}

static ssize_t reset_store(struct device *dev,
			   struct device_attribute *attr, const char *buf,
			   size_t count)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	unsigned long val;
	ssize_t result = strict_strtoul(buf, 0, &val);

	if (result < 0)
		return result;

	if (val != 1)
		return -EINVAL;
	return pci_reset_function(pdev);
}

static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store);

static int pci_create_capabilities_sysfs(struct pci_dev *dev)
{
	int retval;
@@ -943,7 +961,22 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
	/* Active State Power Management */
	pcie_aspm_create_sysfs_dev_files(dev);

	if (!pci_probe_reset_function(dev)) {
		retval = device_create_file(&dev->dev, &reset_attr);
		if (retval)
			goto error;
		dev->reset_fn = 1;
	}
	return 0;

error:
	pcie_aspm_remove_sysfs_dev_files(dev);
	if (dev->vpd && dev->vpd->attr) {
		sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr);
		kfree(dev->vpd->attr);
	}

	return retval;
}

int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
@@ -1037,6 +1070,10 @@ static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
	}

	pcie_aspm_remove_sysfs_dev_files(dev);
	if (dev->reset_fn) {
		device_remove_file(&dev->dev, &reset_attr);
		dev->reset_fn = 0;
	}
}

/**
+16 −0
Original line number Diff line number Diff line
@@ -2261,6 +2261,22 @@ int __pci_reset_function(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(__pci_reset_function);

/**
 * pci_probe_reset_function - check whether the device can be safely reset
 * @dev: PCI device to reset
 *
 * Some devices allow an individual function to be reset without affecting
 * other functions in the same device.  The PCI device must be responsive
 * to PCI config space in order to use this function.
 *
 * Returns 0 if the device function can be reset or negative if the
 * device doesn't support resetting a single function.
 */
int pci_probe_reset_function(struct pci_dev *dev)
{
	return pci_dev_reset(dev, 1);
}

/**
 * pci_reset_function - quiesce and reset a PCI device function
 * @dev: PCI device to reset
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ extern void pci_cleanup_rom(struct pci_dev *dev);
extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
			 struct vm_area_struct *vma);
#endif
int pci_probe_reset_function(struct pci_dev *dev);

/**
 * struct pci_platform_pm_ops - Firmware PM callbacks
+1 −0
Original line number Diff line number Diff line
@@ -276,6 +276,7 @@ struct pci_dev {
	unsigned int	state_saved:1;
	unsigned int	is_physfn:1;
	unsigned int	is_virtfn:1;
	unsigned int	reset_fn:1;
	pci_dev_flags_t dev_flags;
	atomic_t	enable_cnt;	/* pci_enable_device has been called */