1 /* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 * 28 */ 29 30 #include "opt_bus.h" /* XXX trim includes */ 31 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/proc.h> 41 #include <sys/queue.h> 42 #include <sys/types.h> 43 44 #include <vm/vm.h> 45 #include <vm/pmap.h> 46 #include <vm/vm_extern.h> 47 48 #include <sys/bus.h> 49 #include <machine/bus.h> 50 #include <sys/rman.h> 51 #include <machine/resource.h> 52 53 #include <sys/pciio.h> 54 #include <pci/pcireg.h> 55 #include <pci/pcivar.h> 56 57 #include "pcib_if.h" 58 #include "pci_if.h" 59 60 /* 61 * This is the user interface to PCI configuration space. 62 */ 63 64 static d_open_t pci_open; 65 static d_close_t pci_close; 66 static int pci_conf_match(struct pci_match_conf *matches, int num_matches, 67 struct pci_conf *match_buf); 68 static d_ioctl_t pci_ioctl; 69 70 #define PCI_CDEV 78 71 72 struct cdevsw pcicdev = { 73 /* open */ pci_open, 74 /* close */ pci_close, 75 /* read */ noread, 76 /* write */ nowrite, 77 /* ioctl */ pci_ioctl, 78 /* poll */ nopoll, 79 /* mmap */ nommap, 80 /* strategy */ nostrategy, 81 /* name */ "pci", 82 /* maj */ PCI_CDEV, 83 /* dump */ nodump, 84 /* psize */ nopsize, 85 /* flags */ 0, 86 }; 87 88 static int 89 pci_open(dev_t dev, int oflags, int devtype, struct thread *td) 90 { 91 int error; 92 93 if (oflags & FWRITE) { 94 error = securelevel_gt(td->td_ucred, 0); 95 if (error) 96 return (error); 97 } 98 99 return (0); 100 } 101 102 static int 103 pci_close(dev_t dev, int flag, int devtype, struct thread *td) 104 { 105 return 0; 106 } 107 108 /* 109 * Match a single pci_conf structure against an array of pci_match_conf 110 * structures. The first argument, 'matches', is an array of num_matches 111 * pci_match_conf structures. match_buf is a pointer to the pci_conf 112 * structure that will be compared to every entry in the matches array. 113 * This function returns 1 on failure, 0 on success. 114 */ 115 static int 116 pci_conf_match(struct pci_match_conf *matches, int num_matches, 117 struct pci_conf *match_buf) 118 { 119 int i; 120 121 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 122 return(1); 123 124 for (i = 0; i < num_matches; i++) { 125 /* 126 * I'm not sure why someone would do this...but... 127 */ 128 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 129 continue; 130 131 /* 132 * Look at each of the match flags. If it's set, do the 133 * comparison. If the comparison fails, we don't have a 134 * match, go on to the next item if there is one. 135 */ 136 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 137 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 138 continue; 139 140 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 141 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 142 continue; 143 144 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 145 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 146 continue; 147 148 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 149 && (match_buf->pc_vendor != matches[i].pc_vendor)) 150 continue; 151 152 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 153 && (match_buf->pc_device != matches[i].pc_device)) 154 continue; 155 156 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 157 && (match_buf->pc_class != matches[i].pc_class)) 158 continue; 159 160 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 161 && (match_buf->pd_unit != matches[i].pd_unit)) 162 continue; 163 164 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 165 && (strncmp(matches[i].pd_name, match_buf->pd_name, 166 sizeof(match_buf->pd_name)) != 0)) 167 continue; 168 169 return(0); 170 } 171 172 return(1); 173 } 174 175 static int 176 pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 177 { 178 device_t pci, pcib; 179 struct pci_io *io; 180 const char *name; 181 int error; 182 183 if (!(flag & FWRITE)) 184 return EPERM; 185 186 187 switch(cmd) { 188 case PCIOCGETCONF: 189 { 190 struct pci_devinfo *dinfo; 191 struct pci_conf_io *cio; 192 struct devlist *devlist_head; 193 struct pci_match_conf *pattern_buf; 194 int num_patterns; 195 size_t iolen; 196 int ionum, i; 197 198 cio = (struct pci_conf_io *)data; 199 200 num_patterns = 0; 201 dinfo = NULL; 202 203 /* 204 * Hopefully the user won't pass in a null pointer, but it 205 * can't hurt to check. 206 */ 207 if (cio == NULL) { 208 error = EINVAL; 209 break; 210 } 211 212 /* 213 * If the user specified an offset into the device list, 214 * but the list has changed since they last called this 215 * ioctl, tell them that the list has changed. They will 216 * have to get the list from the beginning. 217 */ 218 if ((cio->offset != 0) 219 && (cio->generation != pci_generation)){ 220 cio->num_matches = 0; 221 cio->status = PCI_GETCONF_LIST_CHANGED; 222 error = 0; 223 break; 224 } 225 226 /* 227 * Check to see whether the user has asked for an offset 228 * past the end of our list. 229 */ 230 if (cio->offset >= pci_numdevs) { 231 cio->num_matches = 0; 232 cio->status = PCI_GETCONF_LAST_DEVICE; 233 error = 0; 234 break; 235 } 236 237 /* get the head of the device queue */ 238 devlist_head = &pci_devq; 239 240 /* 241 * Determine how much room we have for pci_conf structures. 242 * Round the user's buffer size down to the nearest 243 * multiple of sizeof(struct pci_conf) in case the user 244 * didn't specify a multiple of that size. 245 */ 246 iolen = min(cio->match_buf_len - 247 (cio->match_buf_len % sizeof(struct pci_conf)), 248 pci_numdevs * sizeof(struct pci_conf)); 249 250 /* 251 * Since we know that iolen is a multiple of the size of 252 * the pciconf union, it's okay to do this. 253 */ 254 ionum = iolen / sizeof(struct pci_conf); 255 256 /* 257 * If this test is true, the user wants the pci_conf 258 * structures returned to match the supplied entries. 259 */ 260 if ((cio->num_patterns > 0) 261 && (cio->pat_buf_len > 0)) { 262 /* 263 * pat_buf_len needs to be: 264 * num_patterns * sizeof(struct pci_match_conf) 265 * While it is certainly possible the user just 266 * allocated a large buffer, but set the number of 267 * matches correctly, it is far more likely that 268 * their kernel doesn't match the userland utility 269 * they're using. It's also possible that the user 270 * forgot to initialize some variables. Yes, this 271 * may be overly picky, but I hazard to guess that 272 * it's far more likely to just catch folks that 273 * updated their kernel but not their userland. 274 */ 275 if ((cio->num_patterns * 276 sizeof(struct pci_match_conf)) != cio->pat_buf_len){ 277 /* The user made a mistake, return an error*/ 278 cio->status = PCI_GETCONF_ERROR; 279 printf("pci_ioctl: pat_buf_len %d != " 280 "num_patterns (%d) * sizeof(struct " 281 "pci_match_conf) (%d)\npci_ioctl: " 282 "pat_buf_len should be = %d\n", 283 cio->pat_buf_len, cio->num_patterns, 284 (int)sizeof(struct pci_match_conf), 285 (int)sizeof(struct pci_match_conf) * 286 cio->num_patterns); 287 printf("pci_ioctl: do your headers match your " 288 "kernel?\n"); 289 cio->num_matches = 0; 290 error = EINVAL; 291 break; 292 } 293 294 /* 295 * Check the user's buffer to make sure it's readable. 296 */ 297 if (!useracc((caddr_t)cio->patterns, 298 cio->pat_buf_len, VM_PROT_READ)) { 299 printf("pci_ioctl: pattern buffer %p, " 300 "length %u isn't user accessible for" 301 " READ\n", cio->patterns, 302 cio->pat_buf_len); 303 error = EACCES; 304 break; 305 } 306 /* 307 * Allocate a buffer to hold the patterns. 308 */ 309 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 310 M_WAITOK); 311 error = copyin(cio->patterns, pattern_buf, 312 cio->pat_buf_len); 313 if (error != 0) 314 break; 315 num_patterns = cio->num_patterns; 316 317 } else if ((cio->num_patterns > 0) 318 || (cio->pat_buf_len > 0)) { 319 /* 320 * The user made a mistake, spit out an error. 321 */ 322 cio->status = PCI_GETCONF_ERROR; 323 cio->num_matches = 0; 324 printf("pci_ioctl: invalid GETCONF arguments\n"); 325 error = EINVAL; 326 break; 327 } else 328 pattern_buf = NULL; 329 330 /* 331 * Make sure we can write to the match buffer. 332 */ 333 if (!useracc((caddr_t)cio->matches, 334 cio->match_buf_len, VM_PROT_WRITE)) { 335 printf("pci_ioctl: match buffer %p, length %u " 336 "isn't user accessible for WRITE\n", 337 cio->matches, cio->match_buf_len); 338 error = EACCES; 339 break; 340 } 341 342 /* 343 * Go through the list of devices and copy out the devices 344 * that match the user's criteria. 345 */ 346 for (cio->num_matches = 0, error = 0, i = 0, 347 dinfo = STAILQ_FIRST(devlist_head); 348 (dinfo != NULL) && (cio->num_matches < ionum) 349 && (error == 0) && (i < pci_numdevs); 350 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 351 352 if (i < cio->offset) 353 continue; 354 355 /* Populate pd_name and pd_unit */ 356 name = NULL; 357 if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0') 358 name = device_get_name(dinfo->cfg.dev); 359 if (name) { 360 strncpy(dinfo->conf.pd_name, name, 361 sizeof(dinfo->conf.pd_name)); 362 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 363 dinfo->conf.pd_unit = 364 device_get_unit(dinfo->cfg.dev); 365 } 366 367 if ((pattern_buf == NULL) || 368 (pci_conf_match(pattern_buf, num_patterns, 369 &dinfo->conf) == 0)) { 370 371 /* 372 * If we've filled up the user's buffer, 373 * break out at this point. Since we've 374 * got a match here, we'll pick right back 375 * up at the matching entry. We can also 376 * tell the user that there are more matches 377 * left. 378 */ 379 if (cio->num_matches >= ionum) 380 break; 381 382 error = copyout(&dinfo->conf, 383 &cio->matches[cio->num_matches], 384 sizeof(struct pci_conf)); 385 cio->num_matches++; 386 } 387 } 388 389 /* 390 * Set the pointer into the list, so if the user is getting 391 * n records at a time, where n < pci_numdevs, 392 */ 393 cio->offset = i; 394 395 /* 396 * Set the generation, the user will need this if they make 397 * another ioctl call with offset != 0. 398 */ 399 cio->generation = pci_generation; 400 401 /* 402 * If this is the last device, inform the user so he won't 403 * bother asking for more devices. If dinfo isn't NULL, we 404 * know that there are more matches in the list because of 405 * the way the traversal is done. 406 */ 407 if (dinfo == NULL) 408 cio->status = PCI_GETCONF_LAST_DEVICE; 409 else 410 cio->status = PCI_GETCONF_MORE_DEVS; 411 412 if (pattern_buf != NULL) 413 free(pattern_buf, M_TEMP); 414 415 break; 416 } 417 case PCIOCREAD: 418 io = (struct pci_io *)data; 419 switch(io->pi_width) { 420 case 4: 421 case 2: 422 case 1: 423 /* 424 * Assume that the user-level bus number is 425 * actually the pciN instance number. We map 426 * from that to the real pcib+bus combination. 427 */ 428 pci = devclass_get_device(devclass_find("pci"), 429 io->pi_sel.pc_bus); 430 if (pci) { 431 int b = pcib_get_bus(pci); 432 pcib = device_get_parent(pci); 433 io->pi_data = 434 PCIB_READ_CONFIG(pcib, 435 b, 436 io->pi_sel.pc_dev, 437 io->pi_sel.pc_func, 438 io->pi_reg, 439 io->pi_width); 440 error = 0; 441 } else { 442 error = ENODEV; 443 } 444 break; 445 default: 446 error = ENODEV; 447 break; 448 } 449 break; 450 451 case PCIOCWRITE: 452 io = (struct pci_io *)data; 453 switch(io->pi_width) { 454 case 4: 455 case 2: 456 case 1: 457 /* 458 * Assume that the user-level bus number is 459 * actually the pciN instance number. We map 460 * from that to the real pcib+bus combination. 461 */ 462 pci = devclass_get_device(devclass_find("pci"), 463 io->pi_sel.pc_bus); 464 if (pci) { 465 int b = pcib_get_bus(pci); 466 pcib = device_get_parent(pci); 467 PCIB_WRITE_CONFIG(pcib, 468 b, 469 io->pi_sel.pc_dev, 470 io->pi_sel.pc_func, 471 io->pi_reg, 472 io->pi_data, 473 io->pi_width); 474 error = 0; 475 } else { 476 error = ENODEV; 477 } 478 break; 479 default: 480 error = ENODEV; 481 break; 482 } 483 break; 484 485 default: 486 error = ENOTTY; 487 break; 488 } 489 490 return (error); 491 } 492 493