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