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 <[email protected]>
25 *
26 */
27
28 #define __STDC_FORMAT_MACROS
29 #include <inttypes.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <pciaccess.h>
35 #include <unistd.h>
36
37 #include "intel_io.h"
38 #include "intel_chipset.h"
39
40 #define KB(x) ((x) * 1024)
41 #define MB(x) ((x) * 1024 * 1024)
42 unsigned char *gtt;
43 uint32_t devid;
44
45 typedef uint32_t gen6_gtt_pte_t;
46 typedef uint64_t gen8_gtt_pte_t;
47
gen6_gtt_pte(const unsigned i)48 static gen6_gtt_pte_t gen6_gtt_pte(const unsigned i)
49 {
50 return *((volatile gen6_gtt_pte_t *)(gtt) + i);
51 }
52
gen8_gtt_pte(const unsigned i)53 static gen8_gtt_pte_t gen8_gtt_pte(const unsigned i)
54 {
55 return *((volatile gen8_gtt_pte_t *)(gtt) + i);
56 }
57
ingtt(const unsigned offset)58 static uint64_t ingtt(const unsigned offset)
59 {
60 if (intel_gen(devid) < 8)
61 return gen6_gtt_pte(offset/KB(4));
62
63 return gen8_gtt_pte(offset/KB(4));
64 }
65
get_phys(uint32_t pt_offset)66 static uint64_t get_phys(uint32_t pt_offset)
67 {
68 uint64_t pae = 0;
69 uint64_t phys = ingtt(pt_offset);
70
71 if (intel_gen(devid) < 4 && !IS_G33(devid))
72 return phys & ~0xfff;
73
74 switch (intel_gen(devid)) {
75 case 3:
76 case 4:
77 case 5:
78 pae = (phys & 0xf0) << 28;
79 break;
80 case 6:
81 case 7:
82 if (IS_HASWELL(devid))
83 pae = (phys & 0x7f0) << 28;
84 else
85 pae = (phys & 0xff0) << 28;
86 break;
87 case 8:
88 case 9:
89 phys = phys & 0x7ffffff000;
90 break;
91 default:
92 fprintf(stderr, "Unsupported platform\n");
93 exit(-1);
94 }
95
96 return (phys | pae) & ~0xfff;
97 }
98
pte_dump(int size,uint32_t offset)99 static void pte_dump(int size, uint32_t offset) {
100 int pte_size;
101 int entries;
102 unsigned int i;
103
104 /* Want to print 4 ptes at a time (4b PTE assumed). */
105 if (size % 16)
106 size = (size + 16) & ~0xffff;
107
108 if (intel_gen(devid) < 8)
109 pte_size = 4;
110 else
111 pte_size = 8;
112
113 entries = size / pte_size;
114
115 printf("GTT offset | %d PTEs (%d MB)\n", entries,
116 entries * 4096 / 1024 / 1024);
117 printf("----------------------------------------------------------\n");
118
119 for (i = 0; i < entries; i += 4) {
120 if (intel_gen(devid) < 8) {
121 printf(" 0x%08x | 0x%08x 0x%08x 0x%08x 0x%08x\n",
122 KB(4 * i),
123 gen6_gtt_pte(i + 0),
124 gen6_gtt_pte(i + 1),
125 gen6_gtt_pte(i + 2),
126 gen6_gtt_pte(i + 3) );
127 } else {
128 printf(" 0x%08x | 0x%016" PRIx64 " 0x%016" PRIx64
129 " 0x%016" PRIx64 " 0x%016" PRIx64 " \n",
130 KB(4 * i),
131 gen8_gtt_pte(i + 0),
132 gen8_gtt_pte(i + 1),
133 gen8_gtt_pte(i + 2),
134 gen8_gtt_pte(i + 3) );
135 }
136 }
137 }
138
main(int argc,char ** argv)139 int main(int argc, char **argv)
140 {
141 struct pci_device *pci_dev;
142 unsigned int start, gtt_size;
143 int flag[] = {
144 PCI_DEV_MAP_FLAG_WRITE_COMBINE,
145 PCI_DEV_MAP_FLAG_WRITABLE,
146 0
147 }, f;
148
149 pci_dev = intel_get_pci_device();
150 devid = pci_dev->device_id;
151
152 if (IS_GEN2(devid)) {
153 printf("Unsupported chipset for gtt dumper\n");
154 exit(1);
155 }
156
157 for (f = 0; flag[f] != 0; f++) {
158 if (IS_GEN3(devid)) {
159 /* 915/945 chips has GTT range in bar 3 */
160 if (pci_device_map_range(pci_dev,
161 pci_dev->regions[3].base_addr,
162 pci_dev->regions[3].size,
163 flag[f],
164 (void **)>t) == 0)
165 break;
166 } else {
167 unsigned offset;
168
169 offset = pci_dev->regions[0].size / 2;
170
171 if (IS_GEN4(devid))
172 offset = KB(512);
173
174 if (pci_device_map_range(pci_dev,
175 pci_dev->regions[0].base_addr + offset,
176 offset,
177 flag[f],
178 (void **)>t) == 0)
179 break;
180 }
181 }
182 if (flag[f] == 0) {
183 printf("Failed to map gtt\n");
184 exit(1);
185 }
186
187 gtt_size = pci_dev->regions[0].size / 2;
188 if (argc > 1 && !strncmp("-d", argv[1], 2)) {
189 pte_dump(gtt_size, 0);
190 return 0;
191 }
192
193 for (start = 0; start < gtt_size; start += KB(4)) {
194 uint64_t start_phys = get_phys(start);
195 uint32_t end;
196 int constant_length = 0;
197 int linear_length = 0;
198
199 /* Check if it's a linear sequence */
200 for (end = start + KB(4); end < gtt_size; end += KB(4)) {
201 uint64_t end_phys = get_phys(end);
202 if (end_phys == start_phys + (end - start))
203 linear_length++;
204 else
205 break;
206 }
207 if (linear_length > 0) {
208 printf("0x%08x - 0x%08x: linear from "
209 "0x%" PRIx64 " to 0x%" PRIx64 "\n",
210 start, end - KB(4),
211 start_phys, start_phys + (end - start) - KB(4));
212 start = end - KB(4);
213 continue;
214 }
215
216 /* Check if it's a constant sequence */
217 for (end = start + KB(4); end < gtt_size; end += KB(4)) {
218 uint64_t end_phys = get_phys(end);
219 if (end_phys == start_phys)
220 constant_length++;
221 else
222 break;
223 }
224 if (constant_length > 0) {
225 printf("0x%08x - 0x%08x: constant 0x%" PRIx64 "\n",
226 start, end - KB(4), start_phys);
227 start = end - KB(4);
228 continue;
229 }
230
231 printf("0x%08x: 0x%" PRIx64 "\n", start, start_phys);
232 }
233
234 return 0;
235 }
236