Commit 021baa0c authored by Anton Blanchard's avatar Anton Blanchard

ppc64: hugetlb fixes for LPAR and numa hugetlb support

parent e04402a3
...@@ -36,18 +36,6 @@ ...@@ -36,18 +36,6 @@
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/hvcall.h> #include <asm/hvcall.h>
long plpar_pte_enter(unsigned long flags,
unsigned long ptex,
unsigned long new_pteh, unsigned long new_ptel,
unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
{
unsigned long dummy, ret;
ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,
old_pteh_ret, old_ptel_ret, &dummy);
return(ret);
}
long plpar_pte_remove(unsigned long flags, long plpar_pte_remove(unsigned long flags,
unsigned long ptex, unsigned long ptex,
unsigned long avpn, unsigned long avpn,
...@@ -83,7 +71,6 @@ long plpar_tce_get(unsigned long liobn, ...@@ -83,7 +71,6 @@ long plpar_tce_get(unsigned long liobn,
tce_ret, &dummy, &dummy); tce_ret, &dummy, &dummy);
} }
long plpar_tce_put(unsigned long liobn, long plpar_tce_put(unsigned long liobn,
unsigned long ioba, unsigned long ioba,
unsigned long tceval) unsigned long tceval)
...@@ -104,10 +91,9 @@ long plpar_put_term_char(unsigned long termno, ...@@ -104,10 +91,9 @@ long plpar_put_term_char(unsigned long termno,
unsigned long len, unsigned long len,
const char *buffer) const char *buffer)
{ {
unsigned long dummy;
unsigned long *lbuf = (unsigned long *)buffer; /* ToDo: alignment? */ unsigned long *lbuf = (unsigned long *)buffer; /* ToDo: alignment? */
return plpar_hcall(H_PUT_TERM_CHAR, termno, len, return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0],
lbuf[0], lbuf[1], &dummy, &dummy, &dummy); lbuf[1]);
} }
static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum,
...@@ -287,12 +273,11 @@ int hvc_get_chars(int index, char *buf, int count) ...@@ -287,12 +273,11 @@ int hvc_get_chars(int index, char *buf, int count)
int hvc_put_chars(int index, const char *buf, int count) int hvc_put_chars(int index, const char *buf, int count)
{ {
unsigned long dummy;
unsigned long *lbuf = (unsigned long *) buf; unsigned long *lbuf = (unsigned long *) buf;
long ret; long ret;
ret = plpar_hcall(H_PUT_TERM_CHAR, index, count, lbuf[0], lbuf[1], ret = plpar_hcall_norets(H_PUT_TERM_CHAR, index, count, lbuf[0],
&dummy, &dummy, &dummy); lbuf[1]);
if (ret == H_Success) if (ret == H_Success)
return count; return count;
if (ret == H_Busy) if (ret == H_Busy)
...@@ -318,7 +303,6 @@ int hvc_count(int *start_termno) ...@@ -318,7 +303,6 @@ int hvc_count(int *start_termno)
long pSeries_lpar_hpte_insert(unsigned long hpte_group, long pSeries_lpar_hpte_insert(unsigned long hpte_group,
unsigned long va, unsigned long prpn, unsigned long va, unsigned long prpn,
int secondary, unsigned long hpteflags, int secondary, unsigned long hpteflags,
...@@ -329,6 +313,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, ...@@ -329,6 +313,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
unsigned long flags; unsigned long flags;
unsigned long slot; unsigned long slot;
HPTE lhpte; HPTE lhpte;
unsigned long dummy0, dummy1;
/* Fill in the local HPTE with absolute rpn, avpn and flags */ /* Fill in the local HPTE with absolute rpn, avpn and flags */
lhpte.dw1.dword1 = 0; lhpte.dw1.dword1 = 0;
...@@ -348,7 +333,6 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, ...@@ -348,7 +333,6 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
/* Now fill in the actual HPTE */ /* Now fill in the actual HPTE */
/* Set CEC cookie to 0 */ /* Set CEC cookie to 0 */
/* Large page = 0 */
/* Zero page = 0 */ /* Zero page = 0 */
/* I-cache Invalidate = 0 */ /* I-cache Invalidate = 0 */
/* I-cache synchronize = 0 */ /* I-cache synchronize = 0 */
...@@ -359,19 +343,8 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, ...@@ -359,19 +343,8 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
lhpte.dw1.flags.flags &= ~_PAGE_COHERENT; lhpte.dw1.flags.flags &= ~_PAGE_COHERENT;
__asm__ __volatile__ ( lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, lhpte.dw0.dword0,
H_ENTER_r3 lhpte.dw1.dword1, &slot, &dummy0, &dummy1);
"mr 4, %2\n"
"mr 5, %3\n"
"mr 6, %4\n"
"mr 7, %5\n"
HSC
"mr %0, 3\n"
"mr %1, 4\n"
: "=r" (lpar_rc), "=r" (slot)
: "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0),
"r" (lhpte.dw1.dword1)
: "r3", "r4", "r5", "r6", "r7", "cc");
if (lpar_rc == H_PTEG_Full) if (lpar_rc == H_PTEG_Full)
return -1; return -1;
......
...@@ -37,7 +37,56 @@ static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; ...@@ -37,7 +37,56 @@ static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
static int htlbpage_free; /* = 0 */ static int htlbpage_free; /* = 0 */
static int htlbpage_total; /* = 0 */ static int htlbpage_total; /* = 0 */
static LIST_HEAD(htlbpage_freelist); static struct list_head hugepage_freelists[MAX_NUMNODES];
static void enqueue_huge_page(struct page *page)
{
list_add(&page->list,
&hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
}
/* XXX make this a sysctl */
unsigned long largepage_roundrobin = 1;
static struct page *dequeue_huge_page(void)
{
static int nid = 0;
struct page *page = NULL;
int i;
if (!largepage_roundrobin)
nid = numa_node_id();
for (i = 0; i < numnodes; i++) {
if (!list_empty(&hugepage_freelists[nid]))
break;
nid = (nid + 1) % numnodes;
}
if (!list_empty(&hugepage_freelists[nid])) {
page = list_entry(hugepage_freelists[nid].next, struct page, list);
list_del(&page->list);
}
if (largepage_roundrobin)
nid = (nid + 1) % numnodes;
return page;
}
static struct page *alloc_fresh_huge_page(void)
{
static int nid = 0;
struct page *page;
page = alloc_pages_node(nid, GFP_HIGHUSER, HUGETLB_PAGE_ORDER);
if (!page)
return NULL;
nid = page_zone(page)->zone_pgdat->node_id;
nid = (nid + 1) % numnodes;
return page;
}
/* HugePTE layout: /* HugePTE layout:
* *
...@@ -103,13 +152,12 @@ static struct page *alloc_hugetlb_page(void) ...@@ -103,13 +152,12 @@ static struct page *alloc_hugetlb_page(void)
struct page *page; struct page *page;
spin_lock(&htlbpage_lock); spin_lock(&htlbpage_lock);
if (list_empty(&htlbpage_freelist)) { page = dequeue_huge_page();
if (!page) {
spin_unlock(&htlbpage_lock); spin_unlock(&htlbpage_lock);
return NULL; return NULL;
} }
page = list_entry(htlbpage_freelist.next, struct page, list);
list_del(&page->list);
htlbpage_free--; htlbpage_free--;
spin_unlock(&htlbpage_lock); spin_unlock(&htlbpage_lock);
set_page_count(page, 1); set_page_count(page, 1);
...@@ -365,7 +413,7 @@ static void free_huge_page(struct page *page) ...@@ -365,7 +413,7 @@ static void free_huge_page(struct page *page)
INIT_LIST_HEAD(&page->list); INIT_LIST_HEAD(&page->list);
spin_lock(&htlbpage_lock); spin_lock(&htlbpage_lock);
list_add(&page->list, &htlbpage_freelist); enqueue_huge_page(page);
htlbpage_free++; htlbpage_free++;
spin_unlock(&htlbpage_lock); spin_unlock(&htlbpage_lock);
} }
...@@ -604,9 +652,11 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access, ...@@ -604,9 +652,11 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access,
if (!in_hugepage_area(mm->context, ea)) if (!in_hugepage_area(mm->context, ea))
return -1; return -1;
ea &= ~(HPAGE_SIZE-1);
/* We have to find the first hugepte in the batch, since /* We have to find the first hugepte in the batch, since
* that's the one that will store the HPTE flags */ * that's the one that will store the HPTE flags */
ptep = hugepte_offset(mm, ea & ~(HPAGE_SIZE-1)); ptep = hugepte_offset(mm, ea);
/* Search the Linux page table for a match with va */ /* Search the Linux page table for a match with va */
va = (vsid << 28) | (ea & 0x0fffffff); va = (vsid << 28) | (ea & 0x0fffffff);
...@@ -675,6 +725,10 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access, ...@@ -675,6 +725,10 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access,
hugepte_val(new_pte) &= ~_HUGEPAGE_HPTEFLAGS; hugepte_val(new_pte) &= ~_HUGEPAGE_HPTEFLAGS;
hugepte_val(new_pte) |= _HUGEPAGE_HASHPTE; hugepte_val(new_pte) |= _HUGEPAGE_HASHPTE;
/* Add in WIMG bits */
/* XXX We should store these in the pte */
hpteflags |= _PAGE_COHERENT;
slot = ppc_md.hpte_insert(hpte_group, va, prpn, 0, slot = ppc_md.hpte_insert(hpte_group, va, prpn, 0,
hpteflags, 0, 1); hpteflags, 0, 1);
...@@ -695,7 +749,7 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access, ...@@ -695,7 +749,7 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access,
} }
if (unlikely(slot == -2)) if (unlikely(slot == -2))
panic("hash_page: pte_insert failed\n"); panic("hash_huge_page: pte_insert failed\n");
hugepte_val(new_pte) |= (slot<<5) & _HUGEPAGE_GROUP_IX; hugepte_val(new_pte) |= (slot<<5) & _HUGEPAGE_GROUP_IX;
...@@ -768,11 +822,11 @@ int set_hugetlb_mem_size(int count) ...@@ -768,11 +822,11 @@ int set_hugetlb_mem_size(int count)
return htlbpage_total; return htlbpage_total;
if (lcount > 0) { /* Increase the mem size. */ if (lcount > 0) { /* Increase the mem size. */
while (lcount--) { while (lcount--) {
page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); page = alloc_fresh_huge_page();
if (page == NULL) if (page == NULL)
break; break;
spin_lock(&htlbpage_lock); spin_lock(&htlbpage_lock);
list_add(&page->list, &htlbpage_freelist); enqueue_huge_page(page);
htlbpage_free++; htlbpage_free++;
htlbpage_total++; htlbpage_total++;
spin_unlock(&htlbpage_lock); spin_unlock(&htlbpage_lock);
...@@ -813,12 +867,15 @@ static int __init hugetlb_init(void) ...@@ -813,12 +867,15 @@ static int __init hugetlb_init(void)
struct page *page; struct page *page;
if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) { if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) {
for (i = 0; i < MAX_NUMNODES; ++i)
INIT_LIST_HEAD(&hugepage_freelists[i]);
for (i = 0; i < htlbpage_max; ++i) { for (i = 0; i < htlbpage_max; ++i) {
page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); page = alloc_fresh_huge_page();
if (!page) if (!page)
break; break;
spin_lock(&htlbpage_lock); spin_lock(&htlbpage_lock);
list_add(&page->list, &htlbpage_freelist); enqueue_huge_page(page);
spin_unlock(&htlbpage_lock); spin_unlock(&htlbpage_lock);
} }
htlbpage_max = htlbpage_free = htlbpage_total = i; htlbpage_max = htlbpage_free = htlbpage_total = i;
...@@ -827,7 +884,7 @@ static int __init hugetlb_init(void) ...@@ -827,7 +884,7 @@ static int __init hugetlb_init(void)
htlbpage_max = 0; htlbpage_max = 0;
printk("CPU does not support HugeTLB\n"); printk("CPU does not support HugeTLB\n");
} }
return 0; return 0;
} }
module_init(hugetlb_init); module_init(hugetlb_init);
......
...@@ -59,9 +59,6 @@ ...@@ -59,9 +59,6 @@
#define H_XIRR 0x74 #define H_XIRR 0x74
#define H_PERFMON 0x7c #define H_PERFMON 0x7c
#define HSC ".long 0x44000022\n"
#define H_ENTER_r3 "li 3, 0x08\n"
/* plpar_hcall() -- Generic call interface using above opcodes /* plpar_hcall() -- Generic call interface using above opcodes
* *
* The actual call interface is a hypervisor call instruction with * The actual call interface is a hypervisor call instruction with
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment