[intel][vulkan] Use "softpin" for magma

Anvil performs the GPU address space management.
Add config parameter softpin_extra_page_count to accomodate
magma system driver's inter-mapping spacing.

MA-465 #comment

Test:
nuc:go/magma-tps#L1
nuc:go/magma-tps#S1
nuc:go/magma-tps#C0
nuc:go/magma-tps#P0

Change-Id: Idca3f2dce9241f322ff7710d77fd229de1a22ee6
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 83e82c4..3eed140 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -409,7 +409,8 @@
                               anv_gem_supports_syncobj_wait(fd);
    device->has_context_priority = anv_gem_has_context_priority(fd);
 
-   device->use_softpin = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_SOFTPIN)
+   device->softpin_extra_page_count = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_SOFTPIN);
+   device->use_softpin = device->softpin_extra_page_count
       && device->supports_48bit_addresses;
 
    device->has_context_isolation =
@@ -2098,22 +2099,25 @@
 
    bo->offset = 0;
 
+   const uint32_t page_size = 4096;
+   uint64_t size = bo->size + device->instance->physicalDevice.softpin_extra_page_count * page_size;
+
    if (bo->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS &&
-       device->vma_hi_available >= bo->size) {
-      uint64_t addr = util_vma_heap_alloc(&device->vma_hi, bo->size, 4096);
+       device->vma_hi_available >= size) {
+      uint64_t addr = util_vma_heap_alloc(&device->vma_hi, size, 4096);
       if (addr) {
          bo->offset = gen_canonical_address(addr);
          assert(addr == gen_48b_address(bo->offset));
-         device->vma_hi_available -= bo->size;
+         device->vma_hi_available -= size;
       }
    }
 
-   if (bo->offset == 0 && device->vma_lo_available >= bo->size) {
-      uint64_t addr = util_vma_heap_alloc(&device->vma_lo, bo->size, 4096);
+   if (bo->offset == 0 && device->vma_lo_available >= size) {
+      uint64_t addr = util_vma_heap_alloc(&device->vma_lo, size, 4096);
       if (addr) {
          bo->offset = gen_canonical_address(addr);
          assert(addr == gen_48b_address(bo->offset));
-         device->vma_lo_available -= bo->size;
+         device->vma_lo_available -= size;
       }
    }
 
@@ -2132,15 +2136,17 @@
 
    pthread_mutex_lock(&device->vma_mutex);
 
+   uint64_t size = bo->size + device->instance->physicalDevice.softpin_extra_page_count * 4096;
+
    if (addr_48b >= LOW_HEAP_MIN_ADDRESS &&
        addr_48b <= LOW_HEAP_MAX_ADDRESS) {
-      util_vma_heap_free(&device->vma_lo, addr_48b, bo->size);
-      device->vma_lo_available += bo->size;
+      util_vma_heap_free(&device->vma_lo, addr_48b, size);
+      device->vma_lo_available += size;
    } else {
       assert(addr_48b >= HIGH_HEAP_MIN_ADDRESS &&
              addr_48b <= HIGH_HEAP_MAX_ADDRESS);
-      util_vma_heap_free(&device->vma_hi, addr_48b, bo->size);
-      device->vma_hi_available += bo->size;
+      util_vma_heap_free(&device->vma_hi, addr_48b, size);
+      device->vma_hi_available += size;
    }
 
    pthread_mutex_unlock(&device->vma_mutex);
diff --git a/src/intel/vulkan/anv_magma.c b/src/intel/vulkan/anv_magma.c
index c90c740..494903b 100644
--- a/src/intel/vulkan/anv_magma.c
+++ b/src/intel/vulkan/anv_magma.c
@@ -29,14 +29,7 @@
       return -1;
    }
 
-   uint64_t extra_page_count;
-   status = magma_query(device->fd, kMsdIntelGenQueryExtraPageCount, &extra_page_count);
-   if (status != MAGMA_STATUS_OK) {
-      DLOG("magma_query failed: %d", status);
-      return -1;
-   }
-
-   device->connection = AnvMagmaCreateConnection(connection, extra_page_count);
+   device->connection = AnvMagmaCreateConnection(connection);
 
    DLOG("created magma connection");
    return 0;
@@ -214,6 +207,17 @@
    case I915_PARAM_HAS_EXEC_FENCE_ARRAY: // Used for semaphores
       value = 1;
       break;
