1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_bus.h" /* XXX trim includes */ 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/module.h> 39 #include <sys/linker.h> 40 #include <sys/fcntl.h> 41 #include <sys/conf.h> 42 #include <sys/kernel.h> 43 #include <sys/mman.h> 44 #include <sys/proc.h> 45 #include <sys/queue.h> 46 #include <sys/rwlock.h> 47 #include <sys/sglist.h> 48 49 #include <vm/vm.h> 50 #include <vm/pmap.h> 51 #include <vm/vm_extern.h> 52 #include <vm/vm_map.h> 53 #include <vm/vm_object.h> 54 #include <vm/vm_page.h> 55 #include <vm/vm_pager.h> 56 57 #include <sys/bus.h> 58 #include <machine/bus.h> 59 #include <sys/rman.h> 60 #include <machine/resource.h> 61 62 #include <sys/pciio.h> 63 #include <dev/pci/pcireg.h> 64 #include <dev/pci/pcivar.h> 65 66 #include "pcib_if.h" 67 #include "pci_if.h" 68 69 #ifdef COMPAT_FREEBSD32 70 struct pci_conf32 { 71 struct pcisel pc_sel; /* domain+bus+slot+function */ 72 u_int8_t pc_hdr; /* PCI header type */ 73 u_int16_t pc_subvendor; /* card vendor ID */ 74 u_int16_t pc_subdevice; /* card device ID, assigned by 75 card vendor */ 76 u_int16_t pc_vendor; /* chip vendor ID */ 77 u_int16_t pc_device; /* chip device ID, assigned by 78 chip vendor */ 79 u_int8_t pc_class; /* chip PCI class */ 80 u_int8_t pc_subclass; /* chip PCI subclass */ 81 u_int8_t pc_progif; /* chip PCI programming interface */ 82 u_int8_t pc_revid; /* chip revision ID */ 83 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 84 u_int32_t pd_unit; /* device unit number */ 85 }; 86 87 struct pci_match_conf32 { 88 struct pcisel pc_sel; /* domain+bus+slot+function */ 89 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 90 u_int32_t pd_unit; /* Unit number */ 91 u_int16_t pc_vendor; /* PCI Vendor ID */ 92 u_int16_t pc_device; /* PCI Device ID */ 93 u_int8_t pc_class; /* PCI class */ 94 u_int32_t flags; /* Matching expression */ 95 }; 96 97 struct pci_conf_io32 { 98 u_int32_t pat_buf_len; /* pattern buffer length */ 99 u_int32_t num_patterns; /* number of patterns */ 100 u_int32_t patterns; /* struct pci_match_conf ptr */ 101 u_int32_t match_buf_len; /* match buffer length */ 102 u_int32_t num_matches; /* number of matches returned */ 103 u_int32_t matches; /* struct pci_conf ptr */ 104 u_int32_t offset; /* offset into device list */ 105 u_int32_t generation; /* device list generation */ 106 u_int32_t status; /* request status */ 107 }; 108 109 #define PCIOCGETCONF32 _IOC_NEWTYPE(PCIOCGETCONF, struct pci_conf_io32) 110 #endif 111 112 /* 113 * This is the user interface to PCI configuration space. 114 */ 115 116 static d_open_t pci_open; 117 static d_close_t pci_close; 118 static d_ioctl_t pci_ioctl; 119 120 struct cdevsw pcicdev = { 121 .d_version = D_VERSION, 122 .d_flags = D_NEEDGIANT, 123 .d_open = pci_open, 124 .d_close = pci_close, 125 .d_ioctl = pci_ioctl, 126 .d_name = "pci", 127 }; 128 129 static int 130 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 131 { 132 int error; 133 134 if (oflags & FWRITE) { 135 error = securelevel_gt(td->td_ucred, 0); 136 if (error) 137 return (error); 138 } 139 140 return (0); 141 } 142 143 static int 144 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td) 145 { 146 return 0; 147 } 148 149 /* 150 * Match a single pci_conf structure against an array of pci_match_conf 151 * structures. The first argument, 'matches', is an array of num_matches 152 * pci_match_conf structures. match_buf is a pointer to the pci_conf 153 * structure that will be compared to every entry in the matches array. 154 * This function returns 1 on failure, 0 on success. 155 */ 156 static int 157 pci_conf_match_native(struct pci_match_conf *matches, int num_matches, 158 struct pci_conf *match_buf) 159 { 160 int i; 161 162 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 163 return(1); 164 165 for (i = 0; i < num_matches; i++) { 166 /* 167 * I'm not sure why someone would do this...but... 168 */ 169 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 170 continue; 171 172 /* 173 * Look at each of the match flags. If it's set, do the 174 * comparison. If the comparison fails, we don't have a 175 * match, go on to the next item if there is one. 176 */ 177 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) 178 && (match_buf->pc_sel.pc_domain != 179 matches[i].pc_sel.pc_domain)) 180 continue; 181 182 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 183 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 184 continue; 185 186 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 187 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 188 continue; 189 190 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 191 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 192 continue; 193 194 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 195 && (match_buf->pc_vendor != matches[i].pc_vendor)) 196 continue; 197 198 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 199 && (match_buf->pc_device != matches[i].pc_device)) 200 continue; 201 202 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 203 && (match_buf->pc_class != matches[i].pc_class)) 204 continue; 205 206 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 207 && (match_buf->pd_unit != matches[i].pd_unit)) 208 continue; 209 210 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 211 && (strncmp(matches[i].pd_name, match_buf->pd_name, 212 sizeof(match_buf->pd_name)) != 0)) 213 continue; 214 215 return(0); 216 } 217 218 return(1); 219 } 220 221 #ifdef COMPAT_FREEBSD32 222 static int 223 pci_conf_match32(struct pci_match_conf32 *matches, int num_matches, 224 struct pci_conf *match_buf) 225 { 226 int i; 227 228 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 229 return(1); 230 231 for (i = 0; i < num_matches; i++) { 232 /* 233 * I'm not sure why someone would do this...but... 234 */ 235 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 236 continue; 237 238 /* 239 * Look at each of the match flags. If it's set, do the 240 * comparison. If the comparison fails, we don't have a 241 * match, go on to the next item if there is one. 242 */ 243 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) 244 && (match_buf->pc_sel.pc_domain != 245 matches[i].pc_sel.pc_domain)) 246 continue; 247 248 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 249 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 250 continue; 251 252 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 253 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 254 continue; 255 256 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 257 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 258 continue; 259 260 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 261 && (match_buf->pc_vendor != matches[i].pc_vendor)) 262 continue; 263 264 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 265 && (match_buf->pc_device != matches[i].pc_device)) 266 continue; 267 268 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 269 && (match_buf->pc_class != matches[i].pc_class)) 270 continue; 271 272 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 273 && (match_buf->pd_unit != matches[i].pd_unit)) 274 continue; 275 276 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 277 && (strncmp(matches[i].pd_name, match_buf->pd_name, 278 sizeof(match_buf->pd_name)) != 0)) 279 continue; 280 281 return(0); 282 } 283 284 return(1); 285 } 286 #endif /* COMPAT_FREEBSD32 */ 287 288 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 289 defined(COMPAT_FREEBSD6) 290 #define PRE7_COMPAT 291 292 typedef enum { 293 PCI_GETCONF_NO_MATCH_OLD = 0x00, 294 PCI_GETCONF_MATCH_BUS_OLD = 0x01, 295 PCI_GETCONF_MATCH_DEV_OLD = 0x02, 296 PCI_GETCONF_MATCH_FUNC_OLD = 0x04, 297 PCI_GETCONF_MATCH_NAME_OLD = 0x08, 298 PCI_GETCONF_MATCH_UNIT_OLD = 0x10, 299 PCI_GETCONF_MATCH_VENDOR_OLD = 0x20, 300 PCI_GETCONF_MATCH_DEVICE_OLD = 0x40, 301 PCI_GETCONF_MATCH_CLASS_OLD = 0x80 302 } pci_getconf_flags_old; 303 304 struct pcisel_old { 305 u_int8_t pc_bus; /* bus number */ 306 u_int8_t pc_dev; /* device on this bus */ 307 u_int8_t pc_func; /* function on this device */ 308 }; 309 310 struct pci_conf_old { 311 struct pcisel_old pc_sel; /* bus+slot+function */ 312 u_int8_t pc_hdr; /* PCI header type */ 313 u_int16_t pc_subvendor; /* card vendor ID */ 314 u_int16_t pc_subdevice; /* card device ID, assigned by 315 card vendor */ 316 u_int16_t pc_vendor; /* chip vendor ID */ 317 u_int16_t pc_device; /* chip device ID, assigned by 318 chip vendor */ 319 u_int8_t pc_class; /* chip PCI class */ 320 u_int8_t pc_subclass; /* chip PCI subclass */ 321 u_int8_t pc_progif; /* chip PCI programming interface */ 322 u_int8_t pc_revid; /* chip revision ID */ 323 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 324 u_long pd_unit; /* device unit number */ 325 }; 326 327 struct pci_match_conf_old { 328 struct pcisel_old pc_sel; /* bus+slot+function */ 329 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 330 u_long pd_unit; /* Unit number */ 331 u_int16_t pc_vendor; /* PCI Vendor ID */ 332 u_int16_t pc_device; /* PCI Device ID */ 333 u_int8_t pc_class; /* PCI class */ 334 pci_getconf_flags_old flags; /* Matching expression */ 335 }; 336 337 struct pci_io_old { 338 struct pcisel_old pi_sel; /* device to operate on */ 339 int pi_reg; /* configuration register to examine */ 340 int pi_width; /* width (in bytes) of read or write */ 341 u_int32_t pi_data; /* data to write or result of read */ 342 }; 343 344 #ifdef COMPAT_FREEBSD32 345 struct pci_conf_old32 { 346 struct pcisel_old pc_sel; /* bus+slot+function */ 347 uint8_t pc_hdr; /* PCI header type */ 348 uint16_t pc_subvendor; /* card vendor ID */ 349 uint16_t pc_subdevice; /* card device ID, assigned by 350 card vendor */ 351 uint16_t pc_vendor; /* chip vendor ID */ 352 uint16_t pc_device; /* chip device ID, assigned by 353 chip vendor */ 354 uint8_t pc_class; /* chip PCI class */ 355 uint8_t pc_subclass; /* chip PCI subclass */ 356 uint8_t pc_progif; /* chip PCI programming interface */ 357 uint8_t pc_revid; /* chip revision ID */ 358 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 359 uint32_t pd_unit; /* device unit number (u_long) */ 360 }; 361 362 struct pci_match_conf_old32 { 363 struct pcisel_old pc_sel; /* bus+slot+function */ 364 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 365 uint32_t pd_unit; /* Unit number (u_long) */ 366 uint16_t pc_vendor; /* PCI Vendor ID */ 367 uint16_t pc_device; /* PCI Device ID */ 368 uint8_t pc_class; /* PCI class */ 369 pci_getconf_flags_old flags; /* Matching expression */ 370 }; 371 372 #define PCIOCGETCONF_OLD32 _IOWR('p', 1, struct pci_conf_io32) 373 #endif /* COMPAT_FREEBSD32 */ 374 375 #define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io) 376 #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old) 377 #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old) 378 379 static int 380 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches, 381 struct pci_conf *match_buf) 382 { 383 int i; 384 385 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 386 return(1); 387 388 for (i = 0; i < num_matches; i++) { 389 if (match_buf->pc_sel.pc_domain != 0) 390 continue; 391 392 /* 393 * I'm not sure why someone would do this...but... 394 */ 395 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD) 396 continue; 397 398 /* 399 * Look at each of the match flags. If it's set, do the 400 * comparison. If the comparison fails, we don't have a 401 * match, go on to the next item if there is one. 402 */ 403 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) 404 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 405 continue; 406 407 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) 408 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 409 continue; 410 411 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) 412 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 413 continue; 414 415 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) 416 && (match_buf->pc_vendor != matches[i].pc_vendor)) 417 continue; 418 419 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) 420 && (match_buf->pc_device != matches[i].pc_device)) 421 continue; 422 423 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) 424 && (match_buf->pc_class != matches[i].pc_class)) 425 continue; 426 427 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) 428 && (match_buf->pd_unit != matches[i].pd_unit)) 429 continue; 430 431 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) 432 && (strncmp(matches[i].pd_name, match_buf->pd_name, 433 sizeof(match_buf->pd_name)) != 0)) 434 continue; 435 436 return(0); 437 } 438 439 return(1); 440 } 441 442 #ifdef COMPAT_FREEBSD32 443 static int 444 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches, 445 struct pci_conf *match_buf) 446 { 447 int i; 448 449 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 450 return(1); 451 452 for (i = 0; i < num_matches; i++) { 453 if (match_buf->pc_sel.pc_domain != 0) 454 continue; 455 456 /* 457 * I'm not sure why someone would do this...but... 458 */ 459 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD) 460 continue; 461 462 /* 463 * Look at each of the match flags. If it's set, do the 464 * comparison. If the comparison fails, we don't have a 465 * match, go on to the next item if there is one. 466 */ 467 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) && 468 (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 469 continue; 470 471 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) && 472 (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 473 continue; 474 475 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) && 476 (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 477 continue; 478 479 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) && 480 (match_buf->pc_vendor != matches[i].pc_vendor)) 481 continue; 482 483 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) && 484 (match_buf->pc_device != matches[i].pc_device)) 485 continue; 486 487 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) && 488 (match_buf->pc_class != matches[i].pc_class)) 489 continue; 490 491 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) && 492 ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit)) 493 continue; 494 495 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) && 496 (strncmp(matches[i].pd_name, match_buf->pd_name, 497 sizeof(match_buf->pd_name)) != 0)) 498 continue; 499 500 return (0); 501 } 502 503 return (1); 504 } 505 #endif /* COMPAT_FREEBSD32 */ 506 #endif /* !PRE7_COMPAT */ 507 508 union pci_conf_union { 509 struct pci_conf pc; 510 #ifdef COMPAT_FREEBSD32 511 struct pci_conf32 pc32; 512 #endif 513 #ifdef PRE7_COMPAT 514 struct pci_conf_old pco; 515 #ifdef COMPAT_FREEBSD32 516 struct pci_conf_old32 pco32; 517 #endif 518 #endif 519 }; 520 521 static int 522 pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches, 523 struct pci_conf *match_buf) 524 { 525 526 switch (cmd) { 527 case PCIOCGETCONF: 528 return (pci_conf_match_native( 529 (struct pci_match_conf *)matches, num_matches, match_buf)); 530 #ifdef COMPAT_FREEBSD32 531 case PCIOCGETCONF32: 532 return (pci_conf_match32((struct pci_match_conf32 *)matches, 533 num_matches, match_buf)); 534 #endif 535 #ifdef PRE7_COMPAT 536 case PCIOCGETCONF_OLD: 537 return (pci_conf_match_old( 538 (struct pci_match_conf_old *)matches, num_matches, 539 match_buf)); 540 #ifdef COMPAT_FREEBSD32 541 case PCIOCGETCONF_OLD32: 542 return (pci_conf_match_old32( 543 (struct pci_match_conf_old32 *)matches, num_matches, 544 match_buf)); 545 #endif 546 #endif 547 default: 548 /* programmer error */ 549 return (0); 550 } 551 } 552 553 /* 554 * Like PVE_NEXT but takes an explicit length since 'pve' is a user 555 * pointer that cannot be dereferenced. 556 */ 557 #define PVE_NEXT_LEN(pve, datalen) \ 558 ((struct pci_vpd_element *)((char *)(pve) + \ 559 sizeof(struct pci_vpd_element) + (datalen))) 560 561 static int 562 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio) 563 { 564 struct pci_vpd_element vpd_element, *vpd_user; 565 struct pcicfg_vpd *vpd; 566 size_t len; 567 int error, i; 568 569 vpd = pci_fetch_vpd_list(dev); 570 if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL) 571 return (ENXIO); 572 573 /* 574 * Calculate the amount of space needed in the data buffer. An 575 * identifier element is always present followed by the read-only 576 * and read-write keywords. 577 */ 578 len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident); 579 for (i = 0; i < vpd->vpd_rocnt; i++) 580 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len; 581 for (i = 0; i < vpd->vpd_wcnt; i++) 582 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len; 583 584 if (lvio->plvi_len == 0) { 585 lvio->plvi_len = len; 586 return (0); 587 } 588 if (lvio->plvi_len < len) { 589 lvio->plvi_len = len; 590 return (ENOMEM); 591 } 592 593 /* 594 * Copyout the identifier string followed by each keyword and 595 * value. 596 */ 597 vpd_user = lvio->plvi_data; 598 vpd_element.pve_keyword[0] = '\0'; 599 vpd_element.pve_keyword[1] = '\0'; 600 vpd_element.pve_flags = PVE_FLAG_IDENT; 601 vpd_element.pve_datalen = strlen(vpd->vpd_ident); 602 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 603 if (error) 604 return (error); 605 error = copyout(vpd->vpd_ident, vpd_user->pve_data, 606 strlen(vpd->vpd_ident)); 607 if (error) 608 return (error); 609 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen); 610 vpd_element.pve_flags = 0; 611 for (i = 0; i < vpd->vpd_rocnt; i++) { 612 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0]; 613 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1]; 614 vpd_element.pve_datalen = vpd->vpd_ros[i].len; 615 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 616 if (error) 617 return (error); 618 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data, 619 vpd->vpd_ros[i].len); 620 if (error) 621 return (error); 622 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen); 623 } 624 vpd_element.pve_flags = PVE_FLAG_RW; 625 for (i = 0; i < vpd->vpd_wcnt; i++) { 626 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0]; 627 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1]; 628 vpd_element.pve_datalen = vpd->vpd_w[i].len; 629 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 630 if (error) 631 return (error); 632 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data, 633 vpd->vpd_w[i].len); 634 if (error) 635 return (error); 636 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen); 637 } 638 KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len, 639 ("length mismatch")); 640 lvio->plvi_len = len; 641 return (0); 642 } 643 644 static size_t 645 pci_match_conf_size(u_long cmd) 646 { 647 648 switch (cmd) { 649 case PCIOCGETCONF: 650 return (sizeof(struct pci_match_conf)); 651 #ifdef COMPAT_FREEBSD32 652 case PCIOCGETCONF32: 653 return (sizeof(struct pci_match_conf32)); 654 #endif 655 #ifdef PRE7_COMPAT 656 case PCIOCGETCONF_OLD: 657 return (sizeof(struct pci_match_conf_old)); 658 #ifdef COMPAT_FREEBSD32 659 case PCIOCGETCONF_OLD32: 660 return (sizeof(struct pci_match_conf_old32)); 661 #endif 662 #endif 663 default: 664 /* programmer error */ 665 return (0); 666 } 667 } 668 669 static size_t 670 pci_conf_size(u_long cmd) 671 { 672 673 switch (cmd) { 674 case PCIOCGETCONF: 675 return (sizeof(struct pci_conf)); 676 #ifdef COMPAT_FREEBSD32 677 case PCIOCGETCONF32: 678 return (sizeof(struct pci_conf32)); 679 #endif 680 #ifdef PRE7_COMPAT 681 case PCIOCGETCONF_OLD: 682 return (sizeof(struct pci_conf_old)); 683 #ifdef COMPAT_FREEBSD32 684 case PCIOCGETCONF_OLD32: 685 return (sizeof(struct pci_conf_old32)); 686 #endif 687 #endif 688 default: 689 /* programmer error */ 690 return (0); 691 } 692 } 693 694 static void 695 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) 696 { 697 #if defined(COMPAT_FREEBSD32) 698 struct pci_conf_io32 *cio32; 699 #endif 700 701 switch (cmd) { 702 case PCIOCGETCONF: 703 #ifdef PRE7_COMPAT 704 case PCIOCGETCONF_OLD: 705 #endif 706 *cio = *(struct pci_conf_io *)data; 707 return; 708 709 #ifdef COMPAT_FREEBSD32 710 case PCIOCGETCONF32: 711 #ifdef PRE7_COMPAT 712 case PCIOCGETCONF_OLD32: 713 #endif 714 cio32 = (struct pci_conf_io32 *)data; 715 cio->pat_buf_len = cio32->pat_buf_len; 716 cio->num_patterns = cio32->num_patterns; 717 cio->patterns = (void *)(uintptr_t)cio32->patterns; 718 cio->match_buf_len = cio32->match_buf_len; 719 cio->num_matches = cio32->num_matches; 720 cio->matches = (void *)(uintptr_t)cio32->matches; 721 cio->offset = cio32->offset; 722 cio->generation = cio32->generation; 723 cio->status = cio32->status; 724 return; 725 #endif 726 727 default: 728 /* programmer error */ 729 return; 730 } 731 } 732 733 static void 734 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, 735 u_long cmd) 736 { 737 struct pci_conf_io *d_cio; 738 #if defined(COMPAT_FREEBSD32) 739 struct pci_conf_io32 *cio32; 740 #endif 741 742 switch (cmd) { 743 case PCIOCGETCONF: 744 #ifdef PRE7_COMPAT 745 case PCIOCGETCONF_OLD: 746 #endif 747 d_cio = (struct pci_conf_io *)data; 748 d_cio->status = cio->status; 749 d_cio->generation = cio->generation; 750 d_cio->offset = cio->offset; 751 d_cio->num_matches = cio->num_matches; 752 return; 753 754 #ifdef COMPAT_FREEBSD32 755 case PCIOCGETCONF32: 756 #ifdef PRE7_COMPAT 757 case PCIOCGETCONF_OLD32: 758 #endif 759 cio32 = (struct pci_conf_io32 *)data; 760 761 cio32->status = cio->status; 762 cio32->generation = cio->generation; 763 cio32->offset = cio->offset; 764 cio32->num_matches = cio->num_matches; 765 return; 766 #endif 767 768 default: 769 /* programmer error */ 770 return; 771 } 772 } 773 774 static void 775 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, 776 u_long cmd) 777 { 778 779 memset(pcup, 0, sizeof(*pcup)); 780 781 switch (cmd) { 782 case PCIOCGETCONF: 783 pcup->pc = *pcp; 784 return; 785 786 #ifdef COMPAT_FREEBSD32 787 case PCIOCGETCONF32: 788 pcup->pc32.pc_sel = pcp->pc_sel; 789 pcup->pc32.pc_hdr = pcp->pc_hdr; 790 pcup->pc32.pc_subvendor = pcp->pc_subvendor; 791 pcup->pc32.pc_subdevice = pcp->pc_subdevice; 792 pcup->pc32.pc_vendor = pcp->pc_vendor; 793 pcup->pc32.pc_device = pcp->pc_device; 794 pcup->pc32.pc_class = pcp->pc_class; 795 pcup->pc32.pc_subclass = pcp->pc_subclass; 796 pcup->pc32.pc_progif = pcp->pc_progif; 797 pcup->pc32.pc_revid = pcp->pc_revid; 798 strlcpy(pcup->pc32.pd_name, pcp->pd_name, 799 sizeof(pcup->pc32.pd_name)); 800 pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit; 801 return; 802 #endif 803 804 #ifdef PRE7_COMPAT 805 #ifdef COMPAT_FREEBSD32 806 case PCIOCGETCONF_OLD32: 807 pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus; 808 pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev; 809 pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func; 810 pcup->pco32.pc_hdr = pcp->pc_hdr; 811 pcup->pco32.pc_subvendor = pcp->pc_subvendor; 812 pcup->pco32.pc_subdevice = pcp->pc_subdevice; 813 pcup->pco32.pc_vendor = pcp->pc_vendor; 814 pcup->pco32.pc_device = pcp->pc_device; 815 pcup->pco32.pc_class = pcp->pc_class; 816 pcup->pco32.pc_subclass = pcp->pc_subclass; 817 pcup->pco32.pc_progif = pcp->pc_progif; 818 pcup->pco32.pc_revid = pcp->pc_revid; 819 strlcpy(pcup->pco32.pd_name, pcp->pd_name, 820 sizeof(pcup->pco32.pd_name)); 821 pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit; 822 return; 823 824 #endif /* COMPAT_FREEBSD32 */ 825 case PCIOCGETCONF_OLD: 826 pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus; 827 pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev; 828 pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func; 829 pcup->pco.pc_hdr = pcp->pc_hdr; 830 pcup->pco.pc_subvendor = pcp->pc_subvendor; 831 pcup->pco.pc_subdevice = pcp->pc_subdevice; 832 pcup->pco.pc_vendor = pcp->pc_vendor; 833 pcup->pco.pc_device = pcp->pc_device; 834 pcup->pco.pc_class = pcp->pc_class; 835 pcup->pco.pc_subclass = pcp->pc_subclass; 836 pcup->pco.pc_progif = pcp->pc_progif; 837 pcup->pco.pc_revid = pcp->pc_revid; 838 strlcpy(pcup->pco.pd_name, pcp->pd_name, 839 sizeof(pcup->pco.pd_name)); 840 pcup->pco.pd_unit = pcp->pd_unit; 841 return; 842 #endif /* PRE7_COMPAT */ 843 844 default: 845 /* programmer error */ 846 return; 847 } 848 } 849 850 static int 851 pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm) 852 { 853 vm_map_t map; 854 vm_object_t obj; 855 struct thread *td; 856 struct sglist *sg; 857 struct pci_map *pm; 858 vm_paddr_t membase; 859 vm_paddr_t pbase; 860 vm_size_t plen; 861 vm_offset_t addr; 862 vm_prot_t prot; 863 int error, flags; 864 865 td = curthread; 866 map = &td->td_proc->p_vmspace->vm_map; 867 if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL | 868 PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 || 869 pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr || 870 !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr)) 871 return (EINVAL); 872 873 /* Fetch the BAR physical base and length. */ 874 pm = pci_find_bar(pcidev, pbm->pbm_reg); 875 if (pm == NULL) 876 return (EINVAL); 877 if (!pci_bar_enabled(pcidev, pm)) 878 return (EBUSY); /* XXXKIB enable if _ACTIVATE */ 879 if (!PCI_BAR_MEM(pm->pm_value)) 880 return (EIO); 881 membase = pm->pm_value & PCIM_BAR_MEM_BASE; 882 pbase = trunc_page(membase); 883 plen = round_page(membase + ((pci_addr_t)1 << pm->pm_size)) - 884 pbase; 885 prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ? 886 VM_PROT_WRITE : 0); 887 888 /* Create vm structures and mmap. */ 889 sg = sglist_alloc(1, M_WAITOK); 890 error = sglist_append_phys(sg, pbase, plen); 891 if (error != 0) 892 goto out; 893 obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred); 894 if (obj == NULL) { 895 error = EIO; 896 goto out; 897 } 898 obj->memattr = pbm->pbm_memattr; 899 flags = MAP_SHARED; 900 addr = 0; 901 if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) { 902 addr = (uintptr_t)pbm->pbm_map_base; 903 flags |= MAP_FIXED; 904 } 905 if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0) 906 flags |= MAP_CHECK_EXCL; 907 error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0, 908 FALSE, td); 909 if (error != 0) { 910 vm_object_deallocate(obj); 911 goto out; 912 } 913 pbm->pbm_map_base = (void *)addr; 914 pbm->pbm_map_length = plen; 915 pbm->pbm_bar_off = membase - pbase; 916 pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size; 917 918 out: 919 sglist_free(sg); 920 return (error); 921 } 922 923 static int 924 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 925 { 926 device_t pcidev; 927 const char *name; 928 struct devlist *devlist_head; 929 struct pci_conf_io *cio = NULL; 930 struct pci_devinfo *dinfo; 931 struct pci_io *io; 932 struct pci_bar_io *bio; 933 struct pci_list_vpd_io *lvio; 934 struct pci_match_conf *pattern_buf; 935 struct pci_map *pm; 936 struct pci_bar_mmap *pbm; 937 size_t confsz, iolen; 938 int error, ionum, i, num_patterns; 939 union pci_conf_union pcu; 940 #ifdef PRE7_COMPAT 941 struct pci_io iodata; 942 struct pci_io_old *io_old; 943 944 io_old = NULL; 945 #endif 946 947 if (!(flag & FWRITE)) { 948 switch (cmd) { 949 case PCIOCGETCONF: 950 #ifdef COMPAT_FREEBSD32 951 case PCIOCGETCONF32: 952 #endif 953 #ifdef PRE7_COMPAT 954 case PCIOCGETCONF_OLD: 955 #ifdef COMPAT_FREEBSD32 956 case PCIOCGETCONF_OLD32: 957 #endif 958 #endif 959 case PCIOCGETBAR: 960 case PCIOCLISTVPD: 961 break; 962 default: 963 return (EPERM); 964 } 965 } 966 967 968 switch (cmd) { 969 case PCIOCGETCONF: 970 #ifdef COMPAT_FREEBSD32 971 case PCIOCGETCONF32: 972 #endif 973 #ifdef PRE7_COMPAT 974 case PCIOCGETCONF_OLD: 975 #ifdef COMPAT_FREEBSD32 976 case PCIOCGETCONF_OLD32: 977 #endif 978 #endif 979 cio = malloc(sizeof(struct pci_conf_io), M_TEMP, 980 M_WAITOK | M_ZERO); 981 pci_conf_io_init(cio, data, cmd); 982 pattern_buf = NULL; 983 num_patterns = 0; 984 dinfo = NULL; 985 986 cio->num_matches = 0; 987 988 /* 989 * If the user specified an offset into the device list, 990 * but the list has changed since they last called this 991 * ioctl, tell them that the list has changed. They will 992 * have to get the list from the beginning. 993 */ 994 if ((cio->offset != 0) 995 && (cio->generation != pci_generation)){ 996 cio->status = PCI_GETCONF_LIST_CHANGED; 997 error = 0; 998 goto getconfexit; 999 } 1000 1001 /* 1002 * Check to see whether the user has asked for an offset 1003 * past the end of our list. 1004 */ 1005 if (cio->offset >= pci_numdevs) { 1006 cio->status = PCI_GETCONF_LAST_DEVICE; 1007 error = 0; 1008 goto getconfexit; 1009 } 1010 1011 /* get the head of the device queue */ 1012 devlist_head = &pci_devq; 1013 1014 /* 1015 * Determine how much room we have for pci_conf structures. 1016 * Round the user's buffer size down to the nearest 1017 * multiple of sizeof(struct pci_conf) in case the user 1018 * didn't specify a multiple of that size. 1019 */ 1020 confsz = pci_conf_size(cmd); 1021 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), 1022 pci_numdevs * confsz); 1023 1024 /* 1025 * Since we know that iolen is a multiple of the size of 1026 * the pciconf union, it's okay to do this. 1027 */ 1028 ionum = iolen / confsz; 1029 1030 /* 1031 * If this test is true, the user wants the pci_conf 1032 * structures returned to match the supplied entries. 1033 */ 1034 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs) 1035 && (cio->pat_buf_len > 0)) { 1036 /* 1037 * pat_buf_len needs to be: 1038 * num_patterns * sizeof(struct pci_match_conf) 1039 * While it is certainly possible the user just 1040 * allocated a large buffer, but set the number of 1041 * matches correctly, it is far more likely that 1042 * their kernel doesn't match the userland utility 1043 * they're using. It's also possible that the user 1044 * forgot to initialize some variables. Yes, this 1045 * may be overly picky, but I hazard to guess that 1046 * it's far more likely to just catch folks that 1047 * updated their kernel but not their userland. 1048 */ 1049 if (cio->num_patterns * pci_match_conf_size(cmd) != 1050 cio->pat_buf_len) { 1051 /* The user made a mistake, return an error. */ 1052 cio->status = PCI_GETCONF_ERROR; 1053 error = EINVAL; 1054 goto getconfexit; 1055 } 1056 1057 /* 1058 * Allocate a buffer to hold the patterns. 1059 */ 1060 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 1061 M_WAITOK); 1062 error = copyin(cio->patterns, pattern_buf, 1063 cio->pat_buf_len); 1064 if (error != 0) { 1065 error = EINVAL; 1066 goto getconfexit; 1067 } 1068 num_patterns = cio->num_patterns; 1069 } else if ((cio->num_patterns > 0) 1070 || (cio->pat_buf_len > 0)) { 1071 /* 1072 * The user made a mistake, spit out an error. 1073 */ 1074 cio->status = PCI_GETCONF_ERROR; 1075 error = EINVAL; 1076 goto getconfexit; 1077 } 1078 1079 /* 1080 * Go through the list of devices and copy out the devices 1081 * that match the user's criteria. 1082 */ 1083 for (cio->num_matches = 0, i = 0, 1084 dinfo = STAILQ_FIRST(devlist_head); 1085 dinfo != NULL; 1086 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 1087 1088 if (i < cio->offset) 1089 continue; 1090 1091 /* Populate pd_name and pd_unit */ 1092 name = NULL; 1093 if (dinfo->cfg.dev) 1094 name = device_get_name(dinfo->cfg.dev); 1095 if (name) { 1096 strncpy(dinfo->conf.pd_name, name, 1097 sizeof(dinfo->conf.pd_name)); 1098 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 1099 dinfo->conf.pd_unit = 1100 device_get_unit(dinfo->cfg.dev); 1101 } else { 1102 dinfo->conf.pd_name[0] = '\0'; 1103 dinfo->conf.pd_unit = 0; 1104 } 1105 1106 if (pattern_buf == NULL || 1107 pci_conf_match(cmd, pattern_buf, num_patterns, 1108 &dinfo->conf) == 0) { 1109 /* 1110 * If we've filled up the user's buffer, 1111 * break out at this point. Since we've 1112 * got a match here, we'll pick right back 1113 * up at the matching entry. We can also 1114 * tell the user that there are more matches 1115 * left. 1116 */ 1117 if (cio->num_matches >= ionum) { 1118 error = 0; 1119 break; 1120 } 1121 1122 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); 1123 error = copyout(&pcu, 1124 (caddr_t)cio->matches + 1125 confsz * cio->num_matches, confsz); 1126 if (error) 1127 break; 1128 cio->num_matches++; 1129 } 1130 } 1131 1132 /* 1133 * Set the pointer into the list, so if the user is getting 1134 * n records at a time, where n < pci_numdevs, 1135 */ 1136 cio->offset = i; 1137 1138 /* 1139 * Set the generation, the user will need this if they make 1140 * another ioctl call with offset != 0. 1141 */ 1142 cio->generation = pci_generation; 1143 1144 /* 1145 * If this is the last device, inform the user so he won't 1146 * bother asking for more devices. If dinfo isn't NULL, we 1147 * know that there are more matches in the list because of 1148 * the way the traversal is done. 1149 */ 1150 if (dinfo == NULL) 1151 cio->status = PCI_GETCONF_LAST_DEVICE; 1152 else 1153 cio->status = PCI_GETCONF_MORE_DEVS; 1154 1155 getconfexit: 1156 pci_conf_io_update_data(cio, data, cmd); 1157 free(cio, M_TEMP); 1158 free(pattern_buf, M_TEMP); 1159 1160 break; 1161 1162 #ifdef PRE7_COMPAT 1163 case PCIOCREAD_OLD: 1164 case PCIOCWRITE_OLD: 1165 io_old = (struct pci_io_old *)data; 1166 iodata.pi_sel.pc_domain = 0; 1167 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus; 1168 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev; 1169 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func; 1170 iodata.pi_reg = io_old->pi_reg; 1171 iodata.pi_width = io_old->pi_width; 1172 iodata.pi_data = io_old->pi_data; 1173 data = (caddr_t)&iodata; 1174 /* FALLTHROUGH */ 1175 #endif 1176 case PCIOCREAD: 1177 case PCIOCWRITE: 1178 io = (struct pci_io *)data; 1179 switch(io->pi_width) { 1180 case 4: 1181 case 2: 1182 case 1: 1183 /* Make sure register is not negative and aligned. */ 1184 if (io->pi_reg < 0 || 1185 io->pi_reg & (io->pi_width - 1)) { 1186 error = EINVAL; 1187 break; 1188 } 1189 /* 1190 * Assume that the user-level bus number is 1191 * in fact the physical PCI bus number. 1192 * Look up the grandparent, i.e. the bridge device, 1193 * so that we can issue configuration space cycles. 1194 */ 1195 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, 1196 io->pi_sel.pc_bus, io->pi_sel.pc_dev, 1197 io->pi_sel.pc_func); 1198 if (pcidev) { 1199 #ifdef PRE7_COMPAT 1200 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD) 1201 #else 1202 if (cmd == PCIOCWRITE) 1203 #endif 1204 pci_write_config(pcidev, 1205 io->pi_reg, 1206 io->pi_data, 1207 io->pi_width); 1208 #ifdef PRE7_COMPAT 1209 else if (cmd == PCIOCREAD_OLD) 1210 io_old->pi_data = 1211 pci_read_config(pcidev, 1212 io->pi_reg, 1213 io->pi_width); 1214 #endif 1215 else 1216 io->pi_data = 1217 pci_read_config(pcidev, 1218 io->pi_reg, 1219 io->pi_width); 1220 error = 0; 1221 } else { 1222 #ifdef COMPAT_FREEBSD4 1223 if (cmd == PCIOCREAD_OLD) { 1224 io_old->pi_data = -1; 1225 error = 0; 1226 } else 1227 #endif 1228 error = ENODEV; 1229 } 1230 break; 1231 default: 1232 error = EINVAL; 1233 break; 1234 } 1235 break; 1236 1237 case PCIOCGETBAR: 1238 bio = (struct pci_bar_io *)data; 1239 1240 /* 1241 * Assume that the user-level bus number is 1242 * in fact the physical PCI bus number. 1243 */ 1244 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain, 1245 bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev, 1246 bio->pbi_sel.pc_func); 1247 if (pcidev == NULL) { 1248 error = ENODEV; 1249 break; 1250 } 1251 pm = pci_find_bar(pcidev, bio->pbi_reg); 1252 if (pm == NULL) { 1253 error = EINVAL; 1254 break; 1255 } 1256 bio->pbi_base = pm->pm_value; 1257 bio->pbi_length = (pci_addr_t)1 << pm->pm_size; 1258 bio->pbi_enabled = pci_bar_enabled(pcidev, pm); 1259 error = 0; 1260 break; 1261 case PCIOCATTACHED: 1262 error = 0; 1263 io = (struct pci_io *)data; 1264 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus, 1265 io->pi_sel.pc_dev, io->pi_sel.pc_func); 1266 if (pcidev != NULL) 1267 io->pi_data = device_is_attached(pcidev); 1268 else 1269 error = ENODEV; 1270 break; 1271 case PCIOCLISTVPD: 1272 lvio = (struct pci_list_vpd_io *)data; 1273 1274 /* 1275 * Assume that the user-level bus number is 1276 * in fact the physical PCI bus number. 1277 */ 1278 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, 1279 lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, 1280 lvio->plvi_sel.pc_func); 1281 if (pcidev == NULL) { 1282 error = ENODEV; 1283 break; 1284 } 1285 error = pci_list_vpd(pcidev, lvio); 1286 break; 1287 1288 case PCIOCBARMMAP: 1289 pbm = (struct pci_bar_mmap *)data; 1290 if ((flag & FWRITE) == 0 && 1291 (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) 1292 return (EPERM); 1293 pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain, 1294 pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev, 1295 pbm->pbm_sel.pc_func); 1296 error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); 1297 break; 1298 1299 default: 1300 error = ENOTTY; 1301 break; 1302 } 1303 1304 return (error); 1305 } 1306