1/* 2 * Written by Kanoj Sarcar (kanoj@sgi.com) Aug 99 3 * Adapted for K8/x86-64 Jul 2002 by Andi Kleen. 4 */ 5#ifndef _ASM_MMZONE_H_ 6#define _ASM_MMZONE_H_ 7 8#include <linux/config.h> 9 10typedef struct plat_pglist_data { 11 pg_data_t gendata; 12 unsigned long start_pfn, end_pfn; 13} plat_pg_data_t; 14 15struct bootmem_data_t; 16 17 18extern plat_pg_data_t *plat_node_data[]; 19 20#define MAXNODE 8 21#define MAX_NUMNODES MAXNODE 22#define NODEMAPSIZE 0xff 23 24/* Simple perfect hash to map physical addresses to node numbers */ 25extern int memnode_shift; 26extern u8 memnodemap[NODEMAPSIZE]; 27extern int maxnode; 28 29#define VIRTUAL_BUG_ON(x) do {} while (0) 30 31/* VALID_PAGE below hardcodes the same algorithm*/ 32static inline int phys_to_nid(unsigned long addr) 33{ 34 int nid; 35 VIRTUAL_BUG_ON((addr >> memnode_shift) >= NODEMAPSIZE); 36 nid = memnodemap[addr >> memnode_shift]; 37 VIRTUAL_BUG_ON(nid > maxnode); 38 return nid; 39} 40 41#define PLAT_NODE_DATA(n) (plat_node_data[(n)]) 42#define PLAT_NODE_DATA_STARTNR(n) \ 43 (PLAT_NODE_DATA(n)->gendata.node_start_mapnr) 44#define PLAT_NODE_DATA_SIZE(n) (PLAT_NODE_DATA(n)->gendata.node_size) 45 46#define PLAT_NODE_DATA_LOCALNR(p, n) \ 47 (((p) - PLAT_NODE_DATA(n)->gendata.node_start_paddr) >> PAGE_SHIFT) 48 49#ifdef CONFIG_DISCONTIGMEM 50 51/* 52 * Following are macros that each numa implmentation must define. 53 */ 54 55/* 56 * Given a kernel address, find the home node of the underlying memory. 57 */ 58#define KVADDR_TO_NID(kaddr) phys_to_nid(__pa(kaddr)) 59 60/* 61 * Return a pointer to the node data for node n. 62 */ 63#define NODE_DATA(n) (&((PLAT_NODE_DATA(n))->gendata)) 64 65/* 66 * NODE_MEM_MAP gives the kaddr for the mem_map of the node. 67 */ 68#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) 69 70/* 71 * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory 72 * and returns the the mem_map of that node. 73 */ 74#define ADDR_TO_MAPBASE(kaddr) \ 75 NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr))) 76 77/* 78 * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory 79 * and returns the kaddr corresponding to first physical page in the 80 * node's mem_map. 81 */ 82#define LOCAL_BASE_ADDR(kaddr) ((unsigned long)__va(NODE_DATA(KVADDR_TO_NID(kaddr))->node_start_paddr)) 83 84#define LOCAL_MAP_NR(kvaddr) \ 85 (((unsigned long)(kvaddr)-LOCAL_BASE_ADDR(kvaddr)) >> PAGE_SHIFT) 86 87#define BAD_PAGE 0xffffffffffff 88 89/* this really should be optimized a bit */ 90static inline unsigned long 91paddr_to_local_pfn(unsigned long phys_addr, struct page **mem_map, int check) 92{ 93 unsigned long nid; 94 if (check) { /* we rely on gcc optimizing this way for most cases */ 95 unsigned long index = phys_addr >> memnode_shift; 96 if (index >= NODEMAPSIZE || memnodemap[index] == 0xff) { 97 *mem_map = NULL; 98 return BAD_PAGE; 99 } 100 nid = memnodemap[index]; 101 } else { 102 nid = phys_to_nid(phys_addr); 103 } 104 plat_pg_data_t *plat_pgdat = plat_node_data[nid]; 105 unsigned long pfn = phys_addr >> PAGE_SHIFT; 106 VIRTUAL_BUG_ON(pfn >= plat_pgdat->end_pfn); 107 VIRTUAL_BUG_ON(pfn < plat_pgdat->start_pfn); 108 *mem_map = plat_pgdat->gendata.node_mem_map; 109 return pfn - plat_pgdat->start_pfn; 110} 111#define virt_to_page(kaddr) \ 112 ({ struct page *lmemmap; \ 113 unsigned long lpfn = paddr_to_local_pfn(__pa(kaddr),&lmemmap,0); \ 114 lmemmap + lpfn; }) 115 116/* needs to handle bad addresses too */ 117#define pte_page(pte) \ 118 ({ struct page *lmemmap; \ 119 unsigned long addr = pte_val(pte) & PHYSICAL_PAGE_MASK; \ 120 unsigned long lpfn = paddr_to_local_pfn(addr,&lmemmap,1); \ 121 lmemmap + lpfn; }) 122 123#define pfn_to_page(pfn) virt_to_page(__va((unsigned long)(pfn) << PAGE_SHIFT)) 124#define page_to_pfn(page) ({ \ 125 int nodeid = phys_to_nid(__pa(page)); \ 126 plat_pg_data_t *nd = PLAT_NODE_DATA(nodeid); \ 127 (page - nd->gendata.node_mem_map) + nd->start_pfn; \ 128}) 129 130#define VALID_PAGE(page_ptr) ({ \ 131 int ok = 0; \ 132 unsigned long phys = __pa(page_ptr); \ 133 unsigned long index = phys >> memnode_shift; \ 134 if (index <= NODEMAPSIZE) { \ 135 unsigned nodeid = memnodemap[index]; \ 136 pg_data_t *nd = NODE_DATA(nodeid); \ 137 struct page *lmemmap = nd->node_mem_map; \ 138 ok = (nodeid != 0xff) && \ 139 (page_ptr >= lmemmap && page_ptr < lmemmap + nd->node_size); \ 140 } \ 141 ok; \ 142}) 143 144#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) 145 146 147 148extern void setup_node_bootmem(int nodeid, unsigned long start_, unsigned long end_); 149 150 151#ifdef CONFIG_NUMA 152extern int fake_node; 153#define cputonode(cpu) (fake_node ? 0 : (cpu)) 154#define numa_node_id() cputonode(smp_processor_id()) 155#endif /* CONFIG_NUMA */ 156 157#define MAX_NR_NODES 8 158 159#endif /* CONFIG_DISCONTIGMEM */ 160 161#endif /* _ASM_MMZONE_H_ */ 162