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