Fix long standing MTRR bug.
[platform/upstream/libpciaccess.git] / src / common_vgaarb.c
1 /*
2  * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti
3  *               2009 Tiago Vignatti
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use,
9  * copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following
12  * conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  *
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <limits.h>
35
36 #include "config.h"
37 #include "pciaccess.h"
38 #include "pciaccess_private.h"
39
40 #define BUFSIZE 64
41
42 static int
43 parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match)
44 {
45     char *tok;
46     char *input_sp = NULL, *count_sp, *pci_sp;
47     char tmp[32];
48
49     tok = strtok_r(input,",",&input_sp);
50     if (!tok)
51         goto fail;
52
53     strncpy(tmp, input, 15);
54     tmp[15] = 0;
55
56     tok = strtok_r(tmp,":",&count_sp);
57     if (!tok)
58         goto fail;
59     tok = strtok_r(NULL, ":",&count_sp);
60     if (!tok)
61         goto fail;
62
63     *vga_count = strtoul(tok, NULL, 10);
64     if (*vga_count == LONG_MAX)
65         goto fail;
66
67 #ifdef DEBUG
68     fprintf(stderr,"vga count is %d\n", *vga_count);
69 #endif
70
71     tok = strtok_r(NULL, ",",&input_sp);
72     if (!tok)
73         goto fail;
74
75     if (match) {
76         strncpy(tmp, tok, 32);
77         tmp[31] = 0;
78         tok = strtok_r(tmp, ":", &pci_sp);
79         if (!tok)
80             goto fail;
81         tok = strtok_r(NULL, ":", &pci_sp);
82         if (!tok)
83             goto fail;
84         match->domain = strtoul(tok, NULL, 16);
85
86         tok = strtok_r(NULL, ":", &pci_sp);
87         if (!tok)
88             goto fail;
89         match->bus = strtoul(tok, NULL, 16);
90
91         tok = strtok_r(NULL, ".", &pci_sp);
92         if (!tok)
93             goto fail;
94         match->dev = strtoul(tok, NULL, 16);
95
96         tok = strtok_r(NULL, ".", &pci_sp);
97         if (!tok)
98             goto fail;
99         match->func = strtoul(tok, NULL, 16);
100     }
101
102     tok = strtok_r(NULL, ",",&input_sp);
103     if (!tok)
104         goto fail;
105     tok = strtok_r(tok, "=", &input_sp);
106     if (!tok)
107         goto fail;
108     tok = strtok_r(NULL, "=", &input_sp);
109     if (!tok)
110         goto fail;
111
112     if (!strncmp(tok, "io+mem", 6))
113         return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM;
114     if (!strncmp(tok, "io", 2))
115         return VGA_ARB_RSRC_LEGACY_IO;
116     if (!strncmp(tok, "mem", 3))
117         return VGA_ARB_RSRC_LEGACY_MEM;
118 fail:
119     return VGA_ARB_RSRC_NONE;
120 }
121
122 int
123 pci_device_vgaarb_init(void)
124 {
125     struct pci_slot_match match;
126     char buf[BUFSIZE];
127     int ret, rsrc;
128
129     if (!pci_sys)
130         return -1;
131
132     if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR)) < 0) {
133         return errno;
134     }
135
136     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
137     if (ret <= 0)
138         return -1;
139
140     memset(&match, 0xff, sizeof(match));
141     /* need to find the device to go back to and what it was decoding */
142     rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match);
143
144     pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func);
145
146     if (pci_sys->vga_default_dev)
147         pci_sys->vga_default_dev->vgaarb_rsrc = rsrc;
148     return 0;
149 }
150
151 void
152 pci_device_vgaarb_fini(void)
153 {
154     if (!pci_sys)
155         return;
156
157     close(pci_sys->vgaarb_fd);
158 }
159
160 /**
161  * Writes message on vga device. The messages are defined by the kernel
162  * implementation.
163  *
164  * \param fd    vga arbiter device.
165  * \param buf   message itself.
166  * \param len   message length.
167  *
168  * \return
169  * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for
170  * 'trylock')
171  */
172 static int
173 vgaarb_write(int fd, char *buf, int len)
174 {
175     int ret;
176
177
178     buf[len] = '\0';
179
180     ret = write(fd, buf, len);
181     if (ret == -1) {
182         /* the user may have called "trylock" and didn't get the lock */
183         if (errno == EBUSY)
184             return 2;
185
186 #ifdef DEBUG
187         fprintf(stderr, "write error");
188 #endif
189         return 1;
190     }
191     else if (ret != len) {
192         /* it's need to receive the exactly amount required. */
193 #ifdef DEBUG
194         fprintf(stderr, "write error: wrote different than expected\n");
195 #endif
196         return 1;
197     }
198
199 #ifdef DEBUG
200     fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf);
201 #endif
202
203     return 0;
204 }
205
206
207 static const char *
208 rsrc_to_str(int iostate)
209 {
210     switch (iostate) {
211     case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM:
212         return "io+mem";
213     case VGA_ARB_RSRC_LEGACY_IO:
214         return "io";
215     case VGA_ARB_RSRC_LEGACY_MEM:
216         return "mem";
217     }
218
219     return "none";
220 }
221
222 int
223 pci_device_vgaarb_set_target(struct pci_device *dev)
224 {
225     int len;
226     char buf[BUFSIZE];
227     int ret;
228
229     if (!dev)
230         dev = pci_sys->vga_default_dev;
231     if (!dev)
232         return -1;
233
234     len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x",
235                    dev->domain, dev->bus, dev->dev, dev->func);
236
237     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
238     if (ret)
239         return ret;
240
241     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
242     if (ret <= 0)
243         return -1;
244
245     dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
246     pci_sys->vga_target = dev;
247     return 0;
248 }
249
250 int
251 pci_device_vgaarb_decodes(int new_vgaarb_rsrc)
252 {
253     int len;
254     char buf[BUFSIZE];
255     int ret;
256     struct pci_device *dev = pci_sys->vga_target;
257
258     if (!dev)
259         return -1;
260     if (dev->vgaarb_rsrc == new_vgaarb_rsrc)
261         return 0;
262
263     len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc));
264     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
265     if (ret == 0)
266         dev->vgaarb_rsrc = new_vgaarb_rsrc;
267
268     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
269     if (ret <= 0)
270         return -1;
271
272     parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
273
274     return ret;
275 }
276
277 int
278 pci_device_vgaarb_lock(void)
279 {
280     int len;
281     char buf[BUFSIZE];
282     struct pci_device *dev = pci_sys->vga_target;
283
284     if (!dev)
285         return -1;
286
287     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
288         return 0;
289
290     len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc));
291
292     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
293 }
294
295 int
296 pci_device_vgaarb_trylock(void)
297 {
298     int len;
299     char buf[BUFSIZE];
300     struct pci_device *dev = pci_sys->vga_target;
301
302     if (!dev)
303         return -1;
304
305     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
306         return 0;
307
308     len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc));
309
310     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
311 }
312
313 int
314 pci_device_vgaarb_unlock(void)
315 {
316     int len;
317     char buf[BUFSIZE];
318     struct pci_device *dev = pci_sys->vga_target;
319
320     if (!dev)
321         return -1;
322
323     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
324         return 0;
325
326     len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc));
327
328     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
329 }
330
331 int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes)
332 {
333     *vga_count = pci_sys->vga_count;
334     if (!dev)
335         return 0;
336
337     *rsrc_decodes = dev->vgaarb_rsrc;
338         return 0;
339 }