1 /* SPDX-License-Identifier: GPL-2.0 */ 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* !! 2 /* clear_page.S: UltraSparc optimized copy page. 3 * copy_page, __copy_user_page, __copy_user im << 4 * 3 * 5 * Copyright (C) 2001 Niibe Yutaka & Kaz Koji !! 4 * Copyright (C) 1996, 1998, 1999, 2000, 2004 David S. Miller (davem@redhat.com) 6 * Copyright (C) 2002 Toshinobu Sugioka !! 5 * Copyright (C) 1997 Jakub Jelinek (jakub@redhat.com) 7 * Copyright (C) 2006 Paul Mundt << 8 */ << 9 #include <linux/linkage.h> << 10 #include <asm/page.h> << 11 << 12 /* << 13 * copy_page << 14 * @to: P1 address << 15 * @from: P1 address << 16 * << 17 * void copy_page(void *to, void *from) << 18 */ 6 */ 19 7 20 /* !! 8 #include <linux/export.h> 21 * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch !! 9 #include <asm/visasm.h> 22 * r8 --- from + PAGE_SIZE !! 10 #include <asm/thread_info.h> 23 * r9 --- not used !! 11 #include <asm/page.h> 24 * r10 --- to !! 12 #include <linux/pgtable.h> 25 * r11 --- from !! 13 #include <asm/spitfire.h> 26 */ !! 14 #include <asm/head.h> 27 ENTRY(copy_page) !! 15 28 mov.l r8,@-r15 !! 16 /* What we used to do was lock a TLB entry into a specific 29 mov.l r10,@-r15 !! 17 * TLB slot, clear the page with interrupts disabled, then 30 mov.l r11,@-r15 !! 18 * restore the original TLB entry. This was great for 31 mov r4,r10 !! 19 * disturbing the TLB as little as possible, but it meant 32 mov r5,r11 !! 20 * we had to keep interrupts disabled for a long time. 33 mov r5,r8 !! 21 * 34 mov #(PAGE_SIZE >> 10), r0 !! 22 * Now, we simply use the normal TLB loading mechanism, 35 shll8 r0 !! 23 * and this makes the cpu choose a slot all by itself. 36 shll2 r0 !! 24 * Then we do a normal TLB flush on exit. We need only 37 add r0,r8 !! 25 * disable preemption during the clear. 38 ! !! 26 */ 39 1: mov.l @r11+,r0 !! 27 40 mov.l @r11+,r1 !! 28 #define DCACHE_SIZE (PAGE_SIZE * 2) 41 mov.l @r11+,r2 !! 29 42 mov.l @r11+,r3 !! 30 #if (PAGE_SHIFT == 13) 43 mov.l @r11+,r4 !! 31 #define PAGE_SIZE_REM 0x80 44 mov.l @r11+,r5 !! 32 #elif (PAGE_SHIFT == 16) 45 mov.l @r11+,r6 !! 33 #define PAGE_SIZE_REM 0x100 46 mov.l @r11+,r7 << 47 #if defined(CONFIG_CPU_SH4) << 48 movca.l r0,@r10 << 49 #else 34 #else 50 mov.l r0,@r10 !! 35 #error Wrong PAGE_SHIFT specified 51 #endif 36 #endif 52 add #32,r10 << 53 mov.l r7,@-r10 << 54 mov.l r6,@-r10 << 55 mov.l r5,@-r10 << 56 mov.l r4,@-r10 << 57 mov.l r3,@-r10 << 58 mov.l r2,@-r10 << 59 mov.l r1,@-r10 << 60 cmp/eq r11,r8 << 61 bf/s 1b << 62 add #28,r10 << 63 ! << 64 mov.l @r15+,r11 << 65 mov.l @r15+,r10 << 66 mov.l @r15+,r8 << 67 rts << 68 nop << 69 37 70 /* !! 38 #define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \ 71 * __kernel_size_t __copy_user(void *to, const !! 39 fsrc2 %reg0, %f48; fsrc2 %reg1, %f50; \ 72 * Return the number of bytes NOT copied !! 40 fsrc2 %reg2, %f52; fsrc2 %reg3, %f54; \ 73 */ !! 41 fsrc2 %reg4, %f56; fsrc2 %reg5, %f58; \ 74 #define EX(...) \ !! 42 fsrc2 %reg6, %f60; fsrc2 %reg7, %f62; 75 9999: __VA_ARGS__ ; \ !! 43 76 .section __ex_table, "a"; \ !! 44 .text 77 .long 9999b, 6000f ; \ !! 45 78 .previous !! 46 .align 32 79 #define EX_NO_POP(...) \ !! 47 .globl copy_user_page 80 9999: __VA_ARGS__ ; \ !! 48 .type copy_user_page,#function 81 .section __ex_table, "a"; \ !! 49 EXPORT_SYMBOL(copy_user_page) 82 .long 9999b, 6005f ; \ !! 50 copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ 83 .previous !! 51 lduw [%g6 + TI_PRE_COUNT], %o4 84 ENTRY(__copy_user) !! 52 sethi %hi(PAGE_OFFSET), %g2 85 ! Check if small number of bytes !! 53 sethi %hi(PAGE_SIZE), %o3 86 mov #11,r0 !! 54 87 mov r4,r3 !! 55 ldx [%g2 + %lo(PAGE_OFFSET)], %g2 88 cmp/gt r0,r6 ! r6 (len) > r !! 56 sethi %hi(PAGE_KERNEL_LOCKED), %g3 89 bf/s .L_cleanup_loop_no_pop !! 57 90 add r6,r3 ! last destina !! 58 ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3 91 !! 59 sub %o0, %g2, %g1 ! dest paddr 92 ! Calculate bytes needed to align to s !! 60 93 mov.l r11,@-r15 !! 61 sub %o1, %g2, %g2 ! src paddr 94 neg r5,r0 !! 62 95 mov.l r10,@-r15 !! 63 and %o2, %o3, %o0 ! vaddr D-cache alias bit 96 add #4,r0 !! 64 or %g1, %g3, %g1 ! dest TTE data 97 mov.l r9,@-r15 !! 65 98 and #3,r0 !! 66 or %g2, %g3, %g2 ! src TTE data 99 mov.l r8,@-r15 !! 67 sethi %hi(TLBTEMP_BASE), %o3 100 tst r0,r0 !! 68 101 bt 2f !! 69 sethi %hi(DCACHE_SIZE), %o1 102 !! 70 add %o0, %o3, %o0 ! dest TTE vaddr 103 1: !! 71 104 ! Copy bytes to long word align src !! 72 add %o4, 1, %o2 105 EX( mov.b @r5+,r1 ) !! 73 add %o0, %o1, %o1 ! src TTE vaddr 106 dt r0 !! 74 107 add #-1,r6 !! 75 /* Disable preemption. */ 108 EX( mov.b r1,@r4 ) !! 76 mov TLB_TAG_ACCESS, %g3 109 bf/s 1b !! 77 stw %o2, [%g6 + TI_PRE_COUNT] 110 add #1,r4 !! 78 111 !! 79 /* Load TLB entries. */ 112 ! Jump to appropriate routine dependin !! 80 rdpr %pstate, %o2 113 2: mov #3,r1 !! 81 wrpr %o2, PSTATE_IE, %pstate 114 mov r6, r2 !! 82 stxa %o0, [%g3] ASI_DMMU 115 and r4,r1 !! 83 stxa %g1, [%g0] ASI_DTLB_DATA_IN 116 shlr2 r2 !! 84 membar #Sync 117 shll2 r1 !! 85 stxa %o1, [%g3] ASI_DMMU 118 mova .L_jump_tbl,r0 !! 86 stxa %g2, [%g0] ASI_DTLB_DATA_IN 119 mov.l @(r0,r1),r1 !! 87 membar #Sync 120 jmp @r1 !! 88 wrpr %o2, 0x0, %pstate 121 nop << 122 << 123 .align 2 << 124 .L_jump_tbl: << 125 .long .L_dest00 << 126 .long .L_dest01 << 127 .long .L_dest10 << 128 .long .L_dest11 << 129 << 130 /* << 131 * Come here if there are less than 12 bytes t << 132 * << 133 * Keep the branch target close, so the bf/s c << 134 * and result in a more expensive branch being << 135 * fast-path for small copies, the jump via th << 136 * default slow-path cleanup. -PFM. << 137 */ << 138 .L_cleanup_loop_no_pop: << 139 tst r6,r6 ! Check explic << 140 bt 1f << 141 << 142 2: << 143 EX_NO_POP( mov.b @r5+,r0 ) << 144 dt r6 << 145 EX_NO_POP( mov.b r0,@r4 ) << 146 bf/s 2b << 147 add #1,r4 << 148 << 149 1: mov #0,r0 ! normal retur << 150 5000: << 151 << 152 # Exception handler: << 153 .section .fixup, "ax" << 154 6005: << 155 mov.l 8000f,r1 << 156 mov r3,r0 << 157 jmp @r1 << 158 sub r4,r0 << 159 .align 2 << 160 8000: .long 5000b << 161 89 162 .previous !! 90 cheetah_copy_page_insn: 163 rts !! 91 ba,pt %xcc, 9f 164 nop 92 nop 165 93 166 ! Destination = 00 << 167 << 168 .L_dest00: << 169 ! Skip the large copy for small transf << 170 mov #(32+32-4), r0 << 171 cmp/gt r6, r0 ! r0 (60) > r6 << 172 bt 1f << 173 << 174 ! Align dest to a 32 byte boundary << 175 neg r4,r0 << 176 add #0x20, r0 << 177 and #0x1f, r0 << 178 tst r0, r0 << 179 bt 2f << 180 << 181 sub r0, r6 << 182 shlr2 r0 << 183 3: << 184 EX( mov.l @r5+,r1 ) << 185 dt r0 << 186 EX( mov.l r1,@r4 ) << 187 bf/s 3b << 188 add #4,r4 << 189 << 190 2: << 191 EX( mov.l @r5+,r0 ) << 192 EX( mov.l @r5+,r1 ) << 193 EX( mov.l @r5+,r2 ) << 194 EX( mov.l @r5+,r7 ) << 195 EX( mov.l @r5+,r8 ) << 196 EX( mov.l @r5+,r9 ) << 197 EX( mov.l @r5+,r10 ) << 198 EX( mov.l @r5+,r11 ) << 199 #ifdef CONFIG_CPU_SH4 << 200 EX( movca.l r0,@r4 ) << 201 #else << 202 EX( mov.l r0,@r4 ) << 203 #endif << 204 add #-32, r6 << 205 EX( mov.l r1,@(4,r4) ) << 206 mov #32, r0 << 207 EX( mov.l r2,@(8,r4) ) << 208 cmp/gt r6, r0 ! r0 (32) > r6 << 209 EX( mov.l r7,@(12,r4) ) << 210 EX( mov.l r8,@(16,r4) ) << 211 EX( mov.l r9,@(20,r4) ) << 212 EX( mov.l r10,@(24,r4) ) << 213 EX( mov.l r11,@(28,r4) ) << 214 bf/s 2b << 215 add #32,r4 << 216 << 217 1: mov r6, r0 << 218 shlr2 r0 << 219 tst r0, r0 << 220 bt .L_cleanup << 221 1: 94 1: 222 EX( mov.l @r5+,r1 ) !! 95 VISEntryHalf 223 dt r0 !! 96 membar #StoreLoad | #StoreStore | #LoadStore 224 EX( mov.l r1,@r4 ) !! 97 sethi %hi((PAGE_SIZE/64)-2), %o2 225 bf/s 1b !! 98 mov %o0, %g1 226 add #4,r4 !! 99 prefetch [%o1 + 0x000], #one_read 227 !! 100 or %o2, %lo((PAGE_SIZE/64)-2), %o2 228 bra .L_cleanup !! 101 prefetch [%o1 + 0x040], #one_read >> 102 prefetch [%o1 + 0x080], #one_read >> 103 prefetch [%o1 + 0x0c0], #one_read >> 104 ldd [%o1 + 0x000], %f0 >> 105 prefetch [%o1 + 0x100], #one_read >> 106 ldd [%o1 + 0x008], %f2 >> 107 prefetch [%o1 + 0x140], #one_read >> 108 ldd [%o1 + 0x010], %f4 >> 109 prefetch [%o1 + 0x180], #one_read >> 110 fsrc2 %f0, %f16 >> 111 ldd [%o1 + 0x018], %f6 >> 112 fsrc2 %f2, %f18 >> 113 ldd [%o1 + 0x020], %f8 >> 114 fsrc2 %f4, %f20 >> 115 ldd [%o1 + 0x028], %f10 >> 116 fsrc2 %f6, %f22 >> 117 ldd [%o1 + 0x030], %f12 >> 118 fsrc2 %f8, %f24 >> 119 ldd [%o1 + 0x038], %f14 >> 120 fsrc2 %f10, %f26 >> 121 ldd [%o1 + 0x040], %f0 >> 122 1: ldd [%o1 + 0x048], %f2 >> 123 fsrc2 %f12, %f28 >> 124 ldd [%o1 + 0x050], %f4 >> 125 fsrc2 %f14, %f30 >> 126 stda %f16, [%o0] ASI_BLK_P >> 127 ldd [%o1 + 0x058], %f6 >> 128 fsrc2 %f0, %f16 >> 129 ldd [%o1 + 0x060], %f8 >> 130 fsrc2 %f2, %f18 >> 131 ldd [%o1 + 0x068], %f10 >> 132 fsrc2 %f4, %f20 >> 133 ldd [%o1 + 0x070], %f12 >> 134 fsrc2 %f6, %f22 >> 135 ldd [%o1 + 0x078], %f14 >> 136 fsrc2 %f8, %f24 >> 137 ldd [%o1 + 0x080], %f0 >> 138 prefetch [%o1 + 0x180], #one_read >> 139 fsrc2 %f10, %f26 >> 140 subcc %o2, 1, %o2 >> 141 add %o0, 0x40, %o0 >> 142 bne,pt %xcc, 1b >> 143 add %o1, 0x40, %o1 >> 144 >> 145 ldd [%o1 + 0x048], %f2 >> 146 fsrc2 %f12, %f28 >> 147 ldd [%o1 + 0x050], %f4 >> 148 fsrc2 %f14, %f30 >> 149 stda %f16, [%o0] ASI_BLK_P >> 150 ldd [%o1 + 0x058], %f6 >> 151 fsrc2 %f0, %f16 >> 152 ldd [%o1 + 0x060], %f8 >> 153 fsrc2 %f2, %f18 >> 154 ldd [%o1 + 0x068], %f10 >> 155 fsrc2 %f4, %f20 >> 156 ldd [%o1 + 0x070], %f12 >> 157 fsrc2 %f6, %f22 >> 158 add %o0, 0x40, %o0 >> 159 ldd [%o1 + 0x078], %f14 >> 160 fsrc2 %f8, %f24 >> 161 fsrc2 %f10, %f26 >> 162 fsrc2 %f12, %f28 >> 163 fsrc2 %f14, %f30 >> 164 stda %f16, [%o0] ASI_BLK_P >> 165 membar #Sync >> 166 VISExitHalf >> 167 ba,pt %xcc, 5f 229 nop 168 nop 230 169 231 ! Destination = 10 !! 170 9: 232 !! 171 VISEntry 233 .L_dest10: !! 172 ldub [%g6 + TI_FAULT_CODE], %g3 234 mov r2,r7 !! 173 mov %o0, %g1 235 shlr2 r7 !! 174 cmp %g3, 0 236 shlr r7 !! 175 rd %asi, %g3 237 tst r7,r7 !! 176 be,a,pt %icc, 1f 238 mov #7,r0 !! 177 wr %g0, ASI_BLK_P, %asi 239 bt/s 1f !! 178 wr %g0, ASI_BLK_COMMIT_P, %asi 240 and r0,r2 !! 179 1: ldda [%o1] ASI_BLK_P, %f0 241 2: !! 180 add %o1, 0x40, %o1 242 dt r7 !! 181 ldda [%o1] ASI_BLK_P, %f16 243 #ifdef CONFIG_CPU_LITTLE_ENDIAN !! 182 add %o1, 0x40, %o1 244 EX( mov.l @r5+,r0 ) !! 183 sethi %hi(PAGE_SIZE), %o2 245 EX( mov.l @r5+,r1 ) !! 184 1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14) 246 EX( mov.l @r5+,r8 ) !! 185 ldda [%o1] ASI_BLK_P, %f32 247 EX( mov.l @r5+,r9 ) !! 186 stda %f48, [%o0] %asi 248 EX( mov.l @r5+,r10 ) !! 187 add %o1, 0x40, %o1 249 EX( mov.w r0,@r4 ) !! 188 sub %o2, 0x40, %o2 250 add #2,r4 !! 189 add %o0, 0x40, %o0 251 xtrct r1,r0 !! 190 TOUCH(f16, f18, f20, f22, f24, f26, f28, f30) 252 xtrct r8,r1 !! 191 ldda [%o1] ASI_BLK_P, %f0 253 xtrct r9,r8 !! 192 stda %f48, [%o0] %asi 254 xtrct r10,r9 !! 193 add %o1, 0x40, %o1 255 !! 194 sub %o2, 0x40, %o2 256 EX( mov.l r0,@r4 ) !! 195 add %o0, 0x40, %o0 257 EX( mov.l r1,@(4,r4) ) !! 196 TOUCH(f32, f34, f36, f38, f40, f42, f44, f46) 258 EX( mov.l r8,@(8,r4) ) !! 197 ldda [%o1] ASI_BLK_P, %f16 259 EX( mov.l r9,@(12,r4) ) !! 198 stda %f48, [%o0] %asi 260 !! 199 sub %o2, 0x40, %o2 261 EX( mov.l @r5+,r1 ) !! 200 add %o1, 0x40, %o1 262 EX( mov.l @r5+,r8 ) !! 201 cmp %o2, PAGE_SIZE_REM 263 EX( mov.l @r5+,r0 ) !! 202 bne,pt %xcc, 1b 264 xtrct r1,r10 !! 203 add %o0, 0x40, %o0 265 xtrct r8,r1 !! 204 #if (PAGE_SHIFT == 16) 266 xtrct r0,r8 !! 205 TOUCH(f0, f2, f4, f6, f8, f10, f12, f14) 267 shlr16 r0 !! 206 ldda [%o1] ASI_BLK_P, %f32 268 EX( mov.l r10,@(16,r4) ) !! 207 stda %f48, [%o0] %asi 269 EX( mov.l r1,@(20,r4) ) !! 208 add %o1, 0x40, %o1 270 EX( mov.l r8,@(24,r4) ) !! 209 sub %o2, 0x40, %o2 271 EX( mov.w r0,@(28,r4) ) !! 210 add %o0, 0x40, %o0 272 bf/s 2b !! 211 TOUCH(f16, f18, f20, f22, f24, f26, f28, f30) 273 add #30,r4 !! 212 ldda [%o1] ASI_BLK_P, %f0 274 #else !! 213 stda %f48, [%o0] %asi 275 EX( mov.l @(28,r5),r0 ) !! 214 add %o1, 0x40, %o1 276 EX( mov.l @(24,r5),r8 ) !! 215 sub %o2, 0x40, %o2 277 EX( mov.l @(20,r5),r9 ) !! 216 add %o0, 0x40, %o0 278 EX( mov.l @(16,r5),r10 ) !! 217 membar #Sync 279 EX( mov.w r0,@(30,r4) ) !! 218 stda %f32, [%o0] %asi 280 add #-2,r4 !! 219 add %o0, 0x40, %o0 281 xtrct r8,r0 !! 220 stda %f0, [%o0] %asi 282 xtrct r9,r8 << 283 xtrct r10,r9 << 284 EX( mov.l r0,@(28,r4) ) << 285 EX( mov.l r8,@(24,r4) ) << 286 EX( mov.l r9,@(20,r4) ) << 287 << 288 EX( mov.l @(12,r5),r0 ) << 289 EX( mov.l @(8,r5),r8 ) << 290 xtrct r0,r10 << 291 EX( mov.l @(4,r5),r9 ) << 292 mov.l r10,@(16,r4) << 293 EX( mov.l @r5,r10 ) << 294 xtrct r8,r0 << 295 xtrct r9,r8 << 296 xtrct r10,r9 << 297 EX( mov.l r0,@(12,r4) ) << 298 EX( mov.l r8,@(8,r4) ) << 299 swap.w r10,r0 << 300 EX( mov.l r9,@(4,r4) ) << 301 EX( mov.w r0,@(2,r4) ) << 302 << 303 add #32,r5 << 304 bf/s 2b << 305 add #34,r4 << 306 #endif << 307 tst r2,r2 << 308 bt .L_cleanup << 309 << 310 1: ! Read longword, write two words per i << 311 EX( mov.l @r5+,r0 ) << 312 dt r2 << 313 #ifdef CONFIG_CPU_LITTLE_ENDIAN << 314 EX( mov.w r0,@r4 ) << 315 shlr16 r0 << 316 EX( mov.w r0,@(2,r4) ) << 317 #else 221 #else 318 EX( mov.w r0,@(2,r4) ) !! 222 membar #Sync 319 shlr16 r0 !! 223 stda %f0, [%o0] %asi 320 EX( mov.w r0,@r4 ) !! 224 add %o0, 0x40, %o0 >> 225 stda %f16, [%o0] %asi 321 #endif 226 #endif 322 bf/s 1b !! 227 membar #Sync 323 add #4,r4 !! 228 wr %g3, 0x0, %asi 324 !! 229 VISExit 325 bra .L_cleanup !! 230 >> 231 5: >> 232 stxa %g0, [%g1] ASI_DMMU_DEMAP >> 233 membar #Sync >> 234 >> 235 sethi %hi(DCACHE_SIZE), %g2 >> 236 stxa %g0, [%g1 + %g2] ASI_DMMU_DEMAP >> 237 membar #Sync >> 238 >> 239 retl >> 240 stw %o4, [%g6 + TI_PRE_COUNT] >> 241 >> 242 .size copy_user_page, .-copy_user_page >> 243 >> 244 .globl cheetah_patch_copy_page >> 245 cheetah_patch_copy_page: >> 246 sethi %hi(0x01000000), %o1 ! NOP >> 247 sethi %hi(cheetah_copy_page_insn), %o0 >> 248 or %o0, %lo(cheetah_copy_page_insn), %o0 >> 249 stw %o1, [%o0] >> 250 membar #StoreStore >> 251 flush %o0 >> 252 retl 326 nop 253 nop 327 << 328 ! Destination = 01 or 11 << 329 << 330 .L_dest01: << 331 .L_dest11: << 332 ! Read longword, write byte, word, byt << 333 EX( mov.l @r5+,r0 ) << 334 dt r2 << 335 #ifdef CONFIG_CPU_LITTLE_ENDIAN << 336 EX( mov.b r0,@r4 ) << 337 shlr8 r0 << 338 add #1,r4 << 339 EX( mov.w r0,@r4 ) << 340 shlr16 r0 << 341 EX( mov.b r0,@(2,r4) ) << 342 bf/s .L_dest01 << 343 add #3,r4 << 344 #else << 345 EX( mov.b r0,@(3,r4) ) << 346 shlr8 r0 << 347 swap.w r0,r7 << 348 EX( mov.b r7,@r4 ) << 349 add #1,r4 << 350 EX( mov.w r0,@r4 ) << 351 bf/s .L_dest01 << 352 add #3,r4 << 353 #endif << 354 << 355 ! Cleanup last few bytes << 356 .L_cleanup: << 357 mov r6,r0 << 358 and #3,r0 << 359 tst r0,r0 << 360 bt .L_exit << 361 mov r0,r6 << 362 << 363 .L_cleanup_loop: << 364 EX( mov.b @r5+,r0 ) << 365 dt r6 << 366 EX( mov.b r0,@r4 ) << 367 bf/s .L_cleanup_loop << 368 add #1,r4 << 369 << 370 .L_exit: << 371 mov #0,r0 ! normal retur << 372 << 373 5000: << 374 << 375 # Exception handler: << 376 .section .fixup, "ax" << 377 6000: << 378 mov.l 8000f,r1 << 379 mov r3,r0 << 380 jmp @r1 << 381 sub r4,r0 << 382 .align 2 << 383 8000: .long 5000b << 384 << 385 .previous << 386 mov.l @r15+,r8 << 387 mov.l @r15+,r9 << 388 mov.l @r15+,r10 << 389 rts << 390 mov.l @r15+,r11 <<
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.