netbsd_pci.c revision a01999d7
1/* 2 * Copyright (c) 2008 Juan Romero Pardines 3 * Copyright (c) 2008 Mark Kettenis 4 * Copyright (c) 2009 Michael Lorenz 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#ifdef HAVE_CONFIG_H 20#include "config.h" 21#endif 22 23#include <sys/param.h> 24#include <sys/ioctl.h> 25#include <sys/mman.h> 26#include <sys/types.h> 27 28#ifdef HAVE_MTRR 29#include <machine/sysarch.h> 30#include <machine/mtrr.h> 31#ifdef _X86_SYSARCH_L 32/* NetBSD 5.x and newer */ 33#define netbsd_set_mtrr(mr, num) _X86_SYSARCH_L(set_mtrr)(mr, num) 34#else 35/* NetBSD 4.x and older */ 36#ifdef __i386__ 37#define netbsd_set_mtrr(mr, num) i386_set_mtrr((mr), (num)) 38#endif 39#ifdef __amd64__ 40#define netbsd_set_mtrr(mr, num) x86_64_set_mtrr((mr), (num)) 41#endif 42#endif 43#endif 44 45#include <dev/pci/pcidevs.h> 46#include <dev/pci/pciio.h> 47#include <dev/pci/pcireg.h> 48 49#include <errno.h> 50#include <fcntl.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <string.h> 54#include <unistd.h> 55 56 57#include <pci.h> 58#include <dev/wscons/wsconsio.h> 59 60#include "pciaccess.h" 61#include "pciaccess_private.h" 62 63typedef struct _pcibus { 64 int fd; /* /dev/pci* */ 65 int num; /* bus number */ 66 int maxdevs; /* maximum number of devices */ 67} PciBus; 68 69static PciBus *buses = NULL; /* indexed by pci_device.domain */ 70static int nbuses = 0; /* number of buses found */ 71 72/* 73 * NetBSD's userland has a /dev/pci* entry for each bus but userland has no way 74 * to tell if a bus is a subordinate of another one or if it's on a different 75 * host bridge. On some architectures ( macppc for example ) all root buses have 76 * bus number 0 but on sparc64 for example the two roots in an Ultra60 have 77 * different bus numbers - one is 0 and the other 128. 78 * With each /dev/pci* we can map everything on the same root and we can also 79 * see all devices on the same root, trying to do that causes problems though: 80 * - since we can't tell which /dev/pci* is a subordinate we would find some 81 * devices more than once 82 * - we would have to guess subordinate bus numbers which is a waste of time 83 * since we can ask each /dev/pci* for its bus number so we can scan only the 84 * buses we know exist, not all 256 which may exist in each domain. 85 * - some bus_space_mmap() methods may limit mappings to address ranges which 86 * belong to known devices on that bus only. 87 * Each host bridge may or may not have its own IO range, to avoid guesswork 88 * here each /dev/pci* will let userland map its appropriate IO range at 89 * PCI_MAGIC_IO_RANGE if defined in <machine/param.h> 90 * With all this we should be able to use any PCI graphics device on any PCI 91 * bus on any architecture as long as Xorg has a driver, without allowing 92 * arbitrary mappings via /dev/mem and without userland having to know or care 93 * about translating bus addresses to physical addresses or the other way 94 * around. 95 */ 96 97static int 98pci_read(int domain, int bus, int dev, int func, uint32_t reg, uint32_t *val) 99{ 100 uint32_t rval; 101 102 if ((domain < 0) || (domain >= nbuses)) 103 return -1; 104 105 if (pcibus_conf_read(buses[domain].fd, (unsigned int)bus, 106 (unsigned int)dev, (unsigned int)func, reg, &rval) == -1) 107 return (-1); 108 109 *val = rval; 110 111 return 0; 112} 113 114static int 115pci_write(int domain, int bus, int dev, int func, uint32_t reg, uint32_t val) 116{ 117 118 if ((domain < 0) || (domain >= nbuses)) 119 return -1; 120 121 return pcibus_conf_write(buses[domain].fd, (unsigned int)bus, 122 (unsigned int)dev, (unsigned int)func, reg, val); 123} 124 125static int 126pci_nfuncs(int domain, int bus, int dev) 127{ 128 uint32_t hdr; 129 130 if ((domain < 0) || (domain >= nbuses)) 131 return -1; 132 133 if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0) 134 return -1; 135 136 return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1); 137} 138 139/*ARGSUSED*/ 140static int 141pci_device_netbsd_map_range(struct pci_device *dev, 142 struct pci_device_mapping *map) 143{ 144#ifdef HAVE_MTRR 145 struct mtrr m; 146 int n = 1; 147#endif 148 int prot, ret = 0; 149 150 prot = PROT_READ; 151 152 if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE) 153 prot |= PROT_WRITE; 154 map->memory = mmap(NULL, (size_t)map->size, prot, MAP_SHARED, 155 buses[dev->domain].fd, (off_t)map->base); 156 if (map->memory == MAP_FAILED) 157 return errno; 158 159#ifdef HAVE_MTRR 160 memset(&m, 0, sizeof(m)); 161 162 /* No need to set an MTRR if it's the default mode. */ 163 if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || 164 (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) { 165 m.base = map->base; 166 m.flags = MTRR_VALID | MTRR_PRIVATE; 167 m.len = map->size; 168 m.owner = getpid(); 169 if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE) 170 m.type = MTRR_TYPE_WB; 171 if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) 172 m.type = MTRR_TYPE_WC; 173 174 if ((netbsd_set_mtrr(&m, &n)) == -1) { 175 fprintf(stderr, "mtrr set failed: %s\n", 176 strerror(errno)); 177 } 178 } 179#endif 180 181 return ret; 182} 183 184static int 185pci_device_netbsd_unmap_range(struct pci_device *dev, 186 struct pci_device_mapping *map) 187{ 188#ifdef HAVE_MTRR 189 struct mtrr m; 190 int n = 1; 191 192 memset(&m, 0, sizeof(m)); 193 194 if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || 195 (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) { 196 m.base = map->base; 197 m.flags = 0; 198 m.len = map->size; 199 m.type = MTRR_TYPE_UC; 200 (void)netbsd_set_mtrr(&m, &n); 201 } 202#endif 203 204 return pci_device_generic_unmap_range(dev, map); 205} 206 207static int 208pci_device_netbsd_read(struct pci_device *dev, void *data, 209 pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) 210{ 211 u_int reg, rval; 212 213 *bytes_read = 0; 214 while (size > 0) { 215 size_t toread = MIN(size, 4 - (offset & 0x3)); 216 217 reg = (u_int)(offset & ~0x3); 218 219 if ((pcibus_conf_read(buses[dev->domain].fd, 220 (unsigned int)dev->bus, (unsigned int)dev->dev, 221 (unsigned int)dev->func, reg, &rval)) == -1) 222 return errno; 223 224 rval = htole32(rval); 225 rval >>= ((offset & 0x3) * 8); 226 227 memcpy(data, &rval, toread); 228 229 offset += toread; 230 data = (char *)data + toread; 231 size -= toread; 232 *bytes_read += toread; 233 } 234 235 return 0; 236} 237 238static int 239pci_device_netbsd_write(struct pci_device *dev, const void *data, 240 pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) 241{ 242 u_int reg, val; 243 244 if ((offset % 4) != 0 || (size % 4) != 0) 245 return EINVAL; 246 247 *bytes_written = 0; 248 while (size > 0) { 249 reg = (u_int)offset; 250 memcpy(&val, data, 4); 251 252 if ((pcibus_conf_write(buses[dev->domain].fd, 253 (unsigned int)dev->bus, (unsigned int)dev->dev, 254 (unsigned int)dev->func, reg, val)) == -1) 255 return errno; 256 257 offset += 4; 258 data = (const char *)data + 4; 259 size -= 4; 260 *bytes_written += 4; 261 } 262 263 return 0; 264} 265 266#if defined(WSDISPLAYIO_GET_BUSID) 267static int 268pci_device_netbsd_boot_vga(struct pci_device *dev) 269{ 270 int ret; 271 struct wsdisplayio_bus_id busid; 272 int fd; 273 274 fd = open("/dev/ttyE0", O_RDONLY); 275 if (fd == -1) { 276 fprintf(stderr, "failed to open /dev/ttyE0: %s\n", 277 strerror(errno)); 278 return 0; 279 } 280 281 ret = ioctl(fd, WSDISPLAYIO_GET_BUSID, &busid); 282 close(fd); 283 if (ret == -1) { 284 fprintf(stderr, "ioctl WSDISPLAYIO_GET_BUSID failed: %s\n", 285 strerror(errno)); 286 return 0; 287 } 288 289 if (busid.bus_type != WSDISPLAYIO_BUS_PCI) 290 return 0; 291 292 if (busid.ubus.pci.domain != dev->domain) 293 return 0; 294 if (busid.ubus.pci.bus != dev->bus) 295 return 0; 296 if (busid.ubus.pci.device != dev->dev) 297 return 0; 298 if (busid.ubus.pci.function != dev->func) 299 return 0; 300 301 return 1; 302} 303#endif 304 305static void 306pci_system_netbsd_destroy(void) 307{ 308 int i; 309 310 for (i = 0; i < nbuses; i++) { 311 close(buses[i].fd); 312 } 313 free(pci_sys); 314 pci_sys = NULL; 315} 316 317static int 318pci_device_netbsd_probe(struct pci_device *device) 319{ 320 struct pci_device_private *priv = 321 (struct pci_device_private *)(void *)device; 322 struct pci_mem_region *region; 323 uint64_t reg64, size64; 324 uint32_t bar, reg, size; 325 int bus, dev, func, err, domain; 326 327 domain = device->domain; 328 bus = device->bus; 329 dev = device->dev; 330 func = device->func; 331 332 /* Enable the device if necessary */ 333 err = pci_read(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, ®); 334 if (err) 335 return err; 336#ifndef AVOID_DEVICE_ENABLE 337 if ((reg & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) != 338 (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) { 339 reg |= PCI_COMMAND_IO_ENABLE | 340 PCI_COMMAND_MEM_ENABLE | 341 PCI_COMMAND_MASTER_ENABLE; 342 err = pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, 343 reg); 344 if (err) 345 return err; 346 } 347#endif 348 err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, ®); 349 if (err) 350 return err; 351 352 priv->header_type = PCI_HDRTYPE_TYPE(reg); 353 if (priv->header_type != 0) 354 return 0; 355 356 region = device->regions; 357 for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; 358 bar += sizeof(uint32_t), region++) { 359 err = pci_read(domain, bus, dev, func, bar, ®); 360 if (err) 361 return err; 362 363 /* Probe the size of the region. */ 364 err = pci_write(domain, bus, dev, func, bar, (unsigned int)~0); 365 if (err) 366 return err; 367 pci_read(domain, bus, dev, func, bar, &size); 368 pci_write(domain, bus, dev, func, bar, reg); 369 370 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { 371 region->is_IO = 1; 372 region->base_addr = PCI_MAPREG_IO_ADDR(reg); 373 region->size = PCI_MAPREG_IO_SIZE(size); 374 } else { 375 if (PCI_MAPREG_MEM_PREFETCHABLE(reg)) 376 region->is_prefetchable = 1; 377 switch(PCI_MAPREG_MEM_TYPE(reg)) { 378 case PCI_MAPREG_MEM_TYPE_32BIT: 379 case PCI_MAPREG_MEM_TYPE_32BIT_1M: 380 region->base_addr = PCI_MAPREG_MEM_ADDR(reg); 381 region->size = PCI_MAPREG_MEM_SIZE(size); 382 break; 383 case PCI_MAPREG_MEM_TYPE_64BIT: 384 region->is_64 = 1; 385 386 reg64 = reg; 387 size64 = size; 388 389 bar += sizeof(uint32_t); 390 391 err = pci_read(domain, bus, dev, func, bar, ®); 392 if (err) 393 return err; 394 reg64 |= (uint64_t)reg << 32; 395 396 err = pci_write(domain, bus, dev, func, bar, 397 (unsigned int)~0); 398 if (err) 399 return err; 400 pci_read(domain, bus, dev, func, bar, &size); 401 pci_write(domain, bus, dev, func, bar, 402 (unsigned int)(reg64 >> 32)); 403 size64 |= (uint64_t)size << 32; 404 405 region->base_addr = 406 (unsigned long)PCI_MAPREG_MEM64_ADDR(reg64); 407 region->size = 408 (unsigned long)PCI_MAPREG_MEM64_SIZE(size64); 409 region++; 410 break; 411 } 412 } 413 } 414 415 /* Probe expansion ROM if present */ 416 err = pci_read(domain, bus, dev, func, PCI_MAPREG_ROM, ®); 417 if (err) 418 return err; 419 if (reg != 0) { 420 err = pci_write(domain, bus, dev, func, PCI_MAPREG_ROM, 421 (uint32_t)(~PCI_MAPREG_ROM_ENABLE)); 422 if (err) 423 return err; 424 pci_read(domain, bus, dev, func, PCI_MAPREG_ROM, &size); 425 pci_write(domain, bus, dev, func, PCI_MAPREG_ROM, reg); 426 if ((reg & PCI_MAPREG_MEM_ADDR_MASK) != 0) { 427 priv->rom_base = reg & PCI_MAPREG_MEM_ADDR_MASK; 428 device->rom_size = -(size & PCI_MAPREG_MEM_ADDR_MASK); 429 } 430 } 431 432 return 0; 433} 434 435/** 436 * Read a VGA rom using the 0xc0000 mapping. 437 * 438 * This function should be extended to handle access through PCI resources, 439 * which should be more reliable when available. 440 */ 441static int 442pci_device_netbsd_read_rom(struct pci_device *dev, void *buffer) 443{ 444 struct pci_device_private *priv = (struct pci_device_private *)(void *)dev; 445 void *bios; 446 pciaddr_t rom_base; 447 size_t rom_size; 448 uint32_t bios_val, command_val; 449 int pci_rom; 450 451 if (((priv->base.device_class >> 16) & 0xff) != PCI_CLASS_DISPLAY || 452 ((priv->base.device_class >> 8) & 0xff) != PCI_SUBCLASS_DISPLAY_VGA) 453 return ENOSYS; 454 455 if (priv->rom_base == 0) { 456#if defined(__amd64__) || defined(__i386__) 457 /* 458 * We need a way to detect when this isn't the console and reject 459 * this request outright. 460 */ 461 rom_base = 0xc0000; 462 rom_size = 0x10000; 463 pci_rom = 0; 464#else 465 return ENOSYS; 466#endif 467 } else { 468 rom_base = priv->rom_base; 469 rom_size = dev->rom_size; 470 pci_rom = 1; 471 if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus, 472 (unsigned int)dev->dev, (unsigned int)dev->func, 473 PCI_COMMAND_STATUS_REG, &command_val)) == -1) 474 return errno; 475 if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) { 476 if ((pcibus_conf_write(buses[dev->domain].fd, 477 (unsigned int)dev->bus, (unsigned int)dev->dev, 478 (unsigned int)dev->func, PCI_COMMAND_STATUS_REG, 479 command_val | PCI_COMMAND_MEM_ENABLE)) == -1) 480 return errno; 481 } 482 if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus, 483 (unsigned int)dev->dev, (unsigned int)dev->func, 484 PCI_MAPREG_ROM, &bios_val)) == -1) 485 return errno; 486 if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) { 487 if ((pcibus_conf_write(buses[dev->domain].fd, 488 (unsigned int)dev->bus, 489 (unsigned int)dev->dev, (unsigned int)dev->func, 490 PCI_MAPREG_ROM, bios_val | PCI_MAPREG_ROM_ENABLE)) == -1) 491 return errno; 492 } 493 } 494 495 fprintf(stderr, "Using rom_base = 0x%lx 0x%lx (pci_rom=%d)\n", 496 (long)rom_base, (long)rom_size, pci_rom); 497 498 bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED, buses[dev->domain].fd, 499 (off_t)rom_base); 500 if (bios == MAP_FAILED) { 501 int serrno = errno; 502 return serrno; 503 } 504 505 memcpy(buffer, bios, rom_size); 506 507 munmap(bios, rom_size); 508 509 if (pci_rom) { 510 if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) { 511 if ((pcibus_conf_write(buses[dev->domain].fd, 512 (unsigned int)dev->bus, 513 (unsigned int)dev->dev, (unsigned int)dev->func, 514 PCI_COMMAND_STATUS_REG, command_val)) == -1) 515 return errno; 516 } 517 if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) { 518 if ((pcibus_conf_write(buses[dev->domain].fd, 519 (unsigned int)dev->bus, 520 (unsigned int)dev->dev, (unsigned int)dev->func, 521 PCI_MAPREG_ROM, bios_val)) == -1) 522 return errno; 523 } 524 } 525 526 return 0; 527} 528 529#if defined(__i386__) || defined(__amd64__) 530#include <machine/sysarch.h> 531 532/* 533 * Functions to provide access to x86 programmed I/O instructions. 534 * 535 * The in[bwl]() and out[bwl]() functions are split into two varieties: one to 536 * use a small, constant, 8-bit port number, and another to use a large or 537 * variable port number. The former can be compiled as a smaller instruction. 538 */ 539 540 541#ifdef __OPTIMIZE__ 542 543#define __use_immediate_port(port) \ 544 (__builtin_constant_p((port)) && (port) < 0x100) 545 546#else 547 548#define __use_immediate_port(port) 0 549 550#endif 551 552 553#define inb(port) \ 554 (/* CONSTCOND */ __use_immediate_port(port) ? __inbc(port) : __inb(port)) 555 556static __inline u_int8_t 557__inbc(unsigned port) 558{ 559 u_int8_t data; 560 __asm __volatile("inb %w1,%0" : "=a" (data) : "id" (port)); 561 return data; 562} 563 564static __inline u_int8_t 565__inb(unsigned port) 566{ 567 u_int8_t data; 568 __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); 569 return data; 570} 571 572static __inline void 573insb(unsigned port, void *addr, int cnt) 574{ 575 void *dummy1; 576 int dummy2; 577 __asm __volatile("cld\n\trepne\n\tinsb" : 578 "=D" (dummy1), "=c" (dummy2) : 579 "d" (port), "0" (addr), "1" (cnt) : 580 "memory"); 581} 582 583#define inw(port) \ 584 (/* CONSTCOND */ __use_immediate_port(port) ? __inwc(port) : __inw(port)) 585 586static __inline u_int16_t 587__inwc(unsigned port) 588{ 589 u_int16_t data; 590 __asm __volatile("inw %w1,%0" : "=a" (data) : "id" (port)); 591 return data; 592} 593 594static __inline u_int16_t 595__inw(unsigned port) 596{ 597 u_int16_t data; 598 __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); 599 return data; 600} 601 602static __inline void 603insw(unsigned port, void *addr, int cnt) 604{ 605 void *dummy1; 606 int dummy2; 607 __asm __volatile("cld\n\trepne\n\tinsw" : 608 "=D" (dummy1), "=c" (dummy2) : 609 "d" (port), "0" (addr), "1" (cnt) : 610 "memory"); 611} 612 613#define inl(port) \ 614 (/* CONSTCOND */ __use_immediate_port(port) ? __inlc(port) : __inl(port)) 615 616static __inline u_int32_t 617__inlc(unsigned port) 618{ 619 u_int32_t data; 620 __asm __volatile("inl %w1,%0" : "=a" (data) : "id" (port)); 621 return data; 622} 623 624static __inline u_int32_t 625__inl(unsigned port) 626{ 627 u_int32_t data; 628 __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); 629 return data; 630} 631 632static __inline void 633insl(unsigned port, void *addr, int cnt) 634{ 635 void *dummy1; 636 int dummy2; 637 __asm __volatile("cld\n\trepne\n\tinsl" : 638 "=D" (dummy1), "=c" (dummy2) : 639 "d" (port), "0" (addr), "1" (cnt) : 640 "memory"); 641} 642 643#define outb(port, data) \ 644 (/* CONSTCOND */__use_immediate_port(port) ? __outbc(port, data) : \ 645 __outb(port, data)) 646 647static __inline void 648__outbc(unsigned port, u_int8_t data) 649{ 650 __asm __volatile("outb %0,%w1" : : "a" (data), "id" (port)); 651} 652 653static __inline void 654__outb(unsigned port, u_int8_t data) 655{ 656 __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); 657} 658 659static __inline void 660outsb(unsigned port, const void *addr, int cnt) 661{ 662 void *dummy1; 663 int dummy2; 664 __asm __volatile("cld\n\trepne\n\toutsb" : 665 "=S" (dummy1), "=c" (dummy2) : 666 "d" (port), "0" (addr), "1" (cnt)); 667} 668 669#define outw(port, data) \ 670 (/* CONSTCOND */ __use_immediate_port(port) ? __outwc(port, data) : \ 671 __outw(port, data)) 672 673static __inline void 674__outwc(unsigned port, u_int16_t data) 675{ 676 __asm __volatile("outw %0,%w1" : : "a" (data), "id" (port)); 677} 678 679static __inline void 680__outw(unsigned port, u_int16_t data) 681{ 682 __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); 683} 684 685static __inline void 686outsw(unsigned port, const void *addr, int cnt) 687{ 688 void *dummy1; 689 int dummy2; 690 __asm __volatile("cld\n\trepne\n\toutsw" : 691 "=S" (dummy1), "=c" (dummy2) : 692 "d" (port), "0" (addr), "1" (cnt)); 693} 694 695#define outl(port, data) \ 696 (/* CONSTCOND */ __use_immediate_port(port) ? __outlc(port, data) : \ 697 __outl(port, data)) 698 699static __inline void 700__outlc(unsigned port, u_int32_t data) 701{ 702 __asm __volatile("outl %0,%w1" : : "a" (data), "id" (port)); 703} 704 705static __inline void 706__outl(unsigned port, u_int32_t data) 707{ 708 __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); 709} 710 711static __inline void 712outsl(unsigned port, const void *addr, int cnt) 713{ 714 void *dummy1; 715 int dummy2; 716 __asm __volatile("cld\n\trepne\n\toutsl" : 717 "=S" (dummy1), "=c" (dummy2) : 718 "d" (port), "0" (addr), "1" (cnt)); 719} 720 721#endif 722 723 724static struct pci_io_handle * 725pci_device_netbsd_open_legacy_io(struct pci_io_handle *ret, 726 struct pci_device *dev, pciaddr_t base, pciaddr_t size) 727{ 728#if defined(__i386__) 729 struct i386_iopl_args ia; 730 731 ia.iopl = 1; 732 if (sysarch(I386_IOPL, &ia)) 733 return NULL; 734 735 ret->base = base; 736 ret->size = size; 737 ret->is_legacy = 1; 738 return ret; 739#elif defined(__amd64__) 740 struct x86_64_iopl_args ia; 741 742 ia.iopl = 1; 743 if (sysarch(X86_64_IOPL, &ia)) 744 return NULL; 745 746 ret->base = base; 747 ret->size = size; 748 ret->is_legacy = 1; 749 return ret; 750#else 751 return NULL; 752#endif 753} 754 755static uint32_t 756pci_device_netbsd_read32(struct pci_io_handle *handle, uint32_t reg) 757{ 758#if defined(__i386__) || defined(__amd64__) 759 return inl(handle->base + reg); 760#else 761 return *(uint32_t *)((uintptr_t)handle->memory + reg); 762#endif 763} 764 765static uint16_t 766pci_device_netbsd_read16(struct pci_io_handle *handle, uint32_t reg) 767{ 768#if defined(__i386__) || defined(__amd64__) 769 return inw(handle->base + reg); 770#else 771 return *(uint16_t *)((uintptr_t)handle->memory + reg); 772#endif 773} 774 775static uint8_t 776pci_device_netbsd_read8(struct pci_io_handle *handle, uint32_t reg) 777{ 778#if defined(__i386__) || defined(__amd64__) 779 return inb(handle->base + reg); 780#else 781 return *(uint8_t *)((uintptr_t)handle->memory + reg); 782#endif 783} 784 785static void 786pci_device_netbsd_write32(struct pci_io_handle *handle, uint32_t reg, 787 uint32_t data) 788{ 789#if defined(__i386__) || defined(__amd64__) 790 outl(handle->base + reg, data); 791#else 792 *(uint16_t *)((uintptr_t)handle->memory + reg) = data; 793#endif 794} 795 796static void 797pci_device_netbsd_write16(struct pci_io_handle *handle, uint32_t reg, 798 uint16_t data) 799{ 800#if defined(__i386__) || defined(__amd64__) 801 outw(handle->base + reg, data); 802#else 803 *(uint8_t *)((uintptr_t)handle->memory + reg) = data; 804#endif 805} 806 807static void 808pci_device_netbsd_write8(struct pci_io_handle *handle, uint32_t reg, 809 uint8_t data) 810{ 811#if defined(__i386__) || defined(__amd64__) 812 outb(handle->base + reg, data); 813#else 814 *(uint32_t *)((uintptr_t)handle->memory + reg) = data; 815#endif 816} 817 818static int 819pci_device_netbsd_map_legacy(struct pci_device *dev, pciaddr_t base, 820 pciaddr_t size, unsigned map_flags, void **addr) 821{ 822 struct pci_device_mapping map; 823 int err; 824 825 map.base = base; 826 map.size = size; 827 map.flags = map_flags; 828 map.memory = NULL; 829 err = pci_device_netbsd_map_range(dev, &map); 830 *addr = map.memory; 831 832 return err; 833} 834 835static int 836pci_device_netbsd_unmap_legacy(struct pci_device *dev, void *addr, 837 pciaddr_t size) 838{ 839 struct pci_device_mapping map; 840 841 map.memory = addr; 842 map.size = size; 843 map.flags = 0; 844 return pci_device_netbsd_unmap_range(dev, &map); 845} 846 847static int 848pci_device_netbsd_has_kernel_driver(struct pci_device *dev) 849{ 850#ifdef PCI_IOC_DRVNAME 851 /* 852 * NetBSD PCI_IOC_DRVNAME appears at the same time as pci_drvname(3), 853 * same as the better onbus version. 854 */ 855 char drvname[16]; 856 int i; 857 858 if (dev->bus >= nbuses) 859 return 0; 860 861 /* 862 * vga(4) should be considered "not bound". 863 */ 864 for (i = 0; i < nbuses; i++) { 865 if (buses[i].num == dev->bus) { 866 int rv; 867 868#ifdef PCI_IOC_DRVNAMEONBUS 869 rv = pci_drvnameonbus(buses[i].fd, dev->bus, 870 dev->dev, dev->func, drvname, sizeof drvname); 871#else 872 rv = pci_drvname(buses[i].fd, 873 dev->dev, dev->func, drvname, sizeof drvname); 874#endif 875 if (rv == 0 && strncmp(drvname, "vga", 3) != 0) 876 return 1; 877 return 0; 878 } 879 } 880#endif 881 return 0; 882} 883 884static const struct pci_system_methods netbsd_pci_methods = { 885 .destroy = pci_system_netbsd_destroy, 886 .destroy_device = NULL, 887 .read_rom = pci_device_netbsd_read_rom, 888 .probe = pci_device_netbsd_probe, 889 .map_range = pci_device_netbsd_map_range, 890 .unmap_range = pci_device_netbsd_unmap_range, 891 .read = pci_device_netbsd_read, 892 .write = pci_device_netbsd_write, 893 .fill_capabilities = pci_fill_capabilities_generic, 894#if defined(WSDISPLAYIO_GET_BUSID) 895 .boot_vga = pci_device_netbsd_boot_vga, 896#else 897 .boot_vga = NULL, 898#endif 899 .open_legacy_io = pci_device_netbsd_open_legacy_io, 900 .read32 = pci_device_netbsd_read32, 901 .read16 = pci_device_netbsd_read16, 902 .read8 = pci_device_netbsd_read8, 903 .write32 = pci_device_netbsd_write32, 904 .write16 = pci_device_netbsd_write16, 905 .write8 = pci_device_netbsd_write8, 906 .map_legacy = pci_device_netbsd_map_legacy, 907 .unmap_legacy = pci_device_netbsd_unmap_legacy, 908 .has_kernel_driver = pci_device_netbsd_has_kernel_driver, 909}; 910 911static int 912pci_system_netbsd_open_device(int unit) 913{ 914 char netbsd_devname[32]; 915 int pcifd; 916 917 snprintf(netbsd_devname, 32, "/dev/pci%d", unit); 918 pcifd = open(netbsd_devname, O_RDWR | O_CLOEXEC); 919 if (pcifd == -1) 920 pcifd = open(netbsd_devname, O_RDONLY | O_CLOEXEC); 921 922 return pcifd; 923} 924 925static int 926pci_system_netbsd_count_buses(void) 927{ 928 int pcifd; 929 930 do { 931 pcifd = pci_system_netbsd_open_device(nbuses); 932 if (pcifd != -1) { 933 close(pcifd); 934 nbuses++; 935 } 936 } while (pcifd != -1); 937 938 return nbuses; 939} 940 941int 942pci_system_netbsd_create(void) 943{ 944 struct pci_device_private *device; 945 int bus, dev, func, ndevs, nfuncs, domain, pcifd, n; 946 uint32_t reg; 947 struct pciio_businfo businfo; 948 949 pci_sys = calloc(1, sizeof(struct pci_system)); 950 951 pci_sys->methods = &netbsd_pci_methods; 952 953 ndevs = 0; 954 nbuses = pci_system_netbsd_count_buses(); 955 if (nbuses > 0) 956 buses = calloc(nbuses, sizeof(PciBus)); 957 958 for (n = 0; n < nbuses; n++) { 959 pcifd = pci_system_netbsd_open_device(n); 960 961 ioctl(pcifd, PCI_IOC_BUSINFO, &businfo); 962 buses[n].fd = pcifd; 963 buses[n].num = bus = businfo.busno; 964 buses[n].maxdevs = businfo.maxdevs; 965 domain = n; 966 for (dev = 0; dev < businfo.maxdevs; dev++) { 967 nfuncs = pci_nfuncs(domain, bus, dev); 968 for (func = 0; func < nfuncs; func++) { 969 if (pci_read(domain, bus, dev, func, PCI_ID_REG, 970 ®) != 0) 971 continue; 972 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || 973 PCI_VENDOR(reg) == 0) 974 continue; 975 976 ndevs++; 977 } 978 } 979 } 980 981 pci_sys->num_devices = ndevs; 982 pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private)); 983 if (pci_sys->devices == NULL) { 984 int i; 985 986 for (i = 0; i < nbuses; i++) 987 close(buses[i].fd); 988 free(pci_sys); 989 pci_sys = NULL; 990 return ENOMEM; 991 } 992 993 device = pci_sys->devices; 994 for (domain = 0; domain < nbuses; domain++) { 995 bus = buses[domain].num; 996 for (dev = 0; dev < buses[domain].maxdevs; dev++) { 997 nfuncs = pci_nfuncs(domain, bus, dev); 998 for (func = 0; func < nfuncs; func++) { 999 if (pci_read(domain, bus, dev, func, 1000 PCI_ID_REG, ®) != 0) 1001 continue; 1002 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || 1003 PCI_VENDOR(reg) == 0) 1004 continue; 1005 1006 device->base.domain = domain; 1007 if (domain > 0xffff) 1008 device->base.domain_16 = 0xffff; 1009 else 1010 device->base.domain_16 = domain & 0xffff; 1011 device->base.bus = bus; 1012 device->base.dev = dev; 1013 device->base.func = func; 1014 device->base.vendor_id = PCI_VENDOR(reg); 1015 device->base.device_id = PCI_PRODUCT(reg); 1016 1017 if (pci_read(domain, bus, dev, func, 1018 PCI_CLASS_REG, ®) != 0) 1019 continue; 1020 1021 device->base.device_class = 1022 PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 | 1023 PCI_SUBCLASS(reg) << 8; 1024 device->base.revision = PCI_REVISION(reg); 1025 1026 if (pci_read(domain, bus, dev, func, 1027 PCI_SUBSYS_ID_REG, ®) != 0) 1028 continue; 1029 1030 device->base.subvendor_id = PCI_VENDOR(reg); 1031 device->base.subdevice_id = PCI_PRODUCT(reg); 1032 1033 device++; 1034 } 1035 } 1036 } 1037 1038 return 0; 1039} 1040