162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
662306a36Sopenharmony_ci *     Author: Alex Williamson <alex.williamson@redhat.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Derived from original vfio:
962306a36Sopenharmony_ci * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
1062306a36Sopenharmony_ci * Author: Tom Lyon, pugs@cisco.com
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/device.h>
1662306a36Sopenharmony_ci#include <linux/eventfd.h>
1762306a36Sopenharmony_ci#include <linux/file.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/iommu.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/mutex.h>
2262306a36Sopenharmony_ci#include <linux/notifier.h>
2362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci#include <linux/types.h>
2662306a36Sopenharmony_ci#include <linux/uaccess.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "vfio_pci_priv.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define DRIVER_AUTHOR   "Alex Williamson <alex.williamson@redhat.com>"
3162306a36Sopenharmony_ci#define DRIVER_DESC     "VFIO PCI - User Level meta-driver"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic char ids[1024] __initdata;
3462306a36Sopenharmony_cimodule_param_string(ids, ids, sizeof(ids), 0);
3562306a36Sopenharmony_ciMODULE_PARM_DESC(ids, "Initial PCI IDs to add to the vfio driver, format is \"vendor:device[:subvendor[:subdevice[:class[:class_mask]]]]\" and multiple comma separated entries can be specified");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic bool nointxmask;
3862306a36Sopenharmony_cimodule_param_named(nointxmask, nointxmask, bool, S_IRUGO | S_IWUSR);
3962306a36Sopenharmony_ciMODULE_PARM_DESC(nointxmask,
4062306a36Sopenharmony_ci		  "Disable support for PCI 2.3 style INTx masking.  If this resolves problems for specific devices, report lspci -vvvxxx to linux-pci@vger.kernel.org so the device can be fixed automatically via the broken_intx_masking flag.");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#ifdef CONFIG_VFIO_PCI_VGA
4362306a36Sopenharmony_cistatic bool disable_vga;
4462306a36Sopenharmony_cimodule_param(disable_vga, bool, S_IRUGO);
4562306a36Sopenharmony_ciMODULE_PARM_DESC(disable_vga, "Disable VGA resource access through vfio-pci");
4662306a36Sopenharmony_ci#endif
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic bool disable_idle_d3;
4962306a36Sopenharmony_cimodule_param(disable_idle_d3, bool, S_IRUGO | S_IWUSR);
5062306a36Sopenharmony_ciMODULE_PARM_DESC(disable_idle_d3,
5162306a36Sopenharmony_ci		 "Disable using the PCI D3 low power state for idle, unused devices");
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic bool enable_sriov;
5462306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
5562306a36Sopenharmony_cimodule_param(enable_sriov, bool, 0644);
5662306a36Sopenharmony_ciMODULE_PARM_DESC(enable_sriov, "Enable support for SR-IOV configuration.  Enabling SR-IOV on a PF typically requires support of the userspace PF driver, enabling VFs without such support may result in non-functional VFs or PF.");
5762306a36Sopenharmony_ci#endif
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic bool disable_denylist;
6062306a36Sopenharmony_cimodule_param(disable_denylist, bool, 0444);
6162306a36Sopenharmony_ciMODULE_PARM_DESC(disable_denylist, "Disable use of device denylist. Disabling the denylist allows binding to devices with known errata that may lead to exploitable stability or security issues when accessed by untrusted users.");
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic bool vfio_pci_dev_in_denylist(struct pci_dev *pdev)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	switch (pdev->vendor) {
6662306a36Sopenharmony_ci	case PCI_VENDOR_ID_INTEL:
6762306a36Sopenharmony_ci		switch (pdev->device) {
6862306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
6962306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF:
7062306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_QAT_C62X:
7162306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_QAT_C62X_VF:
7262306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
7362306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_QAT_DH895XCC_VF:
7462306a36Sopenharmony_ci			return true;
7562306a36Sopenharmony_ci		default:
7662306a36Sopenharmony_ci			return false;
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return false;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic bool vfio_pci_is_denylisted(struct pci_dev *pdev)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	if (!vfio_pci_dev_in_denylist(pdev))
8662306a36Sopenharmony_ci		return false;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (disable_denylist) {
8962306a36Sopenharmony_ci		pci_warn(pdev,
9062306a36Sopenharmony_ci			 "device denylist disabled - allowing device %04x:%04x.\n",
9162306a36Sopenharmony_ci			 pdev->vendor, pdev->device);
9262306a36Sopenharmony_ci		return false;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	pci_warn(pdev, "%04x:%04x exists in vfio-pci device denylist, driver probing disallowed.\n",
9662306a36Sopenharmony_ci		 pdev->vendor, pdev->device);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return true;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int vfio_pci_open_device(struct vfio_device *core_vdev)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct vfio_pci_core_device *vdev =
10462306a36Sopenharmony_ci		container_of(core_vdev, struct vfio_pci_core_device, vdev);
10562306a36Sopenharmony_ci	struct pci_dev *pdev = vdev->pdev;
10662306a36Sopenharmony_ci	int ret;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	ret = vfio_pci_core_enable(vdev);
10962306a36Sopenharmony_ci	if (ret)
11062306a36Sopenharmony_ci		return ret;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (vfio_pci_is_vga(pdev) &&
11362306a36Sopenharmony_ci	    pdev->vendor == PCI_VENDOR_ID_INTEL &&
11462306a36Sopenharmony_ci	    IS_ENABLED(CONFIG_VFIO_PCI_IGD)) {
11562306a36Sopenharmony_ci		ret = vfio_pci_igd_init(vdev);
11662306a36Sopenharmony_ci		if (ret && ret != -ENODEV) {
11762306a36Sopenharmony_ci			pci_warn(pdev, "Failed to setup Intel IGD regions\n");
11862306a36Sopenharmony_ci			vfio_pci_core_disable(vdev);
11962306a36Sopenharmony_ci			return ret;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	vfio_pci_core_finish_enable(vdev);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic const struct vfio_device_ops vfio_pci_ops = {
12962306a36Sopenharmony_ci	.name		= "vfio-pci",
13062306a36Sopenharmony_ci	.init		= vfio_pci_core_init_dev,
13162306a36Sopenharmony_ci	.release	= vfio_pci_core_release_dev,
13262306a36Sopenharmony_ci	.open_device	= vfio_pci_open_device,
13362306a36Sopenharmony_ci	.close_device	= vfio_pci_core_close_device,
13462306a36Sopenharmony_ci	.ioctl		= vfio_pci_core_ioctl,
13562306a36Sopenharmony_ci	.device_feature = vfio_pci_core_ioctl_feature,
13662306a36Sopenharmony_ci	.read		= vfio_pci_core_read,
13762306a36Sopenharmony_ci	.write		= vfio_pci_core_write,
13862306a36Sopenharmony_ci	.mmap		= vfio_pci_core_mmap,
13962306a36Sopenharmony_ci	.request	= vfio_pci_core_request,
14062306a36Sopenharmony_ci	.match		= vfio_pci_core_match,
14162306a36Sopenharmony_ci	.bind_iommufd	= vfio_iommufd_physical_bind,
14262306a36Sopenharmony_ci	.unbind_iommufd	= vfio_iommufd_physical_unbind,
14362306a36Sopenharmony_ci	.attach_ioas	= vfio_iommufd_physical_attach_ioas,
14462306a36Sopenharmony_ci	.detach_ioas	= vfio_iommufd_physical_detach_ioas,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct vfio_pci_core_device *vdev;
15062306a36Sopenharmony_ci	int ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (vfio_pci_is_denylisted(pdev))
15362306a36Sopenharmony_ci		return -EINVAL;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	vdev = vfio_alloc_device(vfio_pci_core_device, vdev, &pdev->dev,
15662306a36Sopenharmony_ci				 &vfio_pci_ops);
15762306a36Sopenharmony_ci	if (IS_ERR(vdev))
15862306a36Sopenharmony_ci		return PTR_ERR(vdev);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	dev_set_drvdata(&pdev->dev, vdev);
16162306a36Sopenharmony_ci	ret = vfio_pci_core_register_device(vdev);
16262306a36Sopenharmony_ci	if (ret)
16362306a36Sopenharmony_ci		goto out_put_vdev;
16462306a36Sopenharmony_ci	return 0;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ciout_put_vdev:
16762306a36Sopenharmony_ci	vfio_put_device(&vdev->vdev);
16862306a36Sopenharmony_ci	return ret;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void vfio_pci_remove(struct pci_dev *pdev)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct vfio_pci_core_device *vdev = dev_get_drvdata(&pdev->dev);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	vfio_pci_core_unregister_device(vdev);
17662306a36Sopenharmony_ci	vfio_put_device(&vdev->vdev);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int vfio_pci_sriov_configure(struct pci_dev *pdev, int nr_virtfn)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct vfio_pci_core_device *vdev = dev_get_drvdata(&pdev->dev);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (!enable_sriov)
18462306a36Sopenharmony_ci		return -ENOENT;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return vfio_pci_core_sriov_configure(vdev, nr_virtfn);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic const struct pci_device_id vfio_pci_table[] = {
19062306a36Sopenharmony_ci	{ PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_ANY_ID, PCI_ANY_ID) }, /* match all by default */
19162306a36Sopenharmony_ci	{}
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, vfio_pci_table);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic struct pci_driver vfio_pci_driver = {
19762306a36Sopenharmony_ci	.name			= "vfio-pci",
19862306a36Sopenharmony_ci	.id_table		= vfio_pci_table,
19962306a36Sopenharmony_ci	.probe			= vfio_pci_probe,
20062306a36Sopenharmony_ci	.remove			= vfio_pci_remove,
20162306a36Sopenharmony_ci	.sriov_configure	= vfio_pci_sriov_configure,
20262306a36Sopenharmony_ci	.err_handler		= &vfio_pci_core_err_handlers,
20362306a36Sopenharmony_ci	.driver_managed_dma	= true,
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic void __init vfio_pci_fill_ids(void)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	char *p, *id;
20962306a36Sopenharmony_ci	int rc;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* no ids passed actually */
21262306a36Sopenharmony_ci	if (ids[0] == '\0')
21362306a36Sopenharmony_ci		return;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* add ids specified in the module parameter */
21662306a36Sopenharmony_ci	p = ids;
21762306a36Sopenharmony_ci	while ((id = strsep(&p, ","))) {
21862306a36Sopenharmony_ci		unsigned int vendor, device, subvendor = PCI_ANY_ID,
21962306a36Sopenharmony_ci			subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
22062306a36Sopenharmony_ci		int fields;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		if (!strlen(id))
22362306a36Sopenharmony_ci			continue;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
22662306a36Sopenharmony_ci				&vendor, &device, &subvendor, &subdevice,
22762306a36Sopenharmony_ci				&class, &class_mask);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		if (fields < 2) {
23062306a36Sopenharmony_ci			pr_warn("invalid id string \"%s\"\n", id);
23162306a36Sopenharmony_ci			continue;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		rc = pci_add_dynid(&vfio_pci_driver, vendor, device,
23562306a36Sopenharmony_ci				   subvendor, subdevice, class, class_mask, 0);
23662306a36Sopenharmony_ci		if (rc)
23762306a36Sopenharmony_ci			pr_warn("failed to add dynamic id [%04x:%04x[%04x:%04x]] class %#08x/%08x (%d)\n",
23862306a36Sopenharmony_ci				vendor, device, subvendor, subdevice,
23962306a36Sopenharmony_ci				class, class_mask, rc);
24062306a36Sopenharmony_ci		else
24162306a36Sopenharmony_ci			pr_info("add [%04x:%04x[%04x:%04x]] class %#08x/%08x\n",
24262306a36Sopenharmony_ci				vendor, device, subvendor, subdevice,
24362306a36Sopenharmony_ci				class, class_mask);
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int __init vfio_pci_init(void)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	int ret;
25062306a36Sopenharmony_ci	bool is_disable_vga = true;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci#ifdef CONFIG_VFIO_PCI_VGA
25362306a36Sopenharmony_ci	is_disable_vga = disable_vga;
25462306a36Sopenharmony_ci#endif
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* Register and scan for devices */
25962306a36Sopenharmony_ci	ret = pci_register_driver(&vfio_pci_driver);
26062306a36Sopenharmony_ci	if (ret)
26162306a36Sopenharmony_ci		return ret;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	vfio_pci_fill_ids();
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (disable_denylist)
26662306a36Sopenharmony_ci		pr_warn("device denylist disabled.\n");
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return 0;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_cimodule_init(vfio_pci_init);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void __exit vfio_pci_cleanup(void)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	pci_unregister_driver(&vfio_pci_driver);
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_cimodule_exit(vfio_pci_cleanup);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
27962306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
28062306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
281