aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorMitchel Humpherys <mitchelh@codeaurora.org>2014-07-30 13:58:13 -0400
committerWill Deacon <will.deacon@arm.com>2014-09-01 11:48:55 -0400
commita18037b27ebd23edf5edad8bc6ceb72e4bb5716d (patch)
tree2623096e55e1f32c3e4f63d726007c825c4c726e /drivers/iommu
parent69e273c0b0a3c337a521d083374c918dc52c666f (diff)
iommu/arm-smmu: avoid calling request_irq in atomic context
request_irq shouldn't be called from atomic context since it might sleep, but we're calling it with a spinlock held, resulting in: [ 9.172202] BUG: sleeping function called from invalid context at kernel/mm/slub.c:926 [ 9.182989] in_atomic(): 1, irqs_disabled(): 128, pid: 1, name: swapper/0 [ 9.189762] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G W 3.10.40-gbc1b510b-38437-g55831d3bd9-dirty #97 [ 9.199757] [<c020c448>] (unwind_backtrace+0x0/0x11c) from [<c02097d0>] (show_stack+0x10/0x14) [ 9.208346] [<c02097d0>] (show_stack+0x10/0x14) from [<c0301d74>] (kmem_cache_alloc_trace+0x3c/0x210) [ 9.217543] [<c0301d74>] (kmem_cache_alloc_trace+0x3c/0x210) from [<c0276a48>] (request_threaded_irq+0x88/0x11c) [ 9.227702] [<c0276a48>] (request_threaded_irq+0x88/0x11c) from [<c0931ca4>] (arm_smmu_attach_dev+0x188/0x858) [ 9.237686] [<c0931ca4>] (arm_smmu_attach_dev+0x188/0x858) from [<c0212cd8>] (arm_iommu_attach_device+0x18/0xd0) [ 9.247837] [<c0212cd8>] (arm_iommu_attach_device+0x18/0xd0) from [<c093314c>] (arm_smmu_test_probe+0x68/0xd4) [ 9.257823] [<c093314c>] (arm_smmu_test_probe+0x68/0xd4) from [<c05aadd0>] (driver_probe_device+0x12c/0x330) [ 9.267629] [<c05aadd0>] (driver_probe_device+0x12c/0x330) from [<c05ab080>] (__driver_attach+0x68/0x8c) [ 9.277090] [<c05ab080>] (__driver_attach+0x68/0x8c) from [<c05a92d4>] (bus_for_each_dev+0x70/0x84) [ 9.286118] [<c05a92d4>] (bus_for_each_dev+0x70/0x84) from [<c05aa3b0>] (bus_add_driver+0x100/0x244) [ 9.295233] [<c05aa3b0>] (bus_add_driver+0x100/0x244) from [<c05ab5d0>] (driver_register+0x9c/0x124) [ 9.304347] [<c05ab5d0>] (driver_register+0x9c/0x124) from [<c0933088>] (arm_smmu_test_init+0x14/0x38) [ 9.313635] [<c0933088>] (arm_smmu_test_init+0x14/0x38) from [<c0200618>] (do_one_initcall+0xb8/0x160) [ 9.322926] [<c0200618>] (do_one_initcall+0xb8/0x160) from [<c1200b7c>] (kernel_init_freeable+0x108/0x1cc) [ 9.332564] [<c1200b7c>] (kernel_init_freeable+0x108/0x1cc) from [<c0b924b0>] (kernel_init+0xc/0xe4) [ 9.341675] [<c0b924b0>] (kernel_init+0xc/0xe4) from [<c0205e38>] (ret_from_fork+0x14/0x3c) Fix this by moving the request_irq out of the critical section. This should be okay since smmu_domain->smmu is still being protected by the critical section. Also, we still don't program the Stream Match Register until after registering our interrupt handler so we shouldn't be missing any interrupts. Cc: <stable@vger.kernel.org> Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org> [will: code cleanup and fixed request_irq token parameter] Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/arm-smmu.c47
1 files changed, 25 insertions, 22 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index ca18d6d42a9b..98fcd87cbacb 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -868,10 +868,15 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
868static int arm_smmu_init_domain_context(struct iommu_domain *domain, 868static int arm_smmu_init_domain_context(struct iommu_domain *domain,
869 struct arm_smmu_device *smmu) 869 struct arm_smmu_device *smmu)
870{ 870{
871 int irq, ret, start; 871 int irq, start, ret = 0;
872 unsigned long flags;
872 struct arm_smmu_domain *smmu_domain = domain->priv; 873 struct arm_smmu_domain *smmu_domain = domain->priv;
873 struct arm_smmu_cfg *cfg = &smmu_domain->cfg; 874 struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
874 875
876 spin_lock_irqsave(&smmu_domain->lock, flags);
877 if (smmu_domain->smmu)
878 goto out_unlock;
879
875 if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) { 880 if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
876 /* 881 /*
877 * We will likely want to change this if/when KVM gets 882 * We will likely want to change this if/when KVM gets
@@ -890,7 +895,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
890 ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, 895 ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
891 smmu->num_context_banks); 896 smmu->num_context_banks);
892 if (IS_ERR_VALUE(ret)) 897 if (IS_ERR_VALUE(ret))
893 return ret; 898 goto out_unlock;
894 899
895 cfg->cbndx = ret; 900 cfg->cbndx = ret;
896 if (smmu->version == 1) { 901 if (smmu->version == 1) {
@@ -900,6 +905,10 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
900 cfg->irptndx = cfg->cbndx; 905 cfg->irptndx = cfg->cbndx;
901 } 906 }
902 907
908 ACCESS_ONCE(smmu_domain->smmu) = smmu;
909 arm_smmu_init_context_bank(smmu_domain);
910 spin_unlock_irqrestore(&smmu_domain->lock, flags);
911
903 irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx]; 912 irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
904 ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED, 913 ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
905 "arm-smmu-context-fault", domain); 914 "arm-smmu-context-fault", domain);
@@ -907,15 +916,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
907 dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n", 916 dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
908 cfg->irptndx, irq); 917 cfg->irptndx, irq);
909 cfg->irptndx = INVALID_IRPTNDX; 918 cfg->irptndx = INVALID_IRPTNDX;
910 goto out_free_context;
911 } 919 }
912 920
913 smmu_domain->smmu = smmu;
914 arm_smmu_init_context_bank(smmu_domain);
915 return 0; 921 return 0;
916 922
917out_free_context: 923out_unlock:
918 __arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx); 924 spin_unlock_irqrestore(&smmu_domain->lock, flags);
919 return ret; 925 return ret;
920} 926}
921 927
@@ -1172,11 +1178,10 @@ static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
1172 1178
1173static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) 1179static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
1174{ 1180{
1175 int ret = -EINVAL; 1181 int ret;
1176 struct arm_smmu_domain *smmu_domain = domain->priv; 1182 struct arm_smmu_domain *smmu_domain = domain->priv;
1177 struct arm_smmu_device *smmu; 1183 struct arm_smmu_device *smmu, *dom_smmu;
1178 struct arm_smmu_master_cfg *cfg; 1184 struct arm_smmu_master_cfg *cfg;
1179 unsigned long flags;
1180 1185
1181 smmu = dev_get_master_dev(dev)->archdata.iommu; 1186 smmu = dev_get_master_dev(dev)->archdata.iommu;
1182 if (!smmu) { 1187 if (!smmu) {
@@ -1188,20 +1193,22 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
1188 * Sanity check the domain. We don't support domains across 1193 * Sanity check the domain. We don't support domains across
1189 * different SMMUs. 1194 * different SMMUs.
1190 */ 1195 */
1191 spin_lock_irqsave(&smmu_domain->lock, flags); 1196 dom_smmu = ACCESS_ONCE(smmu_domain->smmu);
1192 if (!smmu_domain->smmu) { 1197 if (!dom_smmu) {
1193 /* Now that we have a master, we can finalise the domain */ 1198 /* Now that we have a master, we can finalise the domain */
1194 ret = arm_smmu_init_domain_context(domain, smmu); 1199 ret = arm_smmu_init_domain_context(domain, smmu);
1195 if (IS_ERR_VALUE(ret)) 1200 if (IS_ERR_VALUE(ret))
1196 goto err_unlock; 1201 return ret;
1197 } else if (smmu_domain->smmu != smmu) { 1202
1203 dom_smmu = smmu_domain->smmu;
1204 }
1205
1206 if (dom_smmu != smmu) {
1198 dev_err(dev, 1207 dev_err(dev,
1199 "cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n", 1208 "cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
1200 dev_name(smmu_domain->smmu->dev), 1209 dev_name(smmu_domain->smmu->dev), dev_name(smmu->dev));
1201 dev_name(smmu->dev)); 1210 return -EINVAL;
1202 goto err_unlock;
1203 } 1211 }
1204 spin_unlock_irqrestore(&smmu_domain->lock, flags);
1205 1212
1206 /* Looks ok, so add the device to the domain */ 1213 /* Looks ok, so add the device to the domain */
1207 cfg = find_smmu_master_cfg(smmu_domain->smmu, dev); 1214 cfg = find_smmu_master_cfg(smmu_domain->smmu, dev);
@@ -1209,10 +1216,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
1209 return -ENODEV; 1216 return -ENODEV;
1210 1217
1211 return arm_smmu_domain_add_master(smmu_domain, cfg); 1218 return arm_smmu_domain_add_master(smmu_domain, cfg);
1212
1213err_unlock:
1214 spin_unlock_irqrestore(&smmu_domain->lock, flags);
1215 return ret;
1216} 1219}
1217 1220
1218static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev) 1221static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)