blob: f33b182b9353e7c02d5f6294309333563baa269e [file] [log] [blame]
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -06001/*
2 * XGL 3-D graphics library
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Courtney Goeltzenleuchter <courtney@lunarg.com>
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <assert.h>
35#include <string.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <dirent.h>
41#include <errno.h>
42#include <fnmatch.h>
43
44#include <pciaccess.h>
45
46#include <xf86drm.h>
Chia-I Wu155be032014-08-02 09:14:28 +080047#include <i915_drm.h>
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060048
49#include <libudev.h>
50#include <dlfcn.h>
51
52#ifdef HAVE_VALGRIND
53#include <valgrind.h>
54#include <memcheck.h>
55#define VG(x) x
56#else
57#define VG(x)
58#endif
59
60#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s)))
61
62#include "xgl.h"
63#include "xglDbg.h"
64
65#include "driver.h"
66#include "intel_chipset.h"
67#include "gen7_functions.h"
68
69XGL_RESULT XGLAPI GetExtensionSupport(XGL_PHYSICAL_GPU gpu, const XGL_CHAR* pExtName);
70
71
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060072/*
73 * Global to contain application allocation call-backs
74 * and GPU enumeration info.
75 */
76struct _xgl_config icd_data;
77
Chia-I Wu3065c9c2014-08-04 06:28:31 +080078static void loader_err(XGL_INT msg_code, const char *msg)
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060079{
Chia-I Wu3065c9c2014-08-04 06:28:31 +080080 icd_log(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0,
81 XGL_NULL_HANDLE, 0, msg_code, msg);
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060082}
83
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060084static int is_render_node(int fd, struct stat *st)
85{
86 if (fstat(fd, st))
87 return 0;
88
89 if (!S_ISCHR(st->st_mode))
90 return 0;
91
92 return st->st_rdev & 0x80;
93}
94
95static void init_xgl_dispatch_table(struct icd_dispatch_table *pDispatch)
96{
97#define LOAD(xglfunc, driverfunc) do { \
98 pDispatch->xglfunc = driverfunc; \
99} while (0)
100 LOAD(GetGpuInfo, gen7_GetGpuInfo);
101 LOAD(GetExtensionSupport, GetExtensionSupport);
102}
103
104static void init_validation_dispatch_table(struct icd_dispatch_table *pDispatch)
105{
106#define LOAD(xglfunc, driverfunc) do { \
107 pDispatch->xglfunc = driverfunc; \
108} while (0)
109 LOAD(GetGpuInfo, gen7_GetGpuInfo);
110 LOAD(GetExtensionSupport, GetExtensionSupport);
111}
112
Chia-I Wu468e3c32014-08-04 08:03:57 +0800113ICD_EXPORT XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO *
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600114 pAppInfo,
115 const XGL_ALLOC_CALLBACKS *
116 pAllocCb, XGL_UINT maxGpus,
117 XGL_UINT * pGpuCount,
118 XGL_PHYSICAL_GPU * pGpus)
119{
120 struct udev *udev;
121 struct udev_enumerate *e;
122 struct udev_device *device, *parent;
123 struct udev_list_entry *entry;
124 const char *pci_id, *path;
125 const char *usub, *dnode;
126 int fd;
127 struct stat st;
128 char *pci_glob = "*:*";
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800129 XGL_RESULT ret;
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600130 XGL_UINT count = 0;
131 struct _xgl_device *pXglDev;
132
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800133 ret = icd_set_alloc_callbacks(pAllocCb);
134 if (ret != XGL_SUCCESS)
135 return ret;
136
137 ret = XGL_ERROR_UNAVAILABLE;
138
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600139 // TODO: Do we need to keep track of previous calls to xglInitAndEnumerageGpus?
140 /*
141 * xglInitAndEnumerateGpus() can be called multiple times. Calling it more than once
142 * forces driver reinitialization.
143 */
144
145 if (icd_data.num_gpus > 0) {
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600146 // TODO: Free resources and re-initialize
147 }
148 // TODO: Do we need any other validation for incoming pointers?
149
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600150 udev = udev_new();
151 if (udev == NULL) {
152 loader_err(0, "failed to initialize udev context");
153 abort();
154 }
155
156 memset(icd_data.gpu_info, 0,
157 sizeof(icd_data.gpu_info[XGL_MAX_PHYSICAL_GPUS]));
158 memset(icd_data.render_node_list, 0,
159 sizeof(icd_data.render_node_list[XGL_MAX_PHYSICAL_GPUS]));
160
161 fd = -1;
162 e = udev_enumerate_new(udev);
163 udev_enumerate_add_match_subsystem(e, "drm");
164 udev_enumerate_scan_devices(e);
165 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
166 path = udev_list_entry_get_name(entry);
167 device = udev_device_new_from_syspath(udev, path);
168 parent = udev_device_get_parent(device);
169 usub = udev_device_get_subsystem(parent);
170 /* Filter out KMS output devices. */
171 if (!usub || (strcmp(usub, "pci") != 0))
172 continue;
173 pci_id = udev_device_get_property_value(parent, "PCI_ID");
174 if (fnmatch(pci_glob, pci_id, 0) != 0)
175 continue;
176 dnode = udev_device_get_devnode(device);
177 fd = open(dnode, O_RDWR);
178 if (fd < 0)
179 continue;
180 if (!is_render_node(fd, &st)) {
181 close(fd);
182 fd = -1;
183 continue;
184 }
185
186 pXglDev = &icd_data.gpu_info[count];
187
188 sscanf(pci_id, "%x:%x", &pXglDev->ven_id, &pXglDev->dev_id);
189 /*
190 * Currently only allowing Ivybridge and Haswell
191 */
192 if (!IS_HASWELL(pXglDev->dev_id) && !IS_IVYBRIDGE(pXglDev->dev_id)) {
193 close(fd);
194 fd = -1;
195 continue;
196 }
197
198 /*
199 * We'll keep the fd open for any subsequent
200 * xglGetGpuInfo calls.
201 */
202 pXglDev->fd = fd;
203 strncpy(pXglDev->device_path, dnode, XGL_MAX_PHYSICAL_GPU_NAME);
204 icd_data.render_node_list[count] = pXglDev;
205 init_xgl_dispatch_table(&pXglDev->xgl);
206 init_validation_dispatch_table(&pXglDev->validation);
207 pXglDev->exec = & pXglDev->xgl;
208
209 ret = XGL_SUCCESS;
210 count++;
211 }
212 icd_data.num_gpus = count;
213 udev_enumerate_unref(e);
214 udev_unref(udev);
215
216 if (ret == XGL_SUCCESS) {
217 *pGpuCount = icd_data.num_gpus;
218 memcpy(pGpus, icd_data.render_node_list,
219 (icd_data.num_gpus >
220 maxGpus ? maxGpus : icd_data.num_gpus) *
221 sizeof(XGL_PHYSICAL_GPU));
222 }
223
224 return ret;
225}
226
227XGL_RESULT XGLAPI GetExtensionSupport(XGL_PHYSICAL_GPU gpu, const XGL_CHAR* pExtName)
228{
229 // struct _xgl_device *pdev = (struct _xgl_device *) gpu;
230
231 // TODO: Check requested extension
232
233 return XGL_ERROR_INVALID_EXTENSION;
234}