Skip to content

Commit

Permalink
Merge tag 'iommu-updates-v3.6-rc1' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/joro/iommu

Pull IOMMU updates from Joerg Roedel:
 "The most important part of these updates is the IOMMU groups code
  enhancement written by Alex Williamson.  It abstracts the problem that
  a given hardware IOMMU can't isolate any given device from any other
  device (e.g.  32 bit PCI devices can't usually be isolated).  Devices
  that can't be isolated are grouped together.  This code is required
  for the upcoming VFIO framework.

  Another IOMMU-API change written by me is the introduction of domain
  attributes.  This makes it easier to handle GART-like IOMMUs with the
  IOMMU-API because now the start-address and the size of the domain
  address space can be queried.

  Besides that there are a few cleanups and fixes for the NVidia Tegra
  IOMMU drivers and the reworked init-code for the AMD IOMMU.  The
  latter is from my patch-set to support interrupt remapping.  The rest
  of this patch-set requires x86 changes which are not mergabe yet.  So
  full support for interrupt remapping with AMD IOMMUs will come in a
  future merge window."

* tag 'iommu-updates-v3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (33 commits)
  iommu/amd: Fix hotplug with iommu=pt
  iommu/amd: Add missing spin_lock initialization
  iommu/amd: Convert iommu initialization to state machine
  iommu/amd: Introduce amd_iommu_init_dma routine
  iommu/amd: Move unmap_flush message to amd_iommu_init_dma_ops()
  iommu/amd: Split enable_iommus() routine
  iommu/amd: Introduce early_amd_iommu_init routine
  iommu/amd: Move informational prinks out of iommu_enable
  iommu/amd: Split out PCI related parts of IOMMU initialization
  iommu/amd: Use acpi_get_table instead of acpi_table_parse
  iommu/amd: Fix sparse warnings
  iommu/tegra: Don't call alloc_pdir with as->lock
  iommu/tegra: smmu: Fix unsleepable memory allocation at alloc_pdir()
  iommu/tegra: smmu: Remove unnecessary sanity check at alloc_pdir()
  iommu/exynos: Implement DOMAIN_ATTR_GEOMETRY attribute
  iommu/tegra: Implement DOMAIN_ATTR_GEOMETRY attribute
  iommu/msm: Implement DOMAIN_ATTR_GEOMETRY attribute
  iommu/omap: Implement DOMAIN_ATTR_GEOMETRY attribute
  iommu/vt-d: Implement DOMAIN_ATTR_GEOMETRY attribute
  iommu/amd: Implement DOMAIN_ATTR_GEOMETRY attribute
  ...
  • Loading branch information
Linus Torvalds committed Jul 24, 2012
2 parents 6dd53aa + 395e51f commit 97027da
Show file tree
Hide file tree
Showing 25 changed files with 1,527 additions and 481 deletions.
14 changes: 14 additions & 0 deletions Documentation/ABI/testing/sysfs-kernel-iommu_groups
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
What: /sys/kernel/iommu_groups/
Date: May 2012
KernelVersion: v3.5
Contact: Alex Williamson <alex.williamson@redhat.com>
Description: /sys/kernel/iommu_groups/ contains a number of sub-
directories, each representing an IOMMU group. The
name of the sub-directory matches the iommu_group_id()
for the group, which is an integer value. Within each
subdirectory is another directory named "devices" with
links to the sysfs devices contained in this group.
The group directory also optionally contains a "name"
file if the IOMMU driver has chosen to register a more
common name for the group.
Users:
21 changes: 21 additions & 0 deletions Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
NVIDIA Tegra 30 IOMMU H/W, SMMU (System Memory Management Unit)

Required properties:
- compatible : "nvidia,tegra30-smmu"
- reg : Should contain 3 register banks(address and length) for each
of the SMMU register blocks.
- interrupts : Should contain MC General interrupt.
- nvidia,#asids : # of ASIDs
- dma-window : IOVA start address and length.
- nvidia,ahb : phandle to the ahb bus connected to SMMU.

Example:
smmu {
compatible = "nvidia,tegra30-smmu";
reg = <0x7000f010 0x02c
0x7000f1f0 0x010
0x7000f228 0x05c>;
nvidia,#asids = <4>; /* # of ASIDs */
dma-window = <0 0x40000000>; /* IOVA start & length */
nvidia,ahb = <&ahb>;
};
1 change: 0 additions & 1 deletion Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,6 @@ 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: 0 additions & 2 deletions arch/ia64/include/asm/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ 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: 0 additions & 1 deletion arch/ia64/kernel/pci-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ 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: 0 additions & 1 deletion arch/x86/include/asm/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ 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: 0 additions & 11 deletions arch/x86/kernel/pci-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,6 @@ 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 @@ -194,8 +185,6 @@ 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
6 changes: 5 additions & 1 deletion 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 Expand Up @@ -154,7 +158,7 @@ config TEGRA_IOMMU_GART

config TEGRA_IOMMU_SMMU
bool "Tegra SMMU IOMMU Support"
depends on ARCH_TEGRA_3x_SOC
depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
select IOMMU_API
help
Enables support for remapping discontiguous physical memory
Expand Down
1 change: 1 addition & 0 deletions 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
99 changes: 71 additions & 28 deletions drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,21 @@ 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 *pdev = to_pci_dev(dev);
struct pci_dev *dma_pdev, *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 @@ -281,8 +291,43 @@ 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 @@ -311,6 +356,8 @@ 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 @@ -384,7 +431,6 @@ DECLARE_STATS_COUNTER(invalidate_iotlb);
DECLARE_STATS_COUNTER(invalidate_iotlb_all);
DECLARE_STATS_COUNTER(pri_requests);


static struct dentry *stats_dir;
static struct dentry *de_fflush;

Expand Down Expand Up @@ -2073,7 +2119,7 @@ static int pdev_iommuv2_enable(struct pci_dev *pdev)
/* FIXME: Move this to PCI code */
#define PCI_PRI_TLP_OFF (1 << 15)

bool pci_pri_tlp_required(struct pci_dev *pdev)
static bool pci_pri_tlp_required(struct pci_dev *pdev)
{
u16 status;
int pos;
Expand Down Expand Up @@ -2254,6 +2300,18 @@ static int device_change_notifier(struct notifier_block *nb,

iommu_init_device(dev);

/*
* dev_data is still NULL and
* got initialized in iommu_init_device
*/
dev_data = get_dev_data(dev);

if (iommu_pass_through || dev_data->iommu_v2) {
dev_data->passthrough = true;
attach_device(dev, pt_domain);
break;
}

domain = domain_for_device(dev);

/* allocate a protection domain if a device is added */
Expand All @@ -2271,10 +2329,7 @@ static int device_change_notifier(struct notifier_block *nb,

dev_data = get_dev_data(dev);

if (!dev_data->passthrough)
dev->archdata.dma_ops = &amd_iommu_dma_ops;
else
dev->archdata.dma_ops = &nommu_dma_ops;
dev->archdata.dma_ops = &amd_iommu_dma_ops;

break;
case BUS_NOTIFY_DEL_DEVICE:
Expand Down Expand Up @@ -2972,6 +3027,11 @@ int __init amd_iommu_init_dma_ops(void)

amd_iommu_stats_init();

if (amd_iommu_unmap_flush)
pr_info("AMD-Vi: IO/TLB flush on unmap enabled\n");
else
pr_info("AMD-Vi: Lazy IO/TLB flushing enabled\n");

return 0;

free_domains:
Expand Down Expand Up @@ -3078,6 +3138,10 @@ static int amd_iommu_domain_init(struct iommu_domain *dom)

dom->priv = domain;

dom->geometry.aperture_start = 0;
dom->geometry.aperture_end = ~0ULL;
dom->geometry.force_aperture = true;

return 0;

out_free:
Expand Down Expand Up @@ -3236,26 +3300,6 @@ 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 @@ -3265,7 +3309,6 @@ 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
Loading

0 comments on commit 97027da

Please sign in to comment.