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