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 rman_res_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 error = BUS_TRANSLATE_RESOURCE(pcidev, SYS_RES_MEMORY, 881 pm->pm_value & PCIM_BAR_MEM_BASE, &membase); 882 if (error != 0) 883 return (error); 884 885 pbase = trunc_page(membase); 886 plen = round_page(membase + ((pci_addr_t)1 << pm->pm_size)) - 887 pbase; 888 prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ? 889 VM_PROT_WRITE : 0); 890 891 /* Create vm structures and mmap. */ 892 sg = sglist_alloc(1, M_WAITOK); 893 error = sglist_append_phys(sg, pbase, plen); 894 if (error != 0) 895 goto out; 896 obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred); 897 if (obj == NULL) { 898 error = EIO; 899 goto out; 900 } 901 obj->memattr = pbm->pbm_memattr; 902 flags = MAP_SHARED; 903 addr = 0; 904 if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) { 905 addr = (uintptr_t)pbm->pbm_map_base; 906 flags |= MAP_FIXED; 907 } 908 if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0) 909 flags |= MAP_CHECK_EXCL; 910 error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0, 911 FALSE, td); 912 if (error != 0) { 913 vm_object_deallocate(obj); 914 goto out; 915 } 916 pbm->pbm_map_base = (void *)addr; 917 pbm->pbm_map_length = plen; 918 pbm->pbm_bar_off = membase - pbase; 919 pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size; 920 921 out: 922 sglist_free(sg); 923 return (error); 924 } 925 926 static int 927 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 928 { 929 device_t pcidev; 930 const char *name; 931 struct devlist *devlist_head; 932 struct pci_conf_io *cio = NULL; 933 struct pci_devinfo *dinfo; 934 struct pci_io *io; 935 struct pci_bar_io *bio; 936 struct pci_list_vpd_io *lvio; 937 struct pci_match_conf *pattern_buf; 938 struct pci_map *pm; 939 struct pci_bar_mmap *pbm; 940 size_t confsz, iolen; 941 int error, ionum, i, num_patterns; 942 union pci_conf_union pcu; 943 #ifdef PRE7_COMPAT 944 struct pci_io iodata; 945 struct pci_io_old *io_old; 946 947 io_old = NULL; 948 #endif 949 950 if (!(flag & FWRITE)) { 951 switch (cmd) { 952 case PCIOCGETCONF: 953 #ifdef COMPAT_FREEBSD32 954 case PCIOCGETCONF32: 955 #endif 956 #ifdef PRE7_COMPAT 957 case PCIOCGETCONF_OLD: 958 #ifdef COMPAT_FREEBSD32 959 case PCIOCGETCONF_OLD32: 960 #endif 961 #endif 962 case PCIOCGETBAR: 963 case PCIOCLISTVPD: 964 break; 965 default: 966 return (EPERM); 967 } 968 } 969 970 /* Giant because newbus is Giant locked revisit with newbus locking */ 971 mtx_lock(&Giant); 972 973 switch (cmd) { 974 case PCIOCGETCONF: 975 #ifdef COMPAT_FREEBSD32 976 case PCIOCGETCONF32: 977 #endif 978 #ifdef PRE7_COMPAT 979 case PCIOCGETCONF_OLD: 980 #ifdef COMPAT_FREEBSD32 981 case PCIOCGETCONF_OLD32: 982 #endif 983 #endif 984 cio = malloc(sizeof(struct pci_conf_io), M_TEMP, 985 M_WAITOK | M_ZERO); 986 pci_conf_io_init(cio, data, cmd); 987 pattern_buf = NULL; 988 num_patterns = 0; 989 dinfo = NULL; 990 991 cio->num_matches = 0; 992 993 /* 994 * If the user specified an offset into the device list, 995 * but the list has changed since they last called this 996 * ioctl, tell them that the list has changed. They will 997 * have to get the list from the beginning. 998 */ 999 if ((cio->offset != 0) 1000 && (cio->generation != pci_generation)){ 1001 cio->status = PCI_GETCONF_LIST_CHANGED; 1002 error = 0; 1003 goto getconfexit; 1004 } 1005 1006 /* 1007 * Check to see whether the user has asked for an offset 1008 * past the end of our list. 1009 */ 1010 if (cio->offset >= pci_numdevs) { 1011 cio->status = PCI_GETCONF_LAST_DEVICE; 1012 error = 0; 1013 goto getconfexit; 1014 } 1015 1016 /* get the head of the device queue */ 1017 devlist_head = &pci_devq; 1018 1019 /* 1020 * Determine how much room we have for pci_conf structures. 1021 * Round the user's buffer size down to the nearest 1022 * multiple of sizeof(struct pci_conf) in case the user 1023 * didn't specify a multiple of that size. 1024 */ 1025 confsz = pci_conf_size(cmd); 1026 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), 1027 pci_numdevs * confsz); 1028 1029 /* 1030 * Since we know that iolen is a multiple of the size of 1031 * the pciconf union, it's okay to do this. 1032 */ 1033 ionum = iolen / confsz; 1034 1035 /* 1036 * If this test is true, the user wants the pci_conf 1037 * structures returned to match the supplied entries. 1038 */ 1039 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs) 1040 && (cio->pat_buf_len > 0)) { 1041 /* 1042 * pat_buf_len needs to be: 1043 * num_patterns * sizeof(struct pci_match_conf) 1044 * While it is certainly possible the user just 1045 * allocated a large buffer, but set the number of 1046 * matches correctly, it is far more likely that 1047 * their kernel doesn't match the userland utility 1048 * they're using. It's also possible that the user 1049 * forgot to initialize some variables. Yes, this 1050 * may be overly picky, but I hazard to guess that 1051 * it's far more likely to just catch folks that 1052 * updated their kernel but not their userland. 1053 */ 1054 if (cio->num_patterns * pci_match_conf_size(cmd) != 1055 cio->pat_buf_len) { 1056 /* The user made a mistake, return an error. */ 1057 cio->status = PCI_GETCONF_ERROR; 1058 error = EINVAL; 1059 goto getconfexit; 1060 } 1061 1062 /* 1063 * Allocate a buffer to hold the patterns. 1064 */ 1065 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 1066 M_WAITOK); 1067 error = copyin(cio->patterns, pattern_buf, 1068 cio->pat_buf_len); 1069 if (error != 0) { 1070 error = EINVAL; 1071 goto getconfexit; 1072 } 1073 num_patterns = cio->num_patterns; 1074 } else if ((cio->num_patterns > 0) 1075 || (cio->pat_buf_len > 0)) { 1076 /* 1077 * The user made a mistake, spit out an error. 1078 */ 1079 cio->status = PCI_GETCONF_ERROR; 1080 error = EINVAL; 1081 goto getconfexit; 1082 } 1083 1084 /* 1085 * Go through the list of devices and copy out the devices 1086 * that match the user's criteria. 1087 */ 1088 for (cio->num_matches = 0, i = 0, 1089 dinfo = STAILQ_FIRST(devlist_head); 1090 dinfo != NULL; 1091 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 1092 if (i < cio->offset) 1093 continue; 1094 1095 /* Populate pd_name and pd_unit */ 1096 name = NULL; 1097 if (dinfo->cfg.dev) 1098 name = device_get_name(dinfo->cfg.dev); 1099 if (name) { 1100 strncpy(dinfo->conf.pd_name, name, 1101 sizeof(dinfo->conf.pd_name)); 1102 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 1103 dinfo->conf.pd_unit = 1104 device_get_unit(dinfo->cfg.dev); 1105 } else { 1106 dinfo->conf.pd_name[0] = '\0'; 1107 dinfo->conf.pd_unit = 0; 1108 } 1109 1110 if (pattern_buf == NULL || 1111 pci_conf_match(cmd, pattern_buf, num_patterns, 1112 &dinfo->conf) == 0) { 1113 /* 1114 * If we've filled up the user's buffer, 1115 * break out at this point. Since we've 1116 * got a match here, we'll pick right back 1117 * up at the matching entry. We can also 1118 * tell the user that there are more matches 1119 * left. 1120 */ 1121 if (cio->num_matches >= ionum) { 1122 error = 0; 1123 break; 1124 } 1125 1126 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); 1127 error = copyout(&pcu, 1128 (caddr_t)cio->matches + 1129 confsz * cio->num_matches, confsz); 1130 if (error) 1131 break; 1132 cio->num_matches++; 1133 } 1134 } 1135 1136 /* 1137 * Set the pointer into the list, so if the user is getting 1138 * n records at a time, where n < pci_numdevs, 1139 */ 1140 cio->offset = i; 1141 1142 /* 1143 * Set the generation, the user will need this if they make 1144 * another ioctl call with offset != 0. 1145 */ 1146 cio->generation = pci_generation; 1147 1148 /* 1149 * If this is the last device, inform the user so he won't 1150 * bother asking for more devices. If dinfo isn't NULL, we 1151 * know that there are more matches in the list because of 1152 * the way the traversal is done. 1153 */ 1154 if (dinfo == NULL) 1155 cio->status = PCI_GETCONF_LAST_DEVICE; 1156 else 1157 cio->status = PCI_GETCONF_MORE_DEVS; 1158 1159 getconfexit: 1160 pci_conf_io_update_data(cio, data, cmd); 1161 free(cio, M_TEMP); 1162 free(pattern_buf, M_TEMP); 1163 1164 break; 1165 1166 #ifdef PRE7_COMPAT 1167 case PCIOCREAD_OLD: 1168 case PCIOCWRITE_OLD: 1169 io_old = (struct pci_io_old *)data; 1170 iodata.pi_sel.pc_domain = 0; 1171 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus; 1172 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev; 1173 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func; 1174 iodata.pi_reg = io_old->pi_reg; 1175 iodata.pi_width = io_old->pi_width; 1176 iodata.pi_data = io_old->pi_data; 1177 data = (caddr_t)&iodata; 1178 /* FALLTHROUGH */ 1179 #endif 1180 case PCIOCREAD: 1181 case PCIOCWRITE: 1182 io = (struct pci_io *)data; 1183 switch(io->pi_width) { 1184 case 4: 1185 case 2: 1186 case 1: 1187 /* Make sure register is not negative and aligned. */ 1188 if (io->pi_reg < 0 || 1189 io->pi_reg & (io->pi_width - 1)) { 1190 error = EINVAL; 1191 break; 1192 } 1193 /* 1194 * Assume that the user-level bus number is 1195 * in fact the physical PCI bus number. 1196 * Look up the grandparent, i.e. the bridge device, 1197 * so that we can issue configuration space cycles. 1198 */ 1199 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, 1200 io->pi_sel.pc_bus, io->pi_sel.pc_dev, 1201 io->pi_sel.pc_func); 1202 if (pcidev) { 1203 #ifdef PRE7_COMPAT 1204 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD) 1205 #else 1206 if (cmd == PCIOCWRITE) 1207 #endif 1208 pci_write_config(pcidev, 1209 io->pi_reg, 1210 io->pi_data, 1211 io->pi_width); 1212 #ifdef PRE7_COMPAT 1213 else if (cmd == PCIOCREAD_OLD) 1214 io_old->pi_data = 1215 pci_read_config(pcidev, 1216 io->pi_reg, 1217 io->pi_width); 1218 #endif 1219 else 1220 io->pi_data = 1221 pci_read_config(pcidev, 1222 io->pi_reg, 1223 io->pi_width); 1224 error = 0; 1225 } else { 1226 #ifdef COMPAT_FREEBSD4 1227 if (cmd == PCIOCREAD_OLD) { 1228 io_old->pi_data = -1; 1229 error = 0; 1230 } else 1231 #endif 1232 error = ENODEV; 1233 } 1234 break; 1235 default: 1236 error = EINVAL; 1237 break; 1238 } 1239 break; 1240 1241 case PCIOCGETBAR: 1242 bio = (struct pci_bar_io *)data; 1243 1244 /* 1245 * Assume that the user-level bus number is 1246 * in fact the physical PCI bus number. 1247 */ 1248 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain, 1249 bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev, 1250 bio->pbi_sel.pc_func); 1251 if (pcidev == NULL) { 1252 error = ENODEV; 1253 break; 1254 } 1255 pm = pci_find_bar(pcidev, bio->pbi_reg); 1256 if (pm == NULL) { 1257 error = EINVAL; 1258 break; 1259 } 1260 bio->pbi_base = pm->pm_value; 1261 bio->pbi_length = (pci_addr_t)1 << pm->pm_size; 1262 bio->pbi_enabled = pci_bar_enabled(pcidev, pm); 1263 error = 0; 1264 break; 1265 case PCIOCATTACHED: 1266 error = 0; 1267 io = (struct pci_io *)data; 1268 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus, 1269 io->pi_sel.pc_dev, io->pi_sel.pc_func); 1270 if (pcidev != NULL) 1271 io->pi_data = device_is_attached(pcidev); 1272 else 1273 error = ENODEV; 1274 break; 1275 case PCIOCLISTVPD: 1276 lvio = (struct pci_list_vpd_io *)data; 1277 1278 /* 1279 * Assume that the user-level bus number is 1280 * in fact the physical PCI bus number. 1281 */ 1282 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, 1283 lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, 1284 lvio->plvi_sel.pc_func); 1285 if (pcidev == NULL) { 1286 error = ENODEV; 1287 break; 1288 } 1289 error = pci_list_vpd(pcidev, lvio); 1290 break; 1291 1292 case PCIOCBARMMAP: 1293 pbm = (struct pci_bar_mmap *)data; 1294 if ((flag & FWRITE) == 0 && 1295 (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) { 1296 error = EPERM; 1297 break; 1298 } 1299 pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain, 1300 pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev, 1301 pbm->pbm_sel.pc_func); 1302 error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); 1303 break; 1304 1305 default: 1306 error = ENOTTY; 1307 break; 1308 } 1309 1310 mtx_unlock(&Giant); 1311 1312 return (error); 1313 } 1314