1/* 2 * SPU local store allocation routines 3 * 4 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21#undef DEBUG 22 23#include <linux/kernel.h> 24#include <linux/mm.h> 25#include <linux/slab.h> 26#include <linux/vmalloc.h> 27 28#include <asm/spu.h> 29#include <asm/spu_csa.h> 30#include <asm/mmu.h> 31 32#include "spufs.h" 33 34static int spu_alloc_lscsa_std(struct spu_state *csa) 35{ 36 struct spu_lscsa *lscsa; 37 unsigned char *p; 38 39 lscsa = vzalloc(sizeof(struct spu_lscsa)); 40 if (!lscsa) 41 return -ENOMEM; 42 csa->lscsa = lscsa; 43 44 /* Set LS pages reserved to allow for user-space mapping. */ 45 for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE) 46 SetPageReserved(vmalloc_to_page(p)); 47 48 return 0; 49} 50 51static void spu_free_lscsa_std(struct spu_state *csa) 52{ 53 /* Clear reserved bit before vfree. */ 54 unsigned char *p; 55 56 if (csa->lscsa == NULL) 57 return; 58 59 for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE) 60 ClearPageReserved(vmalloc_to_page(p)); 61 62 vfree(csa->lscsa); 63} 64 65#ifdef CONFIG_SPU_FS_64K_LS 66 67#define SPU_64K_PAGE_SHIFT 16 68#define SPU_64K_PAGE_ORDER (SPU_64K_PAGE_SHIFT - PAGE_SHIFT) 69#define SPU_64K_PAGE_COUNT (1ul << SPU_64K_PAGE_ORDER) 70 71int spu_alloc_lscsa(struct spu_state *csa) 72{ 73 struct page **pgarray; 74 unsigned char *p; 75 int i, j, n_4k; 76 77 /* Check availability of 64K pages */ 78 if (!spu_64k_pages_available()) 79 goto fail; 80 81 csa->use_big_pages = 1; 82 83 pr_debug("spu_alloc_lscsa(csa=0x%p), trying to allocate 64K pages\n", 84 csa); 85 86 /* First try to allocate our 64K pages. We need 5 of them 87 * with the current implementation. In the future, we should try 88 * to separate the lscsa with the actual local store image, thus 89 * allowing us to require only 4 64K pages per context 90 */ 91 for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) { 92 /* XXX This is likely to fail, we should use a special pool 93 * similar to what hugetlbfs does. 94 */ 95 csa->lscsa_pages[i] = alloc_pages(GFP_KERNEL, 96 SPU_64K_PAGE_ORDER); 97 if (csa->lscsa_pages[i] == NULL) 98 goto fail; 99 } 100 101 pr_debug(" success ! creating vmap...\n"); 102 103 /* Now we need to create a vmalloc mapping of these for the kernel 104 * and SPU context switch code to use. Currently, we stick to a 105 * normal kernel vmalloc mapping, which in our case will be 4K 106 */ 107 n_4k = SPU_64K_PAGE_COUNT * SPU_LSCSA_NUM_BIG_PAGES; 108 pgarray = kmalloc(sizeof(struct page *) * n_4k, GFP_KERNEL); 109 if (pgarray == NULL) 110 goto fail; 111 for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) 112 for (j = 0; j < SPU_64K_PAGE_COUNT; j++) 113 /* We assume all the struct page's are contiguous 114 * which should be hopefully the case for an order 4 115 * allocation.. 116 */ 117 pgarray[i * SPU_64K_PAGE_COUNT + j] = 118 csa->lscsa_pages[i] + j; 119 csa->lscsa = vmap(pgarray, n_4k, VM_USERMAP, PAGE_KERNEL); 120 kfree(pgarray); 121 if (csa->lscsa == NULL) 122 goto fail; 123 124 memset(csa->lscsa, 0, sizeof(struct spu_lscsa)); 125 126 /* Set LS pages reserved to allow for user-space mapping. 127 * 128 * XXX isn't that a bit obsolete ? I think we should just 129 * make sure the page count is high enough. Anyway, won't harm 130 * for now 131 */ 132 for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE) 133 SetPageReserved(vmalloc_to_page(p)); 134 135 pr_debug(" all good !\n"); 136 137 return 0; 138fail: 139 pr_debug("spufs: failed to allocate lscsa 64K pages, falling back\n"); 140 spu_free_lscsa(csa); 141 return spu_alloc_lscsa_std(csa); 142} 143 144void spu_free_lscsa(struct spu_state *csa) 145{ 146 unsigned char *p; 147 int i; 148 149 if (!csa->use_big_pages) { 150 spu_free_lscsa_std(csa); 151 return; 152 } 153 csa->use_big_pages = 0; 154 155 if (csa->lscsa == NULL) 156 goto free_pages; 157 158 for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE) 159 ClearPageReserved(vmalloc_to_page(p)); 160 161 vunmap(csa->lscsa); 162 csa->lscsa = NULL; 163 164 free_pages: 165 166 for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) 167 if (csa->lscsa_pages[i]) 168 __free_pages(csa->lscsa_pages[i], SPU_64K_PAGE_ORDER); 169} 170 171#else /* CONFIG_SPU_FS_64K_LS */ 172 173int spu_alloc_lscsa(struct spu_state *csa) 174{ 175 return spu_alloc_lscsa_std(csa); 176} 177 178void spu_free_lscsa(struct spu_state *csa) 179{ 180 spu_free_lscsa_std(csa); 181} 182 183#endif /* !defined(CONFIG_SPU_FS_64K_LS) */ 184