Date: Fri, 10 Nov 2017 04:14:49 +0000 (UTC) From: Justin Hibbits <jhibbits@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r325628 - head/sys/powerpc/booke Message-ID: <201711100414.vAA4EnOd070425@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhibbits Date: Fri Nov 10 04:14:48 2017 New Revision: 325628 URL: https://svnweb.freebsd.org/changeset/base/325628 Log: Book-E pmap_mapdev_attr() improvements * Check TLB1 in all mapdev cases, in case the memattr matches an existing mapping (doesn't need to be MAP_DEFAULT). * Fix mapping where the starting address is not a multiple of the widest size base. For instance, it will now properly map 0xffffef000, size 0x11000 using 2 TLB entries, basing it at 0x****f000, instead of 0x***00000. MFC after: 2 weeks Modified: head/sys/powerpc/booke/pmap.c Modified: head/sys/powerpc/booke/pmap.c ============================================================================== --- head/sys/powerpc/booke/pmap.c Fri Nov 10 02:09:37 2017 (r325627) +++ head/sys/powerpc/booke/pmap.c Fri Nov 10 04:14:48 2017 (r325628) @@ -3471,16 +3471,17 @@ mmu_booke_mapdev_attr(mmu_t mmu, vm_paddr_t pa, vm_siz * check whether a sequence of TLB1 entries exist that match the * requirement, but now only checks the easy case. */ - if (ma == VM_MEMATTR_DEFAULT) { - for (i = 0; i < TLB1_ENTRIES; i++) { - tlb1_read_entry(&e, i); - if (!(e.mas1 & MAS1_VALID)) - continue; - if (pa >= e.phys && - (pa + size) <= (e.phys + e.size)) - return (void *)(e.virt + - (vm_offset_t)(pa - e.phys)); - } + for (i = 0; i < TLB1_ENTRIES; i++) { + tlb1_read_entry(&e, i); + if (!(e.mas1 & MAS1_VALID)) + continue; + if (pa >= e.phys && + (pa + size) <= (e.phys + e.size) && + (ma == VM_MEMATTR_DEFAULT || + tlb_calc_wimg(pa, ma) == + (e.mas2 & (MAS2_WIMGE_MASK & ~_TLB_ENTRY_SHARED)))) + return (void *)(e.virt + + (vm_offset_t)(pa - e.phys)); } size = roundup(size, PAGE_SIZE); @@ -3494,10 +3495,19 @@ mmu_booke_mapdev_attr(mmu_t mmu, vm_paddr_t pa, vm_siz * With a sparse mapdev, align to the largest starting region. This * could feasibly be optimized for a 'best-fit' alignment, but that * calculation could be very costly. + * Align to the smaller of: + * - first set bit in overlap of (pa & size mask) + * - largest size envelope + * + * It's possible the device mapping may start at a PA that's not larger + * than the size mask, so we need to offset in to maximize the TLB entry + * range and minimize the number of used TLB entries. */ do { tmpva = tlb1_map_base; - va = roundup(tlb1_map_base, 1 << flsl(size)); + sz = ffsl(((1 << flsl(size-1)) - 1) & pa); + sz = sz ? min(roundup(sz + 3, 4), flsl(size) - 1) : flsl(size) - 1; + va = roundup(tlb1_map_base, 1 << sz) | (((1 << sz) - 1) & pa); #ifdef __powerpc64__ } while (!atomic_cmpset_long(&tlb1_map_base, tmpva, va + size)); #else @@ -3514,6 +3524,13 @@ mmu_booke_mapdev_attr(mmu_t mmu, vm_paddr_t pa, vm_siz do { sz = 1 << (ilog2(size) & ~1); + /* Align size to PA */ + if (pa % sz != 0) { + do { + sz >>= 2; + } while (pa % sz != 0); + } + /* Now align from there to VA */ if (va % sz != 0) { do { sz >>= 2; @@ -3522,8 +3539,9 @@ mmu_booke_mapdev_attr(mmu_t mmu, vm_paddr_t pa, vm_siz if (bootverbose) printf("Wiring VA=%lx to PA=%jx (size=%lx)\n", va, (uintmax_t)pa, sz); - tlb1_set_entry(va, pa, sz, - _TLB_ENTRY_SHARED | tlb_calc_wimg(pa, ma)); + if (tlb1_set_entry(va, pa, sz, + _TLB_ENTRY_SHARED | tlb_calc_wimg(pa, ma)) < 0) + return (NULL); size -= sz; pa += sz; va += sz;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201711100414.vAA4EnOd070425>