Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
[IA64] make uncached allocator more node aware

+57 -29
+57 -29
arch/ia64/kernel/uncached.c
··· 32 32 33 33 extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *); 34 34 35 - #define MAX_UNCACHED_GRANULES 5 36 - static int allocated_granules; 35 + struct uncached_pool { 36 + struct gen_pool *pool; 37 + struct mutex add_chunk_mutex; /* serialize adding a converted chunk */ 38 + int nchunks_added; /* #of converted chunks added to pool */ 39 + atomic_t status; /* smp called function's return status*/ 40 + }; 37 41 38 - struct gen_pool *uncached_pool[MAX_NUMNODES]; 42 + #define MAX_CONVERTED_CHUNKS_PER_NODE 2 43 + 44 + struct uncached_pool uncached_pools[MAX_NUMNODES]; 39 45 40 46 41 47 static void uncached_ipi_visibility(void *data) 42 48 { 43 49 int status; 50 + struct uncached_pool *uc_pool = (struct uncached_pool *)data; 44 51 45 52 status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); 46 53 if ((status != PAL_VISIBILITY_OK) && 47 54 (status != PAL_VISIBILITY_OK_REMOTE_NEEDED)) 48 - printk(KERN_DEBUG "pal_prefetch_visibility() returns %i on " 49 - "CPU %i\n", status, raw_smp_processor_id()); 55 + atomic_inc(&uc_pool->status); 50 56 } 51 57 52 58 53 59 static void uncached_ipi_mc_drain(void *data) 54 60 { 55 61 int status; 62 + struct uncached_pool *uc_pool = (struct uncached_pool *)data; 56 63 57 64 status = ia64_pal_mc_drain(); 58 - if (status) 59 - printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on " 60 - "CPU %i\n", status, raw_smp_processor_id()); 65 + if (status != PAL_STATUS_SUCCESS) 66 + atomic_inc(&uc_pool->status); 61 67 } 62 68 63 69 ··· 76 70 * This is accomplished by first allocating a granule of cached memory pages 77 71 * and then converting them to uncached memory pages. 78 72 */ 79 - static int uncached_add_chunk(struct gen_pool *pool, int nid) 73 + static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid) 80 74 { 81 75 struct page *page; 82 - int status, i; 76 + int status, i, nchunks_added = uc_pool->nchunks_added; 83 77 unsigned long c_addr, uc_addr; 84 78 85 - if (allocated_granules >= MAX_UNCACHED_GRANULES) 79 + if (mutex_lock_interruptible(&uc_pool->add_chunk_mutex) != 0) 80 + return -1; /* interrupted by a signal */ 81 + 82 + if (uc_pool->nchunks_added > nchunks_added) { 83 + /* someone added a new chunk while we were waiting */ 84 + mutex_unlock(&uc_pool->add_chunk_mutex); 85 + return 0; 86 + } 87 + 88 + if (uc_pool->nchunks_added >= MAX_CONVERTED_CHUNKS_PER_NODE) { 89 + mutex_unlock(&uc_pool->add_chunk_mutex); 86 90 return -1; 91 + } 87 92 88 93 /* attempt to allocate a granule's worth of cached memory pages */ 89 94 90 95 page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO, 91 96 IA64_GRANULE_SHIFT-PAGE_SHIFT); 92 - if (!page) 97 + if (!page) { 98 + mutex_unlock(&uc_pool->add_chunk_mutex); 93 99 return -1; 100 + } 94 101 95 102 /* convert the memory pages from cached to uncached */ 96 103 ··· 121 102 flush_tlb_kernel_range(uc_addr, uc_adddr + IA64_GRANULE_SIZE); 122 103 123 104 status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); 124 - if (!status) { 125 - status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1); 126 - if (status) 105 + if (status == PAL_VISIBILITY_OK_REMOTE_NEEDED) { 106 + atomic_set(&uc_pool->status, 0); 107 + status = smp_call_function(uncached_ipi_visibility, uc_pool, 108 + 0, 1); 109 + if (status || atomic_read(&uc_pool->status)) 127 110 goto failed; 128 - } 111 + } else if (status != PAL_VISIBILITY_OK) 112 + goto failed; 129 113 130 114 preempt_disable(); 131 115 ··· 142 120 143 121 preempt_enable(); 144 122 145 - ia64_pal_mc_drain(); 146 - status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1); 147 - if (status) 123 + status = ia64_pal_mc_drain(); 124 + if (status != PAL_STATUS_SUCCESS) 125 + goto failed; 126 + atomic_set(&uc_pool->status, 0); 127 + status = smp_call_function(uncached_ipi_mc_drain, uc_pool, 0, 1); 128 + if (status || atomic_read(&uc_pool->status)) 148 129 goto failed; 149 130 150 131 /* 151 132 * The chunk of memory pages has been converted to uncached so now we 152 133 * can add it to the pool. 153 134 */ 154 - status = gen_pool_add(pool, uc_addr, IA64_GRANULE_SIZE, nid); 135 + status = gen_pool_add(uc_pool->pool, uc_addr, IA64_GRANULE_SIZE, nid); 155 136 if (status) 156 137 goto failed; 157 138 158 - allocated_granules++; 139 + uc_pool->nchunks_added++; 140 + mutex_unlock(&uc_pool->add_chunk_mutex); 159 141 return 0; 160 142 161 143 /* failed to convert or add the chunk so give it back to the kernel */ ··· 168 142 ClearPageUncached(&page[i]); 169 143 170 144 free_pages(c_addr, IA64_GRANULE_SHIFT-PAGE_SHIFT); 145 + mutex_unlock(&uc_pool->add_chunk_mutex); 171 146 return -1; 172 147 } 173 148 ··· 185 158 unsigned long uncached_alloc_page(int starting_nid) 186 159 { 187 160 unsigned long uc_addr; 188 - struct gen_pool *pool; 161 + struct uncached_pool *uc_pool; 189 162 int nid; 190 163 191 164 if (unlikely(starting_nid >= MAX_NUMNODES)) ··· 198 171 do { 199 172 if (!node_online(nid)) 200 173 continue; 201 - pool = uncached_pool[nid]; 202 - if (pool == NULL) 174 + uc_pool = &uncached_pools[nid]; 175 + if (uc_pool->pool == NULL) 203 176 continue; 204 177 do { 205 - uc_addr = gen_pool_alloc(pool, PAGE_SIZE); 178 + uc_addr = gen_pool_alloc(uc_pool->pool, PAGE_SIZE); 206 179 if (uc_addr != 0) 207 180 return uc_addr; 208 - } while (uncached_add_chunk(pool, nid) == 0); 181 + } while (uncached_add_chunk(uc_pool, nid) == 0); 209 182 210 183 } while ((nid = (nid + 1) % MAX_NUMNODES) != starting_nid); 211 184 ··· 224 197 void uncached_free_page(unsigned long uc_addr) 225 198 { 226 199 int nid = paddr_to_nid(uc_addr - __IA64_UNCACHED_OFFSET); 227 - struct gen_pool *pool = uncached_pool[nid]; 200 + struct gen_pool *pool = uncached_pools[nid].pool; 228 201 229 202 if (unlikely(pool == NULL)) 230 203 return; ··· 251 224 unsigned long uc_end, void *arg) 252 225 { 253 226 int nid = paddr_to_nid(uc_start - __IA64_UNCACHED_OFFSET); 254 - struct gen_pool *pool = uncached_pool[nid]; 227 + struct gen_pool *pool = uncached_pools[nid].pool; 255 228 size_t size = uc_end - uc_start; 256 229 257 230 touch_softlockup_watchdog(); ··· 269 242 int nid; 270 243 271 244 for_each_online_node(nid) { 272 - uncached_pool[nid] = gen_pool_create(PAGE_SHIFT, nid); 245 + uncached_pools[nid].pool = gen_pool_create(PAGE_SHIFT, nid); 246 + mutex_init(&uncached_pools[nid].add_chunk_mutex); 273 247 } 274 248 275 249 efi_memmap_walk_uc(uncached_build_memmap, NULL);