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