diff options
author | Anton Blanchard <anton@samba.org> | 2012-10-03 14:57:10 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-10-04 04:03:20 -0400 |
commit | d900bd7366463fd96a907b2c212242e2b68b27d8 (patch) | |
tree | b1837bc8c27d32a159ebc9edea9b1944e9231444 /arch/powerpc/sysdev | |
parent | c8adfeccee01ce3de6a7d14fcd4e3be02e27f03c (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.c | 12 |
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 | ||
76 | static DEFINE_SPINLOCK(invalidate_lock); | ||
77 | |||
76 | static inline void dart_tlb_invalidate_all(void) | 78 | static 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 | ||
115 | static inline void dart_tlb_invalidate_one(unsigned long bus_rpn) | 122 | static 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 | ||
142 | static void dart_flush(struct iommu_table *tbl) | 154 | static void dart_flush(struct iommu_table *tbl) |