xref: /dflybsd-src/sys/bus/pci/pci_user.c (revision 857fcb57d0e5e7f20e3d0ef58163c718377e363e)
14d28e78fSSepherosa Ziehau /*-
24d28e78fSSepherosa Ziehau  * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org>
34d28e78fSSepherosa Ziehau  * All rights reserved.
44d28e78fSSepherosa Ziehau  *
54d28e78fSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
64d28e78fSSepherosa Ziehau  * modification, are permitted provided that the following conditions
74d28e78fSSepherosa Ziehau  * are met:
84d28e78fSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
94d28e78fSSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
104d28e78fSSepherosa Ziehau  *    disclaimer.
114d28e78fSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
124d28e78fSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
134d28e78fSSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
144d28e78fSSepherosa Ziehau  *
154d28e78fSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
164d28e78fSSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
174d28e78fSSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
184d28e78fSSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
194d28e78fSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
204d28e78fSSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
214d28e78fSSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
224d28e78fSSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
234d28e78fSSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
244d28e78fSSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2583c1faaaSSascha Wildner  *
2683c1faaaSSascha Wildner  * $FreeBSD: src/sys/dev/pci/pci_user.c,v 1.22.2.4.2.1 2009/04/15 03:14:26 kensmith Exp $
274d28e78fSSepherosa Ziehau  */
284d28e78fSSepherosa Ziehau 
294d28e78fSSepherosa Ziehau #include <sys/param.h>
304d28e78fSSepherosa Ziehau #include <sys/systm.h>
314d28e78fSSepherosa Ziehau #include <sys/malloc.h>
324d28e78fSSepherosa Ziehau #include <sys/module.h>
334d28e78fSSepherosa Ziehau #include <sys/linker.h>
344d28e78fSSepherosa Ziehau #include <sys/fcntl.h>
35*857fcb57SMatthew Dillon #include <sys/caps.h>
364d28e78fSSepherosa Ziehau #include <sys/conf.h>
374d28e78fSSepherosa Ziehau #include <sys/kernel.h>
384d28e78fSSepherosa Ziehau #include <sys/proc.h>
394d28e78fSSepherosa Ziehau #include <sys/queue.h>
404d28e78fSSepherosa Ziehau #include <sys/types.h>
414d28e78fSSepherosa Ziehau 
424d28e78fSSepherosa Ziehau #include <vm/vm.h>
434d28e78fSSepherosa Ziehau #include <vm/pmap.h>
444d28e78fSSepherosa Ziehau #include <vm/vm_extern.h>
454d28e78fSSepherosa Ziehau 
464d28e78fSSepherosa Ziehau #include <sys/bus.h>
474d28e78fSSepherosa Ziehau #include <sys/rman.h>
484d28e78fSSepherosa Ziehau #include <sys/device.h>
494d28e78fSSepherosa Ziehau #include <sys/pciio.h>
504d28e78fSSepherosa Ziehau #include <bus/pci/pcireg.h>
514d28e78fSSepherosa Ziehau #include <bus/pci/pcivar.h>
524d28e78fSSepherosa Ziehau 
534d28e78fSSepherosa Ziehau #include "pcib_if.h"
544d28e78fSSepherosa Ziehau #include "pci_if.h"
554d28e78fSSepherosa Ziehau 
564d28e78fSSepherosa Ziehau /*
574d28e78fSSepherosa Ziehau  * This is the user interface to PCI configuration space.
584d28e78fSSepherosa Ziehau  */
59481d12aaSMatthew Dillon static struct lwkt_token pci_token = LWKT_TOKEN_INITIALIZER(pci_token);
604d28e78fSSepherosa Ziehau 
614d28e78fSSepherosa Ziehau static d_open_t 	pci_open;
624d28e78fSSepherosa Ziehau static d_close_t	pci_close;
634d28e78fSSepherosa Ziehau static int	pci_conf_match(struct pci_match_conf *matches, int num_matches,
644d28e78fSSepherosa Ziehau 			       struct pci_conf *match_buf);
654d28e78fSSepherosa Ziehau static d_ioctl_t	pci_ioctl;
66442f4326SSascha Wildner 
67f161477dSSascha Wildner struct dev_ops pci_ops = {
68481d12aaSMatthew Dillon 	{ "pci", 0, D_MPSAFE },
694d28e78fSSepherosa Ziehau 	.d_open =       pci_open,
704d28e78fSSepherosa Ziehau 	.d_close =      pci_close,
714d28e78fSSepherosa Ziehau 	.d_ioctl =      pci_ioctl,
724d28e78fSSepherosa Ziehau };
734d28e78fSSepherosa Ziehau 
744d28e78fSSepherosa Ziehau static int
pci_open(struct dev_open_args * ap)754d28e78fSSepherosa Ziehau pci_open(struct dev_open_args *ap)
764d28e78fSSepherosa Ziehau {
77442f4326SSascha Wildner 	int oflags = ap->a_oflags;
78442f4326SSascha Wildner 
79*857fcb57SMatthew Dillon 	/*
80*857fcb57SMatthew Dillon 	 * Disallow access to disk volumes if RESTRICTEDROOT
81*857fcb57SMatthew Dillon 	 */
82*857fcb57SMatthew Dillon 	if (caps_priv_check_self(SYSCAP_RESTRICTEDROOT))
83*857fcb57SMatthew Dillon 		return (EPERM);
84*857fcb57SMatthew Dillon 
854d28e78fSSepherosa Ziehau 	if (oflags & FWRITE) {
86442f4326SSascha Wildner 		if (securelevel > 0)
87442f4326SSascha Wildner 			return (EPERM);
884d28e78fSSepherosa Ziehau 	}
89442f4326SSascha Wildner 
904d28e78fSSepherosa Ziehau 	return (0);
914d28e78fSSepherosa Ziehau }
924d28e78fSSepherosa Ziehau 
934d28e78fSSepherosa Ziehau static int
pci_close(struct dev_close_args * ap)944d28e78fSSepherosa Ziehau pci_close(struct dev_close_args *ap)
954d28e78fSSepherosa Ziehau {
964d28e78fSSepherosa Ziehau 	return 0;
974d28e78fSSepherosa Ziehau }
984d28e78fSSepherosa Ziehau 
994d28e78fSSepherosa Ziehau /*
1004d28e78fSSepherosa Ziehau  * Match a single pci_conf structure against an array of pci_match_conf
1014d28e78fSSepherosa Ziehau  * structures.  The first argument, 'matches', is an array of num_matches
1024d28e78fSSepherosa Ziehau  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
1034d28e78fSSepherosa Ziehau  * structure that will be compared to every entry in the matches array.
1044d28e78fSSepherosa Ziehau  * This function returns 1 on failure, 0 on success.
1054d28e78fSSepherosa Ziehau  */
1064d28e78fSSepherosa Ziehau static int
pci_conf_match(struct pci_match_conf * matches,int num_matches,struct pci_conf * match_buf)1074d28e78fSSepherosa Ziehau pci_conf_match(struct pci_match_conf *matches, int num_matches,
1084d28e78fSSepherosa Ziehau 	       struct pci_conf *match_buf)
1094d28e78fSSepherosa Ziehau {
1104d28e78fSSepherosa Ziehau 	int i;
1114d28e78fSSepherosa Ziehau 
1124d28e78fSSepherosa Ziehau 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
1134d28e78fSSepherosa Ziehau 		return(1);
1144d28e78fSSepherosa Ziehau 
1154d28e78fSSepherosa Ziehau 	for (i = 0; i < num_matches; i++) {
1164d28e78fSSepherosa Ziehau 		/*
1174d28e78fSSepherosa Ziehau 		 * I'm not sure why someone would do this...but...
1184d28e78fSSepherosa Ziehau 		 */
1194d28e78fSSepherosa Ziehau 		if (matches[i].flags == PCI_GETCONF_NO_MATCH)
1204d28e78fSSepherosa Ziehau 			continue;
1214d28e78fSSepherosa Ziehau 
1224d28e78fSSepherosa Ziehau 		/*
1234d28e78fSSepherosa Ziehau 		 * Look at each of the match flags.  If it's set, do the
1244d28e78fSSepherosa Ziehau 		 * comparison.  If the comparison fails, we don't have a
1254d28e78fSSepherosa Ziehau 		 * match, go on to the next item if there is one.
1264d28e78fSSepherosa Ziehau 		 */
1274d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
1284d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_domain !=
1294d28e78fSSepherosa Ziehau 		 matches[i].pc_sel.pc_domain))
1304d28e78fSSepherosa Ziehau 			continue;
1314d28e78fSSepherosa Ziehau 
1324d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
1334d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
1344d28e78fSSepherosa Ziehau 			continue;
1354d28e78fSSepherosa Ziehau 
1364d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
1374d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
1384d28e78fSSepherosa Ziehau 			continue;
1394d28e78fSSepherosa Ziehau 
1404d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
1414d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
1424d28e78fSSepherosa Ziehau 			continue;
1434d28e78fSSepherosa Ziehau 
1444d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
1454d28e78fSSepherosa Ziehau 		 && (match_buf->pc_vendor != matches[i].pc_vendor))
1464d28e78fSSepherosa Ziehau 			continue;
1474d28e78fSSepherosa Ziehau 
1484d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
1494d28e78fSSepherosa Ziehau 		 && (match_buf->pc_device != matches[i].pc_device))
1504d28e78fSSepherosa Ziehau 			continue;
1514d28e78fSSepherosa Ziehau 
1524d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
1534d28e78fSSepherosa Ziehau 		 && (match_buf->pc_class != matches[i].pc_class))
1544d28e78fSSepherosa Ziehau 			continue;
1554d28e78fSSepherosa Ziehau 
1564d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
1574d28e78fSSepherosa Ziehau 		 && (match_buf->pd_unit != matches[i].pd_unit))
1584d28e78fSSepherosa Ziehau 			continue;
1594d28e78fSSepherosa Ziehau 
1604d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
1614d28e78fSSepherosa Ziehau 		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
1624d28e78fSSepherosa Ziehau 			     sizeof(match_buf->pd_name)) != 0))
1634d28e78fSSepherosa Ziehau 			continue;
1644d28e78fSSepherosa Ziehau 
1654d28e78fSSepherosa Ziehau 		return(0);
1664d28e78fSSepherosa Ziehau 	}
1674d28e78fSSepherosa Ziehau 
1684d28e78fSSepherosa Ziehau 	return(1);
1694d28e78fSSepherosa Ziehau }
1704d28e78fSSepherosa Ziehau 
1714d28e78fSSepherosa Ziehau #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1724d28e78fSSepherosa Ziehau     defined(COMPAT_FREEBSD6) || defined(__DragonFly__)
1734d28e78fSSepherosa Ziehau #define PRE7_COMPAT
1744d28e78fSSepherosa Ziehau 
1754d28e78fSSepherosa Ziehau typedef enum {
1764d28e78fSSepherosa Ziehau 	PCI_GETCONF_NO_MATCH_OLD	= 0x00,
1774d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_BUS_OLD	= 0x01,
1784d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_DEV_OLD	= 0x02,
1794d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_FUNC_OLD	= 0x04,
1804d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_NAME_OLD	= 0x08,
1814d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_UNIT_OLD	= 0x10,
1824d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_VENDOR_OLD	= 0x20,
1834d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_DEVICE_OLD	= 0x40,
1844d28e78fSSepherosa Ziehau 	PCI_GETCONF_MATCH_CLASS_OLD	= 0x80
1854d28e78fSSepherosa Ziehau } pci_getconf_flags_old;
1864d28e78fSSepherosa Ziehau 
1874d28e78fSSepherosa Ziehau struct pcisel_old {
1884d28e78fSSepherosa Ziehau 	u_int8_t	pc_bus;		/* bus number */
1894d28e78fSSepherosa Ziehau 	u_int8_t	pc_dev;		/* device on this bus */
1904d28e78fSSepherosa Ziehau 	u_int8_t	pc_func;	/* function on this device */
1914d28e78fSSepherosa Ziehau };
1924d28e78fSSepherosa Ziehau 
1934d28e78fSSepherosa Ziehau struct pci_conf_old {
1944d28e78fSSepherosa Ziehau 	struct pcisel_old pc_sel;	/* bus+slot+function */
1954d28e78fSSepherosa Ziehau 	u_int8_t	pc_hdr;		/* PCI header type */
1964d28e78fSSepherosa Ziehau 	u_int16_t	pc_subvendor;	/* card vendor ID */
1974d28e78fSSepherosa Ziehau 	u_int16_t	pc_subdevice;	/* card device ID, assigned by
1984d28e78fSSepherosa Ziehau 					   card vendor */
1994d28e78fSSepherosa Ziehau 	u_int16_t	pc_vendor;	/* chip vendor ID */
2004d28e78fSSepherosa Ziehau 	u_int16_t	pc_device;	/* chip device ID, assigned by
2014d28e78fSSepherosa Ziehau 					   chip vendor */
2024d28e78fSSepherosa Ziehau 	u_int8_t	pc_class;	/* chip PCI class */
2034d28e78fSSepherosa Ziehau 	u_int8_t	pc_subclass;	/* chip PCI subclass */
2044d28e78fSSepherosa Ziehau 	u_int8_t	pc_progif;	/* chip PCI programming interface */
2054d28e78fSSepherosa Ziehau 	u_int8_t	pc_revid;	/* chip revision ID */
2064d28e78fSSepherosa Ziehau 	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
2074d28e78fSSepherosa Ziehau 	u_long		pd_unit;	/* device unit number */
2084d28e78fSSepherosa Ziehau };
2094d28e78fSSepherosa Ziehau 
2104d28e78fSSepherosa Ziehau struct pci_match_conf_old {
2114d28e78fSSepherosa Ziehau 	struct pcisel_old	pc_sel;		/* bus+slot+function */
2124d28e78fSSepherosa Ziehau 	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
2134d28e78fSSepherosa Ziehau 	u_long			pd_unit;	/* Unit number */
2144d28e78fSSepherosa Ziehau 	u_int16_t		pc_vendor;	/* PCI Vendor ID */
2154d28e78fSSepherosa Ziehau 	u_int16_t		pc_device;	/* PCI Device ID */
2164d28e78fSSepherosa Ziehau 	u_int8_t		pc_class;	/* PCI class */
2174d28e78fSSepherosa Ziehau 	pci_getconf_flags_old	flags;		/* Matching expression */
2184d28e78fSSepherosa Ziehau };
2194d28e78fSSepherosa Ziehau 
2204d28e78fSSepherosa Ziehau struct pci_io_old {
2214d28e78fSSepherosa Ziehau 	struct pcisel_old pi_sel;	/* device to operate on */
2224d28e78fSSepherosa Ziehau 	int		pi_reg;		/* configuration register to examine */
2234d28e78fSSepherosa Ziehau 	int		pi_width;	/* width (in bytes) of read or write */
2244d28e78fSSepherosa Ziehau 	u_int32_t	pi_data;	/* data to write or result of read */
2254d28e78fSSepherosa Ziehau };
2264d28e78fSSepherosa Ziehau 
2274d28e78fSSepherosa Ziehau #define	PCIOCGETCONF_OLD	_IOWR('p', 1, struct pci_conf_io)
2284d28e78fSSepherosa Ziehau #define	PCIOCREAD_OLD		_IOWR('p', 2, struct pci_io_old)
2294d28e78fSSepherosa Ziehau #define	PCIOCWRITE_OLD		_IOWR('p', 3, struct pci_io_old)
2304d28e78fSSepherosa Ziehau 
2314d28e78fSSepherosa Ziehau static int	pci_conf_match_old(struct pci_match_conf_old *matches,
2324d28e78fSSepherosa Ziehau 		    int num_matches, struct pci_conf *match_buf);
2334d28e78fSSepherosa Ziehau 
2344d28e78fSSepherosa Ziehau static int
pci_conf_match_old(struct pci_match_conf_old * matches,int num_matches,struct pci_conf * match_buf)2354d28e78fSSepherosa Ziehau pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
2364d28e78fSSepherosa Ziehau     struct pci_conf *match_buf)
2374d28e78fSSepherosa Ziehau {
2384d28e78fSSepherosa Ziehau 	int i;
2394d28e78fSSepherosa Ziehau 
2404d28e78fSSepherosa Ziehau 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
2414d28e78fSSepherosa Ziehau 		return(1);
2424d28e78fSSepherosa Ziehau 
2434d28e78fSSepherosa Ziehau 	for (i = 0; i < num_matches; i++) {
2444d28e78fSSepherosa Ziehau 		if (match_buf->pc_sel.pc_domain != 0)
2454d28e78fSSepherosa Ziehau 			continue;
2464d28e78fSSepherosa Ziehau 
2474d28e78fSSepherosa Ziehau 		/*
2484d28e78fSSepherosa Ziehau 		 * I'm not sure why someone would do this...but...
2494d28e78fSSepherosa Ziehau 		 */
2504d28e78fSSepherosa Ziehau 		if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
2514d28e78fSSepherosa Ziehau 			continue;
2524d28e78fSSepherosa Ziehau 
2534d28e78fSSepherosa Ziehau 		/*
2544d28e78fSSepherosa Ziehau 		 * Look at each of the match flags.  If it's set, do the
2554d28e78fSSepherosa Ziehau 		 * comparison.  If the comparison fails, we don't have a
2564d28e78fSSepherosa Ziehau 		 * match, go on to the next item if there is one.
2574d28e78fSSepherosa Ziehau 		 */
2584d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
2594d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
2604d28e78fSSepherosa Ziehau 			continue;
2614d28e78fSSepherosa Ziehau 
2624d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
2634d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
2644d28e78fSSepherosa Ziehau 			continue;
2654d28e78fSSepherosa Ziehau 
2664d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
2674d28e78fSSepherosa Ziehau 		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
2684d28e78fSSepherosa Ziehau 			continue;
2694d28e78fSSepherosa Ziehau 
2704d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
2714d28e78fSSepherosa Ziehau 		 && (match_buf->pc_vendor != matches[i].pc_vendor))
2724d28e78fSSepherosa Ziehau 			continue;
2734d28e78fSSepherosa Ziehau 
2744d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
2754d28e78fSSepherosa Ziehau 		 && (match_buf->pc_device != matches[i].pc_device))
2764d28e78fSSepherosa Ziehau 			continue;
2774d28e78fSSepherosa Ziehau 
2784d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
2794d28e78fSSepherosa Ziehau 		 && (match_buf->pc_class != matches[i].pc_class))
2804d28e78fSSepherosa Ziehau 			continue;
2814d28e78fSSepherosa Ziehau 
2824d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
2834d28e78fSSepherosa Ziehau 		 && (match_buf->pd_unit != matches[i].pd_unit))
2844d28e78fSSepherosa Ziehau 			continue;
2854d28e78fSSepherosa Ziehau 
2864d28e78fSSepherosa Ziehau 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
2874d28e78fSSepherosa Ziehau 		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
2884d28e78fSSepherosa Ziehau 			     sizeof(match_buf->pd_name)) != 0))
2894d28e78fSSepherosa Ziehau 			continue;
2904d28e78fSSepherosa Ziehau 
2914d28e78fSSepherosa Ziehau 		return(0);
2924d28e78fSSepherosa Ziehau 	}
2934d28e78fSSepherosa Ziehau 
2944d28e78fSSepherosa Ziehau 	return(1);
2954d28e78fSSepherosa Ziehau }
2964d28e78fSSepherosa Ziehau 
2974d28e78fSSepherosa Ziehau #endif
2984d28e78fSSepherosa Ziehau 
2994d28e78fSSepherosa Ziehau static int
pci_ioctl(struct dev_ioctl_args * ap)3004d28e78fSSepherosa Ziehau pci_ioctl(struct dev_ioctl_args *ap)
3014d28e78fSSepherosa Ziehau {
3024d28e78fSSepherosa Ziehau 	device_t pcidev, brdev;
3034d28e78fSSepherosa Ziehau 	void *confdata;
3044d28e78fSSepherosa Ziehau 	const char *name;
3054d28e78fSSepherosa Ziehau 	struct devlist *devlist_head;
3064d28e78fSSepherosa Ziehau 	struct pci_conf_io *cio;
3074d28e78fSSepherosa Ziehau 	struct pci_devinfo *dinfo;
3084d28e78fSSepherosa Ziehau 	struct pci_io *io;
3094d28e78fSSepherosa Ziehau 	struct pci_bar_io *bio;
3104d28e78fSSepherosa Ziehau 	struct pci_match_conf *pattern_buf;
3114d28e78fSSepherosa Ziehau 	struct resource_list_entry *rle;
3124d28e78fSSepherosa Ziehau 	uint32_t value;
3134d28e78fSSepherosa Ziehau 	size_t confsz, iolen, pbufsz;
3144d28e78fSSepherosa Ziehau 	int error, ionum, i, num_patterns;
3154d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
3164d28e78fSSepherosa Ziehau 	struct pci_conf_old conf_old;
3174d28e78fSSepherosa Ziehau 	struct pci_io iodata;
3184d28e78fSSepherosa Ziehau 	struct pci_io_old *io_old;
3194d28e78fSSepherosa Ziehau 	struct pci_match_conf_old *pattern_buf_old;
3204d28e78fSSepherosa Ziehau 
3214d28e78fSSepherosa Ziehau 	io_old = NULL;
3224d28e78fSSepherosa Ziehau 	pattern_buf_old = NULL;
3234d28e78fSSepherosa Ziehau 
3244d28e78fSSepherosa Ziehau 	if (!(ap->a_fflag & FWRITE) && ap->a_cmd != PCIOCGETBAR &&
3254d28e78fSSepherosa Ziehau 	    ap->a_cmd != PCIOCGETCONF && ap->a_cmd != PCIOCGETCONF_OLD)
3264d28e78fSSepherosa Ziehau 		return EPERM;
3274d28e78fSSepherosa Ziehau #else
3284d28e78fSSepherosa Ziehau 	if (!(ap->a_fflag & FWRITE) && ap->a_cmd != PCIOCGETBAR && ap->a_cmd != PCIOCGETCONF)
3294d28e78fSSepherosa Ziehau 		return EPERM;
3304d28e78fSSepherosa Ziehau #endif
3314d28e78fSSepherosa Ziehau 
332481d12aaSMatthew Dillon 	lwkt_gettoken(&pci_token);
333481d12aaSMatthew Dillon 
3344d28e78fSSepherosa Ziehau 	switch(ap->a_cmd) {
3354d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
3364d28e78fSSepherosa Ziehau 	case PCIOCGETCONF_OLD:
3374d28e78fSSepherosa Ziehau 		/* FALLTHROUGH */
3384d28e78fSSepherosa Ziehau #endif
3394d28e78fSSepherosa Ziehau 	case PCIOCGETCONF:
3404d28e78fSSepherosa Ziehau 		cio = (struct pci_conf_io *)ap->a_data;
3414d28e78fSSepherosa Ziehau 
3424d28e78fSSepherosa Ziehau 		pattern_buf = NULL;
3434d28e78fSSepherosa Ziehau 		num_patterns = 0;
3444d28e78fSSepherosa Ziehau 		dinfo = NULL;
3454d28e78fSSepherosa Ziehau 
3464d28e78fSSepherosa Ziehau 		cio->num_matches = 0;
3474d28e78fSSepherosa Ziehau 
3484d28e78fSSepherosa Ziehau 		/*
3494d28e78fSSepherosa Ziehau 		 * If the user specified an offset into the device list,
3504d28e78fSSepherosa Ziehau 		 * but the list has changed since they last called this
3514d28e78fSSepherosa Ziehau 		 * ioctl, tell them that the list has changed.  They will
3524d28e78fSSepherosa Ziehau 		 * have to get the list from the beginning.
3534d28e78fSSepherosa Ziehau 		 */
3544d28e78fSSepherosa Ziehau 		if ((cio->offset != 0)
3554d28e78fSSepherosa Ziehau 		 && (cio->generation != pci_generation)){
3564d28e78fSSepherosa Ziehau 			cio->status = PCI_GETCONF_LIST_CHANGED;
3574d28e78fSSepherosa Ziehau 			error = 0;
3584d28e78fSSepherosa Ziehau 			break;
3594d28e78fSSepherosa Ziehau 		}
3604d28e78fSSepherosa Ziehau 
3614d28e78fSSepherosa Ziehau 		/*
3624d28e78fSSepherosa Ziehau 		 * Check to see whether the user has asked for an offset
3634d28e78fSSepherosa Ziehau 		 * past the end of our list.
3644d28e78fSSepherosa Ziehau 		 */
3654d28e78fSSepherosa Ziehau 		if (cio->offset >= pci_numdevs) {
3664d28e78fSSepherosa Ziehau 			cio->status = PCI_GETCONF_LAST_DEVICE;
3674d28e78fSSepherosa Ziehau 			error = 0;
3684d28e78fSSepherosa Ziehau 			break;
3694d28e78fSSepherosa Ziehau 		}
3704d28e78fSSepherosa Ziehau 
3714d28e78fSSepherosa Ziehau 		/* get the head of the device queue */
3724d28e78fSSepherosa Ziehau 		devlist_head = &pci_devq;
3734d28e78fSSepherosa Ziehau 
3744d28e78fSSepherosa Ziehau 		/*
3754d28e78fSSepherosa Ziehau 		 * Determine how much room we have for pci_conf structures.
3764d28e78fSSepherosa Ziehau 		 * Round the user's buffer size down to the nearest
3774d28e78fSSepherosa Ziehau 		 * multiple of sizeof(struct pci_conf) in case the user
3784d28e78fSSepherosa Ziehau 		 * didn't specify a multiple of that size.
3794d28e78fSSepherosa Ziehau 		 */
3804d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
3814d28e78fSSepherosa Ziehau 		if (ap->a_cmd == PCIOCGETCONF_OLD)
3824d28e78fSSepherosa Ziehau 			confsz = sizeof(struct pci_conf_old);
3834d28e78fSSepherosa Ziehau 		else
3844d28e78fSSepherosa Ziehau #endif
3854d28e78fSSepherosa Ziehau 			confsz = sizeof(struct pci_conf);
3864d28e78fSSepherosa Ziehau 		iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
3874d28e78fSSepherosa Ziehau 		    pci_numdevs * confsz);
3884d28e78fSSepherosa Ziehau 
3894d28e78fSSepherosa Ziehau 		/*
3904d28e78fSSepherosa Ziehau 		 * Since we know that iolen is a multiple of the size of
3914d28e78fSSepherosa Ziehau 		 * the pciconf union, it's okay to do this.
3924d28e78fSSepherosa Ziehau 		 */
3934d28e78fSSepherosa Ziehau 		ionum = iolen / confsz;
3944d28e78fSSepherosa Ziehau 
3954d28e78fSSepherosa Ziehau 		/*
3964d28e78fSSepherosa Ziehau 		 * If this test is true, the user wants the pci_conf
3974d28e78fSSepherosa Ziehau 		 * structures returned to match the supplied entries.
3984d28e78fSSepherosa Ziehau 		 */
3994d28e78fSSepherosa Ziehau 		if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
4004d28e78fSSepherosa Ziehau 		 && (cio->pat_buf_len > 0)) {
4014d28e78fSSepherosa Ziehau 			/*
4024d28e78fSSepherosa Ziehau 			 * pat_buf_len needs to be:
4034d28e78fSSepherosa Ziehau 			 * num_patterns * sizeof(struct pci_match_conf)
4044d28e78fSSepherosa Ziehau 			 * While it is certainly possible the user just
4054d28e78fSSepherosa Ziehau 			 * allocated a large buffer, but set the number of
4064d28e78fSSepherosa Ziehau 			 * matches correctly, it is far more likely that
4074d28e78fSSepherosa Ziehau 			 * their kernel doesn't match the userland utility
4084d28e78fSSepherosa Ziehau 			 * they're using.  It's also possible that the user
4094d28e78fSSepherosa Ziehau 			 * forgot to initialize some variables.  Yes, this
4104d28e78fSSepherosa Ziehau 			 * may be overly picky, but I hazard to guess that
4114d28e78fSSepherosa Ziehau 			 * it's far more likely to just catch folks that
4124d28e78fSSepherosa Ziehau 			 * updated their kernel but not their userland.
4134d28e78fSSepherosa Ziehau 			 */
4144d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
4154d28e78fSSepherosa Ziehau 			if (ap->a_cmd == PCIOCGETCONF_OLD)
4164d28e78fSSepherosa Ziehau 				pbufsz = sizeof(struct pci_match_conf_old);
4174d28e78fSSepherosa Ziehau 			else
4184d28e78fSSepherosa Ziehau #endif
4194d28e78fSSepherosa Ziehau 				pbufsz = sizeof(struct pci_match_conf);
4204d28e78fSSepherosa Ziehau 			if (cio->num_patterns * pbufsz != cio->pat_buf_len) {
4214d28e78fSSepherosa Ziehau 				/* The user made a mistake, return an error. */
4224d28e78fSSepherosa Ziehau 				cio->status = PCI_GETCONF_ERROR;
4234d28e78fSSepherosa Ziehau 				error = EINVAL;
4244d28e78fSSepherosa Ziehau 				break;
4254d28e78fSSepherosa Ziehau 			}
4264d28e78fSSepherosa Ziehau 
4274d28e78fSSepherosa Ziehau 			/*
4284d28e78fSSepherosa Ziehau 			 * Allocate a buffer to hold the patterns.
4294d28e78fSSepherosa Ziehau 			 */
4304d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
4314d28e78fSSepherosa Ziehau 			if (ap->a_cmd == PCIOCGETCONF_OLD) {
4324d28e78fSSepherosa Ziehau 				pattern_buf_old = kmalloc(cio->pat_buf_len,
4334d28e78fSSepherosa Ziehau 				    M_TEMP, M_WAITOK);
4344d28e78fSSepherosa Ziehau 				error = copyin(cio->patterns,
4354d28e78fSSepherosa Ziehau 				    pattern_buf_old, cio->pat_buf_len);
4364d28e78fSSepherosa Ziehau 			} else
4374d28e78fSSepherosa Ziehau #endif
4384d28e78fSSepherosa Ziehau 			{
4394d28e78fSSepherosa Ziehau 				pattern_buf = kmalloc(cio->pat_buf_len, M_TEMP,
4404d28e78fSSepherosa Ziehau 				    M_WAITOK);
4414d28e78fSSepherosa Ziehau 				error = copyin(cio->patterns, pattern_buf,
4424d28e78fSSepherosa Ziehau 				    cio->pat_buf_len);
4434d28e78fSSepherosa Ziehau 			}
4444d28e78fSSepherosa Ziehau 			if (error != 0) {
4454d28e78fSSepherosa Ziehau 				error = EINVAL;
4464d28e78fSSepherosa Ziehau 				goto getconfexit;
4474d28e78fSSepherosa Ziehau 			}
4484d28e78fSSepherosa Ziehau 			num_patterns = cio->num_patterns;
4494d28e78fSSepherosa Ziehau 		} else if ((cio->num_patterns > 0)
4504d28e78fSSepherosa Ziehau 			|| (cio->pat_buf_len > 0)) {
4514d28e78fSSepherosa Ziehau 			/*
4524d28e78fSSepherosa Ziehau 			 * The user made a mistake, spit out an error.
4534d28e78fSSepherosa Ziehau 			 */
4544d28e78fSSepherosa Ziehau 			cio->status = PCI_GETCONF_ERROR;
4554d28e78fSSepherosa Ziehau 			error = EINVAL;
4564d28e78fSSepherosa Ziehau 			break;
4574d28e78fSSepherosa Ziehau 		}
4584d28e78fSSepherosa Ziehau 
4594d28e78fSSepherosa Ziehau 		/*
4604d28e78fSSepherosa Ziehau 		 * Go through the list of devices and copy out the devices
4614d28e78fSSepherosa Ziehau 		 * that match the user's criteria.
4624d28e78fSSepherosa Ziehau 		 */
4634d28e78fSSepherosa Ziehau 		for (cio->num_matches = 0, error = 0, i = 0,
4644d28e78fSSepherosa Ziehau 		     dinfo = STAILQ_FIRST(devlist_head);
4654d28e78fSSepherosa Ziehau 		     (dinfo != NULL) && (cio->num_matches < ionum)
4664d28e78fSSepherosa Ziehau 		     && (error == 0) && (i < pci_numdevs) && (dinfo != NULL);
4674d28e78fSSepherosa Ziehau 		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
4684d28e78fSSepherosa Ziehau 
4694d28e78fSSepherosa Ziehau 			if (i < cio->offset)
4704d28e78fSSepherosa Ziehau 				continue;
4714d28e78fSSepherosa Ziehau 
4724d28e78fSSepherosa Ziehau 			/* Populate pd_name and pd_unit */
4734d28e78fSSepherosa Ziehau 			name = NULL;
4744d28e78fSSepherosa Ziehau 			if (dinfo->cfg.dev)
4754d28e78fSSepherosa Ziehau 				name = device_get_name(dinfo->cfg.dev);
4764d28e78fSSepherosa Ziehau 			if (name) {
4774d28e78fSSepherosa Ziehau 				strncpy(dinfo->conf.pd_name, name,
4784d28e78fSSepherosa Ziehau 					sizeof(dinfo->conf.pd_name));
4794d28e78fSSepherosa Ziehau 				dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
4804d28e78fSSepherosa Ziehau 				dinfo->conf.pd_unit =
4814d28e78fSSepherosa Ziehau 					device_get_unit(dinfo->cfg.dev);
4824d28e78fSSepherosa Ziehau 			} else {
4834d28e78fSSepherosa Ziehau 				dinfo->conf.pd_name[0] = '\0';
4844d28e78fSSepherosa Ziehau 				dinfo->conf.pd_unit = 0;
4854d28e78fSSepherosa Ziehau 			}
4864d28e78fSSepherosa Ziehau 
4874d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
4884d28e78fSSepherosa Ziehau 			if ((ap->a_cmd == PCIOCGETCONF_OLD &&
4894d28e78fSSepherosa Ziehau 			    (pattern_buf_old == NULL ||
4904d28e78fSSepherosa Ziehau 			    pci_conf_match_old(pattern_buf_old, num_patterns,
4914d28e78fSSepherosa Ziehau 			    &dinfo->conf) == 0)) ||
4924d28e78fSSepherosa Ziehau 			    (ap->a_cmd == PCIOCGETCONF &&
4934d28e78fSSepherosa Ziehau 			    (pattern_buf == NULL ||
4944d28e78fSSepherosa Ziehau 			    pci_conf_match(pattern_buf, num_patterns,
4954d28e78fSSepherosa Ziehau 			    &dinfo->conf) == 0))) {
4964d28e78fSSepherosa Ziehau #else
4974d28e78fSSepherosa Ziehau 			if (pattern_buf == NULL ||
4984d28e78fSSepherosa Ziehau 			    pci_conf_match(pattern_buf, num_patterns,
4994d28e78fSSepherosa Ziehau 			    &dinfo->conf) == 0) {
5004d28e78fSSepherosa Ziehau #endif
5014d28e78fSSepherosa Ziehau 				/*
5024d28e78fSSepherosa Ziehau 				 * If we've filled up the user's buffer,
5034d28e78fSSepherosa Ziehau 				 * break out at this point.  Since we've
5044d28e78fSSepherosa Ziehau 				 * got a match here, we'll pick right back
5054d28e78fSSepherosa Ziehau 				 * up at the matching entry.  We can also
5064d28e78fSSepherosa Ziehau 				 * tell the user that there are more matches
5074d28e78fSSepherosa Ziehau 				 * left.
5084d28e78fSSepherosa Ziehau 				 */
5094d28e78fSSepherosa Ziehau 				if (cio->num_matches >= ionum)
5104d28e78fSSepherosa Ziehau 					break;
5114d28e78fSSepherosa Ziehau 
5124d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
5134d28e78fSSepherosa Ziehau 				if (ap->a_cmd == PCIOCGETCONF_OLD) {
5144d28e78fSSepherosa Ziehau 					conf_old.pc_sel.pc_bus =
5154d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_sel.pc_bus;
5164d28e78fSSepherosa Ziehau 					conf_old.pc_sel.pc_dev =
5174d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_sel.pc_dev;
5184d28e78fSSepherosa Ziehau 					conf_old.pc_sel.pc_func =
5194d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_sel.pc_func;
5204d28e78fSSepherosa Ziehau 					conf_old.pc_hdr = dinfo->conf.pc_hdr;
5214d28e78fSSepherosa Ziehau 					conf_old.pc_subvendor =
5224d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_subvendor;
5234d28e78fSSepherosa Ziehau 					conf_old.pc_subdevice =
5244d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_subdevice;
5254d28e78fSSepherosa Ziehau 					conf_old.pc_vendor =
5264d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_vendor;
5274d28e78fSSepherosa Ziehau 					conf_old.pc_device =
5284d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_device;
5294d28e78fSSepherosa Ziehau 					conf_old.pc_class =
5304d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_class;
5314d28e78fSSepherosa Ziehau 					conf_old.pc_subclass =
5324d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_subclass;
5334d28e78fSSepherosa Ziehau 					conf_old.pc_progif =
5344d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_progif;
5354d28e78fSSepherosa Ziehau 					conf_old.pc_revid =
5364d28e78fSSepherosa Ziehau 					    dinfo->conf.pc_revid;
5374d28e78fSSepherosa Ziehau 					strncpy(conf_old.pd_name,
5384d28e78fSSepherosa Ziehau 					    dinfo->conf.pd_name,
5394d28e78fSSepherosa Ziehau 					    sizeof(conf_old.pd_name));
5404d28e78fSSepherosa Ziehau 					conf_old.pd_name[PCI_MAXNAMELEN] = 0;
5414d28e78fSSepherosa Ziehau 					conf_old.pd_unit =
5424d28e78fSSepherosa Ziehau 					    dinfo->conf.pd_unit;
5434d28e78fSSepherosa Ziehau 					confdata = &conf_old;
5444d28e78fSSepherosa Ziehau 				} else
5454d28e78fSSepherosa Ziehau #endif
5464d28e78fSSepherosa Ziehau 					confdata = &dinfo->conf;
5474d28e78fSSepherosa Ziehau 				/* Only if we can copy it out do we count it. */
5484d28e78fSSepherosa Ziehau 				if (!(error = copyout(confdata,
5494d28e78fSSepherosa Ziehau 				    (caddr_t)cio->matches +
5504d28e78fSSepherosa Ziehau 				    confsz * cio->num_matches, confsz)))
5514d28e78fSSepherosa Ziehau 					cio->num_matches++;
5524d28e78fSSepherosa Ziehau 			}
5534d28e78fSSepherosa Ziehau 		}
5544d28e78fSSepherosa Ziehau 
5554d28e78fSSepherosa Ziehau 		/*
5564d28e78fSSepherosa Ziehau 		 * Set the pointer into the list, so if the user is getting
5574d28e78fSSepherosa Ziehau 		 * n records at a time, where n < pci_numdevs,
5584d28e78fSSepherosa Ziehau 		 */
5594d28e78fSSepherosa Ziehau 		cio->offset = i;
5604d28e78fSSepherosa Ziehau 
5614d28e78fSSepherosa Ziehau 		/*
5624d28e78fSSepherosa Ziehau 		 * Set the generation, the user will need this if they make
5634d28e78fSSepherosa Ziehau 		 * another ioctl call with offset != 0.
5644d28e78fSSepherosa Ziehau 		 */
5654d28e78fSSepherosa Ziehau 		cio->generation = pci_generation;
5664d28e78fSSepherosa Ziehau 
5674d28e78fSSepherosa Ziehau 		/*
5684d28e78fSSepherosa Ziehau 		 * If this is the last device, inform the user so he won't
5694d28e78fSSepherosa Ziehau 		 * bother asking for more devices.  If dinfo isn't NULL, we
5704d28e78fSSepherosa Ziehau 		 * know that there are more matches in the list because of
5714d28e78fSSepherosa Ziehau 		 * the way the traversal is done.
5724d28e78fSSepherosa Ziehau 		 */
5734d28e78fSSepherosa Ziehau 		if (dinfo == NULL)
5744d28e78fSSepherosa Ziehau 			cio->status = PCI_GETCONF_LAST_DEVICE;
5754d28e78fSSepherosa Ziehau 		else
5764d28e78fSSepherosa Ziehau 			cio->status = PCI_GETCONF_MORE_DEVS;
5774d28e78fSSepherosa Ziehau 
5784d28e78fSSepherosa Ziehau getconfexit:
5794d28e78fSSepherosa Ziehau 		if (pattern_buf != NULL)
5804d28e78fSSepherosa Ziehau 			kfree(pattern_buf, M_TEMP);
5814d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
5824d28e78fSSepherosa Ziehau 		if (pattern_buf_old != NULL)
5834d28e78fSSepherosa Ziehau 			kfree(pattern_buf_old, M_TEMP);
5844d28e78fSSepherosa Ziehau #endif
5854d28e78fSSepherosa Ziehau 
5864d28e78fSSepherosa Ziehau 		break;
5874d28e78fSSepherosa Ziehau 
5884d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
5894d28e78fSSepherosa Ziehau 	case PCIOCREAD_OLD:
5904d28e78fSSepherosa Ziehau 	case PCIOCWRITE_OLD:
5914d28e78fSSepherosa Ziehau 		io_old = (struct pci_io_old *)ap->a_data;
5924d28e78fSSepherosa Ziehau 		iodata.pi_sel.pc_domain = 0;
5934d28e78fSSepherosa Ziehau 		iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
5944d28e78fSSepherosa Ziehau 		iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
5954d28e78fSSepherosa Ziehau 		iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
5964d28e78fSSepherosa Ziehau 		iodata.pi_reg = io_old->pi_reg;
5974d28e78fSSepherosa Ziehau 		iodata.pi_width = io_old->pi_width;
5984d28e78fSSepherosa Ziehau 		iodata.pi_data = io_old->pi_data;
5994d28e78fSSepherosa Ziehau 		ap->a_data = (caddr_t)&iodata;
6004d28e78fSSepherosa Ziehau 		/* FALLTHROUGH */
6014d28e78fSSepherosa Ziehau #endif
6024d28e78fSSepherosa Ziehau 	case PCIOCREAD:
6034d28e78fSSepherosa Ziehau 	case PCIOCWRITE:
6044d28e78fSSepherosa Ziehau 		io = (struct pci_io *)ap->a_data;
6054d28e78fSSepherosa Ziehau 		switch(io->pi_width) {
6064d28e78fSSepherosa Ziehau 		case 4:
6074d28e78fSSepherosa Ziehau 		case 2:
6084d28e78fSSepherosa Ziehau 		case 1:
6097a8c7ad6SSascha Wildner 			/* Make sure register is not negative and aligned. */
6104d28e78fSSepherosa Ziehau 			if (io->pi_reg < 0 ||
6114d28e78fSSepherosa Ziehau 			    io->pi_reg & (io->pi_width - 1)) {
6124d28e78fSSepherosa Ziehau 				error = EINVAL;
6134d28e78fSSepherosa Ziehau 				break;
6144d28e78fSSepherosa Ziehau 			}
6154d28e78fSSepherosa Ziehau 			/*
6164d28e78fSSepherosa Ziehau 			 * Assume that the user-level bus number is
6174d28e78fSSepherosa Ziehau 			 * in fact the physical PCI bus number.
6184d28e78fSSepherosa Ziehau 			 * Look up the grandparent, i.e. the bridge device,
6194d28e78fSSepherosa Ziehau 			 * so that we can issue configuration space cycles.
6204d28e78fSSepherosa Ziehau 			 */
6214d28e78fSSepherosa Ziehau 			pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
6224d28e78fSSepherosa Ziehau 			    io->pi_sel.pc_bus, io->pi_sel.pc_dev,
6234d28e78fSSepherosa Ziehau 			    io->pi_sel.pc_func);
6244d28e78fSSepherosa Ziehau 			if (pcidev) {
6254d28e78fSSepherosa Ziehau 				brdev = device_get_parent(
6264d28e78fSSepherosa Ziehau 				    device_get_parent(pcidev));
6274d28e78fSSepherosa Ziehau 
6284d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
6294d28e78fSSepherosa Ziehau 				if (ap->a_cmd == PCIOCWRITE || ap->a_cmd == PCIOCWRITE_OLD)
6304d28e78fSSepherosa Ziehau #else
6314d28e78fSSepherosa Ziehau 				if (ap->a_cmd == PCIOCWRITE)
6324d28e78fSSepherosa Ziehau #endif
6334d28e78fSSepherosa Ziehau 					PCIB_WRITE_CONFIG(brdev,
6344d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_bus,
6354d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_dev,
6364d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_func,
6374d28e78fSSepherosa Ziehau 							  io->pi_reg,
6384d28e78fSSepherosa Ziehau 							  io->pi_data,
6394d28e78fSSepherosa Ziehau 							  io->pi_width);
6404d28e78fSSepherosa Ziehau #ifdef PRE7_COMPAT
6414d28e78fSSepherosa Ziehau 				else if (ap->a_cmd == PCIOCREAD_OLD)
6424d28e78fSSepherosa Ziehau 					io_old->pi_data =
6434d28e78fSSepherosa Ziehau 						PCIB_READ_CONFIG(brdev,
6444d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_bus,
6454d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_dev,
6464d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_func,
6474d28e78fSSepherosa Ziehau 							  io->pi_reg,
6484d28e78fSSepherosa Ziehau 							  io->pi_width);
6494d28e78fSSepherosa Ziehau #endif
6504d28e78fSSepherosa Ziehau 				else
6514d28e78fSSepherosa Ziehau 					io->pi_data =
6524d28e78fSSepherosa Ziehau 						PCIB_READ_CONFIG(brdev,
6534d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_bus,
6544d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_dev,
6554d28e78fSSepherosa Ziehau 							  io->pi_sel.pc_func,
6564d28e78fSSepherosa Ziehau 							  io->pi_reg,
6574d28e78fSSepherosa Ziehau 							  io->pi_width);
6584d28e78fSSepherosa Ziehau 				error = 0;
6594d28e78fSSepherosa Ziehau 			} else {
6604d28e78fSSepherosa Ziehau #ifdef COMPAT_FREEBSD4
6614d28e78fSSepherosa Ziehau 				if (cmd == PCIOCREAD_OLD) {
6624d28e78fSSepherosa Ziehau 					io_old->pi_data = -1;
6634d28e78fSSepherosa Ziehau 					error = 0;
6644d28e78fSSepherosa Ziehau 				} else
6654d28e78fSSepherosa Ziehau #endif
6664d28e78fSSepherosa Ziehau 					error = ENODEV;
6674d28e78fSSepherosa Ziehau 			}
6684d28e78fSSepherosa Ziehau 			break;
6694d28e78fSSepherosa Ziehau 		default:
6704d28e78fSSepherosa Ziehau 			error = EINVAL;
6714d28e78fSSepherosa Ziehau 			break;
6724d28e78fSSepherosa Ziehau 		}
6734d28e78fSSepherosa Ziehau 		break;
6744d28e78fSSepherosa Ziehau 
6754d28e78fSSepherosa Ziehau 	case PCIOCGETBAR:
6764d28e78fSSepherosa Ziehau 		bio = (struct pci_bar_io *)ap->a_data;
6774d28e78fSSepherosa Ziehau 
6784d28e78fSSepherosa Ziehau 		/*
6794d28e78fSSepherosa Ziehau 		 * Assume that the user-level bus number is
6804d28e78fSSepherosa Ziehau 		 * in fact the physical PCI bus number.
6814d28e78fSSepherosa Ziehau 		 */
6824d28e78fSSepherosa Ziehau 		pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
6834d28e78fSSepherosa Ziehau 		    bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
6844d28e78fSSepherosa Ziehau 		    bio->pbi_sel.pc_func);
6854d28e78fSSepherosa Ziehau 		if (pcidev == NULL) {
6864d28e78fSSepherosa Ziehau 			error = ENODEV;
6874d28e78fSSepherosa Ziehau 			break;
6884d28e78fSSepherosa Ziehau 		}
6894d28e78fSSepherosa Ziehau 		dinfo = device_get_ivars(pcidev);
6904d28e78fSSepherosa Ziehau 
6914d28e78fSSepherosa Ziehau 		/*
6924d28e78fSSepherosa Ziehau 		 * Look for a resource list entry matching the requested BAR.
6934d28e78fSSepherosa Ziehau 		 *
6944d28e78fSSepherosa Ziehau 		 * XXX: This will not find BARs that are not initialized, but
6954d28e78fSSepherosa Ziehau 		 * maybe that is ok?
6964d28e78fSSepherosa Ziehau 		 */
6974d28e78fSSepherosa Ziehau 		rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
6984d28e78fSSepherosa Ziehau 		    bio->pbi_reg);
6994d28e78fSSepherosa Ziehau 		if (rle == NULL)
7004d28e78fSSepherosa Ziehau 			rle = resource_list_find(&dinfo->resources,
7014d28e78fSSepherosa Ziehau 			    SYS_RES_IOPORT, bio->pbi_reg);
7024d28e78fSSepherosa Ziehau 		if (rle == NULL || rle->res == NULL) {
7034d28e78fSSepherosa Ziehau 			error = EINVAL;
7044d28e78fSSepherosa Ziehau 			break;
7054d28e78fSSepherosa Ziehau 		}
7064d28e78fSSepherosa Ziehau 
7074d28e78fSSepherosa Ziehau 		/*
7084d28e78fSSepherosa Ziehau 		 * Ok, we have a resource for this BAR.  Read the lower
7094d28e78fSSepherosa Ziehau 		 * 32 bits to get any flags.
7104d28e78fSSepherosa Ziehau 		 */
7114d28e78fSSepherosa Ziehau 		value = pci_read_config(pcidev, bio->pbi_reg, 4);
7124d28e78fSSepherosa Ziehau 		if (PCI_BAR_MEM(value)) {
7134d28e78fSSepherosa Ziehau 			if (rle->type != SYS_RES_MEMORY) {
7144d28e78fSSepherosa Ziehau 				error = EINVAL;
7154d28e78fSSepherosa Ziehau 				break;
7164d28e78fSSepherosa Ziehau 			}
7174d28e78fSSepherosa Ziehau 			value &= ~PCIM_BAR_MEM_BASE;
7184d28e78fSSepherosa Ziehau 		} else {
7194d28e78fSSepherosa Ziehau 			if (rle->type != SYS_RES_IOPORT) {
7204d28e78fSSepherosa Ziehau 				error = EINVAL;
7214d28e78fSSepherosa Ziehau 				break;
7224d28e78fSSepherosa Ziehau 			}
7234d28e78fSSepherosa Ziehau 			value &= ~PCIM_BAR_IO_BASE;
7244d28e78fSSepherosa Ziehau 		}
7254d28e78fSSepherosa Ziehau 		bio->pbi_base = rman_get_start(rle->res) | value;
7264d28e78fSSepherosa Ziehau 		bio->pbi_length = rman_get_size(rle->res);
7274d28e78fSSepherosa Ziehau 
7284d28e78fSSepherosa Ziehau 		/*
7294d28e78fSSepherosa Ziehau 		 * Check the command register to determine if this BAR
7304d28e78fSSepherosa Ziehau 		 * is enabled.
7314d28e78fSSepherosa Ziehau 		 */
7324d28e78fSSepherosa Ziehau 		value = pci_read_config(pcidev, PCIR_COMMAND, 2);
7334d28e78fSSepherosa Ziehau 		if (rle->type == SYS_RES_MEMORY)
7344d28e78fSSepherosa Ziehau 			bio->pbi_enabled = (value & PCIM_CMD_MEMEN) != 0;
7354d28e78fSSepherosa Ziehau 		else
7364d28e78fSSepherosa Ziehau 			bio->pbi_enabled = (value & PCIM_CMD_PORTEN) != 0;
7374d28e78fSSepherosa Ziehau 		error = 0;
7384d28e78fSSepherosa Ziehau 		break;
739a0014d83SSascha Wildner 	case PCIOCATTACHED:
740a0014d83SSascha Wildner 		error = 0;
741a0014d83SSascha Wildner 		io = (struct pci_io *)ap->a_data;
742a0014d83SSascha Wildner 		pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
743a0014d83SSascha Wildner 				       io->pi_sel.pc_dev, io->pi_sel.pc_func);
744a0014d83SSascha Wildner 		if (pcidev != NULL)
745a0014d83SSascha Wildner 			io->pi_data = device_is_attached(pcidev);
746a0014d83SSascha Wildner 		else
747a0014d83SSascha Wildner 			error = ENODEV;
748a0014d83SSascha Wildner 		break;
7494d28e78fSSepherosa Ziehau 	default:
7504d28e78fSSepherosa Ziehau 		error = ENOTTY;
7514d28e78fSSepherosa Ziehau 		break;
7524d28e78fSSepherosa Ziehau 	}
753481d12aaSMatthew Dillon 	lwkt_reltoken(&pci_token);
7544d28e78fSSepherosa Ziehau 
7554d28e78fSSepherosa Ziehau 	return (error);
7564d28e78fSSepherosa Ziehau }
757