Skip to content

Commit

Permalink
[PATCH] powerpc: Fix SLB flushing path in hugepage
Browse files Browse the repository at this point in the history
On ppc64, when opening a new hugepage region, we need to make sure any
old normal-page SLBs for the area are flushed on all CPUs.  There was
a bug in this logic - after putting the new hugepage area masks into
the thread structure, we copied it into the paca (read by the SLB miss
handler) only on one CPU, not on all.  This could cause incorrect SLB
entries to be loaded when a multithreaded program was running
simultaneously on several CPUs.  This patch corrects the error,
copying the context information into the PACA on all CPUs using the mm
in question before flushing any existing SLB entries.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
David Gibson authored and Paul Mackerras committed Dec 9, 2005
1 parent cbf52af commit 23ed6cb
Showing 1 changed file with 41 additions and 16 deletions.
57 changes: 41 additions & 16 deletions arch/powerpc/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,43 +148,63 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
return 0;
}

struct slb_flush_info {
struct mm_struct *mm;
u16 newareas;
};

static void flush_low_segments(void *parm)
{
u16 areas = (unsigned long) parm;
struct slb_flush_info *fi = parm;
unsigned long i;

asm volatile("isync" : : : "memory");
BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_LOW_AREAS);

if (current->active_mm != fi->mm)
return;

BUILD_BUG_ON((sizeof(areas)*8) != NUM_LOW_AREAS);
/* Only need to do anything if this CPU is working in the same
* mm as the one which has changed */

/* update the paca copy of the context struct */
get_paca()->context = current->active_mm->context;

asm volatile("isync" : : : "memory");
for (i = 0; i < NUM_LOW_AREAS; i++) {
if (! (areas & (1U << i)))
if (! (fi->newareas & (1U << i)))
continue;
asm volatile("slbie %0"
: : "r" ((i << SID_SHIFT) | SLBIE_C));
}

asm volatile("isync" : : : "memory");
}

static void flush_high_segments(void *parm)
{
u16 areas = (unsigned long) parm;
struct slb_flush_info *fi = parm;
unsigned long i, j;

asm volatile("isync" : : : "memory");

BUILD_BUG_ON((sizeof(areas)*8) != NUM_HIGH_AREAS);
BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_HIGH_AREAS);

if (current->active_mm != fi->mm)
return;

/* Only need to do anything if this CPU is working in the same
* mm as the one which has changed */

/* update the paca copy of the context struct */
get_paca()->context = current->active_mm->context;

asm volatile("isync" : : : "memory");
for (i = 0; i < NUM_HIGH_AREAS; i++) {
if (! (areas & (1U << i)))
if (! (fi->newareas & (1U << i)))
continue;
for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
asm volatile("slbie %0"
:: "r" (((i << HTLB_AREA_SHIFT)
+ (j << SID_SHIFT)) | SLBIE_C));
+ (j << SID_SHIFT)) | SLBIE_C));
}

asm volatile("isync" : : : "memory");
}

Expand Down Expand Up @@ -229,6 +249,7 @@ static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
{
unsigned long i;
struct slb_flush_info fi;

BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
Expand All @@ -244,19 +265,20 @@ static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)

mm->context.low_htlb_areas |= newareas;

/* update the paca copy of the context struct */
get_paca()->context = mm->context;

/* the context change must make it to memory before the flush,
* so that further SLB misses do the right thing. */
mb();
on_each_cpu(flush_low_segments, (void *)(unsigned long)newareas, 0, 1);

fi.mm = mm;
fi.newareas = newareas;
on_each_cpu(flush_low_segments, &fi, 0, 1);

return 0;
}

static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
{
struct slb_flush_info fi;
unsigned long i;

BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
Expand All @@ -280,7 +302,10 @@ static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
/* the context change must make it to memory before the flush,
* so that further SLB misses do the right thing. */
mb();
on_each_cpu(flush_high_segments, (void *)(unsigned long)newareas, 0, 1);

fi.mm = mm;
fi.newareas = newareas;
on_each_cpu(flush_high_segments, &fi, 0, 1);

return 0;
}
Expand Down

0 comments on commit 23ed6cb

Please sign in to comment.