1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_bus.h" /* XXX trim includes */ 33 34 #include <sys/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/proc.h> 43 #include <sys/queue.h> 44 #include <sys/types.h> 45 46 #include <vm/vm.h> 47 #include <vm/pmap.h> 48 #include <vm/vm_extern.h> 49 50 #include <sys/bus.h> 51 #include <machine/bus.h> 52 #include <sys/rman.h> 53 #include <machine/resource.h> 54 55 #include <sys/pciio.h> 56 #include <dev/pci/pcireg.h> 57 #include <dev/pci/pcivar.h> 58 59 #include "pcib_if.h" 60 #include "pci_if.h" 61 62 /* 63 * This is the user interface to PCI configuration space. 64 */ 65 66 static d_open_t pci_open; 67 static d_close_t pci_close; 68 static d_ioctl_t pci_ioctl; 69 70 struct cdevsw pcicdev = { 71 .d_version = D_VERSION, 72 .d_flags = D_NEEDGIANT, 73 .d_open = pci_open, 74 .d_close = pci_close, 75 .d_ioctl = pci_ioctl, 76 .d_name = "pci", 77 }; 78 79 static int 80 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 81 { 82 int error; 83 84 if (oflags & FWRITE) { 85 error = securelevel_gt(td->td_ucred, 0); 86 if (error) 87 return (error); 88 } 89 90 return (0); 91 } 92 93 static int 94 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td) 95 { 96 return 0; 97 } 98 99 /* 100 * Match a single pci_conf structure against an array of pci_match_conf 101 * structures. The first argument, 'matches', is an array of num_matches 102 * pci_match_conf structures. match_buf is a pointer to the pci_conf 103 * structure that will be compared to every entry in the matches array. 104 * This function returns 1 on failure, 0 on success. 105 */ 106 static int 107 pci_conf_match_native(struct pci_match_conf *matches, int num_matches, 108 struct pci_conf *match_buf) 109 { 110 int i; 111 112 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 113 return(1); 114 115 for (i = 0; i < num_matches; i++) { 116 /* 117 * I'm not sure why someone would do this...but... 118 */ 119 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 120 continue; 121 122 /* 123 * Look at each of the match flags. If it's set, do the 124 * comparison. If the comparison fails, we don't have a 125 * match, go on to the next item if there is one. 126 */ 127 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) 128 && (match_buf->pc_sel.pc_domain != 129 matches[i].pc_sel.pc_domain)) 130 continue; 131 132 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 133 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 134 continue; 135 136 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 137 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 138 continue; 139 140 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 141 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 142 continue; 143 144 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 145 && (match_buf->pc_vendor != matches[i].pc_vendor)) 146 continue; 147 148 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 149 && (match_buf->pc_device != matches[i].pc_device)) 150 continue; 151 152 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 153 && (match_buf->pc_class != matches[i].pc_class)) 154 continue; 155 156 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 157 && (match_buf->pd_unit != matches[i].pd_unit)) 158 continue; 159 160 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 161 && (strncmp(matches[i].pd_name, match_buf->pd_name, 162 sizeof(match_buf->pd_name)) != 0)) 163 continue; 164 165 return(0); 166 } 167 168 return(1); 169 } 170 171 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 172 defined(COMPAT_FREEBSD6) 173 #define PRE7_COMPAT 174 175 typedef enum { 176 PCI_GETCONF_NO_MATCH_OLD = 0x00, 177 PCI_GETCONF_MATCH_BUS_OLD = 0x01, 178 PCI_GETCONF_MATCH_DEV_OLD = 0x02, 179 PCI_GETCONF_MATCH_FUNC_OLD = 0x04, 180 PCI_GETCONF_MATCH_NAME_OLD = 0x08, 181 PCI_GETCONF_MATCH_UNIT_OLD = 0x10, 182 PCI_GETCONF_MATCH_VENDOR_OLD = 0x20, 183 PCI_GETCONF_MATCH_DEVICE_OLD = 0x40, 184 PCI_GETCONF_MATCH_CLASS_OLD = 0x80 185 } pci_getconf_flags_old; 186 187 struct pcisel_old { 188 u_int8_t pc_bus; /* bus number */ 189 u_int8_t pc_dev; /* device on this bus */ 190 u_int8_t pc_func; /* function on this device */ 191 }; 192 193 struct pci_conf_old { 194 struct pcisel_old pc_sel; /* bus+slot+function */ 195 u_int8_t pc_hdr; /* PCI header type */ 196 u_int16_t pc_subvendor; /* card vendor ID */ 197 u_int16_t pc_subdevice; /* card device ID, assigned by 198 card vendor */ 199 u_int16_t pc_vendor; /* chip vendor ID */ 200 u_int16_t pc_device; /* chip device ID, assigned by 201 chip vendor */ 202 u_int8_t pc_class; /* chip PCI class */ 203 u_int8_t pc_subclass; /* chip PCI subclass */ 204 u_int8_t pc_progif; /* chip PCI programming interface */ 205 u_int8_t pc_revid; /* chip revision ID */ 206 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 207 u_long pd_unit; /* device unit number */ 208 }; 209 210 struct pci_match_conf_old { 211 struct pcisel_old pc_sel; /* bus+slot+function */ 212 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 213 u_long pd_unit; /* Unit number */ 214 u_int16_t pc_vendor; /* PCI Vendor ID */ 215 u_int16_t pc_device; /* PCI Device ID */ 216 u_int8_t pc_class; /* PCI class */ 217 pci_getconf_flags_old flags; /* Matching expression */ 218 }; 219 220 struct pci_io_old { 221 struct pcisel_old pi_sel; /* device to operate on */ 222 int pi_reg; /* configuration register to examine */ 223 int pi_width; /* width (in bytes) of read or write */ 224 u_int32_t pi_data; /* data to write or result of read */ 225 }; 226 227 #ifdef COMPAT_FREEBSD32 228 struct pci_conf_old32 { 229 struct pcisel_old pc_sel; /* bus+slot+function */ 230 uint8_t pc_hdr; /* PCI header type */ 231 uint16_t pc_subvendor; /* card vendor ID */ 232 uint16_t pc_subdevice; /* card device ID, assigned by 233 card vendor */ 234 uint16_t pc_vendor; /* chip vendor ID */ 235 uint16_t pc_device; /* chip device ID, assigned by 236 chip vendor */ 237 uint8_t pc_class; /* chip PCI class */ 238 uint8_t pc_subclass; /* chip PCI subclass */ 239 uint8_t pc_progif; /* chip PCI programming interface */ 240 uint8_t pc_revid; /* chip revision ID */ 241 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 242 uint32_t pd_unit; /* device unit number (u_long) */ 243 }; 244 245 struct pci_match_conf_old32 { 246 struct pcisel_old pc_sel; /* bus+slot+function */ 247 char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ 248 uint32_t pd_unit; /* Unit number (u_long) */ 249 uint16_t pc_vendor; /* PCI Vendor ID */ 250 uint16_t pc_device; /* PCI Device ID */ 251 uint8_t pc_class; /* PCI class */ 252 pci_getconf_flags_old flags; /* Matching expression */ 253 }; 254 255 struct pci_conf_io32 { 256 uint32_t pat_buf_len; /* pattern buffer length */ 257 uint32_t num_patterns; /* number of patterns */ 258 uint32_t patterns; /* pattern buffer 259 (struct pci_match_conf_old32 *) */ 260 uint32_t match_buf_len; /* match buffer length */ 261 uint32_t num_matches; /* number of matches returned */ 262 uint32_t matches; /* match buffer 263 (struct pci_conf_old32 *) */ 264 uint32_t offset; /* offset into device list */ 265 uint32_t generation; /* device list generation */ 266 pci_getconf_status status; /* request status */ 267 }; 268 269 #define PCIOCGETCONF_OLD32 _IOWR('p', 1, struct pci_conf_io32) 270 #endif /* COMPAT_FREEBSD32 */ 271 272 #define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io) 273 #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old) 274 #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old) 275 276 static int 277 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches, 278 struct pci_conf *match_buf) 279 { 280 int i; 281 282 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 283 return(1); 284 285 for (i = 0; i < num_matches; i++) { 286 if (match_buf->pc_sel.pc_domain != 0) 287 continue; 288 289 /* 290 * I'm not sure why someone would do this...but... 291 */ 292 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD) 293 continue; 294 295 /* 296 * Look at each of the match flags. If it's set, do the 297 * comparison. If the comparison fails, we don't have a 298 * match, go on to the next item if there is one. 299 */ 300 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) 301 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 302 continue; 303 304 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) 305 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 306 continue; 307 308 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) 309 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 310 continue; 311 312 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) 313 && (match_buf->pc_vendor != matches[i].pc_vendor)) 314 continue; 315 316 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) 317 && (match_buf->pc_device != matches[i].pc_device)) 318 continue; 319 320 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) 321 && (match_buf->pc_class != matches[i].pc_class)) 322 continue; 323 324 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) 325 && (match_buf->pd_unit != matches[i].pd_unit)) 326 continue; 327 328 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) 329 && (strncmp(matches[i].pd_name, match_buf->pd_name, 330 sizeof(match_buf->pd_name)) != 0)) 331 continue; 332 333 return(0); 334 } 335 336 return(1); 337 } 338 339 #ifdef COMPAT_FREEBSD32 340 static int 341 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches, 342 struct pci_conf *match_buf) 343 { 344 int i; 345 346 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 347 return(1); 348 349 for (i = 0; i < num_matches; i++) { 350 if (match_buf->pc_sel.pc_domain != 0) 351 continue; 352 353 /* 354 * I'm not sure why someone would do this...but... 355 */ 356 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD) 357 continue; 358 359 /* 360 * Look at each of the match flags. If it's set, do the 361 * comparison. If the comparison fails, we don't have a 362 * match, go on to the next item if there is one. 363 */ 364 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) && 365 (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 366 continue; 367 368 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) && 369 (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 370 continue; 371 372 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) && 373 (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 374 continue; 375 376 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) && 377 (match_buf->pc_vendor != matches[i].pc_vendor)) 378 continue; 379 380 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) && 381 (match_buf->pc_device != matches[i].pc_device)) 382 continue; 383 384 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) && 385 (match_buf->pc_class != matches[i].pc_class)) 386 continue; 387 388 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) && 389 ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit)) 390 continue; 391 392 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) && 393 (strncmp(matches[i].pd_name, match_buf->pd_name, 394 sizeof(match_buf->pd_name)) != 0)) 395 continue; 396 397 return (0); 398 } 399 400 return (1); 401 } 402 #endif /* COMPAT_FREEBSD32 */ 403 #endif /* !PRE7_COMPAT */ 404 405 union pci_conf_union { 406 struct pci_conf pc; 407 #ifdef PRE7_COMPAT 408 struct pci_conf_old pco; 409 #ifdef COMPAT_FREEBSD32 410 struct pci_conf_old32 pco32; 411 #endif 412 #endif 413 }; 414 415 static int 416 pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches, 417 struct pci_conf *match_buf) 418 { 419 420 switch (cmd) { 421 case PCIOCGETCONF: 422 return (pci_conf_match_native( 423 (struct pci_match_conf *)matches, num_matches, match_buf)); 424 #ifdef PRE7_COMPAT 425 case PCIOCGETCONF_OLD: 426 return (pci_conf_match_old( 427 (struct pci_match_conf_old *)matches, num_matches, 428 match_buf)); 429 #ifdef COMPAT_FREEBSD32 430 case PCIOCGETCONF_OLD32: 431 return (pci_conf_match_old32( 432 (struct pci_match_conf_old32 *)matches, num_matches, 433 match_buf)); 434 #endif 435 #endif 436 default: 437 /* programmer error */ 438 return (0); 439 } 440 } 441 442 static int 443 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio) 444 { 445 struct pci_vpd_element vpd_element, *vpd_user; 446 struct pcicfg_vpd *vpd; 447 size_t len; 448 int error, i; 449 450 vpd = pci_fetch_vpd_list(dev); 451 if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL) 452 return (ENXIO); 453 454 /* 455 * Calculate the amount of space needed in the data buffer. An 456 * identifier element is always present followed by the read-only 457 * and read-write keywords. 458 */ 459 len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident); 460 for (i = 0; i < vpd->vpd_rocnt; i++) 461 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len; 462 for (i = 0; i < vpd->vpd_wcnt; i++) 463 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len; 464 465 if (lvio->plvi_len == 0) { 466 lvio->plvi_len = len; 467 return (0); 468 } 469 if (lvio->plvi_len < len) { 470 lvio->plvi_len = len; 471 return (ENOMEM); 472 } 473 474 /* 475 * Copyout the identifier string followed by each keyword and 476 * value. 477 */ 478 vpd_user = lvio->plvi_data; 479 vpd_element.pve_keyword[0] = '\0'; 480 vpd_element.pve_keyword[1] = '\0'; 481 vpd_element.pve_flags = PVE_FLAG_IDENT; 482 vpd_element.pve_datalen = strlen(vpd->vpd_ident); 483 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 484 if (error) 485 return (error); 486 error = copyout(vpd->vpd_ident, vpd_user->pve_data, 487 strlen(vpd->vpd_ident)); 488 if (error) 489 return (error); 490 vpd_user = PVE_NEXT(vpd_user); 491 vpd_element.pve_flags = 0; 492 for (i = 0; i < vpd->vpd_rocnt; i++) { 493 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0]; 494 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1]; 495 vpd_element.pve_datalen = vpd->vpd_ros[i].len; 496 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 497 if (error) 498 return (error); 499 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data, 500 vpd->vpd_ros[i].len); 501 if (error) 502 return (error); 503 vpd_user = PVE_NEXT(vpd_user); 504 } 505 vpd_element.pve_flags = PVE_FLAG_RW; 506 for (i = 0; i < vpd->vpd_wcnt; i++) { 507 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0]; 508 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1]; 509 vpd_element.pve_datalen = vpd->vpd_w[i].len; 510 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); 511 if (error) 512 return (error); 513 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data, 514 vpd->vpd_w[i].len); 515 if (error) 516 return (error); 517 vpd_user = PVE_NEXT(vpd_user); 518 } 519 KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len, 520 ("length mismatch")); 521 lvio->plvi_len = len; 522 return (0); 523 } 524 525 static size_t 526 pci_match_conf_size(u_long cmd) 527 { 528 529 switch (cmd) { 530 case PCIOCGETCONF: 531 return (sizeof(struct pci_match_conf)); 532 #ifdef PRE7_COMPAT 533 case PCIOCGETCONF_OLD: 534 return (sizeof(struct pci_match_conf_old)); 535 #ifdef COMPAT_FREEBSD32 536 case PCIOCGETCONF_OLD32: 537 return (sizeof(struct pci_match_conf_old32)); 538 #endif 539 #endif 540 default: 541 /* programmer error */ 542 return (0); 543 } 544 } 545 546 static size_t 547 pci_conf_size(u_long cmd) 548 { 549 550 switch (cmd) { 551 case PCIOCGETCONF: 552 return (sizeof(struct pci_conf)); 553 #ifdef PRE7_COMPAT 554 case PCIOCGETCONF_OLD: 555 return (sizeof(struct pci_conf_old)); 556 #ifdef COMPAT_FREEBSD32 557 case PCIOCGETCONF_OLD32: 558 return (sizeof(struct pci_conf_old32)); 559 #endif 560 #endif 561 default: 562 /* programmer error */ 563 return (0); 564 } 565 } 566 567 static void 568 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) 569 { 570 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) 571 struct pci_conf_io32 *cio32; 572 #endif 573 574 switch (cmd) { 575 case PCIOCGETCONF: 576 #ifdef PRE7_COMPAT 577 case PCIOCGETCONF_OLD: 578 #endif 579 *cio = *(struct pci_conf_io *)data; 580 return; 581 582 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) 583 case PCIOCGETCONF_OLD32: 584 cio32 = (struct pci_conf_io32 *)data; 585 cio->pat_buf_len = cio32->pat_buf_len; 586 cio->num_patterns = cio32->num_patterns; 587 cio->patterns = (void *)(uintptr_t)cio32->patterns; 588 cio->match_buf_len = cio32->match_buf_len; 589 cio->num_matches = cio32->num_matches; 590 cio->matches = (void *)(uintptr_t)cio32->matches; 591 cio->offset = cio32->offset; 592 cio->generation = cio32->generation; 593 cio->status = cio32->status; 594 return; 595 #endif 596 597 default: 598 /* programmer error */ 599 return; 600 } 601 } 602 603 static void 604 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, 605 u_long cmd) 606 { 607 struct pci_conf_io *d_cio; 608 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) 609 struct pci_conf_io32 *cio32; 610 #endif 611 612 switch (cmd) { 613 case PCIOCGETCONF: 614 #ifdef PRE7_COMPAT 615 case PCIOCGETCONF_OLD: 616 #endif 617 d_cio = (struct pci_conf_io *)data; 618 d_cio->status = cio->status; 619 d_cio->generation = cio->generation; 620 d_cio->offset = cio->offset; 621 d_cio->num_matches = cio->num_matches; 622 return; 623 624 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) 625 case PCIOCGETCONF_OLD32: 626 cio32 = (struct pci_conf_io32 *)data; 627 628 cio32->status = cio->status; 629 cio32->generation = cio->generation; 630 cio32->offset = cio->offset; 631 cio32->num_matches = cio->num_matches; 632 return; 633 #endif 634 635 default: 636 /* programmer error */ 637 return; 638 } 639 } 640 641 static void 642 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, 643 u_long cmd) 644 { 645 646 memset(pcup, 0, sizeof(*pcup)); 647 648 switch (cmd) { 649 case PCIOCGETCONF: 650 pcup->pc = *pcp; 651 return; 652 653 #ifdef PRE7_COMPAT 654 #ifdef COMPAT_FREEBSD32 655 case PCIOCGETCONF_OLD32: 656 pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus; 657 pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev; 658 pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func; 659 pcup->pco32.pc_hdr = pcp->pc_hdr; 660 pcup->pco32.pc_subvendor = pcp->pc_subvendor; 661 pcup->pco32.pc_subdevice = pcp->pc_subdevice; 662 pcup->pco32.pc_vendor = pcp->pc_vendor; 663 pcup->pco32.pc_device = pcp->pc_device; 664 pcup->pco32.pc_class = pcp->pc_class; 665 pcup->pco32.pc_subclass = pcp->pc_subclass; 666 pcup->pco32.pc_progif = pcp->pc_progif; 667 pcup->pco32.pc_revid = pcp->pc_revid; 668 strlcpy(pcup->pco32.pd_name, pcp->pd_name, 669 sizeof(pcup->pco32.pd_name)); 670 pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit; 671 return; 672 673 #endif /* COMPAT_FREEBSD32 */ 674 case PCIOCGETCONF_OLD: 675 pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus; 676 pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev; 677 pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func; 678 pcup->pco.pc_hdr = pcp->pc_hdr; 679 pcup->pco.pc_subvendor = pcp->pc_subvendor; 680 pcup->pco.pc_subdevice = pcp->pc_subdevice; 681 pcup->pco.pc_vendor = pcp->pc_vendor; 682 pcup->pco.pc_device = pcp->pc_device; 683 pcup->pco.pc_class = pcp->pc_class; 684 pcup->pco.pc_subclass = pcp->pc_subclass; 685 pcup->pco.pc_progif = pcp->pc_progif; 686 pcup->pco.pc_revid = pcp->pc_revid; 687 strlcpy(pcup->pco.pd_name, pcp->pd_name, 688 sizeof(pcup->pco.pd_name)); 689 pcup->pco.pd_unit = pcp->pd_unit; 690 return; 691 #endif /* PRE7_COMPAT */ 692 693 default: 694 /* programmer error */ 695 return; 696 } 697 } 698 699 static int 700 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 701 { 702 device_t pcidev; 703 const char *name; 704 struct devlist *devlist_head; 705 struct pci_conf_io *cio = NULL; 706 struct pci_devinfo *dinfo; 707 struct pci_io *io; 708 struct pci_bar_io *bio; 709 struct pci_list_vpd_io *lvio; 710 struct pci_match_conf *pattern_buf; 711 struct pci_map *pm; 712 size_t confsz, iolen; 713 int error, ionum, i, num_patterns; 714 union pci_conf_union pcu; 715 #ifdef PRE7_COMPAT 716 struct pci_io iodata; 717 struct pci_io_old *io_old; 718 719 io_old = NULL; 720 #endif 721 722 if (!(flag & FWRITE)) { 723 switch (cmd) { 724 case PCIOCGETCONF: 725 #ifdef PRE7_COMPAT 726 case PCIOCGETCONF_OLD: 727 #ifdef COMPAT_FREEBSD32 728 case PCIOCGETCONF_OLD32: 729 #endif 730 #endif 731 case PCIOCGETBAR: 732 case PCIOCLISTVPD: 733 break; 734 default: 735 return (EPERM); 736 } 737 } 738 739 740 switch (cmd) { 741 case PCIOCGETCONF: 742 #ifdef PRE7_COMPAT 743 case PCIOCGETCONF_OLD: 744 #ifdef COMPAT_FREEBSD32 745 case PCIOCGETCONF_OLD32: 746 #endif 747 #endif 748 cio = malloc(sizeof(struct pci_conf_io), M_TEMP, 749 M_WAITOK | M_ZERO); 750 pci_conf_io_init(cio, data, cmd); 751 pattern_buf = NULL; 752 num_patterns = 0; 753 dinfo = NULL; 754 755 cio->num_matches = 0; 756 757 /* 758 * If the user specified an offset into the device list, 759 * but the list has changed since they last called this 760 * ioctl, tell them that the list has changed. They will 761 * have to get the list from the beginning. 762 */ 763 if ((cio->offset != 0) 764 && (cio->generation != pci_generation)){ 765 cio->status = PCI_GETCONF_LIST_CHANGED; 766 error = 0; 767 goto getconfexit; 768 } 769 770 /* 771 * Check to see whether the user has asked for an offset 772 * past the end of our list. 773 */ 774 if (cio->offset >= pci_numdevs) { 775 cio->status = PCI_GETCONF_LAST_DEVICE; 776 error = 0; 777 goto getconfexit; 778 } 779 780 /* get the head of the device queue */ 781 devlist_head = &pci_devq; 782 783 /* 784 * Determine how much room we have for pci_conf structures. 785 * Round the user's buffer size down to the nearest 786 * multiple of sizeof(struct pci_conf) in case the user 787 * didn't specify a multiple of that size. 788 */ 789 confsz = pci_conf_size(cmd); 790 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), 791 pci_numdevs * confsz); 792 793 /* 794 * Since we know that iolen is a multiple of the size of 795 * the pciconf union, it's okay to do this. 796 */ 797 ionum = iolen / confsz; 798 799 /* 800 * If this test is true, the user wants the pci_conf 801 * structures returned to match the supplied entries. 802 */ 803 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs) 804 && (cio->pat_buf_len > 0)) { 805 /* 806 * pat_buf_len needs to be: 807 * num_patterns * sizeof(struct pci_match_conf) 808 * While it is certainly possible the user just 809 * allocated a large buffer, but set the number of 810 * matches correctly, it is far more likely that 811 * their kernel doesn't match the userland utility 812 * they're using. It's also possible that the user 813 * forgot to initialize some variables. Yes, this 814 * may be overly picky, but I hazard to guess that 815 * it's far more likely to just catch folks that 816 * updated their kernel but not their userland. 817 */ 818 if (cio->num_patterns * pci_match_conf_size(cmd) != 819 cio->pat_buf_len) { 820 /* The user made a mistake, return an error. */ 821 cio->status = PCI_GETCONF_ERROR; 822 error = EINVAL; 823 goto getconfexit; 824 } 825 826 /* 827 * Allocate a buffer to hold the patterns. 828 */ 829 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 830 M_WAITOK); 831 error = copyin(cio->patterns, pattern_buf, 832 cio->pat_buf_len); 833 if (error != 0) { 834 error = EINVAL; 835 goto getconfexit; 836 } 837 num_patterns = cio->num_patterns; 838 } else if ((cio->num_patterns > 0) 839 || (cio->pat_buf_len > 0)) { 840 /* 841 * The user made a mistake, spit out an error. 842 */ 843 cio->status = PCI_GETCONF_ERROR; 844 error = EINVAL; 845 goto getconfexit; 846 } 847 848 /* 849 * Go through the list of devices and copy out the devices 850 * that match the user's criteria. 851 */ 852 for (cio->num_matches = 0, i = 0, 853 dinfo = STAILQ_FIRST(devlist_head); 854 dinfo != NULL; 855 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 856 857 if (i < cio->offset) 858 continue; 859 860 /* Populate pd_name and pd_unit */ 861 name = NULL; 862 if (dinfo->cfg.dev) 863 name = device_get_name(dinfo->cfg.dev); 864 if (name) { 865 strncpy(dinfo->conf.pd_name, name, 866 sizeof(dinfo->conf.pd_name)); 867 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 868 dinfo->conf.pd_unit = 869 device_get_unit(dinfo->cfg.dev); 870 } else { 871 dinfo->conf.pd_name[0] = '\0'; 872 dinfo->conf.pd_unit = 0; 873 } 874 875 if (pattern_buf == NULL || 876 pci_conf_match(cmd, pattern_buf, num_patterns, 877 &dinfo->conf) == 0) { 878 /* 879 * If we've filled up the user's buffer, 880 * break out at this point. Since we've 881 * got a match here, we'll pick right back 882 * up at the matching entry. We can also 883 * tell the user that there are more matches 884 * left. 885 */ 886 if (cio->num_matches >= ionum) { 887 error = 0; 888 break; 889 } 890 891 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); 892 error = copyout(&pcu, 893 (caddr_t)cio->matches + 894 confsz * cio->num_matches, confsz); 895 if (error) 896 break; 897 cio->num_matches++; 898 } 899 } 900 901 /* 902 * Set the pointer into the list, so if the user is getting 903 * n records at a time, where n < pci_numdevs, 904 */ 905 cio->offset = i; 906 907 /* 908 * Set the generation, the user will need this if they make 909 * another ioctl call with offset != 0. 910 */ 911 cio->generation = pci_generation; 912 913 /* 914 * If this is the last device, inform the user so he won't 915 * bother asking for more devices. If dinfo isn't NULL, we 916 * know that there are more matches in the list because of 917 * the way the traversal is done. 918 */ 919 if (dinfo == NULL) 920 cio->status = PCI_GETCONF_LAST_DEVICE; 921 else 922 cio->status = PCI_GETCONF_MORE_DEVS; 923 924 getconfexit: 925 pci_conf_io_update_data(cio, data, cmd); 926 free(cio, M_TEMP); 927 free(pattern_buf, M_TEMP); 928 929 break; 930 931 #ifdef PRE7_COMPAT 932 case PCIOCREAD_OLD: 933 case PCIOCWRITE_OLD: 934 io_old = (struct pci_io_old *)data; 935 iodata.pi_sel.pc_domain = 0; 936 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus; 937 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev; 938 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func; 939 iodata.pi_reg = io_old->pi_reg; 940 iodata.pi_width = io_old->pi_width; 941 iodata.pi_data = io_old->pi_data; 942 data = (caddr_t)&iodata; 943 /* FALLTHROUGH */ 944 #endif 945 case PCIOCREAD: 946 case PCIOCWRITE: 947 io = (struct pci_io *)data; 948 switch(io->pi_width) { 949 case 4: 950 case 2: 951 case 1: 952 /* Make sure register is not negative and aligned. */ 953 if (io->pi_reg < 0 || 954 io->pi_reg & (io->pi_width - 1)) { 955 error = EINVAL; 956 break; 957 } 958 /* 959 * Assume that the user-level bus number is 960 * in fact the physical PCI bus number. 961 * Look up the grandparent, i.e. the bridge device, 962 * so that we can issue configuration space cycles. 963 */ 964 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, 965 io->pi_sel.pc_bus, io->pi_sel.pc_dev, 966 io->pi_sel.pc_func); 967 if (pcidev) { 968 #ifdef PRE7_COMPAT 969 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD) 970 #else 971 if (cmd == PCIOCWRITE) 972 #endif 973 pci_write_config(pcidev, 974 io->pi_reg, 975 io->pi_data, 976 io->pi_width); 977 #ifdef PRE7_COMPAT 978 else if (cmd == PCIOCREAD_OLD) 979 io_old->pi_data = 980 pci_read_config(pcidev, 981 io->pi_reg, 982 io->pi_width); 983 #endif 984 else 985 io->pi_data = 986 pci_read_config(pcidev, 987 io->pi_reg, 988 io->pi_width); 989 error = 0; 990 } else { 991 #ifdef COMPAT_FREEBSD4 992 if (cmd == PCIOCREAD_OLD) { 993 io_old->pi_data = -1; 994 error = 0; 995 } else 996 #endif 997 error = ENODEV; 998 } 999 break; 1000 default: 1001 error = EINVAL; 1002 break; 1003 } 1004 break; 1005 1006 case PCIOCGETBAR: 1007 bio = (struct pci_bar_io *)data; 1008 1009 /* 1010 * Assume that the user-level bus number is 1011 * in fact the physical PCI bus number. 1012 */ 1013 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain, 1014 bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev, 1015 bio->pbi_sel.pc_func); 1016 if (pcidev == NULL) { 1017 error = ENODEV; 1018 break; 1019 } 1020 pm = pci_find_bar(pcidev, bio->pbi_reg); 1021 if (pm == NULL) { 1022 error = EINVAL; 1023 break; 1024 } 1025 bio->pbi_base = pm->pm_value; 1026 bio->pbi_length = (pci_addr_t)1 << pm->pm_size; 1027 bio->pbi_enabled = pci_bar_enabled(pcidev, pm); 1028 error = 0; 1029 break; 1030 case PCIOCATTACHED: 1031 error = 0; 1032 io = (struct pci_io *)data; 1033 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus, 1034 io->pi_sel.pc_dev, io->pi_sel.pc_func); 1035 if (pcidev != NULL) 1036 io->pi_data = device_is_attached(pcidev); 1037 else 1038 error = ENODEV; 1039 break; 1040 case PCIOCLISTVPD: 1041 lvio = (struct pci_list_vpd_io *)data; 1042 1043 /* 1044 * Assume that the user-level bus number is 1045 * in fact the physical PCI bus number. 1046 */ 1047 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, 1048 lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, 1049 lvio->plvi_sel.pc_func); 1050 if (pcidev == NULL) { 1051 error = ENODEV; 1052 break; 1053 } 1054 error = pci_list_vpd(pcidev, lvio); 1055 break; 1056 default: 1057 error = ENOTTY; 1058 break; 1059 } 1060 1061 return (error); 1062 } 1063