aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2012-06-03 15:42:13 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-07-03 00:14:46 -0400
commitc1703e85a7b20ffcefd5360e2542460737ecc15c (patch)
treea2aa1cb255beab5b00336121b2aeb9adefc24180 /arch/powerpc
parentb3f271e86e5a440713716bb222e1aa1227994c50 (diff)
powerpc/pseries: Disable interrupts around IOMMU percpu data accesses
tce_buildmulti_pSeriesLP uses a per cpu page to communicate with the hypervisor. We currently rely on the IOMMU table spinlock but subsequent patches will be removing that so disable interrupts around all accesses of tce_page. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index d5d1dd58ca74..07c09cbbfb19 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -192,12 +192,15 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
192 long l, limit; 192 long l, limit;
193 long tcenum_start = tcenum, npages_start = npages; 193 long tcenum_start = tcenum, npages_start = npages;
194 int ret = 0; 194 int ret = 0;
195 unsigned long flags;
195 196
196 if (npages == 1) { 197 if (npages == 1) {
197 return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, 198 return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
198 direction, attrs); 199 direction, attrs);
199 } 200 }
200 201
202 local_irq_save(flags); /* to protect tcep and the page behind it */
203
201 tcep = __get_cpu_var(tce_page); 204 tcep = __get_cpu_var(tce_page);
202 205
203 /* This is safe to do since interrupts are off when we're called 206 /* This is safe to do since interrupts are off when we're called
@@ -207,6 +210,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
207 tcep = (u64 *)__get_free_page(GFP_ATOMIC); 210 tcep = (u64 *)__get_free_page(GFP_ATOMIC);
208 /* If allocation fails, fall back to the loop implementation */ 211 /* If allocation fails, fall back to the loop implementation */
209 if (!tcep) { 212 if (!tcep) {
213 local_irq_restore(flags);
210 return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, 214 return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
211 direction, attrs); 215 direction, attrs);
212 } 216 }
@@ -240,6 +244,8 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
240 tcenum += limit; 244 tcenum += limit;
241 } while (npages > 0 && !rc); 245 } while (npages > 0 && !rc);
242 246
247 local_irq_restore(flags);
248
243 if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) { 249 if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
244 ret = (int)rc; 250 ret = (int)rc;
245 tce_freemulti_pSeriesLP(tbl, tcenum_start, 251 tce_freemulti_pSeriesLP(tbl, tcenum_start,