iommu: Add option to group multi-function devices

The option iommu=group_mf indicates the that the iommu driver should
expose all functions of a multi-function PCI device as the same
iommu_device_group.  This is useful for disallowing individual functions
being exposed as independent devices to userspace as there are often
hidden dependencies.  Virtual functions are not affected by this option.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
Alex Williamson 2011-10-21 15:56:24 -04:00 committed by Joerg Roedel
parent 8fbdce6595
commit bcb71abe7d
7 changed files with 30 additions and 2 deletions

View File

@ -1060,6 +1060,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
forcesac forcesac
soft soft
pt [x86, IA-64] pt [x86, IA-64]
group_mf [x86, IA-64]
io7= [HW] IO7 for Marvel based alpha systems io7= [HW] IO7 for Marvel based alpha systems
See comment before marvel_specify_io7 in See comment before marvel_specify_io7 in

View File

@ -11,10 +11,12 @@ extern void no_iommu_init(void);
extern int force_iommu, no_iommu; extern int force_iommu, no_iommu;
extern int iommu_pass_through; extern int iommu_pass_through;
extern int iommu_detected; extern int iommu_detected;
extern int iommu_group_mf;
#else #else
#define iommu_pass_through (0) #define iommu_pass_through (0)
#define no_iommu (1) #define no_iommu (1)
#define iommu_detected (0) #define iommu_detected (0)
#define iommu_group_mf (0)
#endif #endif
extern void iommu_dma_init(void); extern void iommu_dma_init(void);
extern void machvec_init(const char *name); extern void machvec_init(const char *name);

View File

@ -33,6 +33,7 @@ int force_iommu __read_mostly;
#endif #endif
int iommu_pass_through; int iommu_pass_through;
int iommu_group_mf;
/* Dummy device used for NULL arguments (normally ISA). Better would /* Dummy device used for NULL arguments (normally ISA). Better would
be probably a smaller DMA mask, but this is bug-to-bug compatible be probably a smaller DMA mask, but this is bug-to-bug compatible

View File

@ -5,6 +5,7 @@ extern struct dma_map_ops nommu_dma_ops;
extern int force_iommu, no_iommu; extern int force_iommu, no_iommu;
extern int iommu_detected; extern int iommu_detected;
extern int iommu_pass_through; extern int iommu_pass_through;
extern int iommu_group_mf;
/* 10 seconds */ /* 10 seconds */
#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)

View File

@ -45,6 +45,15 @@ int iommu_detected __read_mostly = 0;
*/ */
int iommu_pass_through __read_mostly; int iommu_pass_through __read_mostly;
/*
* Group multi-function PCI devices into a single device-group for the
* iommu_device_group interface. This tells the iommu driver to pretend
* it cannot distinguish between functions of a device, exposing only one
* group for the device. Useful for disallowing use of individual PCI
* functions from userspace drivers.
*/
int iommu_group_mf __read_mostly;
extern struct iommu_table_entry __iommu_table[], __iommu_table_end[]; extern struct iommu_table_entry __iommu_table[], __iommu_table_end[];
/* Dummy device used for NULL arguments (normally ISA). */ /* Dummy device used for NULL arguments (normally ISA). */
@ -169,6 +178,8 @@ static __init int iommu_setup(char *p)
#endif #endif
if (!strncmp(p, "pt", 2)) if (!strncmp(p, "pt", 2))
iommu_pass_through = 1; iommu_pass_through = 1;
if (!strncmp(p, "group_mf", 8))
iommu_group_mf = 1;
gart_parse_options(p); gart_parse_options(p);

View File

@ -2776,11 +2776,19 @@ static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
static int amd_iommu_device_group(struct device *dev, unsigned int *groupid) static int amd_iommu_device_group(struct device *dev, unsigned int *groupid)
{ {
struct iommu_dev_data *dev_data = dev->archdata.iommu; struct iommu_dev_data *dev_data = dev->archdata.iommu;
struct pci_dev *pdev = to_pci_dev(dev);
u16 devid;
if (!dev_data) if (!dev_data)
return -ENODEV; return -ENODEV;
*groupid = amd_iommu_alias_table[dev_data->devid]; if (pdev->is_virtfn || !iommu_group_mf)
devid = dev_data->devid;
else
devid = calc_devid(pdev->bus->number,
PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
*groupid = amd_iommu_alias_table[devid];
return 0; return 0;
} }

View File

@ -4100,6 +4100,9 @@ static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
} }
} }
if (!pdev->is_virtfn && iommu_group_mf)
id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);
*groupid = id.group; *groupid = id.group;
return 0; return 0;