1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host/magma/DrmBuffer.h"
16
17 #include <errno.h>
18 #include <i915_drm.h>
19 #include <sys/mman.h>
20
21 #include "host-common/logging.h"
22 #include "host/BlobManager.h"
23
24 namespace gfxstream {
25 namespace magma {
26
27 std::atomic_uint64_t DrmBuffer::mIdNext = 1000001;
28
DrmBuffer(DrmBuffer && other)29 DrmBuffer::DrmBuffer(DrmBuffer&& other) noexcept
30 : mDevice(other.mDevice),
31 mContextId(other.mContextId),
32 mGemHandle(other.mGemHandle),
33 mSize(other.mSize),
34 mHva(other.mHva),
35 mId(other.mId) {
36 // Clear the GEM handle to indicate the object is in an invalid state.
37 other.mGemHandle = 0;
38 }
39
~DrmBuffer()40 DrmBuffer::~DrmBuffer() {
41 if (mGemHandle == 0) {
42 // Moved-from object. Return immediately.
43 return;
44 }
45 if (mHva) {
46 BlobManager::get()->removeMapping(mContextId, mId);
47 }
48 drm_gem_close params{.handle = mGemHandle};
49 int result = mDevice.ioctl(DRM_IOCTL_GEM_CLOSE, ¶ms);
50 if (result) {
51 ERR("DRM_IOCTL_GEM_CLOSE(%d) failed: %d", mGemHandle, errno);
52 }
53 }
54
create(DrmDevice & device,uint32_t context_id,uint64_t size)55 std::unique_ptr<DrmBuffer> DrmBuffer::create(DrmDevice& device, uint32_t context_id,
56 uint64_t size) {
57 // Create a new GEM buffer.
58 drm_i915_gem_create create_params{.size = size};
59 int result = device.ioctl(DRM_IOCTL_I915_GEM_CREATE, &create_params);
60 if (result) {
61 ERR("DRM_IOCTL_I915_GEM_CREATE failed: %d", errno);
62 return nullptr;
63 }
64
65 // Create the container to save the various returned handles.
66 std::unique_ptr<DrmBuffer> buffer(new DrmBuffer(device));
67 buffer->mContextId = context_id;
68 buffer->mSize = create_params.size; // Parameter adjusted by ioctl.
69 buffer->mGemHandle = create_params.handle;
70
71 INFO("Created DrmBuffer size %" PRIu64 " gem %" PRIu32, buffer->mSize, buffer->mGemHandle);
72
73 return buffer;
74 }
75
getHandle()76 uint32_t DrmBuffer::getHandle() { return mGemHandle; }
77
size()78 uint64_t DrmBuffer::size() { return mSize; }
79
map()80 void* DrmBuffer::map() {
81 if (mHva) {
82 return mHva;
83 }
84
85 // Map the buffer.
86 drm_i915_gem_mmap mmap_params{.handle = mGemHandle, .size = mSize};
87 int result = mDevice.ioctl(DRM_IOCTL_I915_GEM_MMAP, &mmap_params);
88 if (result) {
89 ERR("DRM_IOCTL_I915_GEM_MMAP failed: %d", errno);
90 return nullptr;
91 }
92
93 // Save the mapped address and assign the next free ID.
94 mHva = reinterpret_cast<void*>(mmap_params.addr_ptr);
95 mId = mIdNext.fetch_add(1);
96
97 // Add the mapping entry.
98 BlobManager::get()->addMapping(mContextId, mId, mHva, MAP_CACHE_CACHED);
99
100 INFO("Mapped DrmBuffer size %" PRIu64 " gem %" PRIu32 " to addr %p mid %" PRIu64, mSize,
101 mGemHandle, mHva, mId);
102
103 return mHva;
104 }
105
getId()106 uint64_t DrmBuffer::getId() {
107 map();
108 return mId;
109 }
110
DrmBuffer(DrmDevice & device)111 DrmBuffer::DrmBuffer(DrmDevice& device) : mDevice(device) {}
112
113 } // namespace magma
114 } // namespace gfxstream
115