LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/gt - gen8_ppgtt.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 379 0.0 %
Date: 2022-04-01 14:58:12 Functions: 0 14 0.0 %
Branches: 0 212 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: MIT
       2                 :            : /*
       3                 :            :  * Copyright © 2020 Intel Corporation
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <linux/log2.h>
       7                 :            : 
       8                 :            : #include "gen8_ppgtt.h"
       9                 :            : #include "i915_scatterlist.h"
      10                 :            : #include "i915_trace.h"
      11                 :            : #include "i915_vgpu.h"
      12                 :            : #include "intel_gt.h"
      13                 :            : #include "intel_gtt.h"
      14                 :            : 
      15                 :          0 : static u64 gen8_pde_encode(const dma_addr_t addr,
      16                 :            :                            const enum i915_cache_level level)
      17                 :            : {
      18                 :          0 :         u64 pde = addr | _PAGE_PRESENT | _PAGE_RW;
      19                 :            : 
      20         [ #  # ]:          0 :         if (level != I915_CACHE_NONE)
      21                 :            :                 pde |= PPAT_CACHED_PDE;
      22                 :            :         else
      23                 :          0 :                 pde |= PPAT_UNCACHED;
      24                 :            : 
      25                 :          0 :         return pde;
      26                 :            : }
      27                 :            : 
      28                 :          0 : static void gen8_ppgtt_notify_vgt(struct i915_ppgtt *ppgtt, bool create)
      29                 :            : {
      30                 :          0 :         struct drm_i915_private *i915 = ppgtt->vm.i915;
      31                 :          0 :         struct intel_uncore *uncore = ppgtt->vm.gt->uncore;
      32                 :          0 :         enum vgt_g2v_type msg;
      33                 :          0 :         int i;
      34                 :            : 
      35         [ #  # ]:          0 :         if (create)
      36                 :          0 :                 atomic_inc(px_used(ppgtt->pd)); /* never remove */
      37                 :            :         else
      38                 :          0 :                 atomic_dec(px_used(ppgtt->pd));
      39                 :            : 
      40                 :          0 :         mutex_lock(&i915->vgpu.lock);
      41                 :            : 
      42         [ #  # ]:          0 :         if (i915_vm_is_4lvl(&ppgtt->vm)) {
      43                 :          0 :                 const u64 daddr = px_dma(ppgtt->pd);
      44                 :            : 
      45                 :          0 :                 intel_uncore_write(uncore,
      46                 :            :                                    vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
      47                 :          0 :                 intel_uncore_write(uncore,
      48                 :          0 :                                    vgtif_reg(pdp[0].hi), upper_32_bits(daddr));
      49                 :            : 
      50                 :          0 :                 msg = create ?
      51         [ #  # ]:          0 :                         VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
      52                 :            :                         VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY;
      53                 :            :         } else {
      54         [ #  # ]:          0 :                 for (i = 0; i < GEN8_3LVL_PDPES; i++) {
      55         [ #  # ]:          0 :                         const u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
      56                 :            : 
      57                 :          0 :                         intel_uncore_write(uncore,
      58                 :          0 :                                            vgtif_reg(pdp[i].lo),
      59                 :            :                                            lower_32_bits(daddr));
      60                 :          0 :                         intel_uncore_write(uncore,
      61                 :          0 :                                            vgtif_reg(pdp[i].hi),
      62                 :          0 :                                            upper_32_bits(daddr));
      63                 :            :                 }
      64                 :            : 
      65                 :          0 :                 msg = create ?
      66         [ #  # ]:          0 :                         VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
      67                 :            :                         VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY;
      68                 :            :         }
      69                 :            : 
      70                 :            :         /* g2v_notify atomically (via hv trap) consumes the message packet. */
      71                 :          0 :         intel_uncore_write(uncore, vgtif_reg(g2v_notify), msg);
      72                 :            : 
      73                 :          0 :         mutex_unlock(&i915->vgpu.lock);
      74                 :          0 : }
      75                 :            : 
      76                 :            : /* Index shifts into the pagetable are offset by GEN8_PTE_SHIFT [12] */
      77                 :            : #define GEN8_PAGE_SIZE (SZ_4K) /* page and page-directory sizes are the same */
      78                 :            : #define GEN8_PTE_SHIFT (ilog2(GEN8_PAGE_SIZE))
      79                 :            : #define GEN8_PDES (GEN8_PAGE_SIZE / sizeof(u64))
      80                 :            : #define gen8_pd_shift(lvl) ((lvl) * ilog2(GEN8_PDES))
      81                 :            : #define gen8_pd_index(i, lvl) i915_pde_index((i), gen8_pd_shift(lvl))
      82                 :            : #define __gen8_pte_shift(lvl) (GEN8_PTE_SHIFT + gen8_pd_shift(lvl))
      83                 :            : #define __gen8_pte_index(a, lvl) i915_pde_index((a), __gen8_pte_shift(lvl))
      84                 :            : 
      85                 :            : #define as_pd(x) container_of((x), typeof(struct i915_page_directory), pt)
      86                 :            : 
      87                 :            : static inline unsigned int
      88                 :          0 : gen8_pd_range(u64 start, u64 end, int lvl, unsigned int *idx)
      89                 :            : {
      90                 :          0 :         const int shift = gen8_pd_shift(lvl);
      91                 :          0 :         const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);
      92                 :            : 
      93                 :          0 :         GEM_BUG_ON(start >= end);
      94                 :          0 :         end += ~mask >> gen8_pd_shift(1);
      95                 :            : 
      96                 :          0 :         *idx = i915_pde_index(start, shift);
      97   [ #  #  #  # ]:          0 :         if ((start ^ end) & mask)
      98                 :          0 :                 return GEN8_PDES - *idx;
      99                 :            :         else
     100                 :          0 :                 return i915_pde_index(end, shift) - *idx;
     101                 :            : }
     102                 :            : 
     103                 :          0 : static inline bool gen8_pd_contains(u64 start, u64 end, int lvl)
     104                 :            : {
     105                 :          0 :         const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);
     106                 :            : 
     107                 :          0 :         GEM_BUG_ON(start >= end);
     108   [ #  #  #  # ]:          0 :         return (start ^ end) & mask && (start & ~mask) == 0;
     109                 :            : }
     110                 :            : 
     111                 :          0 : static inline unsigned int gen8_pt_count(u64 start, u64 end)
     112                 :            : {
     113                 :          0 :         GEM_BUG_ON(start >= end);
     114                 :          0 :         if ((start ^ end) >> gen8_pd_shift(1))
     115                 :          0 :                 return GEN8_PDES - (start & (GEN8_PDES - 1));
     116                 :            :         else
     117                 :          0 :                 return end - start;
     118                 :            : }
     119                 :            : 
     120                 :            : static inline unsigned int
     121                 :          0 : gen8_pd_top_count(const struct i915_address_space *vm)
     122                 :            : {
     123                 :          0 :         unsigned int shift = __gen8_pte_shift(vm->top);
     124                 :          0 :         return (vm->total + (1ull << shift) - 1) >> shift;
     125                 :            : }
     126                 :            : 
     127                 :            : static inline struct i915_page_directory *
     128                 :          0 : gen8_pdp_for_page_index(struct i915_address_space * const vm, const u64 idx)
     129                 :            : {
     130                 :          0 :         struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
     131                 :            : 
     132   [ #  #  #  # ]:          0 :         if (vm->top == 2)
     133                 :          0 :                 return ppgtt->pd;
     134                 :            :         else
     135                 :          0 :                 return i915_pd_entry(ppgtt->pd, gen8_pd_index(idx, vm->top));
     136                 :            : }
     137                 :            : 
     138                 :            : static inline struct i915_page_directory *
     139                 :          0 : gen8_pdp_for_page_address(struct i915_address_space * const vm, const u64 addr)
     140                 :            : {
     141                 :          0 :         return gen8_pdp_for_page_index(vm, addr >> GEN8_PTE_SHIFT);
     142                 :            : }
     143                 :            : 
     144                 :          0 : static void __gen8_ppgtt_cleanup(struct i915_address_space *vm,
     145                 :            :                                  struct i915_page_directory *pd,
     146                 :            :                                  int count, int lvl)
     147                 :            : {
     148         [ #  # ]:          0 :         if (lvl) {
     149                 :          0 :                 void **pde = pd->entry;
     150                 :            : 
     151                 :          0 :                 do {
     152         [ #  # ]:          0 :                         if (!*pde)
     153                 :          0 :                                 continue;
     154                 :            : 
     155                 :          0 :                         __gen8_ppgtt_cleanup(vm, *pde, GEN8_PDES, lvl - 1);
     156         [ #  # ]:          0 :                 } while (pde++, --count);
     157                 :            :         }
     158                 :            : 
     159                 :          0 :         free_px(vm, pd);
     160                 :          0 : }
     161                 :            : 
     162                 :          0 : static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
     163                 :            : {
     164         [ #  # ]:          0 :         struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
     165                 :            : 
     166         [ #  # ]:          0 :         if (intel_vgpu_active(vm->i915))
     167                 :          0 :                 gen8_ppgtt_notify_vgt(ppgtt, false);
     168                 :            : 
     169                 :          0 :         __gen8_ppgtt_cleanup(vm, ppgtt->pd, gen8_pd_top_count(vm), vm->top);
     170                 :          0 :         free_scratch(vm);
     171                 :          0 : }
     172                 :            : 
     173                 :          0 : static u64 __gen8_ppgtt_clear(struct i915_address_space * const vm,
     174                 :            :                               struct i915_page_directory * const pd,
     175                 :            :                               u64 start, const u64 end, int lvl)
     176                 :            : {
     177                 :          0 :         const struct i915_page_scratch * const scratch = &vm->scratch[lvl];
     178                 :          0 :         unsigned int idx, len;
     179                 :            : 
     180                 :          0 :         GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);
     181                 :            : 
     182         [ #  # ]:          0 :         len = gen8_pd_range(start, end, lvl--, &idx);
     183                 :            :         DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
     184                 :            :             __func__, vm, lvl + 1, start, end,
     185                 :          0 :             idx, len, atomic_read(px_used(pd)));
     186                 :          0 :         GEM_BUG_ON(!len || len >= atomic_read(px_used(pd)));
     187                 :            : 
     188                 :          0 :         do {
     189                 :          0 :                 struct i915_page_table *pt = pd->entry[idx];
     190                 :            : 
     191   [ #  #  #  # ]:          0 :                 if (atomic_fetch_inc(&pt->used) >> gen8_pd_shift(1) &&
     192                 :            :                     gen8_pd_contains(start, end, lvl)) {
     193                 :            :                         DBG("%s(%p):{ lvl:%d, idx:%d, start:%llx, end:%llx } removing pd\n",
     194                 :          0 :                             __func__, vm, lvl + 1, idx, start, end);
     195                 :          0 :                         clear_pd_entry(pd, idx, scratch);
     196                 :          0 :                         __gen8_ppgtt_cleanup(vm, as_pd(pt), I915_PDES, lvl);
     197                 :          0 :                         start += (u64)I915_PDES << gen8_pd_shift(lvl);
     198                 :          0 :                         continue;
     199                 :            :                 }
     200                 :            : 
     201         [ #  # ]:          0 :                 if (lvl) {
     202                 :          0 :                         start = __gen8_ppgtt_clear(vm, as_pd(pt),
     203                 :            :                                                    start, end, lvl);
     204                 :            :                 } else {
     205                 :          0 :                         unsigned int count;
     206                 :          0 :                         u64 *vaddr;
     207                 :            : 
     208         [ #  # ]:          0 :                         count = gen8_pt_count(start, end);
     209                 :            :                         DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } removing pte\n",
     210                 :            :                             __func__, vm, lvl, start, end,
     211                 :            :                             gen8_pd_index(start, 0), count,
     212                 :          0 :                             atomic_read(&pt->used));
     213                 :          0 :                         GEM_BUG_ON(!count || count >= atomic_read(&pt->used));
     214                 :            : 
     215                 :          0 :                         vaddr = kmap_atomic_px(pt);
     216                 :          0 :                         memset64(vaddr + gen8_pd_index(start, 0),
     217                 :            :                                  vm->scratch[0].encode,
     218                 :            :                                  count);
     219                 :          0 :                         kunmap_atomic(vaddr);
     220                 :            : 
     221                 :          0 :                         atomic_sub(count, &pt->used);
     222                 :          0 :                         start += count;
     223                 :            :                 }
     224                 :            : 
     225         [ #  # ]:          0 :                 if (release_pd_entry(pd, idx, pt, scratch))
     226                 :          0 :                         free_px(vm, pt);
     227         [ #  # ]:          0 :         } while (idx++, --len);
     228                 :            : 
     229                 :          0 :         return start;
     230                 :            : }
     231                 :            : 
     232                 :          0 : static void gen8_ppgtt_clear(struct i915_address_space *vm,
     233                 :            :                              u64 start, u64 length)
     234                 :            : {
     235                 :          0 :         GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
     236                 :          0 :         GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
     237                 :          0 :         GEM_BUG_ON(range_overflows(start, length, vm->total));
     238                 :            : 
     239                 :          0 :         start >>= GEN8_PTE_SHIFT;
     240                 :          0 :         length >>= GEN8_PTE_SHIFT;
     241                 :          0 :         GEM_BUG_ON(length == 0);
     242                 :            : 
     243                 :          0 :         __gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
     244                 :          0 :                            start, start + length, vm->top);
     245                 :          0 : }
     246                 :            : 
     247                 :          0 : static int __gen8_ppgtt_alloc(struct i915_address_space * const vm,
     248                 :            :                               struct i915_page_directory * const pd,
     249                 :            :                               u64 * const start, const u64 end, int lvl)
     250                 :            : {
     251                 :          0 :         const struct i915_page_scratch * const scratch = &vm->scratch[lvl];
     252                 :          0 :         struct i915_page_table *alloc = NULL;
     253                 :          0 :         unsigned int idx, len;
     254                 :          0 :         int ret = 0;
     255                 :            : 
     256                 :          0 :         GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);
     257                 :            : 
     258         [ #  # ]:          0 :         len = gen8_pd_range(*start, end, lvl--, &idx);
     259                 :            :         DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
     260                 :            :             __func__, vm, lvl + 1, *start, end,
     261                 :          0 :             idx, len, atomic_read(px_used(pd)));
     262                 :          0 :         GEM_BUG_ON(!len || (idx + len - 1) >> gen8_pd_shift(1));
     263                 :            : 
     264                 :          0 :         spin_lock(&pd->lock);
     265                 :          0 :         GEM_BUG_ON(!atomic_read(px_used(pd))); /* Must be pinned! */
     266                 :          0 :         do {
     267                 :          0 :                 struct i915_page_table *pt = pd->entry[idx];
     268                 :            : 
     269         [ #  # ]:          0 :                 if (!pt) {
     270                 :          0 :                         spin_unlock(&pd->lock);
     271                 :            : 
     272                 :            :                         DBG("%s(%p):{ lvl:%d, idx:%d } allocating new tree\n",
     273                 :          0 :                             __func__, vm, lvl + 1, idx);
     274                 :            : 
     275                 :          0 :                         pt = fetch_and_zero(&alloc);
     276         [ #  # ]:          0 :                         if (lvl) {
     277         [ #  # ]:          0 :                                 if (!pt) {
     278                 :          0 :                                         pt = &alloc_pd(vm)->pt;
     279         [ #  # ]:          0 :                                         if (IS_ERR(pt)) {
     280                 :          0 :                                                 ret = PTR_ERR(pt);
     281                 :          0 :                                                 goto out;
     282                 :            :                                         }
     283                 :            :                                 }
     284                 :            : 
     285                 :          0 :                                 fill_px(pt, vm->scratch[lvl].encode);
     286                 :            :                         } else {
     287         [ #  # ]:          0 :                                 if (!pt) {
     288                 :          0 :                                         pt = alloc_pt(vm);
     289         [ #  # ]:          0 :                                         if (IS_ERR(pt)) {
     290                 :          0 :                                                 ret = PTR_ERR(pt);
     291                 :          0 :                                                 goto out;
     292                 :            :                                         }
     293                 :            :                                 }
     294                 :            : 
     295   [ #  #  #  # ]:          0 :                                 if (intel_vgpu_active(vm->i915) ||
     296         [ #  # ]:          0 :                                     gen8_pt_count(*start, end) < I915_PDES)
     297                 :          0 :                                         fill_px(pt, vm->scratch[lvl].encode);
     298                 :            :                         }
     299                 :            : 
     300                 :          0 :                         spin_lock(&pd->lock);
     301         [ #  # ]:          0 :                         if (likely(!pd->entry[idx]))
     302                 :          0 :                                 set_pd_entry(pd, idx, pt);
     303                 :            :                         else
     304                 :            :                                 alloc = pt, pt = pd->entry[idx];
     305                 :            :                 }
     306                 :            : 
     307         [ #  # ]:          0 :                 if (lvl) {
     308                 :          0 :                         atomic_inc(&pt->used);
     309                 :          0 :                         spin_unlock(&pd->lock);
     310                 :            : 
     311                 :          0 :                         ret = __gen8_ppgtt_alloc(vm, as_pd(pt),
     312                 :            :                                                  start, end, lvl);
     313         [ #  # ]:          0 :                         if (unlikely(ret)) {
     314         [ #  # ]:          0 :                                 if (release_pd_entry(pd, idx, pt, scratch))
     315                 :          0 :                                         free_px(vm, pt);
     316                 :          0 :                                 goto out;
     317                 :            :                         }
     318                 :            : 
     319                 :          0 :                         spin_lock(&pd->lock);
     320                 :          0 :                         atomic_dec(&pt->used);
     321                 :          0 :                         GEM_BUG_ON(!atomic_read(&pt->used));
     322                 :            :                 } else {
     323         [ #  # ]:          0 :                         unsigned int count = gen8_pt_count(*start, end);
     324                 :            : 
     325                 :            :                         DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } inserting pte\n",
     326                 :            :                             __func__, vm, lvl, *start, end,
     327                 :            :                             gen8_pd_index(*start, 0), count,
     328                 :          0 :                             atomic_read(&pt->used));
     329                 :            : 
     330                 :          0 :                         atomic_add(count, &pt->used);
     331                 :            :                         /* All other pdes may be simultaneously removed */
     332                 :          0 :                         GEM_BUG_ON(atomic_read(&pt->used) > NALLOC * I915_PDES);
     333                 :          0 :                         *start += count;
     334                 :            :                 }
     335         [ #  # ]:          0 :         } while (idx++, --len);
     336                 :          0 :         spin_unlock(&pd->lock);
     337                 :          0 : out:
     338         [ #  # ]:          0 :         if (alloc)
     339                 :          0 :                 free_px(vm, alloc);
     340                 :          0 :         return ret;
     341                 :            : }
     342                 :            : 
     343                 :          0 : static int gen8_ppgtt_alloc(struct i915_address_space *vm,
     344                 :            :                             u64 start, u64 length)
     345                 :            : {
     346                 :          0 :         u64 from;
     347                 :          0 :         int err;
     348                 :            : 
     349                 :          0 :         GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
     350                 :          0 :         GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
     351                 :          0 :         GEM_BUG_ON(range_overflows(start, length, vm->total));
     352                 :            : 
     353                 :          0 :         start >>= GEN8_PTE_SHIFT;
     354                 :          0 :         length >>= GEN8_PTE_SHIFT;
     355                 :          0 :         GEM_BUG_ON(length == 0);
     356                 :          0 :         from = start;
     357                 :            : 
     358                 :          0 :         err = __gen8_ppgtt_alloc(vm, i915_vm_to_ppgtt(vm)->pd,
     359                 :          0 :                                  &start, start + length, vm->top);
     360   [ #  #  #  # ]:          0 :         if (unlikely(err && from != start))
     361                 :          0 :                 __gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
     362                 :          0 :                                    from, start, vm->top);
     363                 :            : 
     364                 :          0 :         return err;
     365                 :            : }
     366                 :            : 
     367                 :            : static __always_inline u64
     368                 :          0 : gen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt,
     369                 :            :                       struct i915_page_directory *pdp,
     370                 :            :                       struct sgt_dma *iter,
     371                 :            :                       u64 idx,
     372                 :            :                       enum i915_cache_level cache_level,
     373                 :            :                       u32 flags)
     374                 :            : {
     375                 :          0 :         struct i915_page_directory *pd;
     376                 :          0 :         const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags);
     377                 :          0 :         gen8_pte_t *vaddr;
     378                 :            : 
     379                 :          0 :         pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2));
     380                 :          0 :         vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
     381                 :          0 :         do {
     382                 :          0 :                 GEM_BUG_ON(iter->sg->length < I915_GTT_PAGE_SIZE);
     383         [ #  # ]:          0 :                 vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma;
     384                 :            : 
     385                 :          0 :                 iter->dma += I915_GTT_PAGE_SIZE;
     386         [ #  # ]:          0 :                 if (iter->dma >= iter->max) {
     387         [ #  # ]:          0 :                         iter->sg = __sg_next(iter->sg);
     388         [ #  # ]:          0 :                         if (!iter->sg) {
     389                 :            :                                 idx = 0;
     390                 :            :                                 break;
     391                 :            :                         }
     392                 :            : 
     393                 :          0 :                         iter->dma = sg_dma_address(iter->sg);
     394                 :          0 :                         iter->max = iter->dma + iter->sg->length;
     395                 :            :                 }
     396                 :            : 
     397         [ #  # ]:          0 :                 if (gen8_pd_index(++idx, 0) == 0) {
     398         [ #  # ]:          0 :                         if (gen8_pd_index(idx, 1) == 0) {
     399                 :            :                                 /* Limited by sg length for 3lvl */
     400         [ #  # ]:          0 :                                 if (gen8_pd_index(idx, 2) == 0)
     401                 :            :                                         break;
     402                 :            : 
     403                 :          0 :                                 pd = pdp->entry[gen8_pd_index(idx, 2)];
     404                 :            :                         }
     405                 :            : 
     406                 :          0 :                         kunmap_atomic(vaddr);
     407                 :          0 :                         vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
     408                 :            :                 }
     409                 :            :         } while (1);
     410                 :          0 :         kunmap_atomic(vaddr);
     411                 :            : 
     412                 :          0 :         return idx;
     413                 :            : }
     414                 :            : 
     415                 :          0 : static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
     416                 :            :                                    struct sgt_dma *iter,
     417                 :            :                                    enum i915_cache_level cache_level,
     418                 :            :                                    u32 flags)
     419                 :            : {
     420                 :          0 :         const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags);
     421                 :          0 :         u64 start = vma->node.start;
     422                 :          0 :         dma_addr_t rem = iter->sg->length;
     423                 :            : 
     424                 :          0 :         GEM_BUG_ON(!i915_vm_is_4lvl(vma->vm));
     425                 :            : 
     426                 :          0 :         do {
     427                 :          0 :                 struct i915_page_directory * const pdp =
     428         [ #  # ]:          0 :                         gen8_pdp_for_page_address(vma->vm, start);
     429         [ #  # ]:          0 :                 struct i915_page_directory * const pd =
     430         [ #  # ]:          0 :                         i915_pd_entry(pdp, __gen8_pte_index(start, 2));
     431                 :          0 :                 gen8_pte_t encode = pte_encode;
     432                 :          0 :                 unsigned int maybe_64K = -1;
     433                 :          0 :                 unsigned int page_size;
     434                 :          0 :                 gen8_pte_t *vaddr;
     435                 :          0 :                 u16 index;
     436                 :            : 
     437         [ #  # ]:          0 :                 if (vma->page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
     438   [ #  #  #  # ]:          0 :                     IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
     439         [ #  # ]:          0 :                     rem >= I915_GTT_PAGE_SIZE_2M &&
     440                 :            :                     !__gen8_pte_index(start, 0)) {
     441                 :          0 :                         index = __gen8_pte_index(start, 1);
     442                 :          0 :                         encode |= GEN8_PDE_PS_2M;
     443                 :          0 :                         page_size = I915_GTT_PAGE_SIZE_2M;
     444                 :            : 
     445                 :          0 :                         vaddr = kmap_atomic_px(pd);
     446                 :            :                 } else {
     447         [ #  # ]:          0 :                         struct i915_page_table *pt =
     448         [ #  # ]:          0 :                                 i915_pt_entry(pd, __gen8_pte_index(start, 1));
     449                 :            : 
     450                 :          0 :                         index = __gen8_pte_index(start, 0);
     451                 :          0 :                         page_size = I915_GTT_PAGE_SIZE;
     452                 :            : 
     453   [ #  #  #  # ]:          0 :                         if (!index &&
     454                 :          0 :                             vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
     455         [ #  # ]:          0 :                             IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
     456   [ #  #  #  # ]:          0 :                             (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
     457                 :            :                              rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE))
     458                 :          0 :                                 maybe_64K = __gen8_pte_index(start, 1);
     459                 :            : 
     460                 :          0 :                         vaddr = kmap_atomic_px(pt);
     461                 :            :                 }
     462                 :            : 
     463                 :          0 :                 do {
     464                 :          0 :                         GEM_BUG_ON(iter->sg->length < page_size);
     465                 :          0 :                         vaddr[index++] = encode | iter->dma;
     466                 :            : 
     467                 :          0 :                         start += page_size;
     468                 :          0 :                         iter->dma += page_size;
     469                 :          0 :                         rem -= page_size;
     470         [ #  # ]:          0 :                         if (iter->dma >= iter->max) {
     471         [ #  # ]:          0 :                                 iter->sg = __sg_next(iter->sg);
     472         [ #  # ]:          0 :                                 if (!iter->sg)
     473                 :            :                                         break;
     474                 :            : 
     475                 :          0 :                                 rem = iter->sg->length;
     476                 :          0 :                                 iter->dma = sg_dma_address(iter->sg);
     477                 :          0 :                                 iter->max = iter->dma + rem;
     478                 :            : 
     479         [ #  # ]:          0 :                                 if (maybe_64K != -1 && index < I915_PDES &&
     480   [ #  #  #  # ]:          0 :                                     !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
     481                 :          0 :                                       (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
     482         [ #  # ]:          0 :                                        rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE)))
     483                 :          0 :                                         maybe_64K = -1;
     484                 :            : 
     485         [ #  # ]:          0 :                                 if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
     486                 :            :                                         break;
     487                 :            :                         }
     488   [ #  #  #  # ]:          0 :                 } while (rem >= page_size && index < I915_PDES);
     489                 :            : 
     490                 :          0 :                 kunmap_atomic(vaddr);
     491                 :            : 
     492                 :            :                 /*
     493                 :            :                  * Is it safe to mark the 2M block as 64K? -- Either we have
     494                 :            :                  * filled whole page-table with 64K entries, or filled part of
     495                 :            :                  * it and have reached the end of the sg table and we have
     496                 :            :                  * enough padding.
     497                 :            :                  */
     498   [ #  #  #  # ]:          0 :                 if (maybe_64K != -1 &&
     499         [ #  # ]:          0 :                     (index == I915_PDES ||
     500         [ #  # ]:          0 :                      (i915_vm_has_scratch_64K(vma->vm) &&
     501   [ #  #  #  # ]:          0 :                       !iter->sg && IS_ALIGNED(vma->node.start +
     502                 :            :                                               vma->node.size,
     503                 :            :                                               I915_GTT_PAGE_SIZE_2M)))) {
     504                 :          0 :                         vaddr = kmap_atomic_px(pd);
     505                 :          0 :                         vaddr[maybe_64K] |= GEN8_PDE_IPS_64K;
     506                 :          0 :                         kunmap_atomic(vaddr);
     507                 :          0 :                         page_size = I915_GTT_PAGE_SIZE_64K;
     508                 :            : 
     509                 :            :                         /*
     510                 :            :                          * We write all 4K page entries, even when using 64K
     511                 :            :                          * pages. In order to verify that the HW isn't cheating
     512                 :            :                          * by using the 4K PTE instead of the 64K PTE, we want
     513                 :            :                          * to remove all the surplus entries. If the HW skipped
     514                 :            :                          * the 64K PTE, it will read/write into the scratch page
     515                 :            :                          * instead - which we detect as missing results during
     516                 :            :                          * selftests.
     517                 :            :                          */
     518                 :          0 :                         if (I915_SELFTEST_ONLY(vma->vm->scrub_64K)) {
     519                 :            :                                 u16 i;
     520                 :            : 
     521                 :            :                                 encode = vma->vm->scratch[0].encode;
     522                 :            :                                 vaddr = kmap_atomic_px(i915_pt_entry(pd, maybe_64K));
     523                 :            : 
     524                 :            :                                 for (i = 1; i < index; i += 16)
     525                 :            :                                         memset64(vaddr + i, encode, 15);
     526                 :            : 
     527                 :          0 :                                 kunmap_atomic(vaddr);
     528                 :            :                         }
     529                 :            :                 }
     530                 :            : 
     531                 :          0 :                 vma->page_sizes.gtt |= page_size;
     532         [ #  # ]:          0 :         } while (iter->sg);
     533                 :          0 : }
     534                 :            : 
     535                 :          0 : static void gen8_ppgtt_insert(struct i915_address_space *vm,
     536                 :            :                               struct i915_vma *vma,
     537                 :            :                               enum i915_cache_level cache_level,
     538                 :            :                               u32 flags)
     539                 :            : {
     540         [ #  # ]:          0 :         struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
     541         [ #  # ]:          0 :         struct sgt_dma iter = sgt_dma(vma);
     542                 :            : 
     543         [ #  # ]:          0 :         if (vma->page_sizes.sg > I915_GTT_PAGE_SIZE) {
     544                 :          0 :                 gen8_ppgtt_insert_huge(vma, &iter, cache_level, flags);
     545                 :            :         } else  {
     546                 :          0 :                 u64 idx = vma->node.start >> GEN8_PTE_SHIFT;
     547                 :            : 
     548                 :          0 :                 do {
     549         [ #  # ]:          0 :                         struct i915_page_directory * const pdp =
     550                 :            :                                 gen8_pdp_for_page_index(vm, idx);
     551                 :            : 
     552                 :          0 :                         idx = gen8_ppgtt_insert_pte(ppgtt, pdp, &iter, idx,
     553                 :            :                                                     cache_level, flags);
     554         [ #  # ]:          0 :                 } while (idx);
     555                 :            : 
     556                 :          0 :                 vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
     557                 :            :         }
     558                 :          0 : }
     559                 :            : 
     560                 :          0 : static int gen8_init_scratch(struct i915_address_space *vm)
     561                 :            : {
     562                 :          0 :         int ret;
     563                 :          0 :         int i;
     564                 :            : 
     565                 :            :         /*
     566                 :            :          * If everybody agrees to not to write into the scratch page,
     567                 :            :          * we can reuse it for all vm, keeping contexts and processes separate.
     568                 :            :          */
     569   [ #  #  #  #  :          0 :         if (vm->has_read_only && vm->gt->vm && !i915_is_ggtt(vm->gt->vm)) {
                   #  # ]
     570                 :          0 :                 struct i915_address_space *clone = vm->gt->vm;
     571                 :            : 
     572                 :          0 :                 GEM_BUG_ON(!clone->has_read_only);
     573                 :            : 
     574                 :          0 :                 vm->scratch_order = clone->scratch_order;
     575                 :          0 :                 memcpy(vm->scratch, clone->scratch, sizeof(vm->scratch));
     576                 :          0 :                 px_dma(&vm->scratch[0]) = 0; /* no xfer of ownership */
     577                 :          0 :                 return 0;
     578                 :            :         }
     579                 :            : 
     580                 :          0 :         ret = setup_scratch_page(vm, __GFP_HIGHMEM);
     581         [ #  # ]:          0 :         if (ret)
     582                 :            :                 return ret;
     583                 :            : 
     584                 :          0 :         vm->scratch[0].encode =
     585                 :          0 :                 gen8_pte_encode(px_dma(&vm->scratch[0]),
     586                 :          0 :                                 I915_CACHE_LLC, vm->has_read_only);
     587                 :            : 
     588         [ #  # ]:          0 :         for (i = 1; i <= vm->top; i++) {
     589         [ #  # ]:          0 :                 if (unlikely(setup_page_dma(vm, px_base(&vm->scratch[i]))))
     590                 :          0 :                         goto free_scratch;
     591                 :            : 
     592                 :          0 :                 fill_px(&vm->scratch[i], vm->scratch[i - 1].encode);
     593                 :          0 :                 vm->scratch[i].encode =
     594                 :          0 :                         gen8_pde_encode(px_dma(&vm->scratch[i]),
     595                 :            :                                         I915_CACHE_LLC);
     596                 :            :         }
     597                 :            : 
     598                 :            :         return 0;
     599                 :            : 
     600                 :            : free_scratch:
     601                 :          0 :         free_scratch(vm);
     602                 :          0 :         return -ENOMEM;
     603                 :            : }
     604                 :            : 
     605                 :          0 : static int gen8_preallocate_top_level_pdp(struct i915_ppgtt *ppgtt)
     606                 :            : {
     607                 :          0 :         struct i915_address_space *vm = &ppgtt->vm;
     608                 :          0 :         struct i915_page_directory *pd = ppgtt->pd;
     609                 :          0 :         unsigned int idx;
     610                 :            : 
     611                 :          0 :         GEM_BUG_ON(vm->top != 2);
     612                 :          0 :         GEM_BUG_ON(gen8_pd_top_count(vm) != GEN8_3LVL_PDPES);
     613                 :            : 
     614         [ #  # ]:          0 :         for (idx = 0; idx < GEN8_3LVL_PDPES; idx++) {
     615                 :          0 :                 struct i915_page_directory *pde;
     616                 :            : 
     617                 :          0 :                 pde = alloc_pd(vm);
     618         [ #  # ]:          0 :                 if (IS_ERR(pde))
     619                 :          0 :                         return PTR_ERR(pde);
     620                 :            : 
     621                 :          0 :                 fill_px(pde, vm->scratch[1].encode);
     622                 :          0 :                 set_pd_entry(pd, idx, pde);
     623                 :          0 :                 atomic_inc(px_used(pde)); /* keep pinned */
     624                 :            :         }
     625                 :          0 :         wmb();
     626                 :            : 
     627                 :          0 :         return 0;
     628                 :            : }
     629                 :            : 
     630                 :            : static struct i915_page_directory *
     631                 :          0 : gen8_alloc_top_pd(struct i915_address_space *vm)
     632                 :            : {
     633                 :          0 :         const unsigned int count = gen8_pd_top_count(vm);
     634                 :          0 :         struct i915_page_directory *pd;
     635                 :            : 
     636                 :          0 :         GEM_BUG_ON(count > ARRAY_SIZE(pd->entry));
     637                 :            : 
     638                 :          0 :         pd = __alloc_pd(offsetof(typeof(*pd), entry[count]));
     639         [ #  # ]:          0 :         if (unlikely(!pd))
     640                 :            :                 return ERR_PTR(-ENOMEM);
     641                 :            : 
     642         [ #  # ]:          0 :         if (unlikely(setup_page_dma(vm, px_base(pd)))) {
     643                 :          0 :                 kfree(pd);
     644                 :          0 :                 return ERR_PTR(-ENOMEM);
     645                 :            :         }
     646                 :            : 
     647                 :          0 :         fill_page_dma(px_base(pd), vm->scratch[vm->top].encode, count);
     648                 :          0 :         atomic_inc(px_used(pd)); /* mark as pinned */
     649                 :          0 :         return pd;
     650                 :            : }
     651                 :            : 
     652                 :            : /*
     653                 :            :  * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
     654                 :            :  * with a net effect resembling a 2-level page table in normal x86 terms. Each
     655                 :            :  * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
     656                 :            :  * space.
     657                 :            :  *
     658                 :            :  */
     659                 :          0 : struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt)
     660                 :            : {
     661                 :          0 :         struct i915_ppgtt *ppgtt;
     662                 :          0 :         int err;
     663                 :            : 
     664                 :          0 :         ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
     665         [ #  # ]:          0 :         if (!ppgtt)
     666                 :            :                 return ERR_PTR(-ENOMEM);
     667                 :            : 
     668                 :          0 :         ppgtt_init(ppgtt, gt);
     669         [ #  # ]:          0 :         ppgtt->vm.top = i915_vm_is_4lvl(&ppgtt->vm) ? 3 : 2;
     670                 :            : 
     671                 :            :         /*
     672                 :            :          * From bdw, there is hw support for read-only pages in the PPGTT.
     673                 :            :          *
     674                 :            :          * Gen11 has HSDES#:1807136187 unresolved. Disable ro support
     675                 :            :          * for now.
     676                 :            :          *
     677                 :            :          * Gen12 has inherited the same read-only fault issue from gen11.
     678                 :            :          */
     679                 :          0 :         ppgtt->vm.has_read_only = !IS_GEN_RANGE(gt->i915, 11, 12);
     680                 :            : 
     681                 :            :         /*
     682                 :            :          * There are only few exceptions for gen >=6. chv and bxt.
     683                 :            :          * And we are not sure about the latter so play safe for now.
     684                 :            :          */
     685   [ #  #  #  # ]:          0 :         if (IS_CHERRYVIEW(gt->i915) || IS_BROXTON(gt->i915))
     686                 :          0 :                 ppgtt->vm.pt_kmap_wc = true;
     687                 :            : 
     688                 :          0 :         err = gen8_init_scratch(&ppgtt->vm);
     689         [ #  # ]:          0 :         if (err)
     690                 :          0 :                 goto err_free;
     691                 :            : 
     692                 :          0 :         ppgtt->pd = gen8_alloc_top_pd(&ppgtt->vm);
     693         [ #  # ]:          0 :         if (IS_ERR(ppgtt->pd)) {
     694                 :          0 :                 err = PTR_ERR(ppgtt->pd);
     695                 :          0 :                 goto err_free_scratch;
     696                 :            :         }
     697                 :            : 
     698         [ #  # ]:          0 :         if (!i915_vm_is_4lvl(&ppgtt->vm)) {
     699                 :          0 :                 err = gen8_preallocate_top_level_pdp(ppgtt);
     700         [ #  # ]:          0 :                 if (err)
     701                 :          0 :                         goto err_free_pd;
     702                 :            :         }
     703                 :            : 
     704                 :          0 :         ppgtt->vm.bind_async_flags = I915_VMA_LOCAL_BIND;
     705                 :          0 :         ppgtt->vm.insert_entries = gen8_ppgtt_insert;
     706                 :          0 :         ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc;
     707                 :          0 :         ppgtt->vm.clear_range = gen8_ppgtt_clear;
     708                 :            : 
     709         [ #  # ]:          0 :         if (intel_vgpu_active(gt->i915))
     710                 :          0 :                 gen8_ppgtt_notify_vgt(ppgtt, true);
     711                 :            : 
     712                 :          0 :         ppgtt->vm.cleanup = gen8_ppgtt_cleanup;
     713                 :            : 
     714                 :          0 :         return ppgtt;
     715                 :            : 
     716                 :            : err_free_pd:
     717                 :          0 :         __gen8_ppgtt_cleanup(&ppgtt->vm, ppgtt->pd,
     718                 :          0 :                              gen8_pd_top_count(&ppgtt->vm), ppgtt->vm.top);
     719                 :          0 : err_free_scratch:
     720                 :          0 :         free_scratch(&ppgtt->vm);
     721                 :          0 : err_free:
     722                 :          0 :         kfree(ppgtt);
     723                 :          0 :         return ERR_PTR(err);
     724                 :            : }

Generated by: LCOV version 1.14