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

Commit a83b0423 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfio-v5.1-rc1' of git://github.com/awilliam/linux-vfio

Pull VFIO updates from Alex Williamson:

 - Switch mdev to generic UUID API (Andy Shevchenko)

 - Fixup platform reset include paths (Masahiro Yamada)

 - Fix usage of MINORMASK (Chengguang Xu)

 - Remove noise from duplicate spapr table unsets (Alexey Kardashevskiy)

 - Restore device state after PM reset (Alex Williamson)

 - Ensure memory translation enabled for PCI ROM access (Eric Auger)

* tag 'vfio-v5.1-rc1' of git://github.com/awilliam/linux-vfio:
  vfio_pci: Enable memory accesses before calling pci_map_rom
  vfio/pci: Restore device state on PM transition
  vfio/spapr_tce: Skip unsetting already unset table
  samples/vfio-mdev/mtty: expand minor range when registering chrdev region
  samples/vfio-mdev/mdpy: expand minor range when registering chrdev region
  samples/vfio-mdev/mbochs: expand minor range when registering chrdev region
  vfio: expand minor range when registering chrdev region
  vfio: platform: reset: fix up include directives to remove ccflags-y
  vfio-mdev: Switch to use new generic UUID API
parents ee5e0011 0cfd027b
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -60,9 +60,9 @@ struct mdev_device *mdev_from_dev(struct device *dev)
}
EXPORT_SYMBOL(mdev_from_dev);

uuid_le mdev_uuid(struct mdev_device *mdev)
const guid_t *mdev_uuid(struct mdev_device *mdev)
{
	return mdev->uuid;
	return &mdev->uuid;
}
EXPORT_SYMBOL(mdev_uuid);

@@ -88,8 +88,7 @@ static void mdev_release_parent(struct kref *kref)
	put_device(dev);
}

static
inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
static inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
{
	if (parent)
		kref_get(&parent->ref);
@@ -276,7 +275,8 @@ static void mdev_device_release(struct device *dev)
	kfree(mdev);
}

