]> Git Repo - linux.git/commitdiff
Merge tag 'powerpc-4.16-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
authorLinus Torvalds <[email protected]>
Wed, 28 Mar 2018 23:54:03 +0000 (13:54 -1000)
committerLinus Torvalds <[email protected]>
Wed, 28 Mar 2018 23:54:03 +0000 (13:54 -1000)
Pull powerpc fixes from Michael Ellerman:
 "Some more powerpc fixes for 4.16. Apologies if this is a bit big at
  rc7, but they're all reasonably important fixes. None are actually for
  new code, so they aren't indicative of 4.16 being in bad shape from
  our point of view.

   - Fix missing AT_BASE_PLATFORM (in auxv) when we're using a new
     firmware interface for describing CPU features.

   - Fix lost pending interrupts due to a race in our interrupt
     soft-masking code.

   - A workaround for a nest MMU bug with TLB invalidations on Power9.

   - A workaround for broadcast TLB invalidations on Power9.

   - Fix a bug in our instruction SLB miss handler, when handling bad
     addresses (eg. >= TASK_SIZE), which could corrupt non-volatile user
     GPRs.

  Thanks to: Aneesh Kumar K.V, Balbir Singh, Benjamin Herrenschmidt,
  Nicholas Piggin"

* tag 'powerpc-4.16-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/64s: Fix i-side SLB miss bad address handler saving nonvolatile GPRs
  powerpc/mm: Fixup tlbie vs store ordering issue on POWER9
  powerpc/mm/radix: Move the functions that does the actual tlbie closer
  powerpc/mm/radix: Remove unused code
  powerpc/mm: Workaround Nest MMU bug with TLB invalidations
  powerpc/mm: Add tracking of the number of coprocessors using a context
  powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened
  powerpc/64s: Fix NULL AT_BASE_PLATFORM when using DT CPU features

1  2 
arch/powerpc/kvm/book3s_64_mmu_radix.c

index 5cb4e4687107e1204667e3314bee2ce49de32de7,0837b9738d764c8e949902aecb02311443ffd626..5d9bafe9a37165bdfef6f5c0367b82904b6b1bd5
@@@ -157,6 -157,9 +157,9 @@@ static void kvmppc_radix_tlbie_page(str
        asm volatile("ptesync": : :"memory");
        asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
                     : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG))
+               asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
+                            : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
        asm volatile("ptesync": : :"memory");
  }
  
@@@ -195,12 -198,6 +198,12 @@@ static void kvmppc_pte_free(pte_t *ptep
        kmem_cache_free(kvm_pte_cache, ptep);
  }
  
 +/* Like pmd_huge() and pmd_large(), but works regardless of config options */
 +static inline int pmd_is_leaf(pmd_t pmd)
 +{
 +      return !!(pmd_val(pmd) & _PAGE_PTE);
 +}
 +
  static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
                             unsigned int level, unsigned long mmu_seq)
  {
        else
                new_pmd = pmd_alloc_one(kvm->mm, gpa);
  
 -      if (level == 0 && !(pmd && pmd_present(*pmd)))
 +      if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd)))
                new_ptep = kvmppc_pte_alloc();
  
        /* Check if we might have been invalidated; let the guest retry if so */
                new_pmd = NULL;
        }
        pmd = pmd_offset(pud, gpa);
 -      if (pmd_large(*pmd)) {
 -              /* Someone else has instantiated a large page here; retry */
 -              ret = -EAGAIN;
 -              goto out_unlock;
 -      }
 -      if (level == 1 && !pmd_none(*pmd)) {
 +      if (pmd_is_leaf(*pmd)) {
 +              unsigned long lgpa = gpa & PMD_MASK;
 +
 +              /*
 +               * If we raced with another CPU which has just put
 +               * a 2MB pte in after we saw a pte page, try again.
 +               */
 +              if (level == 0 && !new_ptep) {
 +                      ret = -EAGAIN;
 +                      goto out_unlock;
 +              }
 +              /* Valid 2MB page here already, remove it */
 +              old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd),
 +                                            ~0UL, 0, lgpa, PMD_SHIFT);
 +              kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT);
 +              if (old & _PAGE_DIRTY) {
 +                      unsigned long gfn = lgpa >> PAGE_SHIFT;
 +                      struct kvm_memory_slot *memslot;
 +                      memslot = gfn_to_memslot(kvm, gfn);
 +                      if (memslot && memslot->dirty_bitmap)
 +                              kvmppc_update_dirty_map(memslot,
 +                                                      gfn, PMD_SIZE);
 +              }
 +      } else if (level == 1 && !pmd_none(*pmd)) {
                /*
                 * There's a page table page here, but we wanted
                 * to install a large page.  Tell the caller and let
@@@ -436,24 -415,28 +439,24 @@@ int kvmppc_book3s_radix_page_fault(stru
        } else {
                page = pages[0];
                pfn = page_to_pfn(page);
 -              if (PageHuge(page)) {
 -                      page = compound_head(page);
 -                      pte_size <<= compound_order(page);
 +              if (PageCompound(page)) {
 +                      pte_size <<= compound_order(compound_head(page));
                        /* See if we can insert a 2MB large-page PTE here */
                        if (pte_size >= PMD_SIZE &&
 -                          (gpa & PMD_MASK & PAGE_MASK) ==
 -                          (hva & PMD_MASK & PAGE_MASK)) {
 +                          (gpa & (PMD_SIZE - PAGE_SIZE)) ==
 +                          (hva & (PMD_SIZE - PAGE_SIZE))) {
                                level = 1;
                                pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1);
                        }
                }
                /* See if we can provide write access */
                if (writing) {
 -                      /*
 -                       * We assume gup_fast has set dirty on the host PTE.
 -                       */
                        pgflags |= _PAGE_WRITE;
                } else {
                        local_irq_save(flags);
                        ptep = find_current_mm_pte(current->mm->pgd,
                                                   hva, NULL, NULL);
 -                      if (ptep && pte_write(*ptep) && pte_dirty(*ptep))
 +                      if (ptep && pte_write(*ptep))
                                pgflags |= _PAGE_WRITE;
                        local_irq_restore(flags);
                }
                pte = pfn_pte(pfn, __pgprot(pgflags));
                ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq);
        }
 -      if (ret == 0 || ret == -EAGAIN)
 -              ret = RESUME_GUEST;
  
        if (page) {
 -              /*
 -               * We drop pages[0] here, not page because page might
 -               * have been set to the head page of a compound, but
 -               * we have to drop the reference on the correct tail
 -               * page to match the get inside gup()
 -               */
 -              put_page(pages[0]);
 +              if (!ret && (pgflags & _PAGE_WRITE))
 +                      set_page_dirty_lock(page);
 +              put_page(page);
        }
 +
 +      if (ret == 0 || ret == -EAGAIN)
 +              ret = RESUME_GUEST;
        return ret;
  }
  
@@@ -661,7 -647,7 +664,7 @@@ void kvmppc_free_radix(struct kvm *kvm
                                continue;
                        pmd = pmd_offset(pud, 0);
                        for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) {
 -                              if (pmd_huge(*pmd)) {
 +                              if (pmd_is_leaf(*pmd)) {
                                        pmd_clear(pmd);
                                        continue;
                                }
This page took 0.068302 seconds and 4 git commands to generate.