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_bar_io(device_t pcidev, struct pci_bar_ioreq *pbi) 928 { 929 struct pci_map *pm; 930 struct resource *res; 931 uint32_t offset, width; 932 int bar, error, type; 933 934 if (pbi->pbi_op != PCIBARIO_READ && 935 pbi->pbi_op != PCIBARIO_WRITE) 936 return (EINVAL); 937 938 bar = PCIR_BAR(pbi->pbi_bar); 939 pm = pci_find_bar(pcidev, bar); 940 if (pm == NULL) 941 return (EINVAL); 942 943 offset = pbi->pbi_offset; 944 width = pbi->pbi_width; 945 946 if (offset + width < offset || 947 ((pci_addr_t)1 << pm->pm_size) < offset + width) 948 return (EINVAL); 949 950 type = PCI_BAR_MEM(pm->pm_value) ? SYS_RES_MEMORY : SYS_RES_IOPORT; 951 952 /* 953 * This will fail if a driver has allocated the resource. This could be 954 * worked around by detecting that case and using bus_map_resource() to 955 * populate the handle, but so far this is not needed. 956 */ 957 res = bus_alloc_resource_any(pcidev, type, &bar, RF_ACTIVE); 958 if (res == NULL) 959 return (ENOENT); 960 961 error = 0; 962 switch (pbi->pbi_op) { 963 case PCIBARIO_READ: 964 switch (pbi->pbi_width) { 965 case 1: 966 pbi->pbi_value = bus_read_1(res, offset); 967 break; 968 case 2: 969 pbi->pbi_value = bus_read_2(res, offset); 970 break; 971 case 4: 972 pbi->pbi_value = bus_read_4(res, offset); 973 break; 974 #ifndef __i386__ 975 case 8: 976 pbi->pbi_value = bus_read_8(res, offset); 977 break; 978 #endif 979 default: 980 error = EINVAL; 981 break; 982 } 983 break; 984 case PCIBARIO_WRITE: 985 switch (pbi->pbi_width) { 986 case 1: 987 bus_write_1(res, offset, pbi->pbi_value); 988 break; 989 case 2: 990 bus_write_2(res, offset, pbi->pbi_value); 991 break; 992 case 4: 993 bus_write_4(res, offset, pbi->pbi_value); 994 break; 995 #ifndef __i386__ 996 case 8: 997 bus_write_8(res, offset, pbi->pbi_value); 998 break; 999 #endif 1000 default: 1001 error = EINVAL; 1002 break; 1003 } 1004 break; 1005 } 1006 1007 bus_release_resource(pcidev, type, bar, res); 1008 1009 return (error); 1010 } 1011 1012 static int 1013 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1014 { 1015 device_t pcidev; 1016 const char *name; 1017 struct devlist *devlist_head; 1018 struct pci_conf_io *cio = NULL; 1019 struct pci_devinfo *dinfo; 1020 struct pci_io *io; 1021 struct pci_bar_ioreq *pbi; 1022 struct pci_bar_io *bio; 1023 struct pci_list_vpd_io *lvio; 1024 struct pci_match_conf *pattern_buf; 1025 struct pci_map *pm; 1026 struct pci_bar_mmap *pbm; 1027 size_t confsz, iolen; 1028 int error, ionum, i, num_patterns; 1029 union pci_conf_union pcu; 1030 #ifdef PRE7_COMPAT 1031 struct pci_io iodata; 1032 struct pci_io_old *io_old; 1033 1034 io_old = NULL; 1035 #endif 1036 1037 /* 1038 * Interpret read-only opened /dev/pci as a promise that no 1039 * operation of the file descriptor could modify system state, 1040 * including side-effects due to reading devices registers. 1041 */ 1042 if ((flag & FWRITE) == 0) { 1043 switch (cmd) { 1044 case PCIOCGETCONF: 1045 #ifdef COMPAT_FREEBSD32 1046 case PCIOCGETCONF32: 1047 #endif 1048 #ifdef PRE7_COMPAT 1049 case PCIOCGETCONF_OLD: 1050 #ifdef COMPAT_FREEBSD32 1051 case PCIOCGETCONF_OLD32: 1052 #endif 1053 #endif 1054 case PCIOCGETBAR: 1055 case PCIOCLISTVPD: 1056 break; 1057 default: 1058 return (EPERM); 1059 } 1060 } 1061 1062 /* Giant because newbus is Giant locked revisit with newbus locking */ 1063 mtx_lock(&Giant); 1064 1065 switch (cmd) { 1066 case PCIOCGETCONF: 1067 #ifdef COMPAT_FREEBSD32 1068 case PCIOCGETCONF32: 1069 #endif 1070 #ifdef PRE7_COMPAT 1071 case PCIOCGETCONF_OLD: 1072 #ifdef COMPAT_FREEBSD32 1073 case PCIOCGETCONF_OLD32: 1074 #endif 1075 #endif 1076 cio = malloc(sizeof(struct pci_conf_io), M_TEMP, 1077 M_WAITOK | M_ZERO); 1078 pci_conf_io_init(cio, data, cmd); 1079 pattern_buf = NULL; 1080 num_patterns = 0; 1081 dinfo = NULL; 1082 1083 cio->num_matches = 0; 1084 1085 /* 1086 * If the user specified an offset into the device list, 1087 * but the list has changed since they last called this 1088 * ioctl, tell them that the list has changed. They will 1089 * have to get the list from the beginning. 1090 */ 1091 if ((cio->offset != 0) 1092 && (cio->generation != pci_generation)){ 1093 cio->status = PCI_GETCONF_LIST_CHANGED; 1094 error = 0; 1095 goto getconfexit; 1096 } 1097 1098 /* 1099 * Check to see whether the user has asked for an offset 1100 * past the end of our list. 1101 */ 1102 if (cio->offset >= pci_numdevs) { 1103 cio->status = PCI_GETCONF_LAST_DEVICE; 1104 error = 0; 1105 goto getconfexit; 1106 } 1107 1108 /* get the head of the device queue */ 1109 devlist_head = &pci_devq; 1110 1111 /* 1112 * Determine how much room we have for pci_conf structures. 1113 * Round the user's buffer size down to the nearest 1114 * multiple of sizeof(struct pci_conf) in case the user 1115 * didn't specify a multiple of that size. 1116 */ 1117 confsz = pci_conf_size(cmd); 1118 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), 1119 pci_numdevs * confsz); 1120 1121 /* 1122 * Since we know that iolen is a multiple of the size of 1123 * the pciconf union, it's okay to do this. 1124 */ 1125 ionum = iolen / confsz; 1126 1127 /* 1128 * If this test is true, the user wants the pci_conf 1129 * structures returned to match the supplied entries. 1130 */ 1131 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs) 1132 && (cio->pat_buf_len > 0)) { 1133 /* 1134 * pat_buf_len needs to be: 1135 * num_patterns * sizeof(struct pci_match_conf) 1136 * While it is certainly possible the user just 1137 * allocated a large buffer, but set the number of 1138 * matches correctly, it is far more likely that 1139 * their kernel doesn't match the userland utility 1140 * they're using. It's also possible that the user 1141 * forgot to initialize some variables. Yes, this 1142 * may be overly picky, but I hazard to guess that 1143 * it's far more likely to just catch folks that 1144 * updated their kernel but not their userland. 1145 */ 1146 if (cio->num_patterns * pci_match_conf_size(cmd) != 1147 cio->pat_buf_len) { 1148 /* The user made a mistake, return an error. */ 1149 cio->status = PCI_GETCONF_ERROR; 1150 error = EINVAL; 1151 goto getconfexit; 1152 } 1153 1154 /* 1155 * Allocate a buffer to hold the patterns. 1156 */ 1157 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 1158 M_WAITOK); 1159 error = copyin(cio->patterns, pattern_buf, 1160 cio->pat_buf_len); 1161 if (error != 0) { 1162 error = EINVAL; 1163 goto getconfexit; 1164 } 1165 num_patterns = cio->num_patterns; 1166 } else if ((cio->num_patterns > 0) 1167 || (cio->pat_buf_len > 0)) { 1168 /* 1169 * The user made a mistake, spit out an error. 1170 */ 1171 cio->status = PCI_GETCONF_ERROR; 1172 error = EINVAL; 1173 goto getconfexit; 1174 } 1175 1176 /* 1177 * Go through the list of devices and copy out the devices 1178 * that match the user's criteria. 1179 */ 1180 for (cio->num_matches = 0, i = 0, 1181 dinfo = STAILQ_FIRST(devlist_head); 1182 dinfo != NULL; 1183 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 1184 if (i < cio->offset) 1185 continue; 1186 1187 /* Populate pd_name and pd_unit */ 1188 name = NULL; 1189 if (dinfo->cfg.dev) 1190 name = device_get_name(dinfo->cfg.dev); 1191 if (name) { 1192 strncpy(dinfo->conf.pd_name, name, 1193 sizeof(dinfo->conf.pd_name)); 1194 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 1195 dinfo->conf.pd_unit = 1196 device_get_unit(dinfo->cfg.dev); 1197 } else { 1198 dinfo->conf.pd_name[0] = '\0'; 1199 dinfo->conf.pd_unit = 0; 1200 } 1201 1202 if (pattern_buf == NULL || 1203 pci_conf_match(cmd, pattern_buf, num_patterns, 1204 &dinfo->conf) == 0) { 1205 /* 1206 * If we've filled up the user's buffer, 1207 * break out at this point. Since we've 1208 * got a match here, we'll pick right back 1209 * up at the matching entry. We can also 1210 * tell the user that there are more matches 1211 * left. 1212 */ 1213 if (cio->num_matches >= ionum) { 1214 error = 0; 1215 break; 1216 } 1217 1218 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); 1219 error = copyout(&pcu, 1220 (caddr_t)cio->matches + 1221 confsz * cio->num_matches, confsz); 1222 if (error) 1223 break; 1224 cio->num_matches++; 1225 } 1226 } 1227 1228 /* 1229 * Set the pointer into the list, so if the user is getting 1230 * n records at a time, where n < pci_numdevs, 1231 */ 1232 cio->offset = i; 1233 1234 /* 1235 * Set the generation, the user will need this if they make 1236 * another ioctl call with offset != 0. 1237 */ 1238 cio->generation = pci_generation; 1239 1240 /* 1241 * If this is the last device, inform the user so he won't 1242 * bother asking for more devices. If dinfo isn't NULL, we 1243 * know that there are more matches in the list because of 1244 * the way the traversal is done. 1245 */ 1246 if (dinfo == NULL) 1247 cio->status = PCI_GETCONF_LAST_DEVICE; 1248 else 1249 cio->status = PCI_GETCONF_MORE_DEVS; 1250 1251 getconfexit: 1252 pci_conf_io_update_data(cio, data, cmd); 1253 free(cio, M_TEMP); 1254 free(pattern_buf, M_TEMP); 1255 1256 break; 1257 1258 #ifdef PRE7_COMPAT 1259 case PCIOCREAD_OLD: 1260 case PCIOCWRITE_OLD: 1261 io_old = (struct pci_io_old *)data; 1262 iodata.pi_sel.pc_domain = 0; 1263 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus; 1264 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev; 1265 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func; 1266 iodata.pi_reg = io_old->pi_reg; 1267 iodata.pi_width = io_old->pi_width; 1268 iodata.pi_data = io_old->pi_data; 1269 data = (caddr_t)&iodata; 1270 /* FALLTHROUGH */ 1271 #endif 1272 case PCIOCREAD: 1273 case PCIOCWRITE: 1274 io = (struct pci_io *)data; 1275 switch(io->pi_width) { 1276 case 4: 1277 case 2: 1278 case 1: 1279 /* Make sure register is not negative and aligned. */ 1280 if (io->pi_reg < 0 || 1281 io->pi_reg & (io->pi_width - 1)) { 1282 error = EINVAL; 1283 break; 1284 } 1285 /* 1286 * Assume that the user-level bus number is 1287 * in fact the physical PCI bus number. 1288 * Look up the grandparent, i.e. the bridge device, 1289 * so that we can issue configuration space cycles. 1290 */ 1291 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, 1292 io->pi_sel.pc_bus, io->pi_sel.pc_dev, 1293 io->pi_sel.pc_func); 1294 if (pcidev) { 1295 #ifdef PRE7_COMPAT 1296 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD) 1297 #else 1298 if (cmd == PCIOCWRITE) 1299 #endif 1300 pci_write_config(pcidev, 1301 io->pi_reg, 1302 io->pi_data, 1303 io->pi_width); 1304 #ifdef PRE7_COMPAT 1305 else if (cmd == PCIOCREAD_OLD) 1306 io_old->pi_data = 1307 pci_read_config(pcidev, 1308 io->pi_reg, 1309 io->pi_width); 1310 #endif 1311 else 1312 io->pi_data = 1313 pci_read_config(pcidev, 1314 io->pi_reg, 1315 io->pi_width); 1316 error = 0; 1317 } else { 1318 #ifdef COMPAT_FREEBSD4 1319 if (cmd == PCIOCREAD_OLD) { 1320 io_old->pi_data = -1; 1321 error = 0; 1322 } else 1323 #endif 1324 error = ENODEV; 1325 } 1326 break; 1327 default: 1328 error = EINVAL; 1329 break; 1330 } 1331 break; 1332 1333 case PCIOCGETBAR: 1334 bio = (struct pci_bar_io *)data; 1335 1336 /* 1337 * Assume that the user-level bus number is 1338 * in fact the physical PCI bus number. 1339 */ 1340 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain, 1341 bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev, 1342 bio->pbi_sel.pc_func); 1343 if (pcidev == NULL) { 1344 error = ENODEV; 1345 break; 1346 } 1347 pm = pci_find_bar(pcidev, bio->pbi_reg); 1348 if (pm == NULL) { 1349 error = EINVAL; 1350 break; 1351 } 1352 bio->pbi_base = pm->pm_value; 1353 bio->pbi_length = (pci_addr_t)1 << pm->pm_size; 1354 bio->pbi_enabled = pci_bar_enabled(pcidev, pm); 1355 error = 0; 1356 break; 1357 case PCIOCATTACHED: 1358 error = 0; 1359 io = (struct pci_io *)data; 1360 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus, 1361 io->pi_sel.pc_dev, io->pi_sel.pc_func); 1362 if (pcidev != NULL) 1363 io->pi_data = device_is_attached(pcidev); 1364 else 1365 error = ENODEV; 1366 break; 1367 case PCIOCLISTVPD: 1368 lvio = (struct pci_list_vpd_io *)data; 1369 1370 /* 1371 * Assume that the user-level bus number is 1372 * in fact the physical PCI bus number. 1373 */ 1374 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, 1375 lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, 1376 lvio->plvi_sel.pc_func); 1377 if (pcidev == NULL) { 1378 error = ENODEV; 1379 break; 1380 } 1381 error = pci_list_vpd(pcidev, lvio); 1382 break; 1383 1384 case PCIOCBARMMAP: 1385 pbm = (struct pci_bar_mmap *)data; 1386 if ((flag & FWRITE) == 0 && 1387 (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) { 1388 error = EPERM; 1389 break; 1390 } 1391 pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain, 1392 pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev, 1393 pbm->pbm_sel.pc_func); 1394 error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); 1395 break; 1396 1397 case PCIOCBARIO: 1398 pbi = (struct pci_bar_ioreq *)data; 1399 1400 pcidev = pci_find_dbsf(pbi->pbi_sel.pc_domain, 1401 pbi->pbi_sel.pc_bus, pbi->pbi_sel.pc_dev, 1402 pbi->pbi_sel.pc_func); 1403 if (pcidev == NULL) { 1404 error = ENODEV; 1405 break; 1406 } 1407 error = pci_bar_io(pcidev, pbi); 1408 break; 1409 1410 default: 1411 error = ENOTTY; 1412 break; 1413 } 1414 1415 mtx_unlock(&Giant); 1416 1417 return (error); 1418 } 1419