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, &params);
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