Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arch/tile: support kexec() for tilegx

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>

+300 -9
+12
arch/tile/include/asm/kexec.h
··· 19 19 20 20 #include <asm/page.h> 21 21 22 + #ifndef __tilegx__ 22 23 /* Maximum physical address we can use pages from. */ 23 24 #define KEXEC_SOURCE_MEMORY_LIMIT TASK_SIZE 24 25 /* Maximum address we can reach in physical address mode. */ 25 26 #define KEXEC_DESTINATION_MEMORY_LIMIT TASK_SIZE 26 27 /* Maximum address we can use for the control code buffer. */ 27 28 #define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE 29 + #else 30 + /* We need to limit the memory below PGDIR_SIZE since 31 + * we only setup page table for [0, PGDIR_SIZE) before final kexec. 32 + */ 33 + /* Maximum physical address we can use pages from. */ 34 + #define KEXEC_SOURCE_MEMORY_LIMIT PGDIR_SIZE 35 + /* Maximum address we can reach in physical address mode. */ 36 + #define KEXEC_DESTINATION_MEMORY_LIMIT PGDIR_SIZE 37 + /* Maximum address we can use for the control code buffer. */ 38 + #define KEXEC_CONTROL_MEMORY_LIMIT PGDIR_SIZE 39 + #endif 28 40 29 41 #define KEXEC_CONTROL_PAGE_SIZE PAGE_SIZE 30 42
+1 -1
arch/tile/kernel/Makefile
··· 13 13 obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o 14 14 obj-$(CONFIG_MODULES) += module.o 15 15 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 16 - obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o 16 + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_$(BITS).o 17 17 obj-$(CONFIG_PCI) += pci.o
+27 -8
arch/tile/kernel/machine_kexec.c
··· 31 31 #include <asm/pgalloc.h> 32 32 #include <asm/cacheflush.h> 33 33 #include <asm/checksum.h> 34 + #include <asm/tlbflush.h> 35 + #include <asm/homecache.h> 34 36 #include <hv/hypervisor.h> 35 37 36 38 ··· 224 222 return alloc_pages_node(0, gfp_mask, order); 225 223 } 226 224 225 + /* 226 + * Address range in which pa=va mapping is set in setup_quasi_va_is_pa(). 227 + * For tilepro, PAGE_OFFSET is used since this is the largest possbile value 228 + * for tilepro, while for tilegx, we limit it to entire middle level page 229 + * table which we assume has been allocated and is undoubtedly large enough. 230 + */ 231 + #ifndef __tilegx__ 232 + #define QUASI_VA_IS_PA_ADDR_RANGE PAGE_OFFSET 233 + #else 234 + #define QUASI_VA_IS_PA_ADDR_RANGE PGDIR_SIZE 235 + #endif 236 + 227 237 static void setup_quasi_va_is_pa(void) 228 238 { 229 - HV_PTE *pgtable; 230 239 HV_PTE pte; 231 - int i; 240 + unsigned long i; 232 241 233 242 /* 234 243 * Flush our TLB to prevent conflicts between the previous contents ··· 247 234 */ 248 235 local_flush_tlb_all(); 249 236 250 - /* setup VA is PA, at least up to PAGE_OFFSET */ 251 - 252 - pgtable = (HV_PTE *)current->mm->pgd; 237 + /* 238 + * setup VA is PA, at least up to QUASI_VA_IS_PA_ADDR_RANGE. 239 + * Note here we assume that level-1 page table is defined by 240 + * HPAGE_SIZE. 241 + */ 253 242 pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE); 254 243 pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); 255 - 256 - for (i = 0; i < pgd_index(PAGE_OFFSET); i++) { 244 + for (i = 0; i < (QUASI_VA_IS_PA_ADDR_RANGE >> HPAGE_SHIFT); i++) { 245 + unsigned long vaddr = i << HPAGE_SHIFT; 246 + pgd_t *pgd = pgd_offset(current->mm, vaddr); 247 + pud_t *pud = pud_offset(pgd, vaddr); 248 + pte_t *ptep = (pte_t *) pmd_offset(pud, vaddr); 257 249 unsigned long pfn = i << (HPAGE_SHIFT - PAGE_SHIFT); 250 + 258 251 if (pfn_valid(pfn)) 259 - __set_pte(&pgtable[i], pfn_pte(pfn, pte)); 252 + __set_pte(ptep, pfn_pte(pfn, pte)); 260 253 } 261 254 } 262 255
arch/tile/kernel/relocate_kernel.S arch/tile/kernel/relocate_kernel_32.S
+260
arch/tile/kernel/relocate_kernel_64.S
··· 1 + /* 2 + * Copyright 2011 Tilera Corporation. All Rights Reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, but 9 + * WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 11 + * NON INFRINGEMENT. See the GNU General Public License for 12 + * more details. 13 + * 14 + * copy new kernel into place and then call hv_reexec 15 + * 16 + */ 17 + 18 + #include <linux/linkage.h> 19 + #include <arch/chip.h> 20 + #include <asm/page.h> 21 + #include <hv/hypervisor.h> 22 + 23 + #undef RELOCATE_NEW_KERNEL_VERBOSE 24 + 25 + STD_ENTRY(relocate_new_kernel) 26 + 27 + move r30, r0 /* page list */ 28 + move r31, r1 /* address of page we are on */ 29 + move r32, r2 /* start address of new kernel */ 30 + 31 + shrui r1, r1, PAGE_SHIFT 32 + addi r1, r1, 1 33 + shli sp, r1, PAGE_SHIFT 34 + addi sp, sp, -8 35 + /* we now have a stack (whether we need one or not) */ 36 + 37 + moveli r40, hw2_last(hv_console_putc) 38 + shl16insli r40, r40, hw1(hv_console_putc) 39 + shl16insli r40, r40, hw0(hv_console_putc) 40 + 41 + #ifdef RELOCATE_NEW_KERNEL_VERBOSE 42 + moveli r0, 'r' 43 + jalr r40 44 + 45 + moveli r0, '_' 46 + jalr r40 47 + 48 + moveli r0, 'n' 49 + jalr r40 50 + 51 + moveli r0, '_' 52 + jalr r40 53 + 54 + moveli r0, 'k' 55 + jalr r40 56 + 57 + moveli r0, '\n' 58 + jalr r40 59 + #endif 60 + 61 + /* 62 + * Throughout this code r30 is pointer to the element of page 63 + * list we are working on. 64 + * 65 + * Normally we get to the next element of the page list by 66 + * incrementing r30 by eight. The exception is if the element 67 + * on the page list is an IND_INDIRECTION in which case we use 68 + * the element with the low bits masked off as the new value 69 + * of r30. 70 + * 71 + * To get this started, we need the value passed to us (which 72 + * will always be an IND_INDIRECTION) in memory somewhere with 73 + * r30 pointing at it. To do that, we push the value passed 74 + * to us on the stack and make r30 point to it. 75 + */ 76 + 77 + st sp, r30 78 + move r30, sp 79 + addi sp, sp, -16 80 + 81 + #if CHIP_HAS_CBOX_HOME_MAP() 82 + /* 83 + * On TILE-GX, we need to flush all tiles' caches, since we may 84 + * have been doing hash-for-home caching there. Note that we 85 + * must do this _after_ we're completely done modifying any memory 86 + * other than our output buffer (which we know is locally cached). 87 + * We want the caches to be fully clean when we do the reexec, 88 + * because the hypervisor is going to do this flush again at that 89 + * point, and we don't want that second flush to overwrite any memory. 90 + */ 91 + { 92 + move r0, zero /* cache_pa */ 93 + moveli r1, hw2_last(HV_FLUSH_EVICT_L2) 94 + } 95 + { 96 + shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2) 97 + movei r2, -1 /* cache_cpumask; -1 means all client tiles */ 98 + } 99 + { 100 + shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) /* cache_control */ 101 + move r3, zero /* tlb_va */ 102 + } 103 + { 104 + move r4, zero /* tlb_length */ 105 + move r5, zero /* tlb_pgsize */ 106 + } 107 + { 108 + move r6, zero /* tlb_cpumask */ 109 + move r7, zero /* asids */ 110 + } 111 + { 112 + moveli r20, hw2_last(hv_flush_remote) 113 + move r8, zero /* asidcount */ 114 + } 115 + shl16insli r20, r20, hw1(hv_flush_remote) 116 + shl16insli r20, r20, hw0(hv_flush_remote) 117 + 118 + jalr r20 119 + #endif 120 + 121 + /* r33 is destination pointer, default to zero */ 122 + 123 + moveli r33, 0 124 + 125 + .Lloop: ld r10, r30 126 + 127 + andi r9, r10, 0xf /* low 4 bits tell us what type it is */ 128 + xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */ 129 + 130 + cmpeqi r0, r9, 0x1 /* IND_DESTINATION */ 131 + beqzt r0, .Ltry2 132 + 133 + move r33, r10 134 + 135 + #ifdef RELOCATE_NEW_KERNEL_VERBOSE 136 + moveli r0, 'd' 137 + jalr r40 138 + #endif 139 + 140 + addi r30, r30, 8 141 + j .Lloop 142 + 143 + .Ltry2: 144 + cmpeqi r0, r9, 0x2 /* IND_INDIRECTION */ 145 + beqzt r0, .Ltry4 146 + 147 + move r30, r10 148 + 149 + #ifdef RELOCATE_NEW_KERNEL_VERBOSE 150 + moveli r0, 'i' 151 + jalr r40 152 + #endif 153 + 154 + j .Lloop 155 + 156 + .Ltry4: 157 + cmpeqi r0, r9, 0x4 /* IND_DONE */ 158 + beqzt r0, .Ltry8 159 + 160 + mf 161 + 162 + #ifdef RELOCATE_NEW_KERNEL_VERBOSE 163 + moveli r0, 'D' 164 + jalr r40 165 + moveli r0, '\n' 166 + jalr r40 167 + #endif 168 + 169 + move r0, r32 170 + 171 + moveli r41, hw2_last(hv_reexec) 172 + shl16insli r41, r41, hw1(hv_reexec) 173 + shl16insli r41, r41, hw0(hv_reexec) 174 + 175 + jalr r41 176 + 177 + /* we should not get here */ 178 + 179 + moveli r0, '?' 180 + jalr r40 181 + moveli r0, '\n' 182 + jalr r40 183 + 184 + j .Lhalt 185 + 186 + .Ltry8: cmpeqi r0, r9, 0x8 /* IND_SOURCE */ 187 + beqz r0, .Lerr /* unknown type */ 188 + 189 + /* copy page at r10 to page at r33 */ 190 + 191 + move r11, r33 192 + 193 + moveli r0, hw2_last(PAGE_SIZE) 194 + shl16insli r0, r0, hw1(PAGE_SIZE) 195 + shl16insli r0, r0, hw0(PAGE_SIZE) 196 + add r33, r33, r0 197 + 198 + /* copy word at r10 to word at r11 until r11 equals r33 */ 199 + 200 + /* We know page size must be multiple of 8, so we can unroll 201 + * 8 times safely without any edge case checking. 202 + * 203 + * Issue a flush of the destination every 8 words to avoid 204 + * incoherence when starting the new kernel. (Now this is 205 + * just good paranoia because the hv_reexec call will also 206 + * take care of this.) 207 + */ 208 + 209 + 1: 210 + { ld r0, r10; addi r10, r10, 8 } 211 + { st r11, r0; addi r11, r11, 8 } 212 + { ld r0, r10; addi r10, r10, 8 } 213 + { st r11, r0; addi r11, r11, 8 } 214 + { ld r0, r10; addi r10, r10, 8 } 215 + { st r11, r0; addi r11, r11, 8 } 216 + { ld r0, r10; addi r10, r10, 8 } 217 + { st r11, r0; addi r11, r11, 8 } 218 + { ld r0, r10; addi r10, r10, 8 } 219 + { st r11, r0; addi r11, r11, 8 } 220 + { ld r0, r10; addi r10, r10, 8 } 221 + { st r11, r0; addi r11, r11, 8 } 222 + { ld r0, r10; addi r10, r10, 8 } 223 + { st r11, r0; addi r11, r11, 8 } 224 + { ld r0, r10; addi r10, r10, 8 } 225 + { st r11, r0 } 226 + { flush r11 ; addi r11, r11, 8 } 227 + 228 + cmpeq r0, r33, r11 229 + beqzt r0, 1b 230 + 231 + #ifdef RELOCATE_NEW_KERNEL_VERBOSE 232 + moveli r0, 's' 233 + jalr r40 234 + #endif 235 + 236 + addi r30, r30, 8 237 + j .Lloop 238 + 239 + 240 + .Lerr: moveli r0, 'e' 241 + jalr r40 242 + moveli r0, 'r' 243 + jalr r40 244 + moveli r0, 'r' 245 + jalr r40 246 + moveli r0, '\n' 247 + jalr r40 248 + .Lhalt: 249 + moveli r41, hw2_last(hv_halt) 250 + shl16insli r41, r41, hw1(hv_halt) 251 + shl16insli r41, r41, hw0(hv_halt) 252 + 253 + jalr r41 254 + STD_ENDPROC(relocate_new_kernel) 255 + 256 + .section .rodata,"a" 257 + 258 + .globl relocate_new_kernel_size 259 + relocate_new_kernel_size: 260 + .long .Lend_relocate_new_kernel - relocate_new_kernel