Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 316585
b: refs/heads/master
c: 4e0ee78
h: refs/heads/master
i:
  316583: 5a5394d
v: v3
  • Loading branch information
Hiroshi Doyu authored and Joerg Roedel committed Jun 25, 2012
1 parent beeda9e commit 88084b0
Show file tree
Hide file tree
Showing 23 changed files with 248 additions and 1,080 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7d43c2e42cb1e436f97c1763150e4e1122ae0d57
refs/heads/master: 4e0ee78f2af96676c9dca898c13250f62c513058
14 changes: 0 additions & 14 deletions trunk/Documentation/ABI/testing/sysfs-kernel-iommu_groups

This file was deleted.

1 change: 1 addition & 0 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
forcesac
soft
pt [x86, IA-64]
group_mf [x86, IA-64]


io7= [HW] IO7 for Marvel based alpha systems
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/ia64/include/asm/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ extern void no_iommu_init(void);
extern int force_iommu, no_iommu;
extern int iommu_pass_through;
extern int iommu_detected;
extern int iommu_group_mf;
#else
#define iommu_pass_through (0)
#define no_iommu (1)
#define iommu_detected (0)
#define iommu_group_mf (0)
#endif
extern void iommu_dma_init(void);
extern void machvec_init(const char *name);
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/ia64/kernel/pci-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ int force_iommu __read_mostly;
#endif

int iommu_pass_through;
int iommu_group_mf;

/* Dummy device used for NULL arguments (normally ISA). Better would
be probably a smaller DMA mask, but this is bug-to-bug compatible
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/x86/include/asm/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern struct dma_map_ops nommu_dma_ops;
extern int force_iommu, no_iommu;
extern int iommu_detected;
extern int iommu_pass_through;
extern int iommu_group_mf;

/* 10 seconds */
#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
Expand Down
11 changes: 11 additions & 0 deletions trunk/arch/x86/kernel/pci-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ int iommu_detected __read_mostly = 0;
*/
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[];

/* Dummy device used for NULL arguments (normally ISA). */
Expand Down Expand Up @@ -185,6 +194,8 @@ static __init int iommu_setup(char *p)
#endif
if (!strncmp(p, "pt", 2))
iommu_pass_through = 1;
if (!strncmp(p, "group_mf", 8))
iommu_group_mf = 1;

gart_parse_options(p);

Expand Down
4 changes: 4 additions & 0 deletions trunk/drivers/iommu/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ menuconfig IOMMU_SUPPORT

if IOMMU_SUPPORT

config OF_IOMMU
def_bool y
depends on OF

# MSM IOMMU support
config MSM_IOMMU
bool "MSM IOMMU Support"
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/iommu/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
obj-$(CONFIG_IOMMU_API) += iommu.o
obj-$(CONFIG_OF_IOMMU) += of_iommu.o
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
Expand Down
70 changes: 22 additions & 48 deletions trunk/drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,21 +254,11 @@ static bool check_device(struct device *dev)
return true;
}

static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
{
pci_dev_put(*from);
*from = to;
}

#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)

static int iommu_init_device(struct device *dev)
{
struct pci_dev *dma_pdev, *pdev = to_pci_dev(dev);
struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
struct iommu_group *group;
u16 alias;
int ret;

if (dev->archdata.iommu)
return 0;
Expand All @@ -289,43 +279,8 @@ static int iommu_init_device(struct device *dev)
return -ENOTSUPP;
}
dev_data->alias_data = alias_data;

dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
} else
dma_pdev = pci_dev_get(pdev);

swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));

if (dma_pdev->multifunction &&
!pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
swap_pci_ref(&dma_pdev,
pci_get_slot(dma_pdev->bus,
PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
0)));

while (!pci_is_root_bus(dma_pdev->bus)) {
if (pci_acs_path_enabled(dma_pdev->bus->self,
NULL, REQ_ACS_FLAGS))
break;

swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
}

group = iommu_group_get(&dma_pdev->dev);
pci_dev_put(dma_pdev);
if (!group) {
group = iommu_group_alloc();
if (IS_ERR(group))
return PTR_ERR(group);
}

ret = iommu_group_add_device(group, dev);

iommu_group_put(group);

if (ret)
return ret;

