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 8ef63a01e34..bd968a43a48 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) |
