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>
long l, limit;
long tcenum_start = tcenum, npages_start = npages;
int ret = 0;
long l, limit;
long tcenum_start = tcenum, npages_start = npages;
int ret = 0;
if (npages == 1) {
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction, attrs);
}
if (npages == 1) {
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction, attrs);
}
+ local_irq_save(flags); /* to protect tcep and the page behind it */
+
tcep = __get_cpu_var(tce_page);
/* This is safe to do since interrupts are off when we're called
tcep = __get_cpu_var(tce_page);
/* This is safe to do since interrupts are off when we're called
tcep = (u64 *)__get_free_page(GFP_ATOMIC);
/* If allocation fails, fall back to the loop implementation */
if (!tcep) {
tcep = (u64 *)__get_free_page(GFP_ATOMIC);
/* If allocation fails, fall back to the loop implementation */
if (!tcep) {
+ local_irq_restore(flags);
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction, attrs);
}
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction, attrs);
}
tcenum += limit;
} while (npages > 0 && !rc);
tcenum += limit;
} while (npages > 0 && !rc);
+ local_irq_restore(flags);
+
if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
ret = (int)rc;
tce_freemulti_pSeriesLP(tbl, tcenum_start,
if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
ret = (int)rc;
tce_freemulti_pSeriesLP(tbl, tcenum_start,