xref: /freebsd/sys/dev/pci/pci_user.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  *
28  */
29 
30 #include "opt_bus.h"	/* XXX trim includes */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/linker.h>
37 #include <sys/fcntl.h>
38 #include <sys/conf.h>
39 #include <sys/kernel.h>
40 #include <sys/queue.h>
41 #include <sys/types.h>
42 
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45 #include <vm/vm_extern.h>
46 
47 #include <sys/bus.h>
48 #include <machine/bus.h>
49 #include <sys/rman.h>
50 #include <machine/resource.h>
51 
52 #include <sys/pciio.h>
53 #include <pci/pcireg.h>
54 #include <pci/pcivar.h>
55 
56 #include "pcib_if.h"
57 #include "pci_if.h"
58 
59 /*
60  * This is the user interface to PCI configuration space.
61  */
62 
63 static int	pci_open(dev_t dev, int oflags, int devtype, struct proc *p);
64 static int	pci_close(dev_t dev, int flag, int devtype, struct proc *p);
65 static int	pci_conf_match(struct pci_match_conf *matches, int num_matches,
66 			       struct pci_conf *match_buf);
67 static int	pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
68 
69 #define	PCI_CDEV	78
70 
71 struct cdevsw pcicdev = {
72 	/* open */	pci_open,
73 	/* close */	pci_close,
74 	/* read */	noread,
75 	/* write */	nowrite,
76 	/* ioctl */	pci_ioctl,
77 	/* poll */	nopoll,
78 	/* mmap */	nommap,
79 	/* strategy */	nostrategy,
80 	/* name */	"pci",
81 	/* maj */	PCI_CDEV,
82 	/* dump */	nodump,
83 	/* psize */	nopsize,
84 	/* flags */	0,
85 };
86 
87 static int
88 pci_open(dev_t dev, int oflags, int devtype, struct proc *p)
89 {
90 	if ((oflags & FWRITE) && securelevel > 0) {
91 		return EPERM;
92 	}
93 	return 0;
94 }
95 
96 static int
97 pci_close(dev_t dev, int flag, int devtype, struct proc *p)
98 {
99 	return 0;
100 }
101 
102 /*
103  * Match a single pci_conf structure against an array of pci_match_conf
104  * structures.  The first argument, 'matches', is an array of num_matches
105  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
106  * structure that will be compared to every entry in the matches array.
107  * This function returns 1 on failure, 0 on success.
108  */
109 static int
110 pci_conf_match(struct pci_match_conf *matches, int num_matches,
111 	       struct pci_conf *match_buf)
112 {
113 	int i;
114 
115 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
116 		return(1);
117 
118 	for (i = 0; i < num_matches; i++) {
119 		/*
120 		 * I'm not sure why someone would do this...but...
121 		 */
122 		if (matches[i].flags == PCI_GETCONF_NO_MATCH)
123 			continue;
124 
125 		/*
126 		 * Look at each of the match flags.  If it's set, do the
127 		 * comparison.  If the comparison fails, we don't have a
128 		 * match, go on to the next item if there is one.
129 		 */
130 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
131 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
132 			continue;
133 
134 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
135 		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
136 			continue;
137 
138 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
139 		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
140 			continue;
141 
142 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
143 		 && (match_buf->pc_vendor != matches[i].pc_vendor))
144 			continue;
145 
146 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
147 		 && (match_buf->pc_device != matches[i].pc_device))
148 			continue;
149 
150 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
151 		 && (match_buf->pc_class != matches[i].pc_class))
152 			continue;
153 
154 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
155 		 && (match_buf->pd_unit != matches[i].pd_unit))
156 			continue;
157 
158 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
159 		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
160 			     sizeof(match_buf->pd_name)) != 0))
161 			continue;
162 
163 		return(0);
164 	}
165 
166 	return(1);
167 }
168 
169 static int
170 pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
171 {
172 	device_t pci, pcib;
173 	struct pci_io *io;
174 	const char *name;
175 	int error;
176 
177 	if (!(flag & FWRITE))
178 		return EPERM;
179 
180 
181 	switch(cmd) {
182 	case PCIOCGETCONF:
183 		{
184 		struct pci_devinfo *dinfo;
185 		struct pci_conf_io *cio;
186 		struct devlist *devlist_head;
187 		struct pci_match_conf *pattern_buf;
188 		int num_patterns;
189 		size_t iolen;
190 		int ionum, i;
191 
192 		cio = (struct pci_conf_io *)data;
193 
194 		num_patterns = 0;
195 		dinfo = NULL;
196 
197 		/*
198 		 * Hopefully the user won't pass in a null pointer, but it
199 		 * can't hurt to check.
200 		 */
201 		if (cio == NULL) {
202 			error = EINVAL;
203 			break;
204 		}
205 
206 		/*
207 		 * If the user specified an offset into the device list,
208 		 * but the list has changed since they last called this
209 		 * ioctl, tell them that the list has changed.  They will
210 		 * have to get the list from the beginning.
211 		 */
212 		if ((cio->offset != 0)
213 		 && (cio->generation != pci_generation)){
214 			cio->num_matches = 0;
215 			cio->status = PCI_GETCONF_LIST_CHANGED;
216 			error = 0;
217 			break;
218 		}
219 
220 		/*
221 		 * Check to see whether the user has asked for an offset
222 		 * past the end of our list.
223 		 */
224 		if (cio->offset >= pci_numdevs) {
225 			cio->num_matches = 0;
226 			cio->status = PCI_GETCONF_LAST_DEVICE;
227 			error = 0;
228 			break;
229 		}
230 
231 		/* get the head of the device queue */
232 		devlist_head = &pci_devq;
233 
234 		/*
235 		 * Determine how much room we have for pci_conf structures.
236 		 * Round the user's buffer size down to the nearest
237 		 * multiple of sizeof(struct pci_conf) in case the user
238 		 * didn't specify a multiple of that size.
239 		 */
240 		iolen = min(cio->match_buf_len -
241 			    (cio->match_buf_len % sizeof(struct pci_conf)),
242 			    pci_numdevs * sizeof(struct pci_conf));
243 
244 		/*
245 		 * Since we know that iolen is a multiple of the size of
246 		 * the pciconf union, it's okay to do this.
247 		 */
248 		ionum = iolen / sizeof(struct pci_conf);
249 
250 		/*
251 		 * If this test is true, the user wants the pci_conf
252 		 * structures returned to match the supplied entries.
253 		 */
254 		if ((cio->num_patterns > 0)
255 		 && (cio->pat_buf_len > 0)) {
256 			/*
257 			 * pat_buf_len needs to be:
258 			 * num_patterns * sizeof(struct pci_match_conf)
259 			 * While it is certainly possible the user just
260 			 * allocated a large buffer, but set the number of
261 			 * matches correctly, it is far more likely that
262 			 * their kernel doesn't match the userland utility
263 			 * they're using.  It's also possible that the user
264 			 * forgot to initialize some variables.  Yes, this
265 			 * may be overly picky, but I hazard to guess that
266 			 * it's far more likely to just catch folks that
267 			 * updated their kernel but not their userland.
268 			 */
269 			if ((cio->num_patterns *
270 			    sizeof(struct pci_match_conf)) != cio->pat_buf_len){
271 				/* The user made a mistake, return an error*/
272 				cio->status = PCI_GETCONF_ERROR;
273 				printf("pci_ioctl: pat_buf_len %d != "
274 				       "num_patterns (%d) * sizeof(struct "
275 				       "pci_match_conf) (%d)\npci_ioctl: "
276 				       "pat_buf_len should be = %d\n",
277 				       cio->pat_buf_len, cio->num_patterns,
278 				       (int)sizeof(struct pci_match_conf),
279 				       (int)sizeof(struct pci_match_conf) *
280 				       cio->num_patterns);
281 				printf("pci_ioctl: do your headers match your "
282 				       "kernel?\n");
283 				cio->num_matches = 0;
284 				error = EINVAL;
285 				break;
286 			}
287 
288 			/*
289 			 * Check the user's buffer to make sure it's readable.
290 			 */
291 			if (!useracc((caddr_t)cio->patterns,
292 				    cio->pat_buf_len, VM_PROT_READ)) {
293 				printf("pci_ioctl: pattern buffer %p, "
294 				       "length %u isn't user accessible for"
295 				       " READ\n", cio->patterns,
296 				       cio->pat_buf_len);
297 				error = EACCES;
298 				break;
299 			}
300 			/*
301 			 * Allocate a buffer to hold the patterns.
302 			 */
303 			pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
304 					     M_WAITOK);
305 			error = copyin(cio->patterns, pattern_buf,
306 				       cio->pat_buf_len);
307 			if (error != 0)
308 				break;
309 			num_patterns = cio->num_patterns;
310 
311 		} else if ((cio->num_patterns > 0)
312 			|| (cio->pat_buf_len > 0)) {
313 			/*
314 			 * The user made a mistake, spit out an error.
315 			 */
316 			cio->status = PCI_GETCONF_ERROR;
317 			cio->num_matches = 0;
318 			printf("pci_ioctl: invalid GETCONF arguments\n");
319 			error = EINVAL;
320 			break;
321 		} else
322 			pattern_buf = NULL;
323 
324 		/*
325 		 * Make sure we can write to the match buffer.
326 		 */
327 		if (!useracc((caddr_t)cio->matches,
328 			     cio->match_buf_len, VM_PROT_WRITE)) {
329 			printf("pci_ioctl: match buffer %p, length %u "
330 			       "isn't user accessible for WRITE\n",
331 			       cio->matches, cio->match_buf_len);
332 			error = EACCES;
333 			break;
334 		}
335 
336 		/*
337 		 * Go through the list of devices and copy out the devices
338 		 * that match the user's criteria.
339 		 */
340 		for (cio->num_matches = 0, error = 0, i = 0,
341 		     dinfo = STAILQ_FIRST(devlist_head);
342 		     (dinfo != NULL) && (cio->num_matches < ionum)
343 		     && (error == 0) && (i < pci_numdevs);
344 		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
345 
346 			if (i < cio->offset)
347 				continue;
348 
349 			/* Populate pd_name and pd_unit */
350 			name = NULL;
351 			if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0')
352 				name = device_get_name(dinfo->cfg.dev);
353 			if (name) {
354 				strncpy(dinfo->conf.pd_name, name,
355 					sizeof(dinfo->conf.pd_name));
356 				dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
357 				dinfo->conf.pd_unit =
358 					device_get_unit(dinfo->cfg.dev);
359 			}
360 
361 			if ((pattern_buf == NULL) ||
362 			    (pci_conf_match(pattern_buf, num_patterns,
363 					    &dinfo->conf) == 0)) {
364 
365 				/*
366 				 * If we've filled up the user's buffer,
367 				 * break out at this point.  Since we've
368 				 * got a match here, we'll pick right back
369 				 * up at the matching entry.  We can also
370 				 * tell the user that there are more matches
371 				 * left.
372 				 */
373 				if (cio->num_matches >= ionum)
374 					break;
375 
376 				error = copyout(&dinfo->conf,
377 					        &cio->matches[cio->num_matches],
378 						sizeof(struct pci_conf));
379 				cio->num_matches++;
380 			}
381 		}
382 
383 		/*
384 		 * Set the pointer into the list, so if the user is getting
385 		 * n records at a time, where n < pci_numdevs,
386 		 */
387 		cio->offset = i;
388 
389 		/*
390 		 * Set the generation, the user will need this if they make
391 		 * another ioctl call with offset != 0.
392 		 */
393 		cio->generation = pci_generation;
394 
395 		/*
396 		 * If this is the last device, inform the user so he won't
397 		 * bother asking for more devices.  If dinfo isn't NULL, we
398 		 * know that there are more matches in the list because of
399 		 * the way the traversal is done.
400 		 */
401 		if (dinfo == NULL)
402 			cio->status = PCI_GETCONF_LAST_DEVICE;
403 		else
404 			cio->status = PCI_GETCONF_MORE_DEVS;
405 
406 		if (pattern_buf != NULL)
407 			free(pattern_buf, M_TEMP);
408 
409 		break;
410 		}
411 	case PCIOCREAD:
412 		io = (struct pci_io *)data;
413 		switch(io->pi_width) {
414 		case 4:
415 		case 2:
416 		case 1:
417 			/*
418 			 * Assume that the user-level bus number is
419 			 * actually the pciN instance number. We map
420 			 * from that to the real pcib+bus combination.
421 			 */
422 			pci = devclass_get_device(devclass_find("pci"),
423 						  io->pi_sel.pc_bus);
424 			if (pci) {
425 				int b = pcib_get_bus(pci);
426 				pcib = device_get_parent(pci);
427 				io->pi_data =
428 					PCIB_READ_CONFIG(pcib,
429 							 b,
430 							 io->pi_sel.pc_dev,
431 							 io->pi_sel.pc_func,
432 							 io->pi_reg,
433 							 io->pi_width);
434 				error = 0;
435 			} else {
436 				error = ENODEV;
437 			}
438 			break;
439 		default:
440 			error = ENODEV;
441 			break;
442 		}
443 		break;
444 
445 	case PCIOCWRITE:
446 		io = (struct pci_io *)data;
447 		switch(io->pi_width) {
448 		case 4:
449 		case 2:
450 		case 1:
451 			/*
452 			 * Assume that the user-level bus number is
453 			 * actually the pciN instance number. We map
454 			 * from that to the real pcib+bus combination.
455 			 */
456 			pci = devclass_get_device(devclass_find("pci"),
457 						  io->pi_sel.pc_bus);
458 			if (pci) {
459 				int b = pcib_get_bus(pci);
460 				pcib = device_get_parent(pci);
461 				PCIB_WRITE_CONFIG(pcib,
462 						  b,
463 						  io->pi_sel.pc_dev,
464 						  io->pi_sel.pc_func,
465 						  io->pi_reg,
466 						  io->pi_data,
467 						  io->pi_width);
468 				error = 0;
469 			} else {
470 				error = ENODEV;
471 			}
472 			break;
473 		default:
474 			error = ENODEV;
475 			break;
476 		}
477 		break;
478 
479 	default:
480 		error = ENOTTY;
481 		break;
482 	}
483 
484 	return (error);
485 }
486 
487