aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2012-10-03 14:57:10 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-10-04 04:03:20 -0400
commitd900bd7366463fd96a907b2c212242e2b68b27d8 (patch)
treeb1837bc8c27d32a159ebc9edea9b1944e9231444 /arch/powerpc/sysdev
parentc8adfeccee01ce3de6a7d14fcd4e3be02e27f03c (diff)
powerpc/iommu: Fix multiple issues with IOMMU pools code
There are a number of issues in the recent IOMMU pools code: - On a preempt kernel we might switch CPUs in the middle of building a scatter gather list. When this happens the handle hint passed in no longer falls within the local CPU's pool. Check for this and fall back to the pool hint. - We were missing a spin_unlock/spin_lock in one spot where we switch pools. - We need to provide locking around dart_tlb_invalidate_all and dart_tlb_invalidate_one now that the global lock is gone. Reported-by: Alexander Graf <agraf@suse.de> Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> CC: <stable@kernel.org> [v3.6]
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 8ef63a01e345..bd968a43a48b 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -73,11 +73,16 @@ static int dart_is_u4;
73 73
74#define DBG(...) 74#define DBG(...)
75 75
76static DEFINE_SPINLOCK(invalidate_lock);
77
76static inline void dart_tlb_invalidate_all(void) 78static inline void dart_tlb_invalidate_all(void)
77{ 79{
78 unsigned long l = 0; 80 unsigned long l = 0;
79 unsigned int reg, inv_bit; 81 unsigned int reg, inv_bit;
80 unsigned long limit; 82 unsigned long limit;
83 unsigned long flags;
84
85 spin_lock_irqsave(&invalidate_lock, flags);
81 86
82 DBG("dart: flush\n"); 87 DBG("dart: flush\n");
83 88
@@ -110,12 +115,17 @@ retry:
110 panic("DART: TLB did not flush after waiting a long " 115 panic("DART: TLB did not flush after waiting a long "
111 "time. Buggy U3 ?"); 116 "time. Buggy U3 ?");
112 } 117 }
118
119 spin_unlock_irqrestore(&invalidate_lock, flags);
113} 120}
114 121
115static inline void dart_tlb_invalidate_one(unsigned long bus_rpn) 122static inline void dart_tlb_invalidate_one(unsigned long bus_rpn)
116{ 123{
117 unsigned int reg; 124 unsigned int reg;
118 unsigned int l, limit; 125 unsigned int l, limit;
126 unsigned long flags;
127
128 spin_lock_irqsave(&invalidate_lock, flags);
119 129
120 reg = DART_CNTL_U4_ENABLE | DART_CNTL_U4_IONE | 130 reg = DART_CNTL_U4_ENABLE | DART_CNTL_U4_IONE |
121 (bus_rpn & DART_CNTL_U4_IONE_MASK); 131 (bus_rpn & DART_CNTL_U4_IONE_MASK);
@@ -137,6 +147,8 @@ wait_more:
137 panic("DART: TLB did not flush after waiting a long " 147 panic("DART: TLB did not flush after waiting a long "
138 "time. Buggy U4 ?"); 148 "time. Buggy U4 ?");
139 } 149 }
150
151 spin_unlock_irqrestore(&invalidate_lock, flags);
140} 152}
141 153
142static void dart_flush(struct iommu_table *tbl) 154static void dart_flush(struct iommu_table *tbl)