1 /*
2  * Copyright © 2008 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *    Ben Widawsky <ben@bwidawsk.net>
26  *
27  */
28 
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <stdbool.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <err.h>
39 #include <assert.h>
40 #include <sys/ioctl.h>
41 #include <sys/stat.h>
42 #include <sys/mman.h>
43 
44 #include "intel_gpu_tools.h"
45 
46 #define FAKEKEY 0x2468ace0
47 
48 void *mmio;
49 
50 static struct _mmio_data {
51 	int inited;
52 	bool safe;
53 	char debugfs_path[FILENAME_MAX];
54 	char debugfs_forcewake_path[FILENAME_MAX];
55 	uint32_t i915_devid;
56 	struct intel_register_map map;
57 	int key;
58 } mmio_data;
59 
60 void
intel_map_file(char * file)61 intel_map_file(char *file)
62 {
63 	int fd;
64 	struct stat st;
65 
66 	fd = open(file, O_RDWR);
67 	if (fd == -1) {
68 		    fprintf(stderr, "Couldn't open %s: %s\n", file,
69 			    strerror(errno));
70 		    exit(1);
71 	}
72 	fstat(fd, &st);
73 	mmio = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
74 	if (mmio == MAP_FAILED) {
75 		    fprintf(stderr, "Couldn't mmap %s: %s\n", file,
76 			    strerror(errno));
77 		    exit(1);
78 	}
79 	close(fd);
80 }
81 
82 void
intel_get_mmio(struct pci_device * pci_dev)83 intel_get_mmio(struct pci_device *pci_dev)
84 {
85 	uint32_t devid, gen;
86 	int mmio_bar, mmio_size;
87 	int error;
88 
89 	devid = pci_dev->device_id;
90 	if (IS_GEN2(devid))
91 		mmio_bar = 1;
92 	else
93 		mmio_bar = 0;
94 
95 	gen = intel_gen(devid);
96 	if (gen < 3)
97 		mmio_size = 512*1024;
98 	else if (gen < 5)
99 		mmio_size = 512*1024;
100 	else
101 		mmio_size = 2*1024*1024;
102 
103 	error = pci_device_map_range (pci_dev,
104 				      pci_dev->regions[mmio_bar].base_addr,
105 				      mmio_size,
106 				      PCI_DEV_MAP_FLAG_WRITABLE,
107 				      &mmio);
108 
109 	if (error != 0) {
110 		fprintf(stderr, "Couldn't map MMIO region: %s\n",
111 			strerror(error));
112 		exit(1);
113 	}
114 }
115 
116 /*
117  * If successful, i915_debugfs_path and i915_debugfs_forcewake_path are both
118  * updated with the correct path.
119  */
120 static int
find_debugfs_path(const char * dri_base)121 find_debugfs_path(const char *dri_base)
122 {
123 	char buf[FILENAME_MAX];
124 	struct stat sb;
125 	int i, ret;
126 
127 	for (i = 0; i < 16; i++) {
128 		snprintf(buf, FILENAME_MAX, "%s/%i/name", dri_base, i);
129 
130 		snprintf(mmio_data.debugfs_path, FILENAME_MAX,
131 			 "%s/%i/", dri_base, i);
132 		snprintf(mmio_data.debugfs_forcewake_path, FILENAME_MAX,
133 			 "%s/%i/i915_forcewake_user", dri_base, i);
134 
135 		ret = stat(mmio_data.debugfs_forcewake_path, &sb);
136 		if (ret) {
137 			mmio_data.debugfs_path[0] = 0;
138 			mmio_data.debugfs_forcewake_path[0] = 0;
139 		} else
140 			return 0;
141 	}
142 
143 	return -1;
144 }
145 
146 static int
get_forcewake_lock(void)147 get_forcewake_lock(void)
148 {
149 	return open(mmio_data.debugfs_forcewake_path, 0);
150 }
151 
152 static void
release_forcewake_lock(int fd)153 release_forcewake_lock(int fd)
154 {
155 	close(fd);
156 }
157 
158 /* Dumb check to see if i915 was loaded */
159 static bool
i915_loaded(void)160 i915_loaded(void)
161 {
162 	struct stat sb;
163 	int ret;
164 
165 	ret = stat("/sys/module/i915/", &sb);
166 	if (ret) {
167 		return false;
168 	}
169 
170 	assert(S_ISDIR(sb.st_mode));
171 	return true;
172 }
173 
174 /*
175  * Initialize register access library.
176  *
177  * @pci_dev: pci device we're mucking with
178  * @safe: use safe register access tables
179  */
180 int
intel_register_access_init(struct pci_device * pci_dev,int safe)181 intel_register_access_init(struct pci_device *pci_dev, int safe)
182 {
183 	int ret;
184 
185 	/* after old API is deprecated, remove this */
186 	if (mmio == NULL)
187 		intel_get_mmio(pci_dev);
188 
189 	assert(mmio != NULL);
190 
191 	if (mmio_data.inited)
192 		return -1;
193 
194 	mmio_data.safe = (safe != 0 &&
195 			intel_gen(pci_dev->device_id) >= 4) ? true : false;
196 	mmio_data.i915_devid = pci_dev->device_id;
197 	if (mmio_data.safe)
198 		mmio_data.map = intel_get_register_map(mmio_data.i915_devid);
199 
200 	/* Find where the forcewake lock is. Forcewake doesn't exist
201 	 * gen < 6, but the debugfs should do the right things for us.
202 	 */
203 	ret = find_debugfs_path("/sys/kernel/debug/dri");
204 	if (ret) {
205 		ret = find_debugfs_path("/debug/dri");
206 		if (ret) {
207 			fprintf(stderr, "Couldn't find path to dri/debugfs entry\n");
208 			if (i915_loaded()) {
209 				fprintf(stderr, "i915 loaded; not proceeding.\n");
210 				return ret;
211 			}
212 		}
213 		mmio_data.key = FAKEKEY;
214 	} else
215 		mmio_data.key = get_forcewake_lock();
216 
217 	mmio_data.inited++;
218 	return 0;
219 }
220 static int
intel_register_access_needs_wake(void)221 intel_register_access_needs_wake(void)
222 {
223 	return mmio_data.key != FAKEKEY;
224 }
225 
intel_register_access_needs_fakewake(void)226 int intel_register_access_needs_fakewake(void)
227 {
228 	return mmio_data.key == FAKEKEY;
229 }
230 
231 void
intel_register_access_fini(void)232 intel_register_access_fini(void)
233 {
234 	if (mmio_data.key && intel_register_access_needs_wake())
235 		release_forcewake_lock(mmio_data.key);
236 	mmio_data.inited--;
237 }
238 
239 uint32_t
intel_register_read(uint32_t reg)240 intel_register_read(uint32_t reg)
241 {
242 	struct intel_register_range *range;
243 	uint32_t ret;
244 
245 	assert(mmio_data.inited);
246 
247 	if (intel_gen(mmio_data.i915_devid) >= 6)
248 		assert(mmio_data.key != -1);
249 
250 	if (!mmio_data.safe)
251 		goto read_out;
252 
253 	range = intel_get_register_range(mmio_data.map,
254 					 reg,
255 					 INTEL_RANGE_READ);
256 
257 	if(!range) {
258 		fprintf(stderr, "Register read blocked for safety "
259 			"(*0x%08x)\n", reg);
260 		ret = 0xffffffff;
261 		goto out;
262 	}
263 
264 read_out:
265 	ret = *(volatile uint32_t *)((volatile char *)mmio + reg);
266 out:
267 	return ret;
268 }
269 
270 void
intel_register_write(uint32_t reg,uint32_t val)271 intel_register_write(uint32_t reg, uint32_t val)
272 {
273 	struct intel_register_range *range;
274 
275 	assert(mmio_data.inited);
276 
277 	if (intel_gen(mmio_data.i915_devid) >= 6)
278 		assert(mmio_data.key != -1);
279 
280 	if (!mmio_data.safe)
281 		goto write_out;
282 
283 	range = intel_get_register_range(mmio_data.map,
284 					 reg,
285 					 INTEL_RANGE_WRITE);
286 
287 	if (!range) {
288 		fprintf(stderr, "Register write blocked for safety "
289 			"(*0x%08x = 0x%x)\n", reg, val);
290 	}
291 
292 write_out:
293 	*(volatile uint32_t *)((volatile char *)mmio + reg) = val;
294 }
295