int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
int mdev_device_create(struct kobject *kobj,
		       struct device *dev, const guid_t *uuid)
{
	int ret;
	struct mdev_device *mdev, *tmp;
@@ -291,7 +291,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)

	/* Check for duplicate */
	list_for_each_entry(tmp, &mdev_list, next) {
		if (!uuid_le_cmp(tmp->uuid, uuid)) {
		if (guid_equal(&tmp->uuid, uuid)) {
			mutex_unlock(&mdev_list_lock);
			ret = -EEXIST;
			goto mdev_fail;
@@ -305,7 +305,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
		goto mdev_fail;
	}

	memcpy(&mdev->uuid, &uuid, sizeof(uuid_le));
	guid_copy(&mdev->uuid, uuid);
	list_add(&mdev->next, &mdev_list);
	mutex_unlock(&mdev_list_lock);

@@ -315,7 +315,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
	mdev->dev.parent  = dev;
	mdev->dev.bus     = &mdev_bus_type;
	mdev->dev.release = mdev_device_release;
	dev_set_name(&mdev->dev, "%pUl", uuid.b);
	dev_set_name(&mdev->dev, "%pUl", uuid);

	ret = device_register(&mdev->dev);
	if (ret) {
+3 −2
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct mdev_parent {
struct mdev_device {
	struct device dev;
	struct mdev_parent *parent;
	uuid_le uuid;
	guid_t uuid;
	void *driver_data;
	struct kref ref;
	struct list_head next;
@@ -58,7 +58,8 @@ void parent_remove_sysfs_files(struct mdev_parent *parent);
int  mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);

int  mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid);
int  mdev_device_create(struct kobject *kobj,
			struct device *dev, const guid_t *uuid);
int  mdev_device_remove(struct device *dev, bool force_remove);

#endif /* MDEV_PRIVATE_H */
+3 −3
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ static ssize_t create_store(struct kobject *kobj, struct device *dev,
			    const char *buf, size_t count)
{
	char *str;
	uuid_le uuid;
	guid_t uuid;
	int ret;

	if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
@@ -65,12 +65,12 @@ static ssize_t create_store(struct kobject *kobj, struct device *dev,
	if (!str)
		return -ENOMEM;

	ret = uuid_le_to_bin(str, &uuid);
	ret = guid_parse(str, &uuid);
	kfree(str);
	if (ret)
		return ret;

	ret = mdev_device_create(kobj, dev, uuid);
	ret = mdev_device_create(kobj, dev, &uuid);
	if (ret)
		return ret;

+77 −13
Original line number Diff line number Diff line
@@ -209,6 +209,57 @@ static bool vfio_pci_nointx(struct pci_dev *pdev)
	return false;
}

static void vfio_pci_probe_power_state(struct vfio_pci_device *vdev)
{
	struct pci_dev *pdev = vdev->pdev;
	u16 pmcsr;

	if (!pdev->pm_cap)
		return;

	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &pmcsr);

	vdev->needs_pm_restore = !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET);
}

/*
 * pci_set_power_state() wrapper handling devices which perform a soft reset on
 * D3->D0 transition.  Save state prior to D0/1/2->D3, stash it on the vdev,
 * restore when returned to D0.  Saved separately from pci_saved_state for use
 * by PM capability emulation and separately from pci_dev internal saved state
 * to avoid it being overwritten and consumed around other resets.
 */
int vfio_pci_set_power_state(struct vfio_pci_device *vdev, pci_power_t state)
{
	struct pci_dev *pdev = vdev->pdev;
	bool needs_restore = false, needs_save = false;
	int ret;

	if (vdev->needs_pm_restore) {
		if (pdev->current_state < PCI_D3hot && state >= PCI_D3hot) {
			pci_save_state(pdev);
			needs_save = true;
		}

		if (pdev->current_state >= PCI_D3hot && state <= PCI_D0)
			needs_restore = true;
	}

	ret = pci_set_power_state(pdev, state);

	if (!ret) {
		/* D3 might be unsupported via quirk, skip unless in D3 */
		if (needs_save && pdev->current_state >= PCI_D3hot) {
			vdev->pm_save = pci_store_saved_state(pdev);
		} else if (needs_restore) {
			pci_load_and_free_saved_state(pdev, &vdev->pm_save);
			pci_restore_state(pdev);
		}
	}

	return ret;
}

static int vfio_pci_enable(struct vfio_pci_device *vdev)
{
	struct pci_dev *pdev = vdev->pdev;
@@ -216,7 +267,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
	u16 cmd;
	u8 msix_pos;

	pci_set_power_state(pdev, PCI_D0);
	vfio_pci_set_power_state(vdev, PCI_D0);

	/* Don't allow our initial saved state to include busmaster */
	pci_clear_master(pdev);
@@ -407,7 +458,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
	vfio_pci_try_bus_reset(vdev);

	if (!disable_idle_d3)
		pci_set_power_state(pdev, PCI_D3hot);
		vfio_pci_set_power_state(vdev, PCI_D3hot);
}

static void vfio_pci_release(void *device_data)
@@ -708,6 +759,7 @@ static long vfio_pci_ioctl(void *device_data,
		{
			void __iomem *io;
			size_t size;
			u16 orig_cmd;

			info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
			info.flags = 0;
@@ -723,15 +775,23 @@ static long vfio_pci_ioctl(void *device_data,
					break;
			}

			/* Is it really there? */
			/*
			 * Is it really there?  Enable memory decode for
			 * implicit access in pci_map_rom().
			 */
			pci_read_config_word(pdev, PCI_COMMAND, &orig_cmd);
			pci_write_config_word(pdev, PCI_COMMAND,
					      orig_cmd | PCI_COMMAND_MEMORY);

			io = pci_map_rom(pdev, &size);
			if (!io || !size) {
			if (io) {
				info.flags = VFIO_REGION_INFO_FLAG_READ;
				pci_unmap_rom(pdev, io);
			} else {
				info.size = 0;
				break;
			}
			pci_unmap_rom(pdev, io);

			info.flags = VFIO_REGION_INFO_FLAG_READ;
			pci_write_config_word(pdev, PCI_COMMAND, orig_cmd);
			break;
		}
		case VFIO_PCI_VGA_REGION_INDEX:
@@ -1286,6 +1346,8 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
					vfio_pci_set_vga_decode(vdev, false));
	}

	vfio_pci_probe_power_state(vdev);

	if (!disable_idle_d3) {
		/*
		 * pci-core sets the device power state to an unknown value at
@@ -1296,8 +1358,8 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		 * be able to get to D3.  Therefore first do a D0 transition
		 * before going to D3.
		 */
		pci_set_power_state(pdev, PCI_D0);
		pci_set_power_state(pdev, PCI_D3hot);
		vfio_pci_set_power_state(vdev, PCI_D0);
		vfio_pci_set_power_state(vdev, PCI_D3hot);
	}

	return ret;
@@ -1316,6 +1378,11 @@ static void vfio_pci_remove(struct pci_dev *pdev)
	vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
	kfree(vdev->region);
	mutex_destroy(&vdev->ioeventfds_lock);

	if (!disable_idle_d3)
		vfio_pci_set_power_state(vdev, PCI_D0);

	kfree(vdev->pm_save);
	kfree(vdev);

	if (vfio_pci_is_vga(pdev)) {
@@ -1324,9 +1391,6 @@ static void vfio_pci_remove(struct pci_dev *pdev)
				VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM |
				VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM);
	}

	if (!disable_idle_d3)
		pci_set_power_state(pdev, PCI_D0);
}

static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
@@ -1551,7 +1615,7 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
			tmp->needs_reset = false;

			if (tmp != vdev && !disable_idle_d3)
				pci_set_power_state(tmp->pdev, PCI_D3hot);
				vfio_pci_set_power_state(tmp, PCI_D3hot);
		}

		vfio_device_put(devs.devices[i]);
+1 −1
Original line number Diff line number Diff line
@@ -691,7 +691,7 @@ static int vfio_pm_config_write(struct vfio_pci_device *vdev, int pos,
			break;
		}

		pci_set_power_state(vdev->pdev, state);
		vfio_pci_set_power_state(vdev, state);
	}

	return count;
Loading