aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-30 11:49:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-30 11:49:28 -0400
commit2f83766d4b18774c856329a8fca4c9338dfeda39 (patch)
treea19ea2165755f5700d7f37a61ece7edce231744f /drivers/iommu
parent4523e1458566a0e8ecfaff90f380dd23acc44d27 (diff)
parent28f8571e1e84782244cc7bf1b129baf6cdc0832e (diff)
Merge tag 'iommu-updates-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU updates from Joerg Roedel: "Not much stuff this time. The only change to the IOMMU core code is the addition of a handle to the fault handling code. A few updates to the AMD IOMMU driver to work around new errata. The other patches are mostly fixes and enhancements to the existing ARM IOMMU drivers and documentation updates. A new IOMMU driver for the Exynos platform was also underway but got merged via the Samsung tree and is not part of this tree." * tag 'iommu-updates-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: Documentation: kernel-parameters.txt Add amd_iommu_dump iommu/core: pass a user-provided token to fault handlers iommu/tegra: gart: Fix register offset correctly iommu: OMAP: device detach on domain destroy iommu: tegra/gart: Add device tree support iommu: tegra/gart: use correct gart_device iommu/tegra: smmu: Print device name correctly iommu/amd: Add workaround for event log erratum iommu/amd: Check for the right TLP prefix bit dma-debug: release free_entries_lock before saving stack trace
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/amd_iommu.c37
-rw-r--r--drivers/iommu/iommu.c5
-rw-r--r--drivers/iommu/omap-iommu.c32
-rw-r--r--drivers/iommu/tegra-gart.c20
-rw-r--r--drivers/iommu/tegra-smmu.c2
5 files changed, 71 insertions, 25 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a5bee8e2dfce..d90a421e9cac 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -450,12 +450,27 @@ static void dump_command(unsigned long phys_addr)
450 450
451static void iommu_print_event(struct amd_iommu *iommu, void *__evt) 451static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
452{ 452{
453 u32 *event = __evt; 453 int type, devid, domid, flags;
454 int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; 454 volatile u32 *event = __evt;
455 int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK; 455 int count = 0;
456 int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK; 456 u64 address;
457 int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; 457
458 u64 address = (u64)(((u64)event[3]) << 32) | event[2]; 458retry:
459 type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK;
460 devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
461 domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
462 flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
463 address = (u64)(((u64)event[3]) << 32) | event[2];
464
465 if (type == 0) {
466 /* Did we hit the erratum? */
467 if (++count == LOOP_TIMEOUT) {
468 pr_err("AMD-Vi: No event written to event log\n");
469 return;
470 }
471 udelay(1);
472 goto retry;
473 }
459 474
460 printk(KERN_ERR "AMD-Vi: Event logged ["); 475 printk(KERN_ERR "AMD-Vi: Event logged [");
461 476
@@ -508,6 +523,8 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
508 default: 523 default:
509 printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type); 524 printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type);
510 } 525 }
526
527 memset(__evt, 0, 4 * sizeof(u32));
511} 528}
512 529
513static void iommu_poll_events(struct amd_iommu *iommu) 530static void iommu_poll_events(struct amd_iommu *iommu)
@@ -2035,20 +2052,20 @@ out_err:
2035} 2052}
2036 2053
2037/* FIXME: Move this to PCI code */ 2054/* FIXME: Move this to PCI code */
2038#define PCI_PRI_TLP_OFF (1 << 2) 2055#define PCI_PRI_TLP_OFF (1 << 15)
2039 2056
2040bool pci_pri_tlp_required(struct pci_dev *pdev) 2057bool pci_pri_tlp_required(struct pci_dev *pdev)
2041{ 2058{
2042 u16 control; 2059 u16 status;
2043 int pos; 2060 int pos;
2044 2061
2045 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); 2062 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
2046 if (!pos) 2063 if (!pos)
2047 return false; 2064 return false;
2048 2065
2049 pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); 2066 pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
2050 2067
2051 return (control & PCI_PRI_TLP_OFF) ? true : false; 2068 return (status & PCI_PRI_TLP_OFF) ? true : false;
2052} 2069}
2053 2070
2054/* 2071/*
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 2198b2dbbcd3..8b9ded88e6f5 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -119,6 +119,7 @@ EXPORT_SYMBOL_GPL(iommu_present);
119 * iommu_set_fault_handler() - set a fault handler for an iommu domain 119 * iommu_set_fault_handler() - set a fault handler for an iommu domain
120 * @domain: iommu domain 120 * @domain: iommu domain
121 * @handler: fault handler 121 * @handler: fault handler
122 * @token: user data, will be passed back to the fault handler
122 * 123 *
123 * This function should be used by IOMMU users which want to be notified 124 * This function should be used by IOMMU users which want to be notified
124 * whenever an IOMMU fault happens. 125 * whenever an IOMMU fault happens.
@@ -127,11 +128,13 @@ EXPORT_SYMBOL_GPL(iommu_present);
127 * error code otherwise. 128 * error code otherwise.
128 */ 129 */
129void iommu_set_fault_handler(struct iommu_domain *domain, 130void iommu_set_fault_handler(struct iommu_domain *domain,
130 iommu_fault_handler_t handler) 131 iommu_fault_handler_t handler,
132 void *token)
131{ 133{
132 BUG_ON(!domain); 134 BUG_ON(!domain);
133 135
134 domain->handler = handler; 136 domain->handler = handler;
137 domain->handler_token = token;
135} 138}
136EXPORT_SYMBOL_GPL(iommu_set_fault_handler); 139EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
137 140
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 6899dcd02dfa..e70ee2b59df9 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -41,11 +41,13 @@
41 * @pgtable: the page table 41 * @pgtable: the page table
42 * @iommu_dev: an omap iommu device attached to this domain. only a single 42 * @iommu_dev: an omap iommu device attached to this domain. only a single
43 * iommu device can be attached for now. 43 * iommu device can be attached for now.
44 * @dev: Device using this domain.
44 * @lock: domain lock, should be taken when attaching/detaching 45 * @lock: domain lock, should be taken when attaching/detaching
45 */ 46 */
46struct omap_iommu_domain { 47struct omap_iommu_domain {
47 u32 *pgtable; 48 u32 *pgtable;
48 struct omap_iommu *iommu_dev; 49 struct omap_iommu *iommu_dev;
50 struct device *dev;
49 spinlock_t lock; 51 spinlock_t lock;
50}; 52};
51 53
@@ -1081,6 +1083,7 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
1081 } 1083 }
1082 1084
1083 omap_domain->iommu_dev = arch_data->iommu_dev = oiommu; 1085 omap_domain->iommu_dev = arch_data->iommu_dev = oiommu;
1086 omap_domain->dev = dev;
1084 oiommu->domain = domain; 1087 oiommu->domain = domain;
1085 1088
1086out: 1089out:
@@ -1088,19 +1091,16 @@ out:
1088 return ret; 1091 return ret;
1089} 1092}
1090 1093
1091static void omap_iommu_detach_dev(struct iommu_domain *domain, 1094static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain,
1092 struct device *dev) 1095 struct device *dev)
1093{ 1096{
1094 struct omap_iommu_domain *omap_domain = domain->priv;
1095 struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
1096 struct omap_iommu *oiommu = dev_to_omap_iommu(dev); 1097 struct omap_iommu *oiommu = dev_to_omap_iommu(dev);
1097 1098 struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
1098 spin_lock(&omap_domain->lock);
1099 1099
1100 /* only a single device is supported per domain for now */ 1100 /* only a single device is supported per domain for now */
1101 if (omap_domain->iommu_dev != oiommu) { 1101 if (omap_domain->iommu_dev != oiommu) {
1102 dev_err(dev, "invalid iommu device\n"); 1102 dev_err(dev, "invalid iommu device\n");
1103 goto out; 1103 return;
1104 } 1104 }
1105 1105
1106 iopgtable_clear_entry_all(oiommu); 1106 iopgtable_clear_entry_all(oiommu);
@@ -1108,8 +1108,16 @@ static void omap_iommu_detach_dev(struct iommu_domain *domain,
1108 omap_iommu_detach(oiommu); 1108 omap_iommu_detach(oiommu);
1109 1109
1110 omap_domain->iommu_dev = arch_data->iommu_dev = NULL; 1110 omap_domain->iommu_dev = arch_data->iommu_dev = NULL;
1111 omap_domain->dev = NULL;
1112}
1111 1113
1112out: 1114static void omap_iommu_detach_dev(struct iommu_domain *domain,
1115 struct device *dev)
1116{
1117 struct omap_iommu_domain *omap_domain = domain->priv;
1118
1119 spin_lock(&omap_domain->lock);
1120 _omap_iommu_detach_dev(omap_domain, dev);
1113 spin_unlock(&omap_domain->lock); 1121 spin_unlock(&omap_domain->lock);
1114} 1122}
1115 1123
@@ -1148,13 +1156,19 @@ out:
1148 return -ENOMEM; 1156 return -ENOMEM;
1149} 1157}
1150 1158
1151/* assume device was already detached */
1152static void omap_iommu_domain_destroy(struct iommu_domain *domain) 1159static void omap_iommu_domain_destroy(struct iommu_domain *domain)
1153{ 1160{
1154 struct omap_iommu_domain *omap_domain = domain->priv; 1161 struct omap_iommu_domain *omap_domain = domain->priv;
1155 1162
1156 domain->priv = NULL; 1163 domain->priv = NULL;
1157 1164
1165 /*
1166 * An iommu device is still attached
1167 * (currently, only one device can be attached) ?
1168 */
1169 if (omap_domain->iommu_dev)
1170 _omap_iommu_detach_dev(omap_domain, omap_domain->dev);
1171
1158 kfree(omap_domain->pgtable); 1172 kfree(omap_domain->pgtable);
1159 kfree(omap_domain); 1173 kfree(omap_domain);
1160} 1174}
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
index 779306ee7b16..0c0a37792218 100644
--- a/drivers/iommu/tegra-gart.c
+++ b/drivers/iommu/tegra-gart.c
@@ -29,15 +29,17 @@
29#include <linux/device.h> 29#include <linux/device.h>
30#include <linux/io.h> 30#include <linux/io.h>
31#include <linux/iommu.h> 31#include <linux/iommu.h>
32#include <linux/of.h>
32 33
33#include <asm/cacheflush.h> 34#include <asm/cacheflush.h>
34 35
35/* bitmap of the page sizes currently supported */ 36/* bitmap of the page sizes currently supported */
36#define GART_IOMMU_PGSIZES (SZ_4K) 37#define GART_IOMMU_PGSIZES (SZ_4K)
37 38
38#define GART_CONFIG 0x24 39#define GART_REG_BASE 0x24
39#define GART_ENTRY_ADDR 0x28 40#define GART_CONFIG (0x24 - GART_REG_BASE)
40#define GART_ENTRY_DATA 0x2c 41#define GART_ENTRY_ADDR (0x28 - GART_REG_BASE)
42#define GART_ENTRY_DATA (0x2c - GART_REG_BASE)
41#define GART_ENTRY_PHYS_ADDR_VALID (1 << 31) 43#define GART_ENTRY_PHYS_ADDR_VALID (1 << 31)
42 44
43#define GART_PAGE_SHIFT 12 45#define GART_PAGE_SHIFT 12
@@ -158,7 +160,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain,
158 struct gart_client *client, *c; 160 struct gart_client *client, *c;
159 int err = 0; 161 int err = 0;
160 162
161 gart = dev_get_drvdata(dev->parent); 163 gart = gart_handle;
162 if (!gart) 164 if (!gart)
163 return -EINVAL; 165 return -EINVAL;
164 domain->priv = gart; 166 domain->priv = gart;
@@ -422,6 +424,14 @@ const struct dev_pm_ops tegra_gart_pm_ops = {
422 .resume = tegra_gart_resume, 424 .resume = tegra_gart_resume,
423}; 425};
424 426
427#ifdef CONFIG_OF
428static struct of_device_id tegra_gart_of_match[] __devinitdata = {
429 { .compatible = "nvidia,tegra20-gart", },
430 { },
431};
432MODULE_DEVICE_TABLE(of, tegra_gart_of_match);
433#endif
434
425static struct platform_driver tegra_gart_driver = { 435static struct platform_driver tegra_gart_driver = {
426 .probe = tegra_gart_probe, 436 .probe = tegra_gart_probe,
427 .remove = tegra_gart_remove, 437 .remove = tegra_gart_remove,
@@ -429,6 +439,7 @@ static struct platform_driver tegra_gart_driver = {
429 .owner = THIS_MODULE, 439 .owner = THIS_MODULE,
430 .name = "tegra-gart", 440 .name = "tegra-gart",
431 .pm = &tegra_gart_pm_ops, 441 .pm = &tegra_gart_pm_ops,
442 .of_match_table = of_match_ptr(tegra_gart_of_match),
432 }, 443 },
433}; 444};
434 445
@@ -448,4 +459,5 @@ module_exit(tegra_gart_exit);
448 459
449MODULE_DESCRIPTION("IOMMU API for GART in Tegra20"); 460MODULE_DESCRIPTION("IOMMU API for GART in Tegra20");
450MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); 461MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
462MODULE_ALIAS("platform:tegra-gart");
451MODULE_LICENSE("GPL v2"); 463MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index eb93c821f592..ecd679043d77 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -733,7 +733,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
733 pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n"); 733 pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n");
734 } 734 }
735 735
736 dev_dbg(smmu->dev, "%s is attached\n", dev_name(c->dev)); 736 dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev));
737 return 0; 737 return 0;
738 738
739err_client: 739err_client: