1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License") override;
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/DrmDevice.h"
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <i915_drm.h>
20 #include <sys/ioctl.h>
21 #include <unistd.h>
22
23 #include <cstring>
24 #include <string>
25
26 #include "host-common/logging.h"
27 #include "magma/magma_common_defs.h"
28
29 namespace gfxstream {
30 namespace magma {
31
32 // Returns a fd to the first available DRM render node, or -1 if none is found.
openFirstRenderNode()33 static int openFirstRenderNode() {
34 constexpr std::string_view kRenderNodePathPrefix = "/dev/dri/renderD";
35 constexpr uint32_t kRenderNodeStart = 128;
36 constexpr uint32_t kDrmMaxMinor = 15;
37 for (uint32_t n = kRenderNodeStart; n < kRenderNodeStart + kDrmMaxMinor; ++n) {
38 auto path = std::string(kRenderNodePathPrefix) + std::to_string(n);
39 int fd = open(path.c_str(), O_RDWR | O_CLOEXEC);
40 if (fd < 0) {
41 if (errno != ENOENT) {
42 // ENOENT is expected because we're trying all potentially valid paths, but other
43 // errors should be logged.
44 WARN("render node %s exists but could not be opened - (%d) %s", path.c_str(), errno,
45 strerror(errno));
46 }
47 continue;
48 }
49 INFO("opened render node %s", path.c_str());
50 return fd;
51 }
52 return -1;
53 }
54
~DrmDevice()55 DrmDevice::~DrmDevice() {}
56
create()57 std::unique_ptr<DrmDevice> DrmDevice::create() {
58 auto fd = openFirstRenderNode();
59 if (fd == -1) {
60 ERR("failed to find any render nodes");
61 return nullptr;
62 }
63
64 std::unique_ptr<DrmDevice> device(new DrmDevice);
65 device->mFd = fd;
66 return device;
67 }
68
ioctl(unsigned long request,void * arg)69 int DrmDevice::ioctl(unsigned long request, void* arg) {
70 int ret = 0;
71 do {
72 ret = ::ioctl(mFd.get().value(), request, arg);
73 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
74 return ret;
75 }
76
getParam(int param)77 std::optional<int> DrmDevice::getParam(int param) {
78 int value = 0;
79 drm_i915_getparam_t params{.param = param, .value = &value};
80 int result = ioctl(DRM_IOCTL_I915_GETPARAM, ¶ms);
81 if (result != 0) {
82 ERR("DrmDevice::GetParam(%d) failed: (%d) %s", param, errno, strerror(errno));
83 return std::nullopt;
84 }
85 return value;
86 }
87
88 } // namespace magma
89 } // namespace gfxstream
90