+   case I915_PARAM_HAS_EXEC_SOFTPIN: {
+      // client driver manages GPU address space
+      uint64_t extra_page_count = 0;
+      status = magma_query(fd, kMsdIntelGenQueryExtraPageCount, &extra_page_count);
+      if (status != MAGMA_STATUS_OK) {
+         DLOG("magma_query failed: %d", status);
+         break;
+      }
+      value = extra_page_count;
+      break;
+   }
    default:
       status = MAGMA_STATUS_INVALID_ARGS;
    }
@@ -396,7 +400,8 @@
    ANV_FROM_HANDLE(anv_device, device, vk_device);
    ANV_FROM_HANDLE(anv_device_memory, memory, pGetZirconHandleInfo->memory);
 
-   assert(pGetZirconHandleInfo->sType == VK_STRUCTURE_TYPE_TEMP_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA);
+   assert(pGetZirconHandleInfo->sType ==
+          VK_STRUCTURE_TYPE_TEMP_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA);
    assert(pGetZirconHandleInfo->handleType ==
           VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA);
 
diff --git a/src/intel/vulkan/anv_magma.h b/src/intel/vulkan/anv_magma.h
index beface5..c225391 100644
--- a/src/intel/vulkan/anv_magma.h
+++ b/src/intel/vulkan/anv_magma.h
@@ -31,8 +31,7 @@
 #endif
 
 // Transfer ownership of the |connection|.
-struct anv_connection* AnvMagmaCreateConnection(magma_connection_t connection,
-                                                uint64_t extra_page_count);
+struct anv_connection* AnvMagmaCreateConnection(magma_connection_t connection);
 
 void AnvMagmaReleaseConnection(struct anv_connection* connection);
 
diff --git a/src/intel/vulkan/anv_magma_connection.cc b/src/intel/vulkan/anv_magma_connection.cc
index 8f63954..5810647 100644
--- a/src/intel/vulkan/anv_magma_connection.cc
+++ b/src/intel/vulkan/anv_magma_connection.cc
@@ -4,13 +4,12 @@
 
 #include "anv_magma.h"
 #include "drm_command_buffer.h"
+#include "gen_gem.h"
 #include "magma_sysmem.h"
 #include "magma_util/inflight_list.h"
 #include "magma_util/macros.h"
-#include "magma_util/simple_allocator.h"
 #include <chrono>
