Commit 9326a730 authored by Ivan Kokshaysky's avatar Ivan Kokshaysky Committed by Richard Henderson

[PATCH] alpha numa update

From Jeff.Wiedemeier@hp.com:

numa mm update including moving alpha numa support into 
machine vector so a generic numa kernel can be used.
parent ecb581fd
......@@ -228,6 +228,13 @@ EXPORT_SYMBOL(_raw_read_lock);
EXPORT_SYMBOL(cpu_present_mask);
#endif /* CONFIG_SMP */
/*
* NUMA specific symbols
*/
#ifdef CONFIG_DISCONTIGMEM
EXPORT_SYMBOL(node_data);
#endif /* CONFIG_DISCONTIGMEM */
EXPORT_SYMBOL(rtc_lock);
/*
......
......@@ -442,6 +442,33 @@ struct pci_ops wildfire_pci_ops =
.write = wildfire_write_config,
};
/*
* NUMA Support
*/
int wildfire_pa_to_nid(unsigned long pa)
{
return pa >> 36;
}
int wildfire_cpuid_to_nid(int cpuid)
{
/* assume 4 CPUs per node */
return cpuid >> 2;
}
unsigned long wildfire_node_mem_start(int nid)
{
/* 64GB per node */
return (unsigned long)nid * (64UL * 1024 * 1024 * 1024);
}
unsigned long wildfire_node_mem_size(int nid)
{
/* 64GB per node */
return 64UL * 1024 * 1024 * 1024;
}
#if DEBUG_DUMP_REGS
static void __init
......
......@@ -82,6 +82,10 @@ extern void wildfire_init_arch(void);
extern void wildfire_kill_arch(int);
extern void wildfire_machine_check(u64, u64, struct pt_regs *);
extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
extern int wildfire_pa_to_nid(unsigned long);
extern int wildfire_cpuid_to_nid(int);
extern unsigned long wildfire_node_mem_start(int);
extern unsigned long wildfire_node_mem_size(int);
/* setup.c */
extern unsigned long srm_hae;
......
......@@ -353,5 +353,10 @@ struct alpha_machine_vector wildfire_mv __initmv = {
.kill_arch = wildfire_kill_arch,
.pci_map_irq = wildfire_map_irq,
.pci_swizzle = common_swizzle,
.pa_to_nid = wildfire_pa_to_nid,
.cpuid_to_nid = wildfire_cpuid_to_nid,
.node_mem_start = wildfire_node_mem_start,
.node_mem_size = wildfire_node_mem_size,
};
ALIAS_MV(wildfire)
......@@ -19,8 +19,8 @@
#include <asm/hwrpb.h>
#include <asm/pgalloc.h>
plat_pg_data_t *plat_node_data[MAX_NUMNODES];
bootmem_data_t plat_node_bdata[MAX_NUMNODES];
pg_data_t node_data[MAX_NUMNODES];
bootmem_data_t node_bdata[MAX_NUMNODES];
#undef DEBUG_DISCONTIG
#ifdef DEBUG_DISCONTIG
......@@ -65,12 +65,12 @@ setup_memory_node(int nid, void *kernel_end)
unsigned long start, end;
unsigned long node_pfn_start, node_pfn_end;
int i;
unsigned long node_datasz = PFN_UP(sizeof(plat_pg_data_t));
unsigned long node_datasz = PFN_UP(sizeof(pg_data_t));
int show_init = 0;
/* Find the bounds of current node */
node_pfn_start = (nid * NODE_MAX_MEM_SIZE) >> PAGE_SHIFT;
node_pfn_end = node_pfn_start + (NODE_MAX_MEM_SIZE >> PAGE_SHIFT);
node_pfn_start = (node_mem_start(nid)) >> PAGE_SHIFT;
node_pfn_end = node_pfn_start + (node_mem_size(nid) >> PAGE_SHIFT);
/* Find free clusters, and init and free the bootmem accordingly. */
memdesc = (struct memdesc_struct *)
......@@ -93,7 +93,7 @@ setup_memory_node(int nid, void *kernel_end)
if (!show_init) {
show_init = 1;
printk("Initialing bootmem allocator on Node ID %d\n", nid);
printk("Initializing bootmem allocator on Node ID %d\n", nid);
}
printk(" memcluster %2d, usage %1lx, start %8lu, end %8lu\n",
i, cluster->usage, cluster->start_pfn,
......@@ -107,13 +107,17 @@ setup_memory_node(int nid, void *kernel_end)
if (start < min_low_pfn)
min_low_pfn = start;
if (end > max_low_pfn)
max_low_pfn = end;
max_pfn = max_low_pfn = end;
}
if (mem_size_limit && max_low_pfn >= mem_size_limit) {
if (mem_size_limit && max_low_pfn > mem_size_limit) {
static int msg_shown = 0;
if (!msg_shown) {
msg_shown = 1;
printk("setup: forcing memory size to %ldK (from %ldK).\n",
mem_size_limit << (PAGE_SHIFT - 10),
max_low_pfn << (PAGE_SHIFT - 10));
}
max_low_pfn = mem_size_limit;
}
......@@ -122,20 +126,22 @@ setup_memory_node(int nid, void *kernel_end)
num_physpages += max_low_pfn - min_low_pfn;
#if 0 /* we'll try this one again in a little while */
/* Cute trick to make sure our local node data is on local memory */
PLAT_NODE_DATA(nid) = (plat_pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
/* Quasi-mark the plat_pg_data_t as in-use */
node_data[nid] = (pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
#endif
/* Quasi-mark the pg_data_t as in-use */
min_low_pfn += node_datasz;
if (min_low_pfn >= max_low_pfn) {
printk(" not enough mem to reserve PLAT_NODE_DATA");
printk(" not enough mem to reserve NODE_DATA");
return;
}
NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
NODE_DATA(nid)->bdata = &node_bdata[nid];
printk(" Detected node memory: start %8lu, end %8lu\n",
min_low_pfn, max_low_pfn);
DBGDCONT(" DISCONTIG: plat_node_data[%d] is at 0x%p\n", nid, PLAT_NODE_DATA(nid));
DBGDCONT(" DISCONTIG: node_data[%d] is at 0x%p\n", nid, NODE_DATA(nid));
DBGDCONT(" DISCONTIG: NODE_DATA(%d)->bdata is at 0x%p\n", nid, NODE_DATA(nid)->bdata);
/* Find the bounds of kernel memory. */
......@@ -286,8 +292,8 @@ void __init paging_init(void)
dma_local_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
for (nid = 0; nid < numnodes; nid++) {
unsigned long start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT;
unsigned long end_pfn = plat_node_bdata[nid].node_low_pfn;
unsigned long start_pfn = node_bdata[nid].node_boot_start >> PAGE_SHIFT;
unsigned long end_pfn = node_bdata[nid].node_low_pfn;
if (dma_local_pfn >= end_pfn - start_pfn)
zones_size[ZONE_DMA] = end_pfn - start_pfn;
......@@ -302,52 +308,6 @@ void __init paging_init(void)
memset((void *)ZERO_PGE, 0, PAGE_SIZE);
}
#define printkdot() \
do { \
if (!(i++ % ((100UL*1024*1024)>>PAGE_SHIFT))) \
printk("."); \
} while(0)
#define clobber(p, size) memset((p)->virtual, 0xaa, (size))
void __init mem_stress(void)
{
LIST_HEAD(x);
LIST_HEAD(xx);
struct page * p;
unsigned long i = 0;
printk("starting memstress");
while ((p = alloc_pages(GFP_ATOMIC, 1))) {
clobber(p, PAGE_SIZE*2);
list_add(&p->list, &x);
printkdot();
}
while ((p = alloc_page(GFP_ATOMIC))) {
clobber(p, PAGE_SIZE);
list_add(&p->list, &xx);
printkdot();
}
while (!list_empty(&x)) {
p = list_entry(x.next, struct page, list);
clobber(p, PAGE_SIZE*2);
list_del(x.next);
__free_pages(p, 1);
printkdot();
}
while (!list_empty(&xx)) {
p = list_entry(xx.next, struct page, list);
clobber(p, PAGE_SIZE);
list_del(xx.next);
__free_pages(p, 0);
printkdot();
}
printk("I'm still alive duh!\n");
}
#undef printkdot
#undef clobber
void __init mem_init(void)
{
unsigned long codesize, reservedpages, datasize, initsize, pfn;
......@@ -355,9 +315,9 @@ void __init mem_init(void)
extern char _text, _etext, _data, _edata;
extern char __init_begin, __init_end;
unsigned long nid, i;
mem_map_t * lmem_map;
struct page * lmem_map;
high_memory = (void *) __va(max_mapnr <<PAGE_SHIFT);
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
reservedpages = 0;
for (nid = 0; nid < numnodes; nid++) {
......@@ -366,9 +326,9 @@ void __init mem_init(void)
*/
totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
lmem_map = NODE_MEM_MAP(nid);
lmem_map = node_mem_map(nid);
pfn = NODE_DATA(nid)->node_start_pfn;
for (i = 0; i < PLAT_NODE_DATA_SIZE(nid); i++, pfn++)
for (i = 0; i < node_size(nid); i++, pfn++)
if (page_is_ram(pfn) && PageReserved(lmem_map+i))
reservedpages++;
}
......@@ -401,8 +361,8 @@ show_mem(void)
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
for (nid = 0; nid < numnodes; nid++) {
mem_map_t * lmem_map = NODE_MEM_MAP(nid);
i = PLAT_NODE_DATA_SIZE(nid);
struct page * lmem_map = node_mem_map(nid);
i = node_size(nid);
while (i-- > 0) {
total++;
if (PageReserved(lmem_map+i))
......@@ -420,5 +380,4 @@ show_mem(void)
printk("%ld reserved pages\n",reserved);
printk("%ld pages shared\n",shared);
printk("%ld pages swap cached\n",cached);
printk("%ld pages in page table cache\n",pgtable_cache_size);
}
......@@ -83,7 +83,7 @@ static inline void * phys_to_virt(unsigned long address)
}
#endif
#define page_to_phys(page) PAGE_TO_PA(page)
#define page_to_phys(page) page_to_pa(page)
/* This depends on working iommu. */
#define BIO_VMERGE_BOUNDARY (alpha_mv.mv_pci_tbi ? PAGE_SIZE : 0)
......
......@@ -92,6 +92,12 @@ struct alpha_machine_vector
const char *vector_name;
/* NUMA information */
int (*pa_to_nid)(unsigned long);
int (*cpuid_to_nid)(int);
unsigned long (*node_mem_start)(int);
unsigned long (*node_mem_size)(int);
/* System specific parameters. */
union {
struct {
......
......@@ -6,25 +6,7 @@
#define _ASM_MMZONE_H_
#include <linux/config.h>
#ifdef CONFIG_NUMA_SCHED
#include <linux/numa_sched.h>
#endif
#ifdef NOTYET
#include <asm/sn/types.h>
#include <asm/sn/addrs.h>
#include <asm/sn/arch.h>
#include <asm/sn/klkernvars.h>
#endif /* NOTYET */
typedef struct plat_pglist_data {
pg_data_t gendata;
#ifdef NOTYET
kern_vars_t kern_vars;
#endif
#if defined(CONFIG_NUMA) && defined(CONFIG_NUMA_SCHED)
struct numa_schedule_data schedule_data;
#endif
} plat_pg_data_t;
#include <asm/smp.h>
struct bootmem_data_t; /* stupid forward decl. */
......@@ -32,19 +14,26 @@ struct bootmem_data_t; /* stupid forward decl. */
* Following are macros that are specific to this numa platform.
*/
extern plat_pg_data_t *plat_node_data[];
extern pg_data_t node_data[];
#ifdef CONFIG_ALPHA_WILDFIRE
# define ALPHA_PA_TO_NID(pa) ((pa) >> 36) /* 16 nodes max due 43bit kseg */
# define NODE_MAX_MEM_SIZE (64L * 1024L * 1024L * 1024L) /* 64 GB */
#else
# define ALPHA_PA_TO_NID(pa) (0)
# define NODE_MAX_MEM_SIZE (~0UL)
#endif
#define alpha_pa_to_nid(pa) \
(alpha_mv.pa_to_nid \
? alpha_mv.pa_to_nid(pa) \
: (0))
#define node_mem_start(nid) \
(alpha_mv.node_mem_start \
? alpha_mv.node_mem_start(nid) \
: (0UL))
#define node_mem_size(nid) \
(alpha_mv.node_mem_size \
? alpha_mv.node_mem_size(nid) \
: ((nid) ? (0UL) : (~0UL)))
#define pa_to_nid(pa) alpha_pa_to_nid(pa)
#define NODE_DATA(nid) (&node_data[(nid)])
#define node_size(nid) (NODE_DATA(nid)->node_size)
#define PHYSADDR_TO_NID(pa) ALPHA_PA_TO_NID(pa)
#define PLAT_NODE_DATA(n) (plat_node_data[(n)])
#define PLAT_NODE_DATA_SIZE(n) (PLAT_NODE_DATA(n)->gendata.node_size)
#define node_localnr(pfn, nid) ((pfn) - NODE_DATA(nid)->node_start_pfn)
#if 1
#define PLAT_NODE_DATA_LOCALNR(p, n) \
......@@ -68,46 +57,76 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n)
/*
* Given a kernel address, find the home node of the underlying memory.
*/
#define KVADDR_TO_NID(kaddr) PHYSADDR_TO_NID(__pa(kaddr))
#define kvaddr_to_nid(kaddr) pa_to_nid(__pa(kaddr))
#define node_mem_map(nid) (NODE_DATA(nid)->node_mem_map)
#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
/*
* Return a pointer to the node data for node n.
*/
#define NODE_DATA(n) (&((PLAT_NODE_DATA(n))->gendata))
/*
* NODE_MEM_MAP gives the kaddr for the mem_map of the node.
*/
#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map)
/*
* Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
* and returns the mem_map of that node.
*/
#define ADDR_TO_MAPBASE(kaddr) \
NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
#define local_mapnr(kvaddr) \
((__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)))
/*
* Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory
* and returns the kaddr corresponding to first physical page in the
* node's mem_map.
*/
#define LOCAL_BASE_ADDR(kaddr) ((unsigned long)__va(NODE_DATA(KVADDR_TO_NID(kaddr))->node_start_pfn << PAGE_SHIFT))
#define LOCAL_BASE_ADDR(kaddr) \
((unsigned long)__va(NODE_DATA(kvaddr_to_nid(kaddr))->node_start_pfn \
<< PAGE_SHIFT))
#define LOCAL_MAP_NR(kvaddr) \
(((unsigned long)(kvaddr)-LOCAL_BASE_ADDR(kvaddr)) >> PAGE_SHIFT)
#define kern_addr_valid(kaddr) \
test_bit(local_mapnr(kaddr), \
NODE_DATA(kvaddr_to_nid(kaddr))->valid_addr_bitmap)
#define kern_addr_valid(kaddr) test_bit(LOCAL_MAP_NR(kaddr), \
NODE_DATA(KVADDR_TO_NID(kaddr))->valid_addr_bitmap)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define virt_to_page(kaddr) (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr))
#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr)
#ifdef CONFIG_NUMA
#ifdef CONFIG_NUMA_SCHED
#define NODE_SCHEDULE_DATA(nid) (&((PLAT_NODE_DATA(nid))->schedule_data))
#endif
#endif /* CONFIG_NUMA */
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> 32))
#define pte_pfn(pte) (pte_val(pte) >> 32)
#define mk_pte(page, pgprot) \
({ \
pte_t pte; \
unsigned long pfn; \
\
pfn = ((unsigned long)((page)-page_zone(page)->zone_mem_map)) << 32; \
pfn += page_zone(page)->zone_start_pfn << 32; \
pte_val(pte) = pfn | pgprot_val(pgprot); \
\
pte; \
})
#define pte_page(x) \
({ \
unsigned long kvirt; \
struct page * __xx; \
\
kvirt = (unsigned long)__va(pte_val(x) >> (32-PAGE_SHIFT)); \
__xx = virt_to_page(kvirt); \
\
__xx; \
})
#define pfn_to_page(pfn) \
({ \
unsigned long kaddr = (unsigned long)__va(pfn << PAGE_SHIFT); \
(node_mem_map(kvaddr_to_nid(kaddr)) + local_mapnr(kaddr)); \
})
#define page_to_pfn(page) \
((page) - page_zone(page)->zone_mem_map + \
(page_zone(page)->zone_start_pfn))
#define page_to_pa(page) \
((( (page) - page_zone(page)->zone_mem_map ) \
+ page_zone(page)->zone_start_pfn) << PAGE_SHIFT)
#define pfn_to_nid(pfn) pa_to_nid(((u64)pfn << PAGE_SHIFT))
#define pfn_valid(pfn) \
(((pfn) - node_start_pfn(pfn_to_nid(pfn))) < \
node_size(pfn_to_nid(pfn))) \
#define virt_addr_valid(kaddr) pfn_valid((__pa(kaddr) >> PAGE_SHIFT))
#endif /* CONFIG_DISCONTIGMEM */
......
#ifndef _ASM_MAX_NUMNODES_H
#define _ASM_MAX_NUMNODES_H
/*
* Currently the Wildfire is the only discontigmem/NUMA capable Alpha core.
*/
#if defined(CONFIG_ALPHA_WILDFIRE) || defined(CONFIG_ALPHA_GENERIC)
# include <asm/core_wildfire.h>
# define MAX_NUMNODES WILDFIRE_MAX_QBB
#endif
#define MAX_NUMNODES 128 /* Marvel */
#endif /* _ASM_MAX_NUMNODES_H */
......@@ -3,6 +3,7 @@
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
/*
* Allocate and free page tables. The xxx_kernel() versions are
......@@ -13,7 +14,7 @@
static inline void
pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
{
pmd_set(pmd, (pte_t *)(((pte - mem_map) << PAGE_SHIFT) + PAGE_OFFSET));
pmd_set(pmd, (pte_t *)(page_to_pa(pte) + PAGE_OFFSET));
}
static inline void
......
......@@ -192,14 +192,8 @@ extern unsigned long __zero_page(void);
* and a page entry and page directory to the page they refer to.
*/
#ifndef CONFIG_DISCONTIGMEM
#define PAGE_TO_PA(page) ((page - mem_map) << PAGE_SHIFT)
#else
#define PAGE_TO_PA(page) \
((( (page) - (page)->zone->zone_mem_map ) \
+ (page)->zone->zone_start_pfn) << PAGE_SHIFT)
#endif
#define page_to_pa(page) ((page - mem_map) << PAGE_SHIFT)
#ifndef CONFIG_DISCONTIGMEM
#define pte_pfn(pte) (pte_val(pte) >> 32)
#define pte_page(pte) pfn_to_page(pte_pfn(pte))
#define mk_pte(page, pgprot) \
......@@ -209,28 +203,6 @@ extern unsigned long __zero_page(void);
pte_val(pte) = (page_to_pfn(page) << 32) | pgprot_val(pgprot); \
pte; \
})
#else
#define mk_pte(page, pgprot) \
({ \
pte_t pte; \
unsigned long pfn; \
\
pfn = ((unsigned long)((page)-(page)->zone->zone_mem_map)) << 32; \
pfn += (page)->zone->zone_start_pfn << 32); \
pte_val(pte) = pfn | pgprot_val(pgprot); \
\
pte; \
})
#define pte_page(x) \
({ \
unsigned long kvirt; \
struct page * __xx; \
\
kvirt = (unsigned long)__va(pte_val(x) >> (32-PAGE_SHIFT)); \
__xx = virt_to_page(kvirt); \
\
__xx; \
})
#endif
extern inline pte_t pfn_pte(unsigned long physpfn, pgprot_t pgprot)
......@@ -252,7 +224,9 @@ pmd_page_kernel(pmd_t pmd)
return ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT)) + PAGE_OFFSET;
}
#ifndef CONFIG_DISCONTIGMEM
#define pmd_page(pmd) (mem_map + ((pmd_val(pmd) & _PFN_MASK) >> 32))
#endif
extern inline unsigned long pgd_page(pgd_t pgd)
{ return PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
......
#ifndef _ASM_ALPHA_TOPOLOGY_H
#define _ASM_ALPHA_TOPOLOGY_H
#if defined(CONFIG_NUMA) && defined(CONFIG_ALPHA_WILDFIRE)
#include <linux/smp.h>
#include <linux/threads.h>
#include <asm/machvec.h>
/* With wildfire assume 4 CPUs per node */
#define __cpu_to_node(cpu) ((cpu) >> 2)
#ifdef CONFIG_NUMA
static inline int __cpu_to_node(int cpu)
{
int node;
#else /* !CONFIG_NUMA || !CONFIG_ALPHA_WILDFIRE */
if (!alpha_mv.cpuid_to_nid)
return 0;
#include <asm-generic/topology.h>
node = alpha_mv.cpuid_to_nid(cpu);
#endif /* CONFIG_NUMA && CONFIG_ALPHA_WILDFIRE */
#ifdef DEBUG_NUMA
if (node < 0)
BUG();
#endif
return node;
}
static inline int __node_to_cpu_mask(int node)
{
unsigned long node_cpu_mask = 0;
int cpu;
for(cpu = 0; cpu < NR_CPUS; cpu++) {
if (cpu_online(cpu) && (__cpu_to_node(cpu) == node))
node_cpu_mask |= 1UL << cpu;
}
#if DEBUG_NUMA
printk("node %d: cpu_mask: %016lx\n", node, node_cpu_mask);
#endif
return node_cpu_mask;
}
# define __node_to_memblk(node) (node)
# define __memblk_to_node(memblk) (memblk)
#else /* CONFIG_NUMA */
# include <asm-generic/topology.h>
#endif /* !CONFIG_NUMA */
#endif /* _ASM_ALPHA_TOPOLOGY_H */
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