mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-next/iommu/default-domains' into for-next/iommu/core
Support for changing the default domain type for singleton IOMMU groups via sysfs when the constituent device is not already bound to a device driver. * for-next/iommu/default-domains: iommu: Fix htmldocs warnings in sysfs-kernel-iommu_groups iommu: Document usage of "/sys/kernel/iommu_groups/<grp_id>/type" file iommu: Take lock before reading iommu group default domain type iommu: Add support to change default domain of an iommu group iommu: Move def_domain type check for untrusted device into core
This commit is contained in:
commit
33f974dbaa
|
@ -33,3 +33,33 @@ Description: In case an RMRR is used only by graphics or USB devices
|
||||||
it is now exposed as "direct-relaxable" instead of "direct".
|
it is now exposed as "direct-relaxable" instead of "direct".
|
||||||
In device assignment use case, for instance, those RMRR
|
In device assignment use case, for instance, those RMRR
|
||||||
are considered to be relaxable and safe.
|
are considered to be relaxable and safe.
|
||||||
|
|
||||||
|
What: /sys/kernel/iommu_groups/<grp_id>/type
|
||||||
|
Date: November 2020
|
||||||
|
KernelVersion: v5.11
|
||||||
|
Contact: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
|
||||||
|
Description: /sys/kernel/iommu_groups/<grp_id>/type shows the type of default
|
||||||
|
domain in use by iommu for this group. See include/linux/iommu.h
|
||||||
|
for possible read values. A privileged user could request kernel to
|
||||||
|
change the group type by writing to this file. Valid write values:
|
||||||
|
|
||||||
|
======== ======================================================
|
||||||
|
DMA All the DMA transactions from the device in this group
|
||||||
|
are translated by the iommu.
|
||||||
|
identity All the DMA transactions from the device in this group
|
||||||
|
are not translated by the iommu.
|
||||||
|
auto Change to the type the device was booted with.
|
||||||
|
======== ======================================================
|
||||||
|
|
||||||
|
The default domain type of a group may be modified only when
|
||||||
|
|
||||||
|
- The group has only one device.
|
||||||
|
- The device in the group is not bound to any device driver.
|
||||||
|
So, the users must unbind the appropriate driver before
|
||||||
|
changing the default domain type.
|
||||||
|
|
||||||
|
Unbinding a device driver will take away the driver's control
|
||||||
|
over the device and if done on devices that host root file
|
||||||
|
system could lead to catastrophic effects (the users might
|
||||||
|
need to reboot the machine to get it to normal state). So, it's
|
||||||
|
expected that the users understand what they're doing.
|
||||||
|
|
|
@ -2916,13 +2916,6 @@ static int device_def_domain_type(struct device *dev)
|
||||||
if (dev_is_pci(dev)) {
|
if (dev_is_pci(dev)) {
|
||||||
struct pci_dev *pdev = to_pci_dev(dev);
|
struct pci_dev *pdev = to_pci_dev(dev);
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevent any device marked as untrusted from getting
|
|
||||||
* placed into the statically identity mapping domain.
|
|
||||||
*/
|
|
||||||
if (pdev->untrusted)
|
|
||||||
return IOMMU_DOMAIN_DMA;
|
|
||||||
|
|
||||||
if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
|
if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
|
||||||
return IOMMU_DOMAIN_IDENTITY;
|
return IOMMU_DOMAIN_IDENTITY;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,8 @@ static void __iommu_detach_group(struct iommu_domain *domain,
|
||||||
static int iommu_create_device_direct_mappings(struct iommu_group *group,
|
static int iommu_create_device_direct_mappings(struct iommu_group *group,
|
||||||
struct device *dev);
|
struct device *dev);
|
||||||
static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
|
static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
|
||||||
|
static ssize_t iommu_group_store_type(struct iommu_group *group,
|
||||||
|
const char *buf, size_t count);
|
||||||
|
|
||||||
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
|
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
|
||||||
struct iommu_group_attribute iommu_group_attr_##_name = \
|
struct iommu_group_attribute iommu_group_attr_##_name = \
|
||||||
|
@ -499,6 +501,7 @@ static ssize_t iommu_group_show_type(struct iommu_group *group,
|
||||||
{
|
{
|
||||||
char *type = "unknown\n";
|
char *type = "unknown\n";
|
||||||
|
|
||||||
|
mutex_lock(&group->mutex);
|
||||||
if (group->default_domain) {
|
if (group->default_domain) {
|
||||||
switch (group->default_domain->type) {
|
switch (group->default_domain->type) {
|
||||||
case IOMMU_DOMAIN_BLOCKED:
|
case IOMMU_DOMAIN_BLOCKED:
|
||||||
|
@ -515,6 +518,7 @@ static ssize_t iommu_group_show_type(struct iommu_group *group,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&group->mutex);
|
||||||
strcpy(buf, type);
|
strcpy(buf, type);
|
||||||
|
|
||||||
return strlen(type);
|
return strlen(type);
|
||||||
|
@ -525,7 +529,8 @@ static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL);
|
||||||
static IOMMU_GROUP_ATTR(reserved_regions, 0444,
|
static IOMMU_GROUP_ATTR(reserved_regions, 0444,
|
||||||
iommu_group_show_resv_regions, NULL);
|
iommu_group_show_resv_regions, NULL);
|
||||||
|
|
||||||
static IOMMU_GROUP_ATTR(type, 0444, iommu_group_show_type, NULL);
|
static IOMMU_GROUP_ATTR(type, 0644, iommu_group_show_type,
|
||||||
|
iommu_group_store_type);
|
||||||
|
|
||||||
static void iommu_group_release(struct kobject *kobj)
|
static void iommu_group_release(struct kobject *kobj)
|
||||||
{
|
{
|
||||||
|
@ -1460,12 +1465,14 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_group);
|
||||||
static int iommu_get_def_domain_type(struct device *dev)
|
static int iommu_get_def_domain_type(struct device *dev)
|
||||||
{
|
{
|
||||||
const struct iommu_ops *ops = dev->bus->iommu_ops;
|
const struct iommu_ops *ops = dev->bus->iommu_ops;
|
||||||
unsigned int type = 0;
|
|
||||||
|
if (dev_is_pci(dev) && to_pci_dev(dev)->untrusted)
|
||||||
|
return IOMMU_DOMAIN_DMA;
|
||||||
|
|
||||||
if (ops->def_domain_type)
|
if (ops->def_domain_type)
|
||||||
type = ops->def_domain_type(dev);
|
return ops->def_domain_type(dev);
|
||||||
|
|
||||||
return (type == 0) ? iommu_def_domain_type : type;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iommu_group_alloc_default_domain(struct bus_type *bus,
|
static int iommu_group_alloc_default_domain(struct bus_type *bus,
|
||||||
|
@ -1507,7 +1514,7 @@ static int iommu_alloc_default_domain(struct iommu_group *group,
|
||||||
if (group->default_domain)
|
if (group->default_domain)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
type = iommu_get_def_domain_type(dev);
|
type = iommu_get_def_domain_type(dev) ? : iommu_def_domain_type;
|
||||||
|
|
||||||
return iommu_group_alloc_default_domain(dev->bus, group, type);
|
return iommu_group_alloc_default_domain(dev->bus, group, type);
|
||||||
}
|
}
|
||||||
|
@ -1645,12 +1652,8 @@ struct __group_domain_type {
|
||||||
|
|
||||||
static int probe_get_default_domain_type(struct device *dev, void *data)
|
static int probe_get_default_domain_type(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
const struct iommu_ops *ops = dev->bus->iommu_ops;
|
|
||||||
struct __group_domain_type *gtype = data;
|
struct __group_domain_type *gtype = data;
|
||||||
unsigned int type = 0;
|
unsigned int type = iommu_get_def_domain_type(dev);
|
||||||
|
|
||||||
if (ops->def_domain_type)
|
|
||||||
type = ops->def_domain_type(dev);
|
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
if (gtype->type && gtype->type != type) {
|
if (gtype->type && gtype->type != type) {
|
||||||
|
@ -3029,3 +3032,228 @@ u32 iommu_sva_get_pasid(struct iommu_sva *handle)
|
||||||
return ops->sva_get_pasid(handle);
|
return ops->sva_get_pasid(handle);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
|
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changes the default domain of an iommu group that has *only* one device
|
||||||
|
*
|
||||||
|
* @group: The group for which the default domain should be changed
|
||||||
|
* @prev_dev: The device in the group (this is used to make sure that the device
|
||||||
|
* hasn't changed after the caller has called this function)
|
||||||
|
* @type: The type of the new default domain that gets associated with the group
|
||||||
|
*
|
||||||
|
* Returns 0 on success and error code on failure
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* 1. Presently, this function is called only when user requests to change the
|
||||||
|
* group's default domain type through /sys/kernel/iommu_groups/<grp_id>/type
|
||||||
|
* Please take a closer look if intended to use for other purposes.
|
||||||
|
*/
|
||||||
|
static int iommu_change_dev_def_domain(struct iommu_group *group,
|
||||||
|
struct device *prev_dev, int type)
|
||||||
|
{
|
||||||
|
struct iommu_domain *prev_dom;
|
||||||
|
struct group_device *grp_dev;
|
||||||
|
int ret, dev_def_dom;
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
if (!group)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&group->mutex);
|
||||||
|
|
||||||
|
if (group->default_domain != group->domain) {
|
||||||
|
dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* iommu group wasn't locked while acquiring device lock in
|
||||||
|
* iommu_group_store_type(). So, make sure that the device count hasn't
|
||||||
|
* changed while acquiring device lock.
|
||||||
|
*
|
||||||
|
* Changing default domain of an iommu group with two or more devices
|
||||||
|
* isn't supported because there could be a potential deadlock. Consider
|
||||||
|
* the following scenario. T1 is trying to acquire device locks of all
|
||||||
|
* the devices in the group and before it could acquire all of them,
|
||||||
|
* there could be another thread T2 (from different sub-system and use
|
||||||
|
* case) that has already acquired some of the device locks and might be
|
||||||
|
* waiting for T1 to release other device locks.
|
||||||
|
*/
|
||||||
|
if (iommu_group_device_count(group) != 1) {
|
||||||
|
dev_err_ratelimited(prev_dev, "Cannot change default domain: Group has more than one device\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since group has only one device */
|
||||||
|
grp_dev = list_first_entry(&group->devices, struct group_device, list);
|
||||||
|
dev = grp_dev->dev;
|
||||||
|
|
||||||
|
if (prev_dev != dev) {
|
||||||
|
dev_err_ratelimited(prev_dev, "Cannot change default domain: Device has been changed\n");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_dom = group->default_domain;
|
||||||
|
if (!prev_dom) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_def_dom = iommu_get_def_domain_type(dev);
|
||||||
|
if (!type) {
|
||||||
|
/*
|
||||||
|
* If the user hasn't requested any specific type of domain and
|
||||||
|
* if the device supports both the domains, then default to the
|
||||||
|
* domain the device was booted with
|
||||||
|
*/
|
||||||
|
type = dev_def_dom ? : iommu_def_domain_type;
|
||||||
|
} else if (dev_def_dom && type != dev_def_dom) {
|
||||||
|
dev_err_ratelimited(prev_dev, "Device cannot be in %s domain\n",
|
||||||
|
iommu_domain_type_str(type));
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch to a new domain only if the requested domain type is different
|
||||||
|
* from the existing default domain type
|
||||||
|
*/
|
||||||
|
if (prev_dom->type == type) {
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets group->default_domain to the newly allocated domain */
|
||||||
|
ret = iommu_group_alloc_default_domain(dev->bus, group, type);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = iommu_create_device_direct_mappings(group, dev);
|
||||||
|
if (ret)
|
||||||
|
goto free_new_domain;
|
||||||
|
|
||||||
|
ret = __iommu_attach_device(group->default_domain, dev);
|
||||||
|
if (ret)
|
||||||
|
goto free_new_domain;
|
||||||
|
|
||||||
|
group->domain = group->default_domain;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the mutex here because ops->probe_finalize() call-back of
|
||||||
|
* some vendor IOMMU drivers calls arm_iommu_attach_device() which
|
||||||
|
* in-turn might call back into IOMMU core code, where it tries to take
|
||||||
|
* group->mutex, resulting in a deadlock.
|
||||||
|
*/
|
||||||
|
mutex_unlock(&group->mutex);
|
||||||
|
|
||||||
|
/* Make sure dma_ops is appropriatley set */
|
||||||
|
iommu_group_do_probe_finalize(dev, group->default_domain);
|
||||||
|
iommu_domain_free(prev_dom);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_new_domain:
|
||||||
|
iommu_domain_free(group->default_domain);
|
||||||
|
group->default_domain = prev_dom;
|
||||||
|
group->domain = prev_dom;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&group->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changing the default domain through sysfs requires the users to ubind the
|
||||||
|
* drivers from the devices in the iommu group. Return failure if this doesn't
|
||||||
|
* meet.
|
||||||
|
*
|
||||||
|
* We need to consider the race between this and the device release path.
|
||||||
|
* device_lock(dev) is used here to guarantee that the device release path
|
||||||
|
* will not be entered at the same time.
|
||||||
|
*/
|
||||||
|
static ssize_t iommu_group_store_type(struct iommu_group *group,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct group_device *grp_dev;
|
||||||
|
struct device *dev;
|
||||||
|
int ret, req_type;
|
||||||
|
|
||||||
|
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
if (WARN_ON(!group))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (sysfs_streq(buf, "identity"))
|
||||||
|
req_type = IOMMU_DOMAIN_IDENTITY;
|
||||||
|
else if (sysfs_streq(buf, "DMA"))
|
||||||
|
req_type = IOMMU_DOMAIN_DMA;
|
||||||
|
else if (sysfs_streq(buf, "auto"))
|
||||||
|
req_type = 0;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock/Unlock the group mutex here before device lock to
|
||||||
|
* 1. Make sure that the iommu group has only one device (this is a
|
||||||
|
* prerequisite for step 2)
|
||||||
|
* 2. Get struct *dev which is needed to lock device
|
||||||
|
*/
|
||||||
|
mutex_lock(&group->mutex);
|
||||||
|
if (iommu_group_device_count(group) != 1) {
|
||||||
|
mutex_unlock(&group->mutex);
|
||||||
|
pr_err_ratelimited("Cannot change default domain: Group has more than one device\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since group has only one device */
|
||||||
|
grp_dev = list_first_entry(&group->devices, struct group_device, list);
|
||||||
|
dev = grp_dev->dev;
|
||||||
|
get_device(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't hold the group mutex because taking group mutex first and then
|
||||||
|
* the device lock could potentially cause a deadlock as below. Assume
|
||||||
|
* two threads T1 and T2. T1 is trying to change default domain of an
|
||||||
|
* iommu group and T2 is trying to hot unplug a device or release [1] VF
|
||||||
|
* of a PCIe device which is in the same iommu group. T1 takes group
|
||||||
|
* mutex and before it could take device lock assume T2 has taken device
|
||||||
|
* lock and is yet to take group mutex. Now, both the threads will be
|
||||||
|
* waiting for the other thread to release lock. Below, lock order was
|
||||||
|
* suggested.
|
||||||
|
* device_lock(dev);
|
||||||
|
* mutex_lock(&group->mutex);
|
||||||
|
* iommu_change_dev_def_domain();
|
||||||
|
* mutex_unlock(&group->mutex);
|
||||||
|
* device_unlock(dev);
|
||||||
|
*
|
||||||
|
* [1] Typical device release path
|
||||||
|
* device_lock() from device/driver core code
|
||||||
|
* -> bus_notifier()
|
||||||
|
* -> iommu_bus_notifier()
|
||||||
|
* -> iommu_release_device()
|
||||||
|
* -> ops->release_device() vendor driver calls back iommu core code
|
||||||
|
* -> mutex_lock() from iommu core code
|
||||||
|
*/
|
||||||
|
mutex_unlock(&group->mutex);
|
||||||
|
|
||||||
|
/* Check if the device in the group still has a driver bound to it */
|
||||||
|
device_lock(dev);
|
||||||
|
if (device_is_bound(dev)) {
|
||||||
|
pr_err_ratelimited("Device is still bound to driver\n");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = iommu_change_dev_def_domain(group, dev, req_type);
|
||||||
|
ret = ret ?: count;
|
||||||
|
|
||||||
|
out:
|
||||||
|
device_unlock(dev);
|
||||||
|
put_device(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue