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