pci_user.c revision 83366
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: head/sys/dev/pci/pci_user.c 83366 2001-09-12 08:38:13Z julian $
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
63static d_open_t 	pci_open;
64static d_close_t	pci_close;
65static int	pci_conf_match(struct pci_match_conf *matches, int num_matches,
66			       struct pci_conf *match_buf);
67static d_ioctl_t	pci_ioctl;
68
69#define	PCI_CDEV	78
70
71struct 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
87static int
88pci_open(dev_t dev, int oflags, int devtype, struct thread *td)
89{
90	if ((oflags & FWRITE) && securelevel > 0) {
91		return EPERM;
92	}
93	return 0;
94}
95
96static int
97pci_close(dev_t dev, int flag, int devtype, struct thread *td)
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 */
109static int
110pci_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
169static int
170pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
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