···11+#ifndef __ASM_METAG_MMZONE_H22+#define __ASM_METAG_MMZONE_H33+44+#ifdef CONFIG_NEED_MULTIPLE_NODES55+#include <linux/numa.h>66+77+extern struct pglist_data *node_data[];88+#define NODE_DATA(nid) (node_data[nid])99+1010+static inline int pfn_to_nid(unsigned long pfn)1111+{1212+ int nid;1313+1414+ for (nid = 0; nid < MAX_NUMNODES; nid++)1515+ if (pfn >= node_start_pfn(nid) && pfn <= node_end_pfn(nid))1616+ break;1717+1818+ return nid;1919+}2020+2121+static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn)2222+{2323+ return NODE_DATA(pfn_to_nid(pfn));2424+}2525+2626+/* arch/metag/mm/numa.c */2727+void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end);2828+#else2929+static inline void3030+setup_bootmem_node(int nid, unsigned long start, unsigned long end)3131+{3232+}3333+#endif /* CONFIG_NEED_MULTIPLE_NODES */3434+3535+#ifdef CONFIG_NUMA3636+/* SoC specific mem init */3737+void __init soc_mem_setup(void);3838+#else3939+static inline void __init soc_mem_setup(void) {};4040+#endif4141+4242+#endif /* __ASM_METAG_MMZONE_H */
+13
arch/metag/include/asm/sparsemem.h
···11+#ifndef __ASM_METAG_SPARSEMEM_H22+#define __ASM_METAG_SPARSEMEM_H33+44+/*55+ * SECTION_SIZE_BITS 2^N: how big each section will be66+ * MAX_PHYSADDR_BITS 2^N: how much physical address space we have77+ * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space88+ */99+#define SECTION_SIZE_BITS 261010+#define MAX_PHYSADDR_BITS 321111+#define MAX_PHYSMEM_BITS 321212+1313+#endif /* __ASM_METAG_SPARSEMEM_H */
+30
arch/metag/include/asm/tcm.h
···11+#ifndef __ASM_TCM_H__22+#define __ASM_TCM_H__33+44+#include <linux/ioport.h>55+#include <linux/list.h>66+77+struct tcm_allocation {88+ struct list_head list;99+ unsigned int tag;1010+ unsigned long addr;1111+ unsigned long size;1212+};1313+1414+/*1515+ * TCM memory region descriptor.1616+ */1717+struct tcm_region {1818+ unsigned int tag;1919+ struct resource res;2020+};2121+2222+#define TCM_INVALID_TAG 0xffffffff2323+2424+unsigned long tcm_alloc(unsigned int tag, size_t len);2525+void tcm_free(unsigned int tag, unsigned long addr, size_t len);2626+unsigned int tcm_lookup_tag(unsigned long p);2727+2828+int tcm_add_region(struct tcm_region *reg);2929+3030+#endif
+151
arch/metag/kernel/tcm.c
···11+/*22+ * Copyright (C) 2010 Imagination Technologies Ltd.33+ */44+55+#include <linux/init.h>66+#include <linux/kernel.h>77+#include <linux/spinlock.h>88+#include <linux/stddef.h>99+#include <linux/genalloc.h>1010+#include <linux/string.h>1111+#include <linux/list.h>1212+#include <linux/slab.h>1313+#include <asm/page.h>1414+#include <asm/tcm.h>1515+1616+struct tcm_pool {1717+ struct list_head list;1818+ unsigned int tag;1919+ unsigned long start;2020+ unsigned long end;2121+ struct gen_pool *pool;2222+};2323+2424+static LIST_HEAD(pool_list);2525+2626+static struct tcm_pool *find_pool(unsigned int tag)2727+{2828+ struct list_head *lh;2929+ struct tcm_pool *pool;3030+3131+ list_for_each(lh, &pool_list) {3232+ pool = list_entry(lh, struct tcm_pool, list);3333+ if (pool->tag == tag)3434+ return pool;3535+ }3636+3737+ return NULL;3838+}3939+4040+/**4141+ * tcm_alloc - allocate memory from a TCM pool4242+ * @tag: tag of the pool to allocate memory from4343+ * @len: number of bytes to be allocated4444+ *4545+ * Allocate the requested number of bytes from the pool matching4646+ * the specified tag. Returns the address of the allocated memory4747+ * or zero on failure.4848+ */4949+unsigned long tcm_alloc(unsigned int tag, size_t len)5050+{5151+ unsigned long vaddr;5252+ struct tcm_pool *pool;5353+5454+ pool = find_pool(tag);5555+ if (!pool)5656+ return 0;5757+5858+ vaddr = gen_pool_alloc(pool->pool, len);5959+ if (!vaddr)6060+ return 0;6161+6262+ return vaddr;6363+}6464+6565+/**6666+ * tcm_free - free a block of memory to a TCM pool6767+ * @tag: tag of the pool to free memory to6868+ * @addr: address of the memory to be freed6969+ * @len: number of bytes to be freed7070+ *7171+ * Free the requested number of bytes at a specific address to the7272+ * pool matching the specified tag.7373+ */7474+void tcm_free(unsigned int tag, unsigned long addr, size_t len)7575+{7676+ struct tcm_pool *pool;7777+7878+ pool = find_pool(tag);7979+ if (!pool)8080+ return;8181+ gen_pool_free(pool->pool, addr, len);8282+}8383+8484+/**8585+ * tcm_lookup_tag - find the tag matching an address8686+ * @p: memory address to lookup the tag for8787+ *8888+ * Find the tag of the tcm memory region that contains the8989+ * specified address. Returns %TCM_INVALID_TAG if no such9090+ * memory region could be found.9191+ */9292+unsigned int tcm_lookup_tag(unsigned long p)9393+{9494+ struct list_head *lh;9595+ struct tcm_pool *pool;9696+ unsigned long addr = (unsigned long) p;9797+9898+ list_for_each(lh, &pool_list) {9999+ pool = list_entry(lh, struct tcm_pool, list);100100+ if (addr >= pool->start && addr < pool->end)101101+ return pool->tag;102102+ }103103+104104+ return TCM_INVALID_TAG;105105+}106106+107107+/**108108+ * tcm_add_region - add a memory region to TCM pool list109109+ * @reg: descriptor of region to be added110110+ *111111+ * Add a region of memory to the TCM pool list. Returns 0 on success.112112+ */113113+int __init tcm_add_region(struct tcm_region *reg)114114+{115115+ struct tcm_pool *pool;116116+117117+ pool = kmalloc(sizeof(*pool), GFP_KERNEL);118118+ if (!pool) {119119+ pr_err("Failed to alloc memory for TCM pool!\n");120120+ return -ENOMEM;121121+ }122122+123123+ pool->tag = reg->tag;124124+ pool->start = reg->res.start;125125+ pool->end = reg->res.end;126126+127127+ /*128128+ * 2^3 = 8 bytes granularity to allow for 64bit access alignment.129129+ * -1 = NUMA node specifier.130130+ */131131+ pool->pool = gen_pool_create(3, -1);132132+133133+ if (!pool->pool) {134134+ pr_err("Failed to create TCM pool!\n");135135+ kfree(pool);136136+ return -ENOMEM;137137+ }138138+139139+ if (gen_pool_add(pool->pool, reg->res.start,140140+ reg->res.end - reg->res.start + 1, -1)) {141141+ pr_err("Failed to add memory to TCM pool!\n");142142+ return -ENOMEM;143143+ }144144+ pr_info("Added %s TCM pool (%08x bytes @ %08x)\n",145145+ reg->res.name, reg->res.end - reg->res.start + 1,146146+ reg->res.start);147147+148148+ list_add_tail(&pool->list, &pool_list);149149+150150+ return 0;151151+}
+81
arch/metag/mm/numa.c
···11+/*22+ * Multiple memory node support for Meta machines33+ *44+ * Copyright (C) 2007 Paul Mundt55+ * Copyright (C) 2010 Imagination Technologies Ltd.66+ *77+ * This file is subject to the terms and conditions of the GNU General Public88+ * License. See the file "COPYING" in the main directory of this archive99+ * for more details.1010+ */1111+#include <linux/export.h>1212+#include <linux/bootmem.h>1313+#include <linux/memblock.h>1414+#include <linux/mm.h>1515+#include <linux/numa.h>1616+#include <linux/pfn.h>1717+#include <asm/sections.h>1818+1919+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;2020+EXPORT_SYMBOL_GPL(node_data);2121+2222+extern char _heap_start[];2323+2424+/*2525+ * On Meta machines the conventional approach is to stash system RAM2626+ * in node 0, and other memory blocks in to node 1 and up, ordered by2727+ * latency. Each node's pgdat is node-local at the beginning of the node,2828+ * immediately followed by the node mem map.2929+ */3030+void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)3131+{3232+ unsigned long bootmap_pages, bootmem_paddr;3333+ unsigned long start_pfn, end_pfn;3434+ unsigned long pgdat_paddr;3535+3636+ /* Don't allow bogus node assignment */3737+ BUG_ON(nid > MAX_NUMNODES || nid <= 0);3838+3939+ start_pfn = start >> PAGE_SHIFT;4040+ end_pfn = end >> PAGE_SHIFT;4141+4242+ memblock_add(start, end - start);4343+4444+ memblock_set_node(PFN_PHYS(start_pfn),4545+ PFN_PHYS(end_pfn - start_pfn), nid);4646+4747+ /* Node-local pgdat */4848+ pgdat_paddr = memblock_alloc_base(sizeof(struct pglist_data),4949+ SMP_CACHE_BYTES, end);5050+ NODE_DATA(nid) = __va(pgdat_paddr);5151+ memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));5252+5353+ NODE_DATA(nid)->bdata = &bootmem_node_data[nid];5454+ NODE_DATA(nid)->node_start_pfn = start_pfn;5555+ NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn;5656+5757+ /* Node-local bootmap */5858+ bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);5959+ bootmem_paddr = memblock_alloc_base(bootmap_pages << PAGE_SHIFT,6060+ PAGE_SIZE, end);6161+ init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,6262+ start_pfn, end_pfn);6363+6464+ free_bootmem_with_active_regions(nid, end_pfn);6565+6666+ /* Reserve the pgdat and bootmap space with the bootmem allocator */6767+ reserve_bootmem_node(NODE_DATA(nid), pgdat_paddr & PAGE_MASK,6868+ sizeof(struct pglist_data), BOOTMEM_DEFAULT);6969+ reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr,7070+ bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);7171+7272+ /* It's up */7373+ node_set_online(nid);7474+7575+ /* Kick sparsemem */7676+ sparse_memory_present_with_active_regions(nid);7777+}7878+7979+void __init __weak soc_mem_setup(void)8080+{8181+}