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