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