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