VFIO updates for v5.2-rc1
- Improve dev_printk() usage (Bjorn Helgaas) - Fix issue with blocking in !TASK_RUNNING state while waiting for userspace to release devices (Farhan Ali) - Fix error path cleanup in nvlink setup (Greg Kurz) - mdev-core cleanups and fixes in preparation for more use cases (Parav Pandit) - Cornelia has volunteered as an official vfio reviewer (Cornelia Huck) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJc1e9mAAoJECObm247sIsiB+sP/Rs94smfIyO/N3a73gd3KrAV wmnNGLbUGEEoumUmzWYjSq/l3zfehYpe2kiKJklH8sUPP+kGL0eQj2H5++/LWC3E EMMPGVoD0wHHoWwdVKY79xjDIUUeNZe2IFVUjLgwJ9UD79DBBGJUMpWQhbuUDkl1 nGCb0ltzu6H+OzELLZxXSC7QdhnB97mRaamSI2sunTM7tr6QaL13YsrFES4mpj23 vIGElbdpyPBeMMbh2rhhb581RDXEv5GCy6SKfBpHOMay4rpr37YX8CJ/7uh4rNcn DF3aikkK2NpVv5Rk1+AJvvri+MDmOF9TMC5EG24swEAqJrr4jYyWXvPb/WKNDm2w Z0qxBHkZLPJ9kARMQxuAAqJ5vKDwy/FgRjoZi0aEsOjJO+HYeCdIKkueFXdWXw2O pL5IdZr5VSejYdVxjV2Ft6y90dQjxIAdDd6QJDnuEAu2JEb2T1q9iea/QOMnEJyD QM3h1mx/rNZnkmEVgpE4t9TGnoPMmg/grzcfu+8wQZk8ys1uqSfBSdgWoBgheQ9z XJDHCvkRG7bc/VTVcet+HPBvK38Kdv0Er+8eHNmG4c11ifgODzShbXl5oKgDE3iC WJi/ilYVn2dleo/4ZqiCP+U/PEVgED4k4pvj0vWhaE7CfGJDC60Te2/q+aB4sTMI 4EChWOml/T545Hzv6swn =JSGI -----END PGP SIGNATURE----- Merge tag 'vfio-v5.2-rc1' of git://github.com/awilliam/linux-vfio Pull VFIO updates from Alex Williamson: - Improve dev_printk() usage (Bjorn Helgaas) - Fix issue with blocking in !TASK_RUNNING state while waiting for userspace to release devices (Farhan Ali) - Fix error path cleanup in nvlink setup (Greg Kurz) - mdev-core cleanups and fixes in preparation for more use cases (Parav Pandit) - Cornelia has volunteered as an official vfio reviewer (Cornelia Huck) * tag 'vfio-v5.2-rc1' of git://github.com/awilliam/linux-vfio: vfio: Add Cornelia Huck as reviewer vfio/mdev: Avoid inline get and put parent helpers vfio/mdev: Fix aborting mdev child device removal if one fails vfio/mdev: Follow correct remove sequence vfio/mdev: Avoid masking error code to EBUSY vfio/mdev: Drop redundant extern for exported symbols vfio/mdev: Removed unused kref vfio/mdev: Avoid release parent reference during error path vfio-pci/nvlink2: Fix potential VMA leak vfio: Fix WARNING "do not call blocking ops when !TASK_RUNNING" vfio: Use dev_printk() when possible
This commit is contained in:
commit
6fe567df04
@ -16557,6 +16557,7 @@ F: fs/fat/
|
|||||||
|
|
||||||
VFIO DRIVER
|
VFIO DRIVER
|
||||||
M: Alex Williamson <alex.williamson@redhat.com>
|
M: Alex Williamson <alex.williamson@redhat.com>
|
||||||
|
R: Cornelia Huck <cohuck@redhat.com>
|
||||||
L: kvm@vger.kernel.org
|
L: kvm@vger.kernel.org
|
||||||
T: git git://github.com/awilliam/linux-vfio.git
|
T: git git://github.com/awilliam/linux-vfio.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
@ -88,7 +88,7 @@ static void mdev_release_parent(struct kref *kref)
|
|||||||
put_device(dev);
|
put_device(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
|
static struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
|
||||||
{
|
{
|
||||||
if (parent)
|
if (parent)
|
||||||
kref_get(&parent->ref);
|
kref_get(&parent->ref);
|
||||||
@ -96,7 +96,7 @@ static inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mdev_put_parent(struct mdev_parent *parent)
|
static void mdev_put_parent(struct mdev_parent *parent)
|
||||||
{
|
{
|
||||||
if (parent)
|
if (parent)
|
||||||
kref_put(&parent->ref, mdev_release_parent);
|
kref_put(&parent->ref, mdev_release_parent);
|
||||||
@ -141,7 +141,7 @@ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove)
|
|||||||
*/
|
*/
|
||||||
ret = parent->ops->remove(mdev);
|
ret = parent->ops->remove(mdev);
|
||||||
if (ret && !force_remove)
|
if (ret && !force_remove)
|
||||||
return -EBUSY;
|
return ret;
|
||||||
|
|
||||||
sysfs_remove_groups(&mdev->dev.kobj, parent->ops->mdev_attr_groups);
|
sysfs_remove_groups(&mdev->dev.kobj, parent->ops->mdev_attr_groups);
|
||||||
return 0;
|
return 0;
|
||||||
@ -149,10 +149,10 @@ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove)
|
|||||||
|
|
||||||
static int mdev_device_remove_cb(struct device *dev, void *data)
|
static int mdev_device_remove_cb(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
if (!dev_is_mdev(dev))
|
if (dev_is_mdev(dev))
|
||||||
return 0;
|
mdev_device_remove(dev, true);
|
||||||
|
|
||||||
return mdev_device_remove(dev, data ? *(bool *)data : true);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -181,6 +181,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
|
|||||||
/* Check for duplicate */
|
/* Check for duplicate */
|
||||||
parent = __find_parent_device(dev);
|
parent = __find_parent_device(dev);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
parent = NULL;
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
goto add_dev_err;
|
goto add_dev_err;
|
||||||
}
|
}
|
||||||
@ -239,7 +240,6 @@ EXPORT_SYMBOL(mdev_register_device);
|
|||||||
void mdev_unregister_device(struct device *dev)
|
void mdev_unregister_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct mdev_parent *parent;
|
struct mdev_parent *parent;
|
||||||
bool force_remove = true;
|
|
||||||
|
|
||||||
mutex_lock(&parent_list_lock);
|
mutex_lock(&parent_list_lock);
|
||||||
parent = __find_parent_device(dev);
|
parent = __find_parent_device(dev);
|
||||||
@ -253,8 +253,7 @@ void mdev_unregister_device(struct device *dev)
|
|||||||
list_del(&parent->next);
|
list_del(&parent->next);
|
||||||
class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
|
class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
|
||||||
|
|
||||||
device_for_each_child(dev, (void *)&force_remove,
|
device_for_each_child(dev, NULL, mdev_device_remove_cb);
|
||||||
mdev_device_remove_cb);
|
|
||||||
|
|
||||||
parent_remove_sysfs_files(parent);
|
parent_remove_sysfs_files(parent);
|
||||||
|
|
||||||
@ -310,7 +309,6 @@ int mdev_device_create(struct kobject *kobj,
|
|||||||
mutex_unlock(&mdev_list_lock);
|
mutex_unlock(&mdev_list_lock);
|
||||||
|
|
||||||
mdev->parent = parent;
|
mdev->parent = parent;
|
||||||
kref_init(&mdev->ref);
|
|
||||||
|
|
||||||
mdev->dev.parent = dev;
|
mdev->dev.parent = dev;
|
||||||
mdev->dev.bus = &mdev_bus_type;
|
mdev->dev.bus = &mdev_bus_type;
|
||||||
|
@ -30,7 +30,6 @@ struct mdev_device {
|
|||||||
struct mdev_parent *parent;
|
struct mdev_parent *parent;
|
||||||
guid_t uuid;
|
guid_t uuid;
|
||||||
void *driver_data;
|
void *driver_data;
|
||||||
struct kref ref;
|
|
||||||
struct list_head next;
|
struct list_head next;
|
||||||
struct kobject *type_kobj;
|
struct kobject *type_kobj;
|
||||||
bool active;
|
bool active;
|
||||||
|
@ -280,7 +280,7 @@ type_link_failed:
|
|||||||
|
|
||||||
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type)
|
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type)
|
||||||
{
|
{
|
||||||
|
sysfs_remove_files(&dev->kobj, mdev_device_attrs);
|
||||||
sysfs_remove_link(&dev->kobj, "mdev_type");
|
sysfs_remove_link(&dev->kobj, "mdev_type");
|
||||||
sysfs_remove_link(type->devices_kobj, dev_name(dev));
|
sysfs_remove_link(type->devices_kobj, dev_name(dev));
|
||||||
sysfs_remove_files(&dev->kobj, mdev_device_attrs);
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
#define dev_fmt pr_fmt
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/eventfd.h>
|
#include <linux/eventfd.h>
|
||||||
@ -287,12 +288,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
pci_save_state(pdev);
|
pci_save_state(pdev);
|
||||||
vdev->pci_saved_state = pci_store_saved_state(pdev);
|
vdev->pci_saved_state = pci_store_saved_state(pdev);
|
||||||
if (!vdev->pci_saved_state)
|
if (!vdev->pci_saved_state)
|
||||||
pr_debug("%s: Couldn't store %s saved state\n",
|
pci_dbg(pdev, "%s: Couldn't store saved state\n", __func__);
|
||||||
__func__, dev_name(&pdev->dev));
|
|
||||||
|
|
||||||
if (likely(!nointxmask)) {
|
if (likely(!nointxmask)) {
|
||||||
if (vfio_pci_nointx(pdev)) {
|
if (vfio_pci_nointx(pdev)) {
|
||||||
dev_info(&pdev->dev, "Masking broken INTx support\n");
|
pci_info(pdev, "Masking broken INTx support\n");
|
||||||
vdev->nointx = true;
|
vdev->nointx = true;
|
||||||
pci_intx(pdev, 0);
|
pci_intx(pdev, 0);
|
||||||
} else
|
} else
|
||||||
@ -336,8 +336,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
IS_ENABLED(CONFIG_VFIO_PCI_IGD)) {
|
IS_ENABLED(CONFIG_VFIO_PCI_IGD)) {
|
||||||
ret = vfio_pci_igd_init(vdev);
|
ret = vfio_pci_igd_init(vdev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_warn(&vdev->pdev->dev,
|
pci_warn(pdev, "Failed to setup Intel IGD regions\n");
|
||||||
"Failed to setup Intel IGD regions\n");
|
|
||||||
goto disable_exit;
|
goto disable_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,8 +345,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
IS_ENABLED(CONFIG_VFIO_PCI_NVLINK2)) {
|
IS_ENABLED(CONFIG_VFIO_PCI_NVLINK2)) {
|
||||||
ret = vfio_pci_nvdia_v100_nvlink2_init(vdev);
|
ret = vfio_pci_nvdia_v100_nvlink2_init(vdev);
|
||||||
if (ret && ret != -ENODEV) {
|
if (ret && ret != -ENODEV) {
|
||||||
dev_warn(&vdev->pdev->dev,
|
pci_warn(pdev, "Failed to setup NVIDIA NV2 RAM region\n");
|
||||||
"Failed to setup NVIDIA NV2 RAM region\n");
|
|
||||||
goto disable_exit;
|
goto disable_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,8 +354,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
IS_ENABLED(CONFIG_VFIO_PCI_NVLINK2)) {
|
IS_ENABLED(CONFIG_VFIO_PCI_NVLINK2)) {
|
||||||
ret = vfio_pci_ibm_npu2_init(vdev);
|
ret = vfio_pci_ibm_npu2_init(vdev);
|
||||||
if (ret && ret != -ENODEV) {
|
if (ret && ret != -ENODEV) {
|
||||||
dev_warn(&vdev->pdev->dev,
|
pci_warn(pdev, "Failed to setup NVIDIA NV2 ATSD region\n");
|
||||||
"Failed to setup NVIDIA NV2 ATSD region\n");
|
|
||||||
goto disable_exit;
|
goto disable_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,8 +426,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
|
|||||||
* is just busy work.
|
* is just busy work.
|
||||||
*/
|
*/
|
||||||
if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) {
|
if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) {
|
||||||
pr_info("%s: Couldn't reload %s saved state\n",
|
pci_info(pdev, "%s: Couldn't reload saved state\n", __func__);
|
||||||
__func__, dev_name(&pdev->dev));
|
|
||||||
|
|
||||||
if (!vdev->reset_works)
|
if (!vdev->reset_works)
|
||||||
goto out;
|
goto out;
|
||||||
@ -1255,17 +1251,18 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
|
|||||||
static void vfio_pci_request(void *device_data, unsigned int count)
|
static void vfio_pci_request(void *device_data, unsigned int count)
|
||||||
{
|
{
|
||||||
struct vfio_pci_device *vdev = device_data;
|
struct vfio_pci_device *vdev = device_data;
|
||||||
|
struct pci_dev *pdev = vdev->pdev;
|
||||||
|
|
||||||
mutex_lock(&vdev->igate);
|
mutex_lock(&vdev->igate);
|
||||||
|
|
||||||
if (vdev->req_trigger) {
|
if (vdev->req_trigger) {
|
||||||
if (!(count % 10))
|
if (!(count % 10))
|
||||||
dev_notice_ratelimited(&vdev->pdev->dev,
|
pci_notice_ratelimited(pdev,
|
||||||
"Relaying device request to user (#%u)\n",
|
"Relaying device request to user (#%u)\n",
|
||||||
count);
|
count);
|
||||||
eventfd_signal(vdev->req_trigger, 1);
|
eventfd_signal(vdev->req_trigger, 1);
|
||||||
} else if (count == 0) {
|
} else if (count == 0) {
|
||||||
dev_warn(&vdev->pdev->dev,
|
pci_warn(pdev,
|
||||||
"No device request channel registered, blocked until released by user\n");
|
"No device request channel registered, blocked until released by user\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,8 +412,7 @@ static void vfio_bar_restore(struct vfio_pci_device *vdev)
|
|||||||
if (pdev->is_virtfn)
|
if (pdev->is_virtfn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pr_info("%s: %s reset recovery - restoring bars\n",
|
pci_info(pdev, "%s: reset recovery - restoring BARs\n", __func__);
|
||||||
__func__, dev_name(&pdev->dev));
|
|
||||||
|
|
||||||
for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4, rbar++)
|
for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4, rbar++)
|
||||||
pci_user_write_config_dword(pdev, i, *rbar);
|
pci_user_write_config_dword(pdev, i, *rbar);
|
||||||
@ -1298,8 +1297,8 @@ static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
|
|||||||
else
|
else
|
||||||
return PCI_SATA_SIZEOF_SHORT;
|
return PCI_SATA_SIZEOF_SHORT;
|
||||||
default:
|
default:
|
||||||
pr_warn("%s: %s unknown length for pci cap 0x%x@0x%x\n",
|
pci_warn(pdev, "%s: unknown length for PCI cap %#x@%#x\n",
|
||||||
dev_name(&pdev->dev), __func__, cap, pos);
|
__func__, cap, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1372,8 +1371,8 @@ static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)
|
|||||||
}
|
}
|
||||||
return PCI_TPH_BASE_SIZEOF;
|
return PCI_TPH_BASE_SIZEOF;
|
||||||
default:
|
default:
|
||||||
pr_warn("%s: %s unknown length for pci ecap 0x%x@0x%x\n",
|
pci_warn(pdev, "%s: unknown length for PCI ecap %#x@%#x\n",
|
||||||
dev_name(&pdev->dev), __func__, ecap, epos);
|
__func__, ecap, epos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1474,8 +1473,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!len) {
|
if (!len) {
|
||||||
pr_info("%s: %s hiding cap 0x%x\n",
|
pci_info(pdev, "%s: hiding cap %#x@%#x\n", __func__,
|
||||||
__func__, dev_name(&pdev->dev), cap);
|
cap, pos);
|
||||||
*prev = next;
|
*prev = next;
|
||||||
pos = next;
|
pos = next;
|
||||||
continue;
|
continue;
|
||||||
@ -1486,9 +1485,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
|
|||||||
if (likely(map[pos + i] == PCI_CAP_ID_INVALID))
|
if (likely(map[pos + i] == PCI_CAP_ID_INVALID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pr_warn("%s: %s pci config conflict @0x%x, was cap 0x%x now cap 0x%x\n",
|
pci_warn(pdev, "%s: PCI config conflict @%#x, was cap %#x now cap %#x\n",
|
||||||
__func__, dev_name(&pdev->dev),
|
__func__, pos + i, map[pos + i], cap);
|
||||||
pos + i, map[pos + i], cap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BUILD_BUG_ON(PCI_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
|
BUILD_BUG_ON(PCI_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
|
||||||
@ -1549,8 +1547,8 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!len) {
|
if (!len) {
|
||||||
pr_info("%s: %s hiding ecap 0x%x@0x%x\n",
|
pci_info(pdev, "%s: hiding ecap %#x@%#x\n",
|
||||||
__func__, dev_name(&pdev->dev), ecap, epos);
|
__func__, ecap, epos);
|
||||||
|
|
||||||
/* If not the first in the chain, we can skip over it */
|
/* If not the first in the chain, we can skip over it */
|
||||||
if (prev) {
|
if (prev) {
|
||||||
@ -1572,9 +1570,8 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
|
|||||||
if (likely(map[epos + i] == PCI_CAP_ID_INVALID))
|
if (likely(map[epos + i] == PCI_CAP_ID_INVALID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pr_warn("%s: %s pci config conflict @0x%x, was ecap 0x%x now ecap 0x%x\n",
|
pci_warn(pdev, "%s: PCI config conflict @%#x, was ecap %#x now ecap %#x\n",
|
||||||
__func__, dev_name(&pdev->dev),
|
__func__, epos + i, map[epos + i], ecap);
|
||||||
epos + i, map[epos + i], ecap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -472,6 +472,8 @@ int vfio_pci_ibm_npu2_init(struct vfio_pci_device *vdev)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_exit:
|
free_exit:
|
||||||
|
if (data->base)
|
||||||
|
memunmap(data->base);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -89,7 +89,8 @@ static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
|
|||||||
} while ((pcs_value & MDIO_CTRL1_RESET) && --count);
|
} while ((pcs_value & MDIO_CTRL1_RESET) && --count);
|
||||||
|
|
||||||
if (pcs_value & MDIO_CTRL1_RESET)
|
if (pcs_value & MDIO_CTRL1_RESET)
|
||||||
pr_warn("%s XGBE PHY reset timeout\n", __func__);
|
dev_warn(vdev->device, "%s: XGBE PHY reset timeout\n",
|
||||||
|
__func__);
|
||||||
|
|
||||||
/* disable auto-negotiation */
|
/* disable auto-negotiation */
|
||||||
value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1);
|
value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1);
|
||||||
@ -114,7 +115,7 @@ static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
|
|||||||
usleep_range(500, 600);
|
usleep_range(500, 600);
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
pr_warn("%s MAC SW reset failed\n", __func__);
|
dev_warn(vdev->device, "%s: MAC SW reset failed\n", __func__);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define dev_fmt(fmt) "VFIO: " fmt
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
@ -63,7 +65,7 @@ static int vfio_platform_acpi_probe(struct vfio_platform_device *vdev,
|
|||||||
|
|
||||||
adev = ACPI_COMPANION(dev);
|
adev = ACPI_COMPANION(dev);
|
||||||
if (!adev) {
|
if (!adev) {
|
||||||
pr_err("VFIO: ACPI companion device not found for %s\n",
|
dev_err(dev, "ACPI companion device not found for %s\n",
|
||||||
vdev->name);
|
vdev->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@ -638,7 +640,7 @@ static int vfio_platform_of_probe(struct vfio_platform_device *vdev,
|
|||||||
ret = device_property_read_string(dev, "compatible",
|
ret = device_property_read_string(dev, "compatible",
|
||||||
&vdev->compat);
|
&vdev->compat);
|
||||||
if (ret)
|
if (ret)
|
||||||
pr_err("VFIO: Cannot retrieve compat for %s\n", vdev->name);
|
dev_err(dev, "Cannot retrieve compat for %s\n", vdev->name);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -680,14 +682,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
|
|||||||
|
|
||||||
ret = vfio_platform_get_reset(vdev);
|
ret = vfio_platform_get_reset(vdev);
|
||||||
if (ret && vdev->reset_required) {
|
if (ret && vdev->reset_required) {
|
||||||
pr_err("VFIO: No reset function found for device %s\n",
|
dev_err(dev, "No reset function found for device %s\n",
|
||||||
vdev->name);
|
vdev->name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
group = vfio_iommu_group_get(dev);
|
group = vfio_iommu_group_get(dev);
|
||||||
if (!group) {
|
if (!group) {
|
||||||
pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
|
dev_err(dev, "No IOMMU group for device %s\n", vdev->name);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto put_reset;
|
goto put_reset;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/vfio.h>
|
#include <linux/vfio.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
#include <linux/sched/signal.h>
|
||||||
|
|
||||||
#define DRIVER_VERSION "0.3"
|
#define DRIVER_VERSION "0.3"
|
||||||
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
|
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
|
||||||
@ -704,7 +705,7 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* TODO Prevent device auto probing */
|
/* TODO Prevent device auto probing */
|
||||||
WARN(1, "Device %s added to live group %d!\n", dev_name(dev),
|
dev_WARN(dev, "Device added to live group %d!\n",
|
||||||
iommu_group_id(group->iommu_group));
|
iommu_group_id(group->iommu_group));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -748,24 +749,21 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
|
|||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
|
case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
|
||||||
pr_debug("%s: Device %s, group %d binding to driver\n",
|
dev_dbg(dev, "%s: group %d binding to driver\n", __func__,
|
||||||
__func__, dev_name(dev),
|
|
||||||
iommu_group_id(group->iommu_group));
|
iommu_group_id(group->iommu_group));
|
||||||
break;
|
break;
|
||||||
case IOMMU_GROUP_NOTIFY_BOUND_DRIVER:
|
case IOMMU_GROUP_NOTIFY_BOUND_DRIVER:
|
||||||
pr_debug("%s: Device %s, group %d bound to driver %s\n",
|
dev_dbg(dev, "%s: group %d bound to driver %s\n", __func__,
|
||||||
__func__, dev_name(dev),
|
|
||||||
iommu_group_id(group->iommu_group), dev->driver->name);
|
iommu_group_id(group->iommu_group), dev->driver->name);
|
||||||
BUG_ON(vfio_group_nb_verify(group, dev));
|
BUG_ON(vfio_group_nb_verify(group, dev));
|
||||||
break;
|
break;
|
||||||
case IOMMU_GROUP_NOTIFY_UNBIND_DRIVER:
|
case IOMMU_GROUP_NOTIFY_UNBIND_DRIVER:
|
||||||
pr_debug("%s: Device %s, group %d unbinding from driver %s\n",
|
dev_dbg(dev, "%s: group %d unbinding from driver %s\n",
|
||||||
__func__, dev_name(dev),
|
__func__, iommu_group_id(group->iommu_group),
|
||||||
iommu_group_id(group->iommu_group), dev->driver->name);
|
dev->driver->name);
|
||||||
break;
|
break;
|
||||||
case IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER:
|
case IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER:
|
||||||
pr_debug("%s: Device %s, group %d unbound from driver\n",
|
dev_dbg(dev, "%s: group %d unbound from driver\n", __func__,
|
||||||
__func__, dev_name(dev),
|
|
||||||
iommu_group_id(group->iommu_group));
|
iommu_group_id(group->iommu_group));
|
||||||
/*
|
/*
|
||||||
* XXX An unbound device in a live group is ok, but we'd
|
* XXX An unbound device in a live group is ok, but we'd
|
||||||
@ -830,8 +828,8 @@ int vfio_add_group_dev(struct device *dev,
|
|||||||
|
|
||||||
device = vfio_group_get_device(group, dev);
|
device = vfio_group_get_device(group, dev);
|
||||||
if (device) {
|
if (device) {
|
||||||
WARN(1, "Device %s already exists on group %d\n",
|
dev_WARN(dev, "Device already exists on group %d\n",
|
||||||
dev_name(dev), iommu_group_id(iommu_group));
|
iommu_group_id(iommu_group));
|
||||||
vfio_device_put(device);
|
vfio_device_put(device);
|
||||||
vfio_group_put(group);
|
vfio_group_put(group);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
@ -904,30 +902,17 @@ void *vfio_device_data(struct vfio_device *device)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vfio_device_data);
|
EXPORT_SYMBOL_GPL(vfio_device_data);
|
||||||
|
|
||||||
/* Given a referenced group, check if it contains the device */
|
|
||||||
static bool vfio_dev_present(struct vfio_group *group, struct device *dev)
|
|
||||||
{
|
|
||||||
struct vfio_device *device;
|
|
||||||
|
|
||||||
device = vfio_group_get_device(group, dev);
|
|
||||||
if (!device)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
vfio_device_put(device);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decrement the device reference count and wait for the device to be
|
* Decrement the device reference count and wait for the device to be
|
||||||
* removed. Open file descriptors for the device... */
|
* removed. Open file descriptors for the device... */
|
||||||
void *vfio_del_group_dev(struct device *dev)
|
void *vfio_del_group_dev(struct device *dev)
|
||||||
{
|
{
|
||||||
|
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||||
struct vfio_device *device = dev_get_drvdata(dev);
|
struct vfio_device *device = dev_get_drvdata(dev);
|
||||||
struct vfio_group *group = device->group;
|
struct vfio_group *group = device->group;
|
||||||
void *device_data = device->device_data;
|
void *device_data = device->device_data;
|
||||||
struct vfio_unbound_dev *unbound;
|
struct vfio_unbound_dev *unbound;
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
long ret;
|
|
||||||
bool interrupted = false;
|
bool interrupted = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -964,6 +949,8 @@ void *vfio_del_group_dev(struct device *dev)
|
|||||||
* interval with counter to allow the driver to take escalating
|
* interval with counter to allow the driver to take escalating
|
||||||
* measures to release the device if it has the ability to do so.
|
* measures to release the device if it has the ability to do so.
|
||||||
*/
|
*/
|
||||||
|
add_wait_queue(&vfio.release_q, &wait);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
device = vfio_group_get_device(group, dev);
|
device = vfio_group_get_device(group, dev);
|
||||||
if (!device)
|
if (!device)
|
||||||
@ -975,12 +962,10 @@ void *vfio_del_group_dev(struct device *dev)
|
|||||||
vfio_device_put(device);
|
vfio_device_put(device);
|
||||||
|
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
ret = wait_event_timeout(vfio.release_q,
|
wait_woken(&wait, TASK_UNINTERRUPTIBLE, HZ * 10);
|
||||||
!vfio_dev_present(group, dev), HZ * 10);
|
|
||||||
} else {
|
} else {
|
||||||
ret = wait_event_interruptible_timeout(vfio.release_q,
|
wait_woken(&wait, TASK_INTERRUPTIBLE, HZ * 10);
|
||||||
!vfio_dev_present(group, dev), HZ * 10);
|
if (signal_pending(current)) {
|
||||||
if (ret == -ERESTARTSYS) {
|
|
||||||
interrupted = true;
|
interrupted = true;
|
||||||
dev_warn(dev,
|
dev_warn(dev,
|
||||||
"Device is currently in use, task"
|
"Device is currently in use, task"
|
||||||
@ -989,8 +974,10 @@ void *vfio_del_group_dev(struct device *dev)
|
|||||||
current->comm, task_pid_nr(current));
|
current->comm, task_pid_nr(current));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (ret <= 0);
|
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
remove_wait_queue(&vfio.release_q, &wait);
|
||||||
/*
|
/*
|
||||||
* In order to support multiple devices per group, devices can be
|
* In order to support multiple devices per group, devices can be
|
||||||
* plucked from the group while other devices in the group are still
|
* plucked from the group while other devices in the group are still
|
||||||
|
@ -118,21 +118,20 @@ struct mdev_driver {
|
|||||||
|
|
||||||
#define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver)
|
#define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver)
|
||||||
|
|
||||||
extern void *mdev_get_drvdata(struct mdev_device *mdev);
|
void *mdev_get_drvdata(struct mdev_device *mdev);
|
||||||
extern void mdev_set_drvdata(struct mdev_device *mdev, void *data);
|
void mdev_set_drvdata(struct mdev_device *mdev, void *data);
|
||||||
extern const guid_t *mdev_uuid(struct mdev_device *mdev);
|
const guid_t *mdev_uuid(struct mdev_device *mdev);
|
||||||
|
|
||||||
extern struct bus_type mdev_bus_type;
|
extern struct bus_type mdev_bus_type;
|
||||||
|
|
||||||
extern int mdev_register_device(struct device *dev,
|
int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops);
|
||||||
const struct mdev_parent_ops *ops);
|
void mdev_unregister_device(struct device *dev);
|
||||||
extern void mdev_unregister_device(struct device *dev);
|
|
||||||
|
|
||||||
extern int mdev_register_driver(struct mdev_driver *drv, struct module *owner);
|
int mdev_register_driver(struct mdev_driver *drv, struct module *owner);
|
||||||
extern void mdev_unregister_driver(struct mdev_driver *drv);
|
void mdev_unregister_driver(struct mdev_driver *drv);
|
||||||
|
|
||||||
extern struct device *mdev_parent_dev(struct mdev_device *mdev);
|
struct device *mdev_parent_dev(struct mdev_device *mdev);
|
||||||
extern struct device *mdev_dev(struct mdev_device *mdev);
|
struct device *mdev_dev(struct mdev_device *mdev);
|
||||||
extern struct mdev_device *mdev_from_dev(struct device *dev);
|
struct mdev_device *mdev_from_dev(struct device *dev);
|
||||||
|
|
||||||
#endif /* MDEV_H */
|
#endif /* MDEV_H */
|
||||||
|
@ -2363,4 +2363,7 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
|
|||||||
#define pci_info(pdev, fmt, arg...) dev_info(&(pdev)->dev, fmt, ##arg)
|
#define pci_info(pdev, fmt, arg...) dev_info(&(pdev)->dev, fmt, ##arg)
|
||||||
#define pci_dbg(pdev, fmt, arg...) dev_dbg(&(pdev)->dev, fmt, ##arg)
|
#define pci_dbg(pdev, fmt, arg...) dev_dbg(&(pdev)->dev, fmt, ##arg)
|
||||||
|
|
||||||
|
#define pci_notice_ratelimited(pdev, fmt, arg...) \
|
||||||
|
dev_notice_ratelimited(&(pdev)->dev, fmt, ##arg)
|
||||||
|
|
||||||
#endif /* LINUX_PCI_H */
|
#endif /* LINUX_PCI_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user