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