if (pci_iommuv2_capable(pdev)) {
struct amd_iommu *iommu;

Expand Down Expand Up @@ -354,8 +309,6 @@ static void iommu_ignore_device(struct device *dev)

static void iommu_uninit_device(struct device *dev)
{
iommu_group_remove_device(dev);

/*
* Nothing to do here - we keep dev_data around for unplugged devices
* and reuse it when the device is re-plugged - not doing so would
Expand Down Expand Up @@ -3274,6 +3227,26 @@ static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
return 0;
}

static int amd_iommu_device_group(struct device *dev, unsigned int *groupid)
{
struct iommu_dev_data *dev_data = dev->archdata.iommu;
struct pci_dev *pdev = to_pci_dev(dev);
u16 devid;

if (!dev_data)
return -ENODEV;

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;
}

static struct iommu_ops amd_iommu_ops = {
.domain_init = amd_iommu_domain_init,
.domain_destroy = amd_iommu_domain_destroy,
Expand All @@ -3283,6 +3256,7 @@ static struct iommu_ops amd_iommu_ops = {
.unmap = amd_iommu_unmap,
.iova_to_phys = amd_iommu_iova_to_phys,
.domain_has_cap = amd_iommu_domain_has_cap,
.device_group = amd_iommu_device_group,
.pgsize_bitmap = AMD_IOMMU_PGSIZES,
};

Expand Down
89 changes: 35 additions & 54 deletions trunk/drivers/iommu/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4090,70 +4090,52 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
return 0;
}

static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
/*
* Group numbers are arbitrary. Device with the same group number
* indicate the iommu cannot differentiate between them. To avoid
* tracking used groups we just use the seg|bus|devfn of the lowest
* level we're able to differentiate devices
*/
static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
{
pci_dev_put(*from);
*from = to;
}
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_dev *bridge;
union {
struct {
u8 devfn;
u8 bus;
u16 segment;
} pci;
u32 group;
} id;

#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
if (iommu_no_mapping(dev))
return -ENODEV;

static int intel_iommu_add_device(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_dev *bridge, *dma_pdev;
struct iommu_group *group;
int ret;
id.pci.segment = pci_domain_nr(pdev->bus);
id.pci.bus = pdev->bus->number;
id.pci.devfn = pdev->devfn;

if (!device_to_iommu(pci_domain_nr(pdev->bus),
pdev->bus->number, pdev->devfn))
if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn))
return -ENODEV;

bridge = pci_find_upstream_pcie_bridge(pdev);
if (bridge) {
if (pci_is_pcie(bridge))
dma_pdev = pci_get_domain_bus_and_slot(
pci_domain_nr(pdev->bus),
bridge->subordinate->number, 0);
else
dma_pdev = pci_dev_get(bridge);
} else
dma_pdev = pci_dev_get(pdev);

swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));

if (dma_pdev->multifunction &&
!pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
swap_pci_ref(&dma_pdev,
pci_get_slot(dma_pdev->bus,
PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
0)));

while (!pci_is_root_bus(dma_pdev->bus)) {
if (pci_acs_path_enabled(dma_pdev->bus->self,
NULL, REQ_ACS_FLAGS))
break;

swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
}

group = iommu_group_get(&dma_pdev->dev);
pci_dev_put(dma_pdev);
if (!group) {
group = iommu_group_alloc();
if (IS_ERR(group))
return PTR_ERR(group);
if (pci_is_pcie(bridge)) {
id.pci.bus = bridge->subordinate->number;
id.pci.devfn = 0;
} else {
id.pci.bus = bridge->bus->number;
id.pci.devfn = bridge->devfn;
}
}

ret = iommu_group_add_device(group, dev);
if (!pdev->is_virtfn && iommu_group_mf)
id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);

iommu_group_put(group);
return ret;
}
*groupid = id.group;

static void intel_iommu_remove_device(struct device *dev)
{
iommu_group_remove_device(dev);
return 0;
}

static struct iommu_ops intel_iommu_ops = {
Expand All @@ -4165,8 +4147,7 @@ static struct iommu_ops intel_iommu_ops = {
.unmap = intel_iommu_unmap,
.iova_to_phys = intel_iommu_iova_to_phys,
.domain_has_cap = intel_iommu_domain_has_cap,
.add_device = intel_iommu_add_device,
.remove_device = intel_iommu_remove_device,
.device_group = intel_iommu_device_group,
.pgsize_bitmap = INTEL_IOMMU_PGSIZES,
};

Expand Down
Loading

0 comments on commit 88084b0

Please sign in to comment.