Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  * This file contains miscellaneous low-level functions.
0004  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
0005  *
0006  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
0007  * and Paul Mackerras.
0008  *
0009  */
0010 
0011 #include <linux/sys.h>
0012 #include <asm/unistd.h>
0013 #include <asm/errno.h>
0014 #include <asm/reg.h>
0015 #include <asm/page.h>
0016 #include <asm/cache.h>
0017 #include <asm/cputable.h>
0018 #include <asm/mmu.h>
0019 #include <asm/ppc_asm.h>
0020 #include <asm/thread_info.h>
0021 #include <asm/asm-offsets.h>
0022 #include <asm/processor.h>
0023 #include <asm/bug.h>
0024 #include <asm/ptrace.h>
0025 #include <asm/export.h>
0026 #include <asm/feature-fixups.h>
0027 
0028     .text
0029 
0030 /*
0031  * This returns the high 64 bits of the product of two 64-bit numbers.
0032  */
0033 _GLOBAL(mulhdu)
0034     cmpwi   r6,0
0035     cmpwi   cr1,r3,0
0036     mr  r10,r4
0037     mulhwu  r4,r4,r5
0038     beq 1f
0039     mulhwu  r0,r10,r6
0040     mullw   r7,r10,r5
0041     addc    r7,r0,r7
0042     addze   r4,r4
0043 1:  beqlr   cr1     /* all done if high part of A is 0 */
0044     mullw   r9,r3,r5
0045     mulhwu  r10,r3,r5
0046     beq 2f
0047     mullw   r0,r3,r6
0048     mulhwu  r8,r3,r6
0049     addc    r7,r0,r7
0050     adde    r4,r4,r8
0051     addze   r10,r10
0052 2:  addc    r4,r4,r9
0053     addze   r3,r10
0054     blr
0055 
0056 /*
0057  * reloc_got2 runs through the .got2 section adding an offset
0058  * to each entry.
0059  */
0060 _GLOBAL(reloc_got2)
0061     mflr    r11
0062     lis r7,__got2_start@ha
0063     addi    r7,r7,__got2_start@l
0064     lis r8,__got2_end@ha
0065     addi    r8,r8,__got2_end@l
0066     subf    r8,r7,r8
0067     srwi.   r8,r8,2
0068     beqlr
0069     mtctr   r8
0070     bcl 20,31,$+4
0071 1:  mflr    r0
0072     lis r4,1b@ha
0073     addi    r4,r4,1b@l
0074     subf    r0,r4,r0
0075     add r7,r0,r7
0076 2:  lwz r0,0(r7)
0077     add r0,r0,r3
0078     stw r0,0(r7)
0079     addi    r7,r7,4
0080     bdnz    2b
0081     mtlr    r11
0082     blr
0083 
0084 /*
0085  * call_setup_cpu - call the setup_cpu function for this cpu
0086  * r3 = data offset, r24 = cpu number
0087  *
0088  * Setup function is called with:
0089  *   r3 = data offset
0090  *   r4 = ptr to CPU spec (relocated)
0091  */
0092 _GLOBAL(call_setup_cpu)
0093     addis   r4,r3,cur_cpu_spec@ha
0094     addi    r4,r4,cur_cpu_spec@l
0095     lwz r4,0(r4)
0096     add r4,r4,r3
0097     lwz r5,CPU_SPEC_SETUP(r4)
0098     cmpwi   0,r5,0
0099     add r5,r5,r3
0100     beqlr
0101     mtctr   r5
0102     bctr
0103 
0104 #if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_PPC_BOOK3S_32)
0105 
0106 /* This gets called by via-pmu.c to switch the PLL selection
0107  * on 750fx CPU. This function should really be moved to some
0108  * other place (as most of the cpufreq code in via-pmu
0109  */
0110 _GLOBAL(low_choose_750fx_pll)
0111     /* Clear MSR:EE */
0112     mfmsr   r7
0113     rlwinm  r0,r7,0,17,15
0114     mtmsr   r0
0115 
0116     /* If switching to PLL1, disable HID0:BTIC */
0117     cmplwi  cr0,r3,0
0118     beq 1f
0119     mfspr   r5,SPRN_HID0
0120     rlwinm  r5,r5,0,27,25
0121     sync
0122     mtspr   SPRN_HID0,r5
0123     isync
0124     sync
0125 
0126 1:
0127     /* Calc new HID1 value */
0128     mfspr   r4,SPRN_HID1    /* Build a HID1:PS bit from parameter */
0129     rlwinm  r5,r3,16,15,15  /* Clear out HID1:PS from value read */
0130     rlwinm  r4,r4,0,16,14   /* Could have I used rlwimi here ? */
0131     or  r4,r4,r5
0132     mtspr   SPRN_HID1,r4
0133 
0134 #ifdef CONFIG_SMP
0135     /* Store new HID1 image */
0136     lwz r6,TASK_CPU(r2)
0137     slwi    r6,r6,2
0138 #else
0139     li  r6, 0
0140 #endif
0141     addis   r6,r6,nap_save_hid1@ha
0142     stw r4,nap_save_hid1@l(r6)
0143 
0144     /* If switching to PLL0, enable HID0:BTIC */
0145     cmplwi  cr0,r3,0
0146     bne 1f
0147     mfspr   r5,SPRN_HID0
0148     ori r5,r5,HID0_BTIC
0149     sync
0150     mtspr   SPRN_HID0,r5
0151     isync
0152     sync
0153 
0154 1:
0155     /* Return */
0156     mtmsr   r7
0157     blr
0158 
0159 _GLOBAL(low_choose_7447a_dfs)
0160     /* Clear MSR:EE */
0161     mfmsr   r7
0162     rlwinm  r0,r7,0,17,15
0163     mtmsr   r0
0164     
0165     /* Calc new HID1 value */
0166     mfspr   r4,SPRN_HID1
0167     insrwi  r4,r3,1,9   /* insert parameter into bit 9 */
0168     sync
0169     mtspr   SPRN_HID1,r4
0170     sync
0171     isync
0172 
0173     /* Return */
0174     mtmsr   r7
0175     blr
0176 
0177 #endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_PPC_BOOK3S_32 */
0178 
0179 #ifdef CONFIG_40x
0180 
0181 /*
0182  * Do an IO access in real mode
0183  */
0184 _GLOBAL(real_readb)
0185     mfmsr   r7
0186     rlwinm  r0,r7,0,~MSR_DR
0187     sync
0188     mtmsr   r0
0189     sync
0190     isync
0191     lbz r3,0(r3)
0192     sync
0193     mtmsr   r7
0194     sync
0195     isync
0196     blr
0197 _ASM_NOKPROBE_SYMBOL(real_readb)
0198 
0199     /*
0200  * Do an IO access in real mode
0201  */
0202 _GLOBAL(real_writeb)
0203     mfmsr   r7
0204     rlwinm  r0,r7,0,~MSR_DR
0205     sync
0206     mtmsr   r0
0207     sync
0208     isync
0209     stb r3,0(r4)
0210     sync
0211     mtmsr   r7
0212     sync
0213     isync
0214     blr
0215 _ASM_NOKPROBE_SYMBOL(real_writeb)
0216 
0217 #endif /* CONFIG_40x */
0218 
0219 /*
0220  * Copy a whole page.  We use the dcbz instruction on the destination
0221  * to reduce memory traffic (it eliminates the unnecessary reads of
0222  * the destination into cache).  This requires that the destination
0223  * is cacheable.
0224  */
0225 #define COPY_16_BYTES       \
0226     lwz r6,4(r4);   \
0227     lwz r7,8(r4);   \
0228     lwz r8,12(r4);  \
0229     lwzu    r9,16(r4);  \
0230     stw r6,4(r3);   \
0231     stw r7,8(r3);   \
0232     stw r8,12(r3);  \
0233     stwu    r9,16(r3)
0234 
0235 _GLOBAL(copy_page)
0236     rlwinm  r5, r3, 0, L1_CACHE_BYTES - 1
0237     addi    r3,r3,-4
0238 
0239 0:  twnei   r5, 0   /* WARN if r3 is not cache aligned */
0240     EMIT_WARN_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING
0241 
0242     addi    r4,r4,-4
0243 
0244     li  r5,4
0245 
0246 #if MAX_COPY_PREFETCH > 1
0247     li  r0,MAX_COPY_PREFETCH
0248     li  r11,4
0249     mtctr   r0
0250 11: dcbt    r11,r4
0251     addi    r11,r11,L1_CACHE_BYTES
0252     bdnz    11b
0253 #else /* MAX_COPY_PREFETCH == 1 */
0254     dcbt    r5,r4
0255     li  r11,L1_CACHE_BYTES+4
0256 #endif /* MAX_COPY_PREFETCH */
0257     li  r0,PAGE_SIZE/L1_CACHE_BYTES - MAX_COPY_PREFETCH
0258     crclr   4*cr0+eq
0259 2:
0260     mtctr   r0
0261 1:
0262     dcbt    r11,r4
0263     dcbz    r5,r3
0264     COPY_16_BYTES
0265 #if L1_CACHE_BYTES >= 32
0266     COPY_16_BYTES
0267 #if L1_CACHE_BYTES >= 64
0268     COPY_16_BYTES
0269     COPY_16_BYTES
0270 #if L1_CACHE_BYTES >= 128
0271     COPY_16_BYTES
0272     COPY_16_BYTES
0273     COPY_16_BYTES
0274     COPY_16_BYTES
0275 #endif
0276 #endif
0277 #endif
0278     bdnz    1b
0279     beqlr
0280     crnot   4*cr0+eq,4*cr0+eq
0281     li  r0,MAX_COPY_PREFETCH
0282     li  r11,4
0283     b   2b
0284 EXPORT_SYMBOL(copy_page)
0285 
0286 /*
0287  * Extended precision shifts.
0288  *
0289  * Updated to be valid for shift counts from 0 to 63 inclusive.
0290  * -- Gabriel
0291  *
0292  * R3/R4 has 64 bit value
0293  * R5    has shift count
0294  * result in R3/R4
0295  *
0296  *  ashrdi3: arithmetic right shift (sign propagation)  
0297  *  lshrdi3: logical right shift
0298  *  ashldi3: left shift
0299  */
0300 _GLOBAL(__ashrdi3)
0301     subfic  r6,r5,32
0302     srw r4,r4,r5    # LSW = count > 31 ? 0 : LSW >> count
0303     addi    r7,r5,32    # could be xori, or addi with -32
0304     slw r6,r3,r6    # t1 = count > 31 ? 0 : MSW << (32-count)
0305     rlwinm  r8,r7,0,32  # t3 = (count < 32) ? 32 : 0
0306     sraw    r7,r3,r7    # t2 = MSW >> (count-32)
0307     or  r4,r4,r6    # LSW |= t1
0308     slw r7,r7,r8    # t2 = (count < 32) ? 0 : t2
0309     sraw    r3,r3,r5    # MSW = MSW >> count
0310     or  r4,r4,r7    # LSW |= t2
0311     blr
0312 EXPORT_SYMBOL(__ashrdi3)
0313 
0314 _GLOBAL(__ashldi3)
0315     subfic  r6,r5,32
0316     slw r3,r3,r5    # MSW = count > 31 ? 0 : MSW << count
0317     addi    r7,r5,32    # could be xori, or addi with -32
0318     srw r6,r4,r6    # t1 = count > 31 ? 0 : LSW >> (32-count)
0319     slw r7,r4,r7    # t2 = count < 32 ? 0 : LSW << (count-32)
0320     or  r3,r3,r6    # MSW |= t1
0321     slw r4,r4,r5    # LSW = LSW << count
0322     or  r3,r3,r7    # MSW |= t2
0323     blr
0324 EXPORT_SYMBOL(__ashldi3)
0325 
0326 _GLOBAL(__lshrdi3)
0327     subfic  r6,r5,32
0328     srw r4,r4,r5    # LSW = count > 31 ? 0 : LSW >> count
0329     addi    r7,r5,32    # could be xori, or addi with -32
0330     slw r6,r3,r6    # t1 = count > 31 ? 0 : MSW << (32-count)
0331     srw r7,r3,r7    # t2 = count < 32 ? 0 : MSW >> (count-32)
0332     or  r4,r4,r6    # LSW |= t1
0333     srw r3,r3,r5    # MSW = MSW >> count
0334     or  r4,r4,r7    # LSW |= t2
0335     blr
0336 EXPORT_SYMBOL(__lshrdi3)
0337 
0338 /*
0339  * 64-bit comparison: __cmpdi2(s64 a, s64 b)
0340  * Returns 0 if a < b, 1 if a == b, 2 if a > b.
0341  */
0342 _GLOBAL(__cmpdi2)
0343     cmpw    r3,r5
0344     li  r3,1
0345     bne 1f
0346     cmplw   r4,r6
0347     beqlr
0348 1:  li  r3,0
0349     bltlr
0350     li  r3,2
0351     blr
0352 EXPORT_SYMBOL(__cmpdi2)
0353 /*
0354  * 64-bit comparison: __ucmpdi2(u64 a, u64 b)
0355  * Returns 0 if a < b, 1 if a == b, 2 if a > b.
0356  */
0357 _GLOBAL(__ucmpdi2)
0358     cmplw   r3,r5
0359     li  r3,1
0360     bne 1f
0361     cmplw   r4,r6
0362     beqlr
0363 1:  li  r3,0
0364     bltlr
0365     li  r3,2
0366     blr
0367 EXPORT_SYMBOL(__ucmpdi2)
0368 
0369 _GLOBAL(__bswapdi2)
0370     rotlwi  r9,r4,8
0371     rotlwi  r10,r3,8
0372     rlwimi  r9,r4,24,0,7
0373     rlwimi  r10,r3,24,0,7
0374     rlwimi  r9,r4,24,16,23
0375     rlwimi  r10,r3,24,16,23
0376     mr      r3,r9
0377     mr      r4,r10
0378     blr
0379 EXPORT_SYMBOL(__bswapdi2)
0380 
0381 #ifdef CONFIG_SMP
0382 _GLOBAL(start_secondary_resume)
0383     /* Reset stack */
0384     rlwinm  r1, r1, 0, 0, 31 - THREAD_SHIFT
0385     addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
0386     li  r3,0
0387     stw r3,0(r1)        /* Zero the stack frame pointer */
0388     bl  start_secondary
0389     b   .
0390 #endif /* CONFIG_SMP */