1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 #include "opt_bus.h" /* XXX trim includes */ 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/module.h> 36 #include <sys/linker.h> 37 #include <sys/fcntl.h> 38 #include <sys/conf.h> 39 #include <sys/kernel.h> 40 #include <sys/mman.h> 41 #include <sys/proc.h> 42 #include <sys/queue.h> 43 #include <sys/rwlock.h> 44 #include <sys/sglist.h> 45 46 #include <vm/vm.h> 47 #include <vm/pmap.h> 48 #include <vm/vm_extern.h> 49 #include <vm/vm_map.h> 50 #include <vm/vm_object.h> 51 #include <vm/vm_page.h> 52 #include <vm/vm_pager.h> 53 54 #include <sys/bus.h> 55 #include <machine/bus.h> 56 #include <sys/rman.h> 57 #include <machine/resource.h> 58 59 #include <sys/pciio.h> 60 #include <dev/pci/pcireg.h> 61 #include <dev/pci/pcivar.h> 62 63 #include "pcib_if.h" 64 #include "pci_if.h" 65 66 #ifdef COMPAT_FREEBSD32 67 struct pci_conf32 { 68 struct pcisel pc_sel; /* domain+bus+slot+function */ 69 u_int8_t pc_hdr; /* PCI header type */ 70 u_int16_t pc_subvendor; /* card vendor ID */ 71 u_int16_t pc_subdevice; /* card device ID, assigned by 72 card vendor */ 73 u_int16_t pc_vendor; /* chip vendor ID */ 74 u_int16_t pc_device; /* chip device ID, assigned by 75 chip vendor */ 76 u_int8_t pc_class; /* chip PCI class */ 77 u_int8_t pc_subclass; /* chip PCI subclass */ 78 u_int8_t pc_progif; /* chip PCI programming interface */ 79 u_int8_t pc_revid; /* chip revision ID */ 80 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 81 u_int32_t pd_unit; /* device unit number */ 82 }; 83 84 struct pci_match_conf32 { 85 struct pcisel pc_sel; /* domain+bus+slot+function */ 86 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 87 u_int32_t pd_unit; /* Unit number */ 88 u_int16_t pc_vendor; /* PCI Vendor ID */ 89 u_int16_t pc_device; /* PCI Device ID */ 90 u_int8_t pc_class; /* PCI class */ 91 u_int32_t flags; /* Matching expression */ 92 }; 93 94 struct pci_conf_io32 { 95 u_int32_t pat_buf_len; /* pattern buffer length */ 96 u_int32_t num_patterns; /* number of patterns */ 97 u_int32_t patterns; /* struct pci_match_conf ptr */ 98 u_int32_t match_buf_len; /* match buffer length */ 99 u_int32_t num_matches; /* number of matches returned */ 100 u_int32_t matches; /* struct pci_conf ptr */ 101 u_int32_t offset; /* offset into device list */ 102 u_int32_t generation; /* device list generation */ 103 u_int32_t status; /* request status */ 104 }; 105 106 #define PCIOCGETCONF32 _IOC_NEWTYPE(PCIOCGETCONF, struct pci_conf_io32) 107 #endif 108 109 /* 110 * This is the user interface to PCI configuration space. 111 */ 112 113 static d_open_t pci_open; 114 static d_close_t pci_close; 115 static d_ioctl_t pci_ioctl; 116 117 struct cdevsw pcicdev = { 118 .d_version = D_VERSION, 119 .d_flags = 0, 120 .d_open = pci_open, 121 .d_close = pci_close, 122 .d_ioctl = pci_ioctl, 123 .d_name = "pci", 124 }; 125 126 static int 127 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 128 { 129 int error; 130 131 if (oflags & FWRITE) { 132 error = securelevel_gt(td->td_ucred, 0); 133 if (error) 134 return (error); 135 } 136 137 return (0); 138 } 139 140 static int 141 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td) 142 { 143 return 0; 144 } 145 146 /* 147 * Match a single pci_conf structure against an array of pci_match_conf 148 * structures. The first argument, 'matches', is an array of num_matches 149 * pci_match_conf structures. match_buf is a pointer to the pci_conf 150 * structure that will be compared to every entry in the matches array. 151 * This function returns 1 on failure, 0 on success. 152 */ 153 static int 154 pci_conf_match_native(struct pci_match_conf *matches, int num_matches, 155 struct pci_conf *match_buf) 156 { 157 int i; 158 159 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 160 return(1); 161 162 for (i = 0; i < num_matches; i++) { 163 /* 164 * I'm not sure why someone would do this...but... 165 */ 166 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 167 continue; 168 169 /* 170 * Look at each of the match flags. If it's set, do the 171 * comparison. If the comparison fails, we don't have a 172 * match, go on to the next item if there is one. 173 */ 174 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) 175 && (match_buf->pc_sel.pc_domain != 176 matches[i].pc_sel.pc_domain)) 177 continue; 178 179 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 180 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 181 continue; 182 183 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 184 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 185 continue; 186 187 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 188 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 189 continue; 190 191 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 192 && (match_buf->pc_vendor != matches[i].pc_vendor)) 193 continue; 194 195 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 196 && (match_buf->pc_device != matches[i].pc_device)) 197 continue; 198 199 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 200 && (match_buf->pc_class != matches[i].pc_class)) 201 continue; 202 203 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 204 && (match_buf->pd_unit != matches[i].pd_unit)) 205 continue; 206 207 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 208 && (strncmp(matches[i].pd_name, match_buf->pd_name, 209 sizeof(match_buf->pd_name)) != 0)) 210 continue; 211 212 return(0); 213 } 214 215 return(1); 216 } 217 218 #ifdef COMPAT_FREEBSD32 219 static int 220 pci_conf_match32(struct pci_match_conf32 *matches, int num_matches, 221 struct pci_conf *match_buf) 222 { 223 int i; 224 225 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 226 return(1); 227 228 for (i = 0; i < num_matches; i++) { 229 /* 230 * I'm not sure why someone would do this...but... 231 */ 232 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 233 continue; 234 235 /* 236 * Look at each of the match flags. If it's set, do the 237 * comparison. If the comparison fails, we don't have a 238 * match, go on to the next item if there is one. 239 */ 240 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) 241 && (match_buf->pc_sel.pc_domain != 242 matches[i].pc_sel.pc_domain)) 243 continue; 244 245 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 246 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 247 continue; 248 249 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 250 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 251 continue; 252 253 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 254 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 255 continue; 256 257 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 258 && (match_buf->pc_vendor != matches[i].pc_vendor)) 259 continue; 260 261 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 262 && (match_buf->pc_device != matches[i].pc_device)) 263 continue; 264 265 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 266 && (match_buf->pc_class != matches[i].pc_class)) 267 continue; 268 269 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 270 && (match_buf->pd_unit != matches[i].pd_unit)) 271 continue; 272 273 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 274 && (strncmp(matches[i].pd_name, match_buf->pd_name, 275 sizeof(match_buf->pd_name)) != 0)) 276 continue; 277 278 return(0); 279 } 280 281 return(1); 282 } 283 #endif /* COMPAT_FREEBSD32 */ 284 285 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 286 defined(COMPAT_FREEBSD6) 287 #define PRE7_COMPAT 288 289 typedef enum { 290 PCI_GETCONF_NO_MATCH_FREEBSD6 = 0x00, 291 PCI_GETCONF_MATCH_BUS_FREEBSD6 = 0x01, 292 PCI_GETCONF_MATCH_DEV_FREEBSD6 = 0x02, 293 PCI_GETCONF_MATCH_FUNC_FREEBSD6 = 0x04, 294 PCI_GETCONF_MATCH_NAME_FREEBSD6 = 0x08, 295 PCI_GETCONF_MATCH_UNIT_FREEBSD6 = 0x10, 296 PCI_GETCONF_MATCH_VENDOR_FREEBSD6 = 0x20, 297 PCI_GETCONF_MATCH_DEVICE_FREEBSD6 = 0x40, 298 PCI_GETCONF_MATCH_CLASS_FREEBSD6 = 0x80 299 } pci_getconf_flags_freebsd6; 300 301 struct pcisel_freebsd6 { 302 u_int8_t pc_bus; /* bus number */ 303 u_int8_t pc_dev; /* device on this bus */ 304 u_int8_t pc_func; /* function on this device */ 305 }; 306 307 struct pci_conf_freebsd6 { 308 struct pcisel_freebsd6 pc_sel; /* bus+slot+function */ 309 u_int8_t pc_hdr; /* PCI header type */ 310 u_int16_t pc_subvendor; /* card vendor ID */ 311 u_int16_t pc_subdevice; /* card device ID, assigned by 312 card vendor */ 313 u_int16_t pc_vendor; /* chip vendor ID */ 314 u_int16_t pc_device; /* chip device ID, assigned by 315 chip vendor */ 316 u_int8_t pc_class; /* chip PCI class */ 317 u_int8_t pc_subclass; /* chip PCI subclass */ 318 u_int8_t pc_progif; /* chip PCI programming interface */ 319 u_int8_t pc_revid; /* chip revision ID */ 320 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 321 u_long pd_unit; /* device unit number */ 322 }; 323 324 struct pci_match_conf_freebsd6 { 325 struct pcisel_freebsd6 pc_sel; /* bus+slot+function */ 326 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 327 u_long pd_unit; /* Unit number */ 328 u_int16_t pc_vendor; /* PCI Vendor ID */ 329 u_int16_t pc_device; /* PCI Device ID */ 330 u_int8_t pc_class; /* PCI class */ 331 pci_getconf_flags_freebsd6 flags; /* Matching expression */ 332 }; 333 334 struct pci_io_freebsd6 { 335 struct pcisel_freebsd6 pi_sel; /* device to operate on */ 336 int pi_reg; /* configuration register to examine */ 337 int pi_width; /* width (in bytes) of read or write */ 338 u_int32_t pi_data; /* data to write or result of read */ 339 }; 340 341 #ifdef COMPAT_FREEBSD32 342 struct pci_conf_freebsd6_32 { 343 struct pcisel_freebsd6 pc_sel; /* bus+slot+function */ 344 uint8_t pc_hdr; /* PCI header type */ 345 uint16_t pc_subvendor; /* card vendor ID */ 346 uint16_t pc_subdevice; /* card device ID, assigned by 347 card vendor */ 348 uint16_t pc_vendor; /* chip vendor ID */ 349 uint16_t pc_device; /* chip device ID, assigned by 350 chip vendor */ 351 uint8_t pc_class; /* chip PCI class */ 352 uint8_t pc_subclass; /* chip PCI subclass */ 353 uint8_t pc_progif; /* chip PCI programming interface */ 354 uint8_t pc_revid; /* chip revision ID */ 355 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 356 uint32_t pd_unit; /* device unit number (u_long) */ 357 }; 358 359 struct pci_match_conf_freebsd6_32 { 360 struct pcisel_freebsd6 pc_sel; /* bus+slot+function */ 361 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 362 uint32_t pd_unit; /* Unit number (u_long) */ 363 uint16_t pc_vendor; /* PCI Vendor ID */ 364 uint16_t pc_device; /* PCI Device ID */ 365 uint8_t pc_class; /* PCI class */ 366 pci_getconf_flags_freebsd6 flags; /* Matching expression */ 367 }; 368 369 #define PCIOCGETCONF_FREEBSD6_32 _IOWR('p', 1, struct pci_conf_io32) 370 #endif /* COMPAT_FREEBSD32 */ 371 372 #define PCIOCGETCONF_FREEBSD6 _IOWR('p', 1, struct pci_conf_io) 373 #define PCIOCREAD_FREEBSD6 _IOWR('p', 2, struct pci_io_freebsd6) 374 #define PCIOCWRITE_FREEBSD6 _IOWR('p', 3, struct pci_io_freebsd6) 375 376 static int 377 pci_conf_match_freebsd6(struct pci_match_conf_freebsd6 *matches, int num_matches, 378 struct pci_conf *match_buf) 379 { 380 int i; 381 382 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 383 return(1); 384 385 for (i = 0; i < num_matches; i++) { 386 if (match_buf->pc_sel.pc_domain != 0) 387 continue; 388 389 /* 390 * I'm not sure why someone would do this...but... 391 */ 392 if (matches[i].flags == PCI_GETCONF_NO_MATCH_FREEBSD6) 393 continue; 394 395 /* 396 * Look at each of the match flags. If it's set, do the 397 * comparison. If the comparison fails, we don't have a 398 * match, go on to the next item if there is one. 399 */ 400 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_FREEBSD6) != 0) 401 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 402 continue; 403 404 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_FREEBSD6) != 0) 405 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 406 continue; 407 408 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_FREEBSD6) != 0) 409 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 410 continue; 411 412 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_FREEBSD6) != 0) 413 && (match_buf->pc_vendor != matches[i].pc_vendor)) 414 continue; 415 416 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_FREEBSD6) != 0) 417 && (match_buf->pc_device != matches[i].pc_device)) 418 continue; 419 420 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_FREEBSD6) != 0) 421 && (match_buf->pc_class != matches[i].pc_class)) 422 continue; 423 424 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_FREEBSD6) != 0) 425 && (match_buf->pd_unit != matches[i].pd_unit)) 426 continue; 427 428 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_FREEBSD6) != 0) 429 && (strncmp(matches[i].pd_name, match_buf->pd_name, 430 sizeof(match_buf->pd_name)) != 0)) 431 continue; 432 433 return(0); 434 } 435 436 return(1); 437 } 438 439 #ifdef COMPAT_FREEBSD32 440 static int 441 pci_conf_match_freebsd6_32(struct pci_match_conf_freebsd6_32 *matches, int num_matches, 442 struct pci_conf *match_buf) 443 { 444 int i; 445 446 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 447 return(1); 448 449 for (i = 0; i < num_matches; i++) { 450 if (match_buf->pc_sel.pc_domain != 0) 451 continue; 452 453 /* 454 * I'm not sure why someone would do this...but... 455 */ 456 if (matches[i].flags == PCI_GETCONF_NO_MATCH_FREEBSD6) 457 continue; 458 459 /* 460 * Look at each of the match flags. If it's set, do the 461 * comparison. If the comparison fails, we don't have a 462 * match, go on to the next item if there is one. 463 */ 464 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_FREEBSD6) != 0) && 465 (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 466 continue; 467 468 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_FREEBSD6) != 0) && 469 (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 470 continue; 471 472 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_FREEBSD6) != 0) && 473 (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 474 continue; 475 476 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_FREEBSD6) != 0) && 477 (match_buf->pc_vendor != matches[i].pc_vendor)) 478 continue; 479 480 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_FREEBSD6) != 0) && 481 (match_buf->pc_device != matches[i].pc_device)) 482 continue; 483 484 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_FREEBSD6) != 0) && 485 (match_buf->pc_class != matches[i].pc_class)) 486 continue; 487 488 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_FREEBSD6) != 0) && 489 ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit)) 490 continue; 491 492 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_FREEBSD6) != 0) && 493 (strncmp(matches[i].pd_name, match_buf->pd_name, 494 sizeof(match_buf->pd_name)) != 0)) 495 continue; 496 497 return (0); 498 } 499 500 return (1); 501 } 502 #endif /* COMPAT_FREEBSD32 */ 503 #endif /* !PRE7_COMPAT */ 504 505 union pci_conf_union { 506 struct pci_conf pc; 507 #ifdef COMPAT_FREEBSD32 508 struct pci_conf32 pc32; 509 #endif 510 #ifdef PRE7_COMPAT 511 struct pci_conf_freebsd6 pco; 512 #ifdef COMPAT_FREEBSD32 513 struct pci_conf_freebsd6_32 pco32; 514 #endif 515 #endif 516 }; 517 518 static int 519 pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches, 520 struct pci_conf *match_buf) 521 { 522 523 switch (cmd) { 524 case PCIOCGETCONF: 525 return (pci_conf_match_native( 526 (struct pci_match_conf *)matches, num_matches, match_buf)); 527 #ifdef COMPAT_FREEBSD32 528 case PCIOCGETCONF32: 529 return (pci_conf_match32((struct pci_match_conf32 *)matches, 530 num_matches, match_buf)); 531 #endif 532 #ifdef PRE7_COMPAT 533 case PCIOCGETCONF_FREEBSD6: 534 return (pci_conf_match_freebsd6( 535 (struct pci_match_conf_freebsd6 *)matches, num_matches, 536 match_buf)); 537 #ifdef COMPAT_FREEBSD32 538 case PCIOCGETCONF_FREEBSD6_32: 539 return (pci_conf_match_freebsd6_32( 540 (struct pci_match_conf_freebsd6_32 *)matches, num_matches, 541 match_buf)); 542 #endif 543 #endif 544 default: 545 /* programmer error */ 546 return (0); 547 } 548 } 549 550 /* 551 * Like PVE_NEXT but takes an explicit length since 'pve' is a user 552 * pointer that cannot be dereferenced. 553 */ 554 #define PVE_NEXT_LEN(pve, datalen) \ 555 ((struct pci_vpd_element *)((char *)(pve) + \ 556 sizeof(struct pci_vpd_element) + (datalen))) 557 558 static int 559 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio) 560 { 561 struct pci_vpd_element vpd_element, *vpd_user; 562 struct pcicfg_vpd *vpd; 563 size_t len, datalen; 564 int error, i; 565 566 vpd = pci_fetch_vpd_list(dev); 567 if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL) 568 return (ENXIO); 569 570 /* 571 * Calculate the amount of space needed in the data buffer. An 572 * identifier element is always present followed by the read-only 573 * and read-write keywords. 574 */ 575 len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident); 576 for (i = 0; i < vpd->vpd_rocnt; i++) 577 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len; 578 for (i = 0; i < vpd->vpd_wcnt; i++) 579 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len; 580 581 if (lvio->plvi_len == 0) { 582 lvio->plvi_len = len; 583 return (0); 584 } 585 if (lvio->plvi_len < len) { 586 lvio->plvi_len = len; 587 return (ENOMEM); 588 } 589 590 /* 591 * Copyout the identifier string followed by each keyword and 592 * value. 593 */ 594 datalen = strlen(vpd->vpd_ident); 595 KASSERT(datalen <= 255, ("invalid VPD ident length")); 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 = datalen; 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, datalen); 605 if (error) 606 return (error); 607 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen); 608 vpd_element.pve_flags = 0; 609 for (i = 0; i < vpd->vpd_rocnt; i++) { 610 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0]; 611 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1]; 612 vpd_element.pve_datalen = vpd->vpd_ros[i].len; 613 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 614 if (error) 615 return (error); 616 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data, 617 vpd->vpd_ros[i].len); 618 if (error) 619 return (error); 620 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen); 621 } 622 vpd_element.pve_flags = PVE_FLAG_RW; 623 for (i = 0; i < vpd->vpd_wcnt; i++) { 624 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0]; 625 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1]; 626 vpd_element.pve_datalen = vpd->vpd_w[i].len; 627 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 628 if (error) 629 return (error); 630 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data, 631 vpd->vpd_w[i].len); 632 if (error) 633 return (error); 634 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen); 635 } 636 KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len, 637 ("length mismatch")); 638 lvio->plvi_len = len; 639 return (0); 640 } 641 642 static size_t 643 pci_match_conf_size(u_long cmd) 644 { 645 646 switch (cmd) { 647 case PCIOCGETCONF: 648 return (sizeof(struct pci_match_conf)); 649 #ifdef COMPAT_FREEBSD32 650 case PCIOCGETCONF32: 651 return (sizeof(struct pci_match_conf32)); 652 #endif 653 #ifdef PRE7_COMPAT 654 case PCIOCGETCONF_FREEBSD6: 655 return (sizeof(struct pci_match_conf_freebsd6)); 656 #ifdef COMPAT_FREEBSD32 657 case PCIOCGETCONF_FREEBSD6_32: 658 return (sizeof(struct pci_match_conf_freebsd6_32)); 659 #endif 660 #endif 661 default: 662 /* programmer error */ 663 return (0); 664 } 665 } 666 667 static size_t 668 pci_conf_size(u_long cmd) 669 { 670 671 switch (cmd) { 672 case PCIOCGETCONF: 673 return (sizeof(struct pci_conf)); 674 #ifdef COMPAT_FREEBSD32 675 case PCIOCGETCONF32: 676 return (sizeof(struct pci_conf32)); 677 #endif 678 #ifdef PRE7_COMPAT 679 case PCIOCGETCONF_FREEBSD6: 680 return (sizeof(struct pci_conf_freebsd6)); 681 #ifdef COMPAT_FREEBSD32 682 case PCIOCGETCONF_FREEBSD6_32: 683 return (sizeof(struct pci_conf_freebsd6_32)); 684 #endif 685 #endif 686 default: 687 /* programmer error */ 688 return (0); 689 } 690 } 691 692 static void 693 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) 694 { 695 #if defined(COMPAT_FREEBSD32) 696 struct pci_conf_io32 *cio32; 697 #endif 698 699 switch (cmd) { 700 case PCIOCGETCONF: 701 #ifdef PRE7_COMPAT 702 case PCIOCGETCONF_FREEBSD6: 703 #endif 704 *cio = *(struct pci_conf_io *)data; 705 return; 706 707 #ifdef COMPAT_FREEBSD32 708 case PCIOCGETCONF32: 709 #ifdef PRE7_COMPAT 710 case PCIOCGETCONF_FREEBSD6_32: 711 #endif 712 cio32 = (struct pci_conf_io32 *)data; 713 cio->pat_buf_len = cio32->pat_buf_len; 714 cio->num_patterns = cio32->num_patterns; 715 cio->patterns = (void *)(uintptr_t)cio32->patterns; 716 cio->match_buf_len = cio32->match_buf_len; 717 cio->num_matches = cio32->num_matches; 718 cio->matches = (void *)(uintptr_t)cio32->matches; 719 cio->offset = cio32->offset; 720 cio->generation = cio32->generation; 721 cio->status = cio32->status; 722 return; 723 #endif 724 725 default: 726 /* programmer error */ 727 return; 728 } 729 } 730 731 static void 732 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, 733 u_long cmd) 734 { 735 struct pci_conf_io *d_cio; 736 #if defined(COMPAT_FREEBSD32) 737 struct pci_conf_io32 *cio32; 738 #endif 739 740 switch (cmd) { 741 case PCIOCGETCONF: 742 #ifdef PRE7_COMPAT 743 case PCIOCGETCONF_FREEBSD6: 744 #endif 745 d_cio = (struct pci_conf_io *)data; 746 d_cio->status = cio->status; 747 d_cio->generation = cio->generation; 748 d_cio->offset = cio->offset; 749 d_cio->num_matches = cio->num_matches; 750 return; 751 752 #ifdef COMPAT_FREEBSD32 753 case PCIOCGETCONF32: 754 #ifdef PRE7_COMPAT 755 case PCIOCGETCONF_FREEBSD6_32: 756 #endif 757 cio32 = (struct pci_conf_io32 *)data; 758 759 cio32->status = cio->status; 760 cio32->generation = cio->generation; 761 cio32->offset = cio->offset; 762 cio32->num_matches = cio->num_matches; 763 return; 764 #endif 765 766 default: 767 /* programmer error */ 768 return; 769 } 770 } 771 772 static void 773 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, 774 u_long cmd) 775 { 776 777 memset(pcup, 0, sizeof(*pcup)); 778 779 switch (cmd) { 780 case PCIOCGETCONF: 781 pcup->pc = *pcp; 782 return; 783 784 #ifdef COMPAT_FREEBSD32 785 case PCIOCGETCONF32: 786 pcup->pc32.pc_sel = pcp->pc_sel; 787 pcup->pc32.pc_hdr = pcp->pc_hdr; 788 pcup->pc32.pc_subvendor = pcp->pc_subvendor; 789 pcup->pc32.pc_subdevice = pcp->pc_subdevice; 790 pcup->pc32.pc_vendor = pcp->pc_vendor; 791 pcup->pc32.pc_device = pcp->pc_device; 792 pcup->pc32.pc_class = pcp->pc_class; 793 pcup->pc32.pc_subclass = pcp->pc_subclass; 794 pcup->pc32.pc_progif = pcp->pc_progif; 795 pcup->pc32.pc_revid = pcp->pc_revid; 796 strlcpy(pcup->pc32.pd_name, pcp->pd_name, 797 sizeof(pcup->pc32.pd_name)); 798 pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit; 799 return; 800 #endif 801 802 #ifdef PRE7_COMPAT 803 #ifdef COMPAT_FREEBSD32 804 case PCIOCGETCONF_FREEBSD6_32: 805 pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus; 806 pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev; 807 pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func; 808 pcup->pco32.pc_hdr = pcp->pc_hdr; 809 pcup->pco32.pc_subvendor = pcp->pc_subvendor; 810 pcup->pco32.pc_subdevice = pcp->pc_subdevice; 811 pcup->pco32.pc_vendor = pcp->pc_vendor; 812 pcup->pco32.pc_device = pcp->pc_device; 813 pcup->pco32.pc_class = pcp->pc_class; 814 pcup->pco32.pc_subclass = pcp->pc_subclass; 815 pcup->pco32.pc_progif = pcp->pc_progif; 816 pcup->pco32.pc_revid = pcp->pc_revid; 817 strlcpy(pcup->pco32.pd_name, pcp->pd_name, 818 sizeof(pcup->pco32.pd_name)); 819 pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit; 820 return; 821 822 #endif /* COMPAT_FREEBSD32 */ 823 case PCIOCGETCONF_FREEBSD6: 824 pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus; 825 pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev; 826 pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func; 827 pcup->pco.pc_hdr = pcp->pc_hdr; 828 pcup->pco.pc_subvendor = pcp->pc_subvendor; 829 pcup->pco.pc_subdevice = pcp->pc_subdevice; 830 pcup->pco.pc_vendor = pcp->pc_vendor; 831 pcup->pco.pc_device = pcp->pc_device; 832 pcup->pco.pc_class = pcp->pc_class; 833 pcup->pco.pc_subclass = pcp->pc_subclass; 834 pcup->pco.pc_progif = pcp->pc_progif; 835 pcup->pco.pc_revid = pcp->pc_revid; 836 strlcpy(pcup->pco.pd_name, pcp->pd_name, 837 sizeof(pcup->pco.pd_name)); 838 pcup->pco.pd_unit = pcp->pd_unit; 839 return; 840 #endif /* PRE7_COMPAT */ 841 842 default: 843 /* programmer error */ 844 return; 845 } 846 } 847 848 static int 849 pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm) 850 { 851 vm_map_t map; 852 vm_object_t obj; 853 struct thread *td; 854 struct sglist *sg; 855 struct pci_map *pm; 856 rman_res_t membase; 857 vm_paddr_t pbase; 858 vm_size_t plen; 859 vm_offset_t addr; 860 vm_prot_t prot; 861 int error, flags; 862 863 td = curthread; 864 map = &td->td_proc->p_vmspace->vm_map; 865 if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL | 866 PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 || 867 pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr || 868 !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr)) 869 return (EINVAL); 870 871 /* Fetch the BAR physical base and length. */ 872 pm = pci_find_bar(pcidev, pbm->pbm_reg); 873 if (pm == NULL) 874 return (EINVAL); 875 if (!pci_bar_enabled(pcidev, pm)) 876 return (EBUSY); /* XXXKIB enable if _ACTIVATE */ 877 if (!PCI_BAR_MEM(pm->pm_value)) 878 return (EIO); 879 error = bus_translate_resource(pcidev, SYS_RES_MEMORY, 880 pm->pm_value & PCIM_BAR_MEM_BASE, &membase); 881 if (error != 0) 882 return (error); 883 884 pbase = trunc_page(membase); 885 plen = round_page(membase + ((pci_addr_t)1 << pm->pm_size)) - 886 pbase; 887 prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ? 888 VM_PROT_WRITE : 0); 889 890 /* Create vm structures and mmap. */ 891 sg = sglist_alloc(1, M_WAITOK); 892 error = sglist_append_phys(sg, pbase, plen); 893 if (error != 0) 894 goto out; 895 obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred); 896 if (obj == NULL) { 897 error = EIO; 898 goto out; 899 } 900 obj->memattr = pbm->pbm_memattr; 901 flags = MAP_SHARED; 902 addr = 0; 903 if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) { 904 addr = (uintptr_t)pbm->pbm_map_base; 905 flags |= MAP_FIXED; 906 } 907 if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0) 908 flags |= MAP_CHECK_EXCL; 909 error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0, 910 FALSE, td); 911 if (error != 0) { 912 vm_object_deallocate(obj); 913 goto out; 914 } 915 pbm->pbm_map_base = (void *)addr; 916 pbm->pbm_map_length = plen; 917 pbm->pbm_bar_off = membase - pbase; 918 pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size; 919 920 out: 921 sglist_free(sg); 922 return (error); 923 } 924 925 static int 926 pci_bar_io(device_t pcidev, struct pci_bar_ioreq *pbi) 927 { 928 struct pci_map *pm; 929 struct resource *res; 930 uint32_t offset, width; 931 int bar, error, type; 932 933 if (pbi->pbi_op != PCIBARIO_READ && 934 pbi->pbi_op != PCIBARIO_WRITE) 935 return (EINVAL); 936 937 bar = PCIR_BAR(pbi->pbi_bar); 938 pm = pci_find_bar(pcidev, bar); 939 if (pm == NULL) 940 return (EINVAL); 941 942 offset = pbi->pbi_offset; 943 width = pbi->pbi_width; 944 945 if (offset + width < offset || 946 ((pci_addr_t)1 << pm->pm_size) < offset + width) 947 return (EINVAL); 948 949 type = PCI_BAR_MEM(pm->pm_value) ? SYS_RES_MEMORY : SYS_RES_IOPORT; 950 951 /* 952 * This will fail if a driver has allocated the resource. This could be 953 * worked around by detecting that case and using bus_map_resource() to 954 * populate the handle, but so far this is not needed. 955 */ 956 res = bus_alloc_resource_any(pcidev, type, &bar, RF_ACTIVE); 957 if (res == NULL) 958 return (ENOENT); 959 960 error = 0; 961 switch (pbi->pbi_op) { 962 case PCIBARIO_READ: 963 switch (pbi->pbi_width) { 964 case 1: 965 pbi->pbi_value = bus_read_1(res, offset); 966 break; 967 case 2: 968 pbi->pbi_value = bus_read_2(res, offset); 969 break; 970 case 4: 971 pbi->pbi_value = bus_read_4(res, offset); 972 break; 973 #ifndef __i386__ 974 case 8: 975 pbi->pbi_value = bus_read_8(res, offset); 976 break; 977 #endif 978 default: 979 error = EINVAL; 980 break; 981 } 982 break; 983 case PCIBARIO_WRITE: 984 switch (pbi->pbi_width) { 985 case 1: 986 bus_write_1(res, offset, pbi->pbi_value); 987 break; 988 case 2: 989 bus_write_2(res, offset, pbi->pbi_value); 990 break; 991 case 4: 992 bus_write_4(res, offset, pbi->pbi_value); 993 break; 994 #ifndef __i386__ 995 case 8: 996 bus_write_8(res, offset, pbi->pbi_value); 997 break; 998 #endif 999 default: 1000 error = EINVAL; 1001 break; 1002 } 1003 break; 1004 } 1005 1006 bus_release_resource(pcidev, type, bar, res); 1007 1008 return (error); 1009 } 1010 1011 static int 1012 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1013 { 1014 device_t pcidev; 1015 const char *name; 1016 struct devlist *devlist_head; 1017 struct pci_conf_io *cio = NULL; 1018 struct pci_devinfo *dinfo; 1019 struct pci_io *io; 1020 struct pci_bar_ioreq *pbi; 1021 struct pci_bar_io *bio; 1022 struct pci_list_vpd_io *lvio; 1023 struct pci_match_conf *pattern_buf; 1024 struct pci_map *pm; 1025 struct pci_bar_mmap *pbm; 1026 size_t confsz, iolen; 1027 int error, ionum, i, num_patterns; 1028 union pci_conf_union pcu; 1029 #ifdef PRE7_COMPAT 1030 struct pci_io iodata; 1031 struct pci_io_freebsd6 *io_freebsd6; 1032 1033 io_freebsd6 = NULL; 1034 #endif 1035 1036 /* 1037 * Interpret read-only opened /dev/pci as a promise that no 1038 * operation of the file descriptor could modify system state, 1039 * including side-effects due to reading devices registers. 1040 */ 1041 if ((flag & FWRITE) == 0) { 1042 switch (cmd) { 1043 case PCIOCGETCONF: 1044 #ifdef COMPAT_FREEBSD32 1045 case PCIOCGETCONF32: 1046 #endif 1047 #ifdef PRE7_COMPAT 1048 case PCIOCGETCONF_FREEBSD6: 1049 #ifdef COMPAT_FREEBSD32 1050 case PCIOCGETCONF_FREEBSD6_32: 1051 #endif 1052 #endif 1053 case PCIOCGETBAR: 1054 case PCIOCLISTVPD: 1055 break; 1056 default: 1057 return (EPERM); 1058 } 1059 } 1060 1061 /* 1062 * Use bus topology lock to ensure that the pci list of devies doesn't 1063 * change while we're traversing the list, in some cases multiple times. 1064 */ 1065 bus_topo_lock(); 1066 1067 switch (cmd) { 1068 case PCIOCGETCONF: 1069 #ifdef COMPAT_FREEBSD32 1070 case PCIOCGETCONF32: 1071 #endif 1072 #ifdef PRE7_COMPAT 1073 case PCIOCGETCONF_FREEBSD6: 1074 #ifdef COMPAT_FREEBSD32 1075 case PCIOCGETCONF_FREEBSD6_32: 1076 #endif 1077 #endif 1078 cio = malloc(sizeof(struct pci_conf_io), M_TEMP, 1079 M_WAITOK | M_ZERO); 1080 pci_conf_io_init(cio, data, cmd); 1081 pattern_buf = NULL; 1082 num_patterns = 0; 1083 dinfo = NULL; 1084 1085 cio->num_matches = 0; 1086 1087 /* 1088 * If the user specified an offset into the device list, 1089 * but the list has changed since they last called this 1090 * ioctl, tell them that the list has changed. They will 1091 * have to get the list from the beginning. 1092 */ 1093 if ((cio->offset != 0) 1094 && (cio->generation != pci_generation)){ 1095 cio->status = PCI_GETCONF_LIST_CHANGED; 1096 error = 0; 1097 goto getconfexit; 1098 } 1099 1100 /* 1101 * Check to see whether the user has asked for an offset 1102 * past the end of our list. 1103 */ 1104 if (cio->offset >= pci_numdevs) { 1105 cio->status = PCI_GETCONF_LAST_DEVICE; 1106 error = 0; 1107 goto getconfexit; 1108 } 1109 1110 /* get the head of the device queue */ 1111 devlist_head = &pci_devq; 1112 1113 /* 1114 * Determine how much room we have for pci_conf structures. 1115 * Round the user's buffer size down to the nearest 1116 * multiple of sizeof(struct pci_conf) in case the user 1117 * didn't specify a multiple of that size. 1118 */ 1119 confsz = pci_conf_size(cmd); 1120 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), 1121 pci_numdevs * confsz); 1122 1123 /* 1124 * Since we know that iolen is a multiple of the size of 1125 * the pciconf union, it's okay to do this. 1126 */ 1127 ionum = iolen / confsz; 1128 1129 /* 1130 * If this test is true, the user wants the pci_conf 1131 * structures returned to match the supplied entries. 1132 */ 1133 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs) 1134 && (cio->pat_buf_len > 0)) { 1135 /* 1136 * pat_buf_len needs to be: 1137 * num_patterns * sizeof(struct pci_match_conf) 1138 * While it is certainly possible the user just 1139 * allocated a large buffer, but set the number of 1140 * matches correctly, it is far more likely that 1141 * their kernel doesn't match the userland utility 1142 * they're using. It's also possible that the user 1143 * forgot to initialize some variables. Yes, this 1144 * may be overly picky, but I hazard to guess that 1145 * it's far more likely to just catch folks that 1146 * updated their kernel but not their userland. 1147 */ 1148 if (cio->num_patterns * pci_match_conf_size(cmd) != 1149 cio->pat_buf_len) { 1150 /* The user made a mistake, return an error. */ 1151 cio->status = PCI_GETCONF_ERROR; 1152 error = EINVAL; 1153 goto getconfexit; 1154 } 1155 1156 /* 1157 * Allocate a buffer to hold the patterns. 1158 */ 1159 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 1160 M_WAITOK); 1161 error = copyin(cio->patterns, pattern_buf, 1162 cio->pat_buf_len); 1163 if (error != 0) { 1164 error = EINVAL; 1165 goto getconfexit; 1166 } 1167 num_patterns = cio->num_patterns; 1168 } else if ((cio->num_patterns > 0) 1169 || (cio->pat_buf_len > 0)) { 1170 /* 1171 * The user made a mistake, spit out an error. 1172 */ 1173 cio->status = PCI_GETCONF_ERROR; 1174 error = EINVAL; 1175 goto getconfexit; 1176 } 1177 1178 /* 1179 * Go through the list of devices and copy out the devices 1180 * that match the user's criteria. 1181 */ 1182 for (cio->num_matches = 0, i = 0, 1183 dinfo = STAILQ_FIRST(devlist_head); 1184 dinfo != NULL; 1185 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 1186 if (i < cio->offset) 1187 continue; 1188 1189 /* Populate pd_name and pd_unit */ 1190 name = NULL; 1191 if (dinfo->cfg.dev) 1192 name = device_get_name(dinfo->cfg.dev); 1193 if (name) { 1194 strncpy(dinfo->conf.pd_name, name, 1195 sizeof(dinfo->conf.pd_name)); 1196 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 1197 dinfo->conf.pd_unit = 1198 device_get_unit(dinfo->cfg.dev); 1199 } else { 1200 dinfo->conf.pd_name[0] = '\0'; 1201 dinfo->conf.pd_unit = 0; 1202 } 1203 1204 if (pattern_buf == NULL || 1205 pci_conf_match(cmd, pattern_buf, num_patterns, 1206 &dinfo->conf) == 0) { 1207 /* 1208 * If we've filled up the user's buffer, 1209 * break out at this point. Since we've 1210 * got a match here, we'll pick right back 1211 * up at the matching entry. We can also 1212 * tell the user that there are more matches 1213 * left. 1214 */ 1215 if (cio->num_matches >= ionum) { 1216 error = 0; 1217 break; 1218 } 1219 1220 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); 1221 error = copyout(&pcu, 1222 (caddr_t)cio->matches + 1223 confsz * cio->num_matches, confsz); 1224 if (error) 1225 break; 1226 cio->num_matches++; 1227 } 1228 } 1229 1230 /* 1231 * Set the pointer into the list, so if the user is getting 1232 * n records at a time, where n < pci_numdevs, 1233 */ 1234 cio->offset = i; 1235 1236 /* 1237 * Set the generation, the user will need this if they make 1238 * another ioctl call with offset != 0. 1239 */ 1240 cio->generation = pci_generation; 1241 1242 /* 1243 * If this is the last device, inform the user so he won't 1244 * bother asking for more devices. If dinfo isn't NULL, we 1245 * know that there are more matches in the list because of 1246 * the way the traversal is done. 1247 */ 1248 if (dinfo == NULL) 1249 cio->status = PCI_GETCONF_LAST_DEVICE; 1250 else 1251 cio->status = PCI_GETCONF_MORE_DEVS; 1252 1253 getconfexit: 1254 pci_conf_io_update_data(cio, data, cmd); 1255 free(cio, M_TEMP); 1256 free(pattern_buf, M_TEMP); 1257 1258 break; 1259 1260 #ifdef PRE7_COMPAT 1261 case PCIOCREAD_FREEBSD6: 1262 case PCIOCWRITE_FREEBSD6: 1263 io_freebsd6 = (struct pci_io_freebsd6 *)data; 1264 iodata.pi_sel.pc_domain = 0; 1265 iodata.pi_sel.pc_bus = io_freebsd6->pi_sel.pc_bus; 1266 iodata.pi_sel.pc_dev = io_freebsd6->pi_sel.pc_dev; 1267 iodata.pi_sel.pc_func = io_freebsd6->pi_sel.pc_func; 1268 iodata.pi_reg = io_freebsd6->pi_reg; 1269 iodata.pi_width = io_freebsd6->pi_width; 1270 iodata.pi_data = io_freebsd6->pi_data; 1271 data = (caddr_t)&iodata; 1272 /* FALLTHROUGH */ 1273 #endif 1274 case PCIOCREAD: 1275 case PCIOCWRITE: 1276 io = (struct pci_io *)data; 1277 switch(io->pi_width) { 1278 case 4: 1279 case 2: 1280 case 1: 1281 /* Make sure register is not negative and aligned. */ 1282 if (io->pi_reg < 0 || 1283 io->pi_reg & (io->pi_width - 1)) { 1284 error = EINVAL; 1285 break; 1286 } 1287 /* 1288 * Assume that the user-level bus number is 1289 * in fact the physical PCI bus number. 1290 * Look up the grandparent, i.e. the bridge device, 1291 * so that we can issue configuration space cycles. 1292 */ 1293 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, 1294 io->pi_sel.pc_bus, io->pi_sel.pc_dev, 1295 io->pi_sel.pc_func); 1296 if (pcidev) { 1297 #ifdef PRE7_COMPAT 1298 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_FREEBSD6) 1299 #else 1300 if (cmd == PCIOCWRITE) 1301 #endif 1302 pci_write_config(pcidev, 1303 io->pi_reg, 1304 io->pi_data, 1305 io->pi_width); 1306 #ifdef PRE7_COMPAT 1307 else if (cmd == PCIOCREAD_FREEBSD6) 1308 io_freebsd6->pi_data = 1309 pci_read_config(pcidev, 1310 io->pi_reg, 1311 io->pi_width); 1312 #endif 1313 else 1314 io->pi_data = 1315 pci_read_config(pcidev, 1316 io->pi_reg, 1317 io->pi_width); 1318 error = 0; 1319 } else { 1320 #ifdef COMPAT_FREEBSD4 1321 if (cmd == PCIOCREAD_FREEBSD6) { 1322 io_freebsd6->pi_data = -1; 1323 error = 0; 1324 } else 1325 #endif 1326 error = ENODEV; 1327 } 1328 break; 1329 default: 1330 error = EINVAL; 1331 break; 1332 } 1333 break; 1334 1335 case PCIOCGETBAR: 1336 bio = (struct pci_bar_io *)data; 1337 1338 /* 1339 * Assume that the user-level bus number is 1340 * in fact the physical PCI bus number. 1341 */ 1342 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain, 1343 bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev, 1344 bio->pbi_sel.pc_func); 1345 if (pcidev == NULL) { 1346 error = ENODEV; 1347 break; 1348 } 1349 pm = pci_find_bar(pcidev, bio->pbi_reg); 1350 if (pm == NULL) { 1351 error = EINVAL; 1352 break; 1353 } 1354 bio->pbi_base = pm->pm_value; 1355 bio->pbi_length = (pci_addr_t)1 << pm->pm_size; 1356 bio->pbi_enabled = pci_bar_enabled(pcidev, pm); 1357 error = 0; 1358 break; 1359 case PCIOCATTACHED: 1360 error = 0; 1361 io = (struct pci_io *)data; 1362 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus, 1363 io->pi_sel.pc_dev, io->pi_sel.pc_func); 1364 if (pcidev != NULL) 1365 io->pi_data = device_is_attached(pcidev); 1366 else 1367 error = ENODEV; 1368 break; 1369 case PCIOCLISTVPD: 1370 lvio = (struct pci_list_vpd_io *)data; 1371 1372 /* 1373 * Assume that the user-level bus number is 1374 * in fact the physical PCI bus number. 1375 */ 1376 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, 1377 lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, 1378 lvio->plvi_sel.pc_func); 1379 if (pcidev == NULL) { 1380 error = ENODEV; 1381 break; 1382 } 1383 error = pci_list_vpd(pcidev, lvio); 1384 break; 1385 1386 case PCIOCBARMMAP: 1387 pbm = (struct pci_bar_mmap *)data; 1388 if ((flag & FWRITE) == 0 && 1389 (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) { 1390 error = EPERM; 1391 break; 1392 } 1393 pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain, 1394 pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev, 1395 pbm->pbm_sel.pc_func); 1396 error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); 1397 break; 1398 1399 case PCIOCBARIO: 1400 pbi = (struct pci_bar_ioreq *)data; 1401 1402 pcidev = pci_find_dbsf(pbi->pbi_sel.pc_domain, 1403 pbi->pbi_sel.pc_bus, pbi->pbi_sel.pc_dev, 1404 pbi->pbi_sel.pc_func); 1405 if (pcidev == NULL) { 1406 error = ENODEV; 1407 break; 1408 } 1409 error = pci_bar_io(pcidev, pbi); 1410 break; 1411 1412 default: 1413 error = ENOTTY; 1414 break; 1415 } 1416 1417 bus_topo_unlock(); 1418 1419 return (error); 1420 } 1421