powerpc/mm/32s: add setibat() clearibat() and update_bats()
authorChristophe Leroy <christophe.leroy@c-s.fr>
Thu, 21 Feb 2019 19:08:48 +0000 (19:08 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 23 Feb 2019 10:04:32 +0000 (21:04 +1100)
setibat() and clearibat() allows to manipulate IBATs independently
of DBATs.

update_bats() allows to update bats after init. This is done
with MMU off.

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/book3s/32/mmu-hash.h
arch/powerpc/kernel/head_32.S
arch/powerpc/mm/ppc_mmu_32.c

index 0c261ba2c8263b1e8dbb2afe4408511215330f9e..5cb588395fdcfdc7044dcecd0b3bcf9ecd89d73c 100644 (file)
@@ -92,6 +92,8 @@ typedef struct {
        unsigned long vdso_base;
 } mm_context_t;
 
+void update_bats(void);
+
 /* patch sites */
 extern s32 patch__hash_page_A0, patch__hash_page_A1, patch__hash_page_A2;
 extern s32 patch__hash_page_B, patch__hash_page_C;
index fdb587c96a80d293fbd400d0d2d9ebff588915aa..613900bb8c39412893eca20b1bbf2586fc2c10ae 100644 (file)
@@ -1096,6 +1096,41 @@ BEGIN_MMU_FTR_SECTION
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
        blr
 
+_ENTRY(update_bats)
+       lis     r4, 1f@h
+       ori     r4, r4, 1f@l
+       tophys(r4, r4)
+       mfmsr   r6
+       mflr    r7
+       li      r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)
+       rlwinm  r0, r6, 0, ~MSR_RI
+       rlwinm  r0, r0, 0, ~MSR_EE
+       mtmsr   r0
+       mtspr   SPRN_SRR0, r4
+       mtspr   SPRN_SRR1, r3
+       SYNC
+       RFI
+1:     bl      clear_bats
+       lis     r3, BATS@ha
+       addi    r3, r3, BATS@l
+       tophys(r3, r3)
+       LOAD_BAT(0, r3, r4, r5)
+       LOAD_BAT(1, r3, r4, r5)
+       LOAD_BAT(2, r3, r4, r5)
+       LOAD_BAT(3, r3, r4, r5)
+BEGIN_MMU_FTR_SECTION
+       LOAD_BAT(4, r3, r4, r5)
+       LOAD_BAT(5, r3, r4, r5)
+       LOAD_BAT(6, r3, r4, r5)
+       LOAD_BAT(7, r3, r4, r5)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+       li      r3, MSR_KERNEL & ~(MSR_IR | MSR_DR | MSR_RI)
+       mtmsr   r3
+       mtspr   SPRN_SRR0, r7
+       mtspr   SPRN_SRR1, r6
+       SYNC
+       RFI
+
 flush_tlbs:
        lis     r10, 0x40
 1:     addic.  r10, r10, -0x1000
index 9225da8bae4c4a4d58828e735731c944dda90649..7b011280d0762518e68d9b85327e03d786aacd16 100644 (file)
@@ -106,6 +106,38 @@ static unsigned int block_size(unsigned long base, unsigned long top)
        return min3(max_size, 1U << base_shift, 1U << block_shift);
 }
 
+/*
+ * Set up one of the IBAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ * Only for 603+ ...
+ */
+static void setibat(int index, unsigned long virt, phys_addr_t phys,
+                   unsigned int size, pgprot_t prot)
+{
+       unsigned int bl = (size >> 17) - 1;
+       int wimgxpp;
+       struct ppc_bat *bat = BATS[index];
+       unsigned long flags = pgprot_val(prot);
+
+       if (!cpu_has_feature(CPU_FTR_NEED_COHERENT))
+               flags &= ~_PAGE_COHERENT;
+
+       wimgxpp = (flags & _PAGE_COHERENT) | (_PAGE_EXEC ? BPP_RX : BPP_XX);
+       bat[0].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+       bat[0].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
+       if (flags & _PAGE_USER)
+               bat[0].batu |= 1;       /* Vp = 1 */
+}
+
+static void clearibat(int index)
+{
+       struct ppc_bat *bat = BATS[index];
+
+       bat[0].batu = 0;
+       bat[0].batl = 0;
+}
+
 unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
 {
        int idx;