diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-30 11:49:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-30 11:49:28 -0400 |
commit | 2f83766d4b18774c856329a8fca4c9338dfeda39 (patch) | |
tree | a19ea2165755f5700d7f37a61ece7edce231744f /drivers/iommu | |
parent | 4523e1458566a0e8ecfaff90f380dd23acc44d27 (diff) | |
parent | 28f8571e1e84782244cc7bf1b129baf6cdc0832e (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.c | 37 | ||||
-rw-r--r-- | drivers/iommu/iommu.c | 5 | ||||
-rw-r--r-- | drivers/iommu/omap-iommu.c | 32 | ||||
-rw-r--r-- | drivers/iommu/tegra-gart.c | 20 | ||||
-rw-r--r-- | drivers/iommu/tegra-smmu.c | 2 |
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 | ||
451 | static void iommu_print_event(struct amd_iommu *iommu, void *__evt) | 451 | static 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]; | 458 | retry: |
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 | ||
513 | static void iommu_poll_events(struct amd_iommu *iommu) | 530 | static 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 | ||
2040 | bool pci_pri_tlp_required(struct pci_dev *pdev) | 2057 | bool 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 | */ |
129 | void iommu_set_fault_handler(struct iommu_domain *domain, | 130 | void 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 | } |
136 | EXPORT_SYMBOL_GPL(iommu_set_fault_handler); | 139 | EXPORT_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 | */ |
46 | struct omap_iommu_domain { | 47 | struct 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 | ||
1086 | out: | 1089 | out: |
@@ -1088,19 +1091,16 @@ out: | |||
1088 | return ret; | 1091 | return ret; |
1089 | } | 1092 | } |
1090 | 1093 | ||
1091 | static void omap_iommu_detach_dev(struct iommu_domain *domain, | 1094 | static 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 | ||
1112 | out: | 1114 | static 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 */ | ||
1152 | static void omap_iommu_domain_destroy(struct iommu_domain *domain) | 1159 | static 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 | ||
428 | static struct of_device_id tegra_gart_of_match[] __devinitdata = { | ||
429 | { .compatible = "nvidia,tegra20-gart", }, | ||
430 | { }, | ||
431 | }; | ||
432 | MODULE_DEVICE_TABLE(of, tegra_gart_of_match); | ||
433 | #endif | ||
434 | |||
425 | static struct platform_driver tegra_gart_driver = { | 435 | static 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 | ||
449 | MODULE_DESCRIPTION("IOMMU API for GART in Tegra20"); | 460 | MODULE_DESCRIPTION("IOMMU API for GART in Tegra20"); |
450 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); | 461 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); |
462 | MODULE_ALIAS("platform:tegra-gart"); | ||
451 | MODULE_LICENSE("GPL v2"); | 463 | MODULE_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 | ||
739 | err_client: | 739 | err_client: |