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