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