-#include <limits.h>
-#include <mutex>
+#include <map>
 #include <vector>
 
 class Buffer : public anv_magma_buffer {
@@ -29,43 +28,35 @@
 
    void AddMapping(uint64_t page_offset, uint64_t page_count, uint64_t addr)
    {
-      mappings_.push_back({addr, page_offset, page_count});
+      mappings_[addr] = {page_offset, page_count};
    }
 
-   bool HasMapping(uint64_t page_offset, uint64_t page_count, uint64_t* addr_out)
-   {
-      for (auto& mapping : mappings_) {
-         if (mapping.page_offset == page_offset && mapping.page_count == page_count) {
-            if (addr_out) {
-               *addr_out = mapping.addr;
-            }
-            return true;
-         }
-      }
-      return false;
-   }
-
-   struct Mapping {
-      uint64_t addr = 0;
+   struct Segment {
       uint64_t page_offset = 0;
       uint64_t page_count = 0;
    };
 
-   void TakeMappings(std::vector<Mapping>* mappings_out)
+   bool HasMapping(uint64_t addr, Segment* segment_out) const
    {
-      *mappings_out = std::move(mappings_);
-      mappings_.clear();
+      auto iter = mappings_.find(addr);
+      if (iter != mappings_.end()) {
+         if (segment_out) {
+            *segment_out = iter->second;
+         }
+         return true;
+      }
+      return false;
    }
 
+   void RemoveMapping(uint64_t addr) { mappings_.erase(addr); }
+
 private:
-   std::vector<Mapping> mappings_;
+   std::map<uint64_t, Segment> mappings_;
 };
 
 class Connection : public anv_connection {
 public:
-   Connection(magma_connection_t magma_connection, uint64_t guard_page_count)
-       : allocator_(magma::SimpleAllocator::Create(0, 1ull << 48)),
-         guard_page_count_(guard_page_count)
+   Connection(magma_connection_t magma_connection)
    {
       anv_connection::connection = magma_connection;
    }
@@ -82,30 +73,6 @@
 
    magma::InflightList* inflight_list() { return &inflight_list_; }
 
-   uint64_t guard_page_count() const { return guard_page_count_; }
-
-   bool MapGpu(uint64_t page_count, uint64_t* gpu_addr_out)
-   {
-      std::lock_guard<std::mutex> lock(allocator_mutex_);
-
-      uint64_t length = (page_count + guard_page_count_) * magma::page_size();
-
-      if (length > allocator_->size())
-         return DRETF(false, "length (0x%lx) > address space size (0x%lx)", length,
-                      allocator_->size());
-
-      if (!allocator_->Alloc(length, magma::page_shift(), gpu_addr_out))
-         return DRETF(false, "failed to allocate gpu address");
-
-      return true;
-   }
-
-   void UnmapGpu(uint64_t gpu_addr)
-   {
-      std::lock_guard<std::mutex> lock(allocator_mutex_);
-      allocator_->Free(gpu_addr);
-   }
-
    magma_status_t GetSysmemConnection(magma_sysmem_connection_t* sysmem_connection_out)
    {
       if (!sysmem_connection_) {
@@ -125,15 +92,11 @@
 private:
    magma_sysmem_connection_t sysmem_connection_{};
    magma::InflightList inflight_list_;
-   std::unique_ptr<magma::AddressSpaceAllocator> allocator_;
-   // Protect the allocator from simultaneous Map and Unmap from different threads
-   std::mutex allocator_mutex_;
-   uint64_t guard_page_count_;
 };
 
-anv_connection* AnvMagmaCreateConnection(magma_connection_t connection, uint64_t extra_page_count)
+anv_connection* AnvMagmaCreateConnection(magma_connection_t connection)
 {
-   return new Connection(connection, extra_page_count);
+   return new Connection(connection);
 }
 
 void AnvMagmaReleaseConnection(anv_connection* connection)
@@ -195,16 +158,26 @@
       if (!magma::is_page_aligned(offset))
          return DRET_MSG(-1, "offset (0x%lx) not page aligned", offset);
 
+      uint64_t gpu_addr = gen_48b_address(exec_objects[i].offset);
       uint64_t page_offset = offset / magma::page_size();
       uint64_t page_count =
           magma::round_up(exec_objects[i].rsvd2, magma::page_size()) / magma::page_size();
 
-      if (!buffer->HasMapping(page_offset, page_count, nullptr)) {
-         uint64_t gpu_addr;
-         if (!Connection::cast(connection)->MapGpu(page_count, &gpu_addr))
-            return DRET_MSG(-1, "failed to map gpu addr");
+      Buffer::Segment segment;
+      bool has_mapping = buffer->HasMapping(gpu_addr, &segment);
+      if (has_mapping) {
+         assert(page_offset == segment.page_offset);
+         if (page_count > segment.page_count) {
+            // Growing an existing mapping.
+            buffer->RemoveMapping(gpu_addr);
+            has_mapping = false;
+         } else {
+            assert(page_count == segment.page_count);
+         }
+      }
 
-         DLOG("mapping to gpu addr %lu: id %lu page_offset %lu page_count %lu\n", gpu_addr,
+      if (!has_mapping) {
+         DLOG("mapping to gpu addr 0x%lx: id %lu page_offset %lu page_count %lu", gpu_addr,
               buffer_ids[i], page_offset, page_count);
          magma_map_buffer_gpu(Connection::cast(connection)->magma_connection(), buffer->get(),
                               page_offset, page_count, gpu_addr, 0);
@@ -280,15 +253,6 @@
 {
    auto buffer = static_cast<Buffer*>(anv_buffer);
    // Hardware mappings are released when the buffer is released.
-   // Do this before unmapping to avoid remap before release.
    buffer->release(Connection::cast(connection)->magma_connection());
-
-   std::vector<Buffer::Mapping> mappings;
-   buffer->TakeMappings(&mappings);
-   // Each Unmap takes a lock, however multiple mappings per buffer is rare
-   for (auto& mapping : mappings) {
-      Connection::cast(connection)->UnmapGpu(mapping.addr);
-   }
-
    delete buffer;
 }
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index fce08c4..38ce859 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -873,6 +873,7 @@
     bool                                        has_context_priority;
     bool                                        use_softpin;
     bool                                        has_context_isolation;
+    uint32_t                                    softpin_extra_page_count;
 
     struct anv_device_extension_table           supported_extensions;