x86_pci.c revision 2029f493
128d65773Smrg/* 22029f493Smrg * Copyright (c) 2018 Damien Zammit 32029f493Smrg * Copyright (c) 2017 Joan Lledó 486ea1d58Smrg * Copyright (c) 2009, 2012 Samuel Thibault 528d65773Smrg * Heavily inspired from the freebsd, netbsd, and openbsd backends 628d65773Smrg * (C) Copyright Eric Anholt 2006 728d65773Smrg * (C) Copyright IBM Corporation 2006 828d65773Smrg * Copyright (c) 2008 Juan Romero Pardines 928d65773Smrg * Copyright (c) 2008 Mark Kettenis 1028d65773Smrg * 1128d65773Smrg * Permission to use, copy, modify, and distribute this software for any 1228d65773Smrg * purpose with or without fee is hereby granted, provided that the above 1328d65773Smrg * copyright notice and this permission notice appear in all copies. 1428d65773Smrg * 1528d65773Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1628d65773Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1728d65773Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1828d65773Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1928d65773Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 2028d65773Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 2128d65773Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2228d65773Smrg */ 2349310723Smrg#ifdef HAVE_CONFIG_H 2449310723Smrg#include "config.h" 2549310723Smrg#endif 2628d65773Smrg 272029f493Smrg#include "x86_pci.h" 282029f493Smrg 2928d65773Smrg#include <unistd.h> 3028d65773Smrg#include <stdio.h> 3128d65773Smrg#include <stdlib.h> 3228d65773Smrg#include <errno.h> 3328d65773Smrg#include <fcntl.h> 3428d65773Smrg#include <sys/mman.h> 3528d65773Smrg#include <string.h> 3628d65773Smrg#include <strings.h> 3728d65773Smrg 3828d65773Smrg#include "pciaccess.h" 3928d65773Smrg#include "pciaccess_private.h" 4028d65773Smrg 4128d65773Smrg#if defined(__GNU__) 4228d65773Smrg 4328d65773Smrg#include <sys/io.h> 4428d65773Smrg 452029f493Smrgint 4628d65773Smrgx86_enable_io(void) 4728d65773Smrg{ 4828d65773Smrg if (!ioperm(0, 0xffff, 1)) 4928d65773Smrg return 0; 5028d65773Smrg return errno; 5128d65773Smrg} 5228d65773Smrg 532029f493Smrgint 5428d65773Smrgx86_disable_io(void) 5528d65773Smrg{ 5628d65773Smrg if (!ioperm(0, 0xffff, 0)) 5728d65773Smrg return 0; 5828d65773Smrg return errno; 5928d65773Smrg} 6028d65773Smrg 6128d65773Smrg#elif defined(__GLIBC__) 6228d65773Smrg 6328d65773Smrg#include <sys/io.h> 6428d65773Smrg 6528d65773Smrgstatic int 6628d65773Smrgx86_enable_io(void) 6728d65773Smrg{ 6828d65773Smrg if (!iopl(3)) 6928d65773Smrg return 0; 7028d65773Smrg return errno; 7128d65773Smrg} 7228d65773Smrg 7328d65773Smrgstatic int 7428d65773Smrgx86_disable_io(void) 7528d65773Smrg{ 7628d65773Smrg if (!iopl(0)) 7728d65773Smrg return 0; 7828d65773Smrg return errno; 7928d65773Smrg} 8028d65773Smrg 816a94483fSmrg#elif defined(__CYGWIN__) 826a94483fSmrg 836a94483fSmrg#include <windows.h> 846a94483fSmrg 856a94483fSmrg/* WinIo declarations */ 866a94483fSmrgtypedef BYTE bool; 876a94483fSmrgtypedef struct tagPhysStruct { 886a94483fSmrg DWORD64 dwPhysMemSizeInBytes; 896a94483fSmrg DWORD64 pvPhysAddress; 906a94483fSmrg DWORD64 PhysicalMemoryHandle; 916a94483fSmrg DWORD64 pvPhysMemLin; 926a94483fSmrg DWORD64 pvPhysSection; 936a94483fSmrg} tagPhysStruct; 946a94483fSmrg 956a94483fSmrgtypedef bool (_stdcall* INITIALIZEWINIO)(void); 966a94483fSmrgtypedef void (_stdcall* SHUTDOWNWINIO)(void); 976a94483fSmrgtypedef bool (_stdcall* GETPORTVAL)(WORD,PDWORD,BYTE); 986a94483fSmrgtypedef bool (_stdcall* SETPORTVAL)(WORD,DWORD,BYTE); 996a94483fSmrgtypedef PBYTE (_stdcall* MAPPHYSTOLIN)(tagPhysStruct*); 1006a94483fSmrgtypedef bool (_stdcall* UNMAPPHYSMEM)(tagPhysStruct*); 1016a94483fSmrg 1026a94483fSmrgSHUTDOWNWINIO ShutdownWinIo; 1036a94483fSmrgGETPORTVAL GetPortVal; 1046a94483fSmrgSETPORTVAL SetPortVal; 1056a94483fSmrgINITIALIZEWINIO InitializeWinIo; 1066a94483fSmrgMAPPHYSTOLIN MapPhysToLin; 1076a94483fSmrgUNMAPPHYSMEM UnmapPhysicalMemory; 1086a94483fSmrg 1096a94483fSmrgstatic int 1106a94483fSmrgx86_enable_io(void) 1116a94483fSmrg{ 1126a94483fSmrg HMODULE lib = NULL; 1136a94483fSmrg 1146a94483fSmrg if ((GetVersion() & 0x80000000) == 0) { 1156a94483fSmrg /* running on NT, try WinIo version 3 (32 or 64 bits) */ 1166a94483fSmrg#ifdef WIN64 1176a94483fSmrg lib = LoadLibrary("WinIo64.dll"); 1186a94483fSmrg#else 1196a94483fSmrg lib = LoadLibrary("WinIo32.dll"); 1206a94483fSmrg#endif 1216a94483fSmrg } 1226a94483fSmrg 1236a94483fSmrg if (!lib) { 1246a94483fSmrg fprintf(stderr, "Failed to load WinIo library.\n"); 1256a94483fSmrg return 1; 1266a94483fSmrg } 1276a94483fSmrg 1286a94483fSmrg#define GETPROC(n, d) \ 1296a94483fSmrg n = (d) GetProcAddress(lib, #n); \ 1306a94483fSmrg if (!n) { \ 1316a94483fSmrg fprintf(stderr, "Failed to load " #n " function.\n"); \ 1326a94483fSmrg return 1; \ 1336a94483fSmrg } 1346a94483fSmrg 1356a94483fSmrg GETPROC(InitializeWinIo, INITIALIZEWINIO); 1366a94483fSmrg GETPROC(ShutdownWinIo, SHUTDOWNWINIO); 1376a94483fSmrg GETPROC(GetPortVal, GETPORTVAL); 1386a94483fSmrg GETPROC(SetPortVal, SETPORTVAL); 1396a94483fSmrg GETPROC(MapPhysToLin, MAPPHYSTOLIN); 1406a94483fSmrg GETPROC(UnmapPhysicalMemory, UNMAPPHYSMEM); 1416a94483fSmrg 1426a94483fSmrg#undef GETPROC 1436a94483fSmrg 1446a94483fSmrg if (!InitializeWinIo()) { 1456a94483fSmrg fprintf(stderr, "Failed to initialize WinIo.\n" 1466a94483fSmrg "NOTE: WinIo.dll and WinIo.sys must be in the same directory as the executable!\n"); 1476a94483fSmrg return 0; 1486a94483fSmrg } 1496a94483fSmrg 1506a94483fSmrg return 0; 1516a94483fSmrg} 1526a94483fSmrg 1536a94483fSmrgstatic int 1546a94483fSmrgx86_disable_io(void) 1556a94483fSmrg{ 1566a94483fSmrg ShutdownWinIo(); 1576a94483fSmrg return 1; 1586a94483fSmrg} 1596a94483fSmrg 1606a94483fSmrgstatic inline uint8_t 1616a94483fSmrginb(uint16_t port) 1626a94483fSmrg{ 1636a94483fSmrg DWORD pv; 1646a94483fSmrg 1656a94483fSmrg if (GetPortVal(port, &pv, 1)) 1666a94483fSmrg return (uint8_t)pv; 1676a94483fSmrg return 0; 1686a94483fSmrg} 1696a94483fSmrg 1706a94483fSmrgstatic inline uint16_t 1716a94483fSmrginw(uint16_t port) 1726a94483fSmrg{ 1736a94483fSmrg DWORD pv; 1746a94483fSmrg 1756a94483fSmrg if (GetPortVal(port, &pv, 2)) 1766a94483fSmrg return (uint16_t)pv; 1776a94483fSmrg return 0; 1786a94483fSmrg} 1796a94483fSmrg 1806a94483fSmrgstatic inline uint32_t 1816a94483fSmrginl(uint16_t port) 1826a94483fSmrg{ 1836a94483fSmrg DWORD pv; 1846a94483fSmrg 1856a94483fSmrg if (GetPortVal(port, &pv, 4)) 1866a94483fSmrg return (uint32_t)pv; 1876a94483fSmrg return 0; 1886a94483fSmrg} 1896a94483fSmrg 1906a94483fSmrgstatic inline void 1916a94483fSmrgoutb(uint8_t value, uint16_t port) 1926a94483fSmrg{ 1936a94483fSmrg SetPortVal(port, value, 1); 1946a94483fSmrg} 1956a94483fSmrg 1966a94483fSmrgstatic inline void 1976a94483fSmrgoutw(uint16_t value, uint16_t port) 1986a94483fSmrg{ 1996a94483fSmrg SetPortVal(port, value, 2); 2006a94483fSmrg} 2016a94483fSmrg 2026a94483fSmrgstatic inline void 2036a94483fSmrgoutl(uint32_t value, uint16_t port) 2046a94483fSmrg{ 2056a94483fSmrg SetPortVal(port, value, 4); 2066a94483fSmrg} 2076a94483fSmrg 20828d65773Smrg#else 20928d65773Smrg 21028d65773Smrg#error How to enable IO ports on this system? 21128d65773Smrg 21228d65773Smrg#endif 21328d65773Smrg 21428d65773Smrgstatic int 21528d65773Smrgpci_system_x86_conf1_probe(void) 21628d65773Smrg{ 21728d65773Smrg unsigned long sav; 21828d65773Smrg int res = ENODEV; 21928d65773Smrg 22028d65773Smrg outb(0x01, 0xCFB); 22128d65773Smrg sav = inl(0xCF8); 22228d65773Smrg outl(0x80000000, 0xCF8); 22328d65773Smrg if (inl(0xCF8) == 0x80000000) 22428d65773Smrg res = 0; 22528d65773Smrg outl(sav, 0xCF8); 22628d65773Smrg 22728d65773Smrg return res; 22828d65773Smrg} 22928d65773Smrg 23028d65773Smrgstatic int 23128d65773Smrgpci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size) 23228d65773Smrg{ 23328d65773Smrg unsigned addr = 0xCFC + (reg & 3); 23428d65773Smrg unsigned long sav; 23528d65773Smrg int ret = 0; 23628d65773Smrg 23728d65773Smrg if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3) 23828d65773Smrg return EIO; 23928d65773Smrg 24028d65773Smrg sav = inl(0xCF8); 24128d65773Smrg outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8); 24228d65773Smrg /* NOTE: x86 is already LE */ 24328d65773Smrg switch (size) { 24428d65773Smrg case 1: { 24528d65773Smrg uint8_t *val = data; 24628d65773Smrg *val = inb(addr); 24728d65773Smrg break; 24828d65773Smrg } 24928d65773Smrg case 2: { 25028d65773Smrg uint16_t *val = data; 25128d65773Smrg *val = inw(addr); 25228d65773Smrg break; 25328d65773Smrg } 25428d65773Smrg case 4: { 25528d65773Smrg uint32_t *val = data; 25628d65773Smrg *val = inl(addr); 25728d65773Smrg break; 25828d65773Smrg } 25928d65773Smrg } 26028d65773Smrg outl(sav, 0xCF8); 26128d65773Smrg 26228d65773Smrg return ret; 26328d65773Smrg} 26428d65773Smrg 26528d65773Smrgstatic int 26628d65773Smrgpci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size) 26728d65773Smrg{ 26828d65773Smrg unsigned addr = 0xCFC + (reg & 3); 26928d65773Smrg unsigned long sav; 27028d65773Smrg int ret = 0; 27128d65773Smrg 27228d65773Smrg if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3) 27328d65773Smrg return EIO; 27428d65773Smrg 27528d65773Smrg sav = inl(0xCF8); 27628d65773Smrg outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8); 27728d65773Smrg /* NOTE: x86 is already LE */ 27828d65773Smrg switch (size) { 27928d65773Smrg case 1: { 28028d65773Smrg const uint8_t *val = data; 28128d65773Smrg outb(*val, addr); 28228d65773Smrg break; 28328d65773Smrg } 28428d65773Smrg case 2: { 28528d65773Smrg const uint16_t *val = data; 28628d65773Smrg outw(*val, addr); 28728d65773Smrg break; 28828d65773Smrg } 28928d65773Smrg case 4: { 29028d65773Smrg const uint32_t *val = data; 29128d65773Smrg outl(*val, addr); 29228d65773Smrg break; 29328d65773Smrg } 29428d65773Smrg } 29528d65773Smrg outl(sav, 0xCF8); 29628d65773Smrg 29728d65773Smrg return ret; 29828d65773Smrg} 29928d65773Smrg 30028d65773Smrgstatic int 30128d65773Smrgpci_system_x86_conf2_probe(void) 30228d65773Smrg{ 30328d65773Smrg outb(0, 0xCFB); 30428d65773Smrg outb(0, 0xCF8); 30528d65773Smrg outb(0, 0xCFA); 30628d65773Smrg if (inb(0xCF8) == 0 && inb(0xCFA) == 0) 30728d65773Smrg return 0; 30828d65773Smrg 30928d65773Smrg return ENODEV; 31028d65773Smrg} 31128d65773Smrg 31228d65773Smrgstatic int 31328d65773Smrgpci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size) 31428d65773Smrg{ 31528d65773Smrg unsigned addr = 0xC000 | dev << 8 | reg; 31628d65773Smrg int ret = 0; 31728d65773Smrg 31828d65773Smrg if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) 31928d65773Smrg return EIO; 32028d65773Smrg 32128d65773Smrg outb((func << 1) | 0xF0, 0xCF8); 32228d65773Smrg outb(bus, 0xCFA); 32328d65773Smrg /* NOTE: x86 is already LE */ 32428d65773Smrg switch (size) { 32528d65773Smrg case 1: { 32628d65773Smrg uint8_t *val = data; 32728d65773Smrg *val = inb(addr); 32828d65773Smrg break; 32928d65773Smrg } 33028d65773Smrg case 2: { 33128d65773Smrg uint16_t *val = data; 33228d65773Smrg *val = inw(addr); 33328d65773Smrg break; 33428d65773Smrg } 33528d65773Smrg case 4: { 33628d65773Smrg uint32_t *val = data; 33728d65773Smrg *val = inl(addr); 33828d65773Smrg break; 33928d65773Smrg } 34028d65773Smrg default: 34128d65773Smrg ret = EIO; 34228d65773Smrg break; 34328d65773Smrg } 34428d65773Smrg outb(0, 0xCF8); 34528d65773Smrg 34628d65773Smrg return ret; 34728d65773Smrg} 34828d65773Smrg 34928d65773Smrgstatic int 35028d65773Smrgpci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size) 35128d65773Smrg{ 35228d65773Smrg unsigned addr = 0xC000 | dev << 8 | reg; 35328d65773Smrg int ret = 0; 35428d65773Smrg 35528d65773Smrg if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) 35628d65773Smrg return EIO; 35728d65773Smrg 35828d65773Smrg outb((func << 1) | 0xF0, 0xCF8); 35928d65773Smrg outb(bus, 0xCFA); 36028d65773Smrg /* NOTE: x86 is already LE */ 36128d65773Smrg switch (size) { 36228d65773Smrg case 1: { 36328d65773Smrg const uint8_t *val = data; 36428d65773Smrg outb(*val, addr); 36528d65773Smrg break; 36628d65773Smrg } 36728d65773Smrg case 2: { 36828d65773Smrg const uint16_t *val = data; 36928d65773Smrg outw(*val, addr); 37028d65773Smrg break; 37128d65773Smrg } 37228d65773Smrg case 4: { 37328d65773Smrg const uint32_t *val = data; 37428d65773Smrg outl(*val, addr); 37528d65773Smrg break; 37628d65773Smrg } 37728d65773Smrg default: 37828d65773Smrg ret = EIO; 37928d65773Smrg break; 38028d65773Smrg } 38128d65773Smrg outb(0, 0xCF8); 38228d65773Smrg 38328d65773Smrg return ret; 38428d65773Smrg} 38528d65773Smrg 38628d65773Smrg/* Check that this really looks like a PCI configuration. */ 3872029f493Smrgstatic error_t 3882029f493Smrgpci_system_x86_check (void) 38928d65773Smrg{ 39028d65773Smrg int dev; 39128d65773Smrg uint16_t class, vendor; 3922029f493Smrg struct pci_device tmpdev = { 0 }; 39328d65773Smrg 39428d65773Smrg /* Look on bus 0 for a device that is a host bridge, a VGA card, 39528d65773Smrg * or an intel or compaq device. */ 3962029f493Smrg tmpdev.bus = 0; 3972029f493Smrg tmpdev.func = 0; 3982029f493Smrg class = 0; 3992029f493Smrg vendor = 0; 40028d65773Smrg 40128d65773Smrg for (dev = 0; dev < 32; dev++) { 4022029f493Smrg tmpdev.dev = dev; 4032029f493Smrg if (pci_device_cfg_read_u16 (&tmpdev, &class, PCI_CLASS_DEVICE)) 4042029f493Smrg continue; 4052029f493Smrg if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) 4062029f493Smrg return 0; 4072029f493Smrg if (pci_device_cfg_read_u16 (&tmpdev, &vendor, PCI_VENDOR_ID)) 4082029f493Smrg continue; 4092029f493Smrg if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) 4102029f493Smrg return 0; 41128d65773Smrg } 41228d65773Smrg 41328d65773Smrg return ENODEV; 41428d65773Smrg} 41528d65773Smrg 41628d65773Smrgstatic int 4172029f493Smrgpci_nfuncs(struct pci_device *dev, uint8_t *nfuncs) 41828d65773Smrg{ 41928d65773Smrg uint8_t hdr; 42028d65773Smrg int err; 4212029f493Smrg struct pci_device tmpdev = *dev; 42228d65773Smrg 4232029f493Smrg tmpdev.func = 0; 4242029f493Smrg 4252029f493Smrg err = pci_device_cfg_read_u8 (&tmpdev, &hdr, PCI_HDRTYPE); 42628d65773Smrg 42728d65773Smrg if (err) 42828d65773Smrg return err; 42928d65773Smrg 4302029f493Smrg *nfuncs = hdr & 0x80 ? 8 : 1; 4312029f493Smrg return err; 43228d65773Smrg} 43328d65773Smrg 43428d65773Smrg/** 4352029f493Smrg * Read a PCI rom. 43628d65773Smrg */ 4372029f493Smrgstatic error_t 43828d65773Smrgpci_device_x86_read_rom(struct pci_device *dev, void *buffer) 43928d65773Smrg{ 44028d65773Smrg void *bios; 44128d65773Smrg int memfd; 4422029f493Smrg struct pci_device_private *d = (struct pci_device_private *)dev; 44328d65773Smrg 444cad31331Smrg memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC); 44528d65773Smrg if (memfd == -1) 44628d65773Smrg return errno; 44728d65773Smrg 4482029f493Smrg bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, d->rom_base); 44928d65773Smrg if (bios == MAP_FAILED) { 45028d65773Smrg close(memfd); 45128d65773Smrg return errno; 45228d65773Smrg } 45328d65773Smrg 45428d65773Smrg memcpy(buffer, bios, dev->rom_size); 45528d65773Smrg 45628d65773Smrg munmap(bios, dev->rom_size); 45728d65773Smrg close(memfd); 45828d65773Smrg 45928d65773Smrg return 0; 46028d65773Smrg} 46128d65773Smrg 46228d65773Smrg/** Returns the number of regions (base address registers) the device has */ 46328d65773Smrgstatic int 46428d65773Smrgpci_device_x86_get_num_regions(uint8_t header_type) 46528d65773Smrg{ 46628d65773Smrg switch (header_type & 0x7f) { 46728d65773Smrg case 0: 46828d65773Smrg return 6; 46928d65773Smrg case 1: 47028d65773Smrg return 2; 47128d65773Smrg case 2: 47228d65773Smrg return 1; 47328d65773Smrg default: 47428d65773Smrg fprintf(stderr,"unknown header type %02x\n", header_type); 47528d65773Smrg return 0; 47628d65773Smrg } 47728d65773Smrg} 47828d65773Smrg 47928d65773Smrg/** Masks out the flag bigs of the base address register value */ 48028d65773Smrgstatic uint32_t 48128d65773Smrgget_map_base( uint32_t val ) 48228d65773Smrg{ 48328d65773Smrg if (val & 0x01) 48428d65773Smrg return val & ~0x03; 48528d65773Smrg else 48628d65773Smrg return val & ~0x0f; 48728d65773Smrg} 48828d65773Smrg 48928d65773Smrg/** Returns the size of a region based on the all-ones test value */ 49028d65773Smrgstatic unsigned 49128d65773Smrgget_test_val_size( uint32_t testval ) 49228d65773Smrg{ 49328d65773Smrg unsigned size = 1; 49428d65773Smrg 49528d65773Smrg if (testval == 0) 49628d65773Smrg return 0; 49728d65773Smrg 49828d65773Smrg /* Mask out the flag bits */ 49928d65773Smrg testval = get_map_base( testval ); 50028d65773Smrg if (!testval) 50128d65773Smrg return 0; 50228d65773Smrg 50328d65773Smrg while ((testval & 1) == 0) { 50428d65773Smrg size <<= 1; 50528d65773Smrg testval >>= 1; 50628d65773Smrg } 50728d65773Smrg 50828d65773Smrg return size; 50928d65773Smrg} 51028d65773Smrg 5112029f493Smrg/* Read BAR `reg_num' in `dev' and map the data if any */ 5122029f493Smrgstatic error_t 5132029f493Smrgpci_device_x86_region_probe (struct pci_device *dev, int reg_num) 51428d65773Smrg{ 5152029f493Smrg error_t err; 5162029f493Smrg uint8_t offset; 5172029f493Smrg uint32_t reg, addr, testval; 5182029f493Smrg int memfd; 51928d65773Smrg 5202029f493Smrg offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; 52128d65773Smrg 5222029f493Smrg /* Get the base address */ 5232029f493Smrg err = pci_device_cfg_read_u32 (dev, &addr, offset); 52428d65773Smrg if (err) 5252029f493Smrg return err; 52628d65773Smrg 5272029f493Smrg /* Test write all ones to the register, then restore it. */ 5282029f493Smrg reg = 0xffffffff; 5292029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, offset); 53028d65773Smrg if (err) 5312029f493Smrg return err; 5322029f493Smrg err = pci_device_cfg_read_u32 (dev, &testval, offset); 5332029f493Smrg if (err) 5342029f493Smrg return err; 5352029f493Smrg err = pci_device_cfg_write_u32 (dev, addr, offset); 5362029f493Smrg if (err) 5372029f493Smrg return err; 53828d65773Smrg 5392029f493Smrg if (addr & 0x01) 5402029f493Smrg dev->regions[reg_num].is_IO = 1; 5412029f493Smrg if (addr & 0x04) 5422029f493Smrg dev->regions[reg_num].is_64 = 1; 5432029f493Smrg if (addr & 0x08) 5442029f493Smrg dev->regions[reg_num].is_prefetchable = 1; 5452029f493Smrg 5462029f493Smrg /* Set the size */ 5472029f493Smrg dev->regions[reg_num].size = get_test_val_size (testval); 5482029f493Smrg 5492029f493Smrg /* Set the base address value */ 5502029f493Smrg dev->regions[reg_num].base_addr = get_map_base (addr); 5512029f493Smrg 5522029f493Smrg if (dev->regions[reg_num].is_64) 5532029f493Smrg { 5542029f493Smrg err = pci_device_cfg_read_u32 (dev, &addr, offset + 4); 5552029f493Smrg if (err) 5562029f493Smrg return err; 5572029f493Smrg 5582029f493Smrg dev->regions[reg_num].base_addr |= ((uint64_t) addr << 32); 5592029f493Smrg } 5602029f493Smrg 5612029f493Smrg if (dev->regions[reg_num].is_IO) 5622029f493Smrg { 5632029f493Smrg /* Enable the I/O Space bit */ 5642029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); 5652029f493Smrg if (err) 5662029f493Smrg return err; 5672029f493Smrg 5682029f493Smrg if (!(reg & 0x1)) 5692029f493Smrg { 5702029f493Smrg reg |= 0x1; 5712029f493Smrg 5722029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); 5732029f493Smrg if (err) 5742029f493Smrg return err; 5752029f493Smrg } 5762029f493Smrg 5772029f493Smrg /* Clear the map pointer */ 5782029f493Smrg dev->regions[reg_num].memory = 0; 5792029f493Smrg } 5802029f493Smrg else if (dev->regions[reg_num].size > 0) 5812029f493Smrg { 5822029f493Smrg /* Enable the Memory Space bit */ 5832029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); 5842029f493Smrg if (err) 5852029f493Smrg return err; 5862029f493Smrg 5872029f493Smrg if (!(reg & 0x2)) 5882029f493Smrg { 5892029f493Smrg reg |= 0x2; 5902029f493Smrg 5912029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); 5922029f493Smrg if (err) 5932029f493Smrg return err; 5942029f493Smrg } 5952029f493Smrg 5962029f493Smrg /* Map the region in our space */ 5972029f493Smrg memfd = open ("/dev/mem", O_RDONLY | O_CLOEXEC); 5982029f493Smrg if (memfd == -1) 5992029f493Smrg return errno; 6002029f493Smrg 6012029f493Smrg dev->regions[reg_num].memory = 6022029f493Smrg mmap (NULL, dev->regions[reg_num].size, PROT_READ | PROT_WRITE, 0, 6032029f493Smrg memfd, dev->regions[reg_num].base_addr); 6042029f493Smrg if (dev->regions[reg_num].memory == MAP_FAILED) 6052029f493Smrg { 6062029f493Smrg dev->regions[reg_num].memory = 0; 6072029f493Smrg close (memfd); 6082029f493Smrg return errno; 6092029f493Smrg } 6102029f493Smrg 6112029f493Smrg close (memfd); 6122029f493Smrg } 6132029f493Smrg 6142029f493Smrg return 0; 6152029f493Smrg} 6162029f493Smrg 6172029f493Smrg/* Read the XROMBAR in `dev' and save the rom size and rom base */ 6182029f493Smrgstatic error_t 6192029f493Smrgpci_device_x86_probe_rom (struct pci_device *dev) 6202029f493Smrg{ 6212029f493Smrg error_t err; 6222029f493Smrg uint8_t reg_8, xrombar_addr; 6232029f493Smrg uint32_t reg, reg_back; 6242029f493Smrg pciaddr_t rom_size; 6252029f493Smrg pciaddr_t rom_base; 6262029f493Smrg struct pci_device_private *d = (struct pci_device_private *)dev; 6272029f493Smrg 6282029f493Smrg /* First we need to know which type of header is this */ 6292029f493Smrg err = pci_device_cfg_read_u8 (dev, ®_8, PCI_HDRTYPE); 6302029f493Smrg if (err) 6312029f493Smrg return err; 6322029f493Smrg 6332029f493Smrg /* Get the XROMBAR register address */ 6342029f493Smrg switch (reg_8 & 0x3) 6352029f493Smrg { 6362029f493Smrg case PCI_HDRTYPE_DEVICE: 6372029f493Smrg xrombar_addr = PCI_XROMBAR_ADDR_00; 6382029f493Smrg break; 6392029f493Smrg case PCI_HDRTYPE_BRIDGE: 6402029f493Smrg xrombar_addr = PCI_XROMBAR_ADDR_01; 6412029f493Smrg break; 6422029f493Smrg default: 6432029f493Smrg return -1; 6442029f493Smrg } 6452029f493Smrg 6462029f493Smrg /* Get size and physical address */ 6472029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, xrombar_addr); 6482029f493Smrg if (err) 6492029f493Smrg return err; 6502029f493Smrg 6512029f493Smrg reg_back = reg; 6522029f493Smrg reg = 0xFFFFF800; /* Base address: first 21 bytes */ 6532029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, xrombar_addr); 6542029f493Smrg if (err) 6552029f493Smrg return err; 6562029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, xrombar_addr); 6572029f493Smrg if (err) 6582029f493Smrg return err; 6592029f493Smrg 6602029f493Smrg rom_size = (~reg + 1); 6612029f493Smrg rom_base = reg_back & reg; 6622029f493Smrg 6632029f493Smrg if (rom_size == 0) 6642029f493Smrg return 0; 6652029f493Smrg 6662029f493Smrg /* Enable the address decoder and write the physical address back */ 6672029f493Smrg reg_back |= 0x1; 6682029f493Smrg err = pci_device_cfg_write_u32 (dev, reg_back, xrombar_addr); 6692029f493Smrg if (err) 6702029f493Smrg return err; 6712029f493Smrg 6722029f493Smrg /* Enable the Memory Space bit */ 6732029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); 6742029f493Smrg if (err) 6752029f493Smrg return err; 6762029f493Smrg 6772029f493Smrg if (!(reg & 0x2)) 6782029f493Smrg { 6792029f493Smrg reg |= 0x2; 6802029f493Smrg 6812029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); 6822029f493Smrg if (err) 6832029f493Smrg return err; 6842029f493Smrg } 6852029f493Smrg 6862029f493Smrg dev->rom_size = rom_size; 6872029f493Smrg d->rom_base = rom_base; 6882029f493Smrg 6892029f493Smrg return 0; 6902029f493Smrg} 6912029f493Smrg 6922029f493Smrg/* Configure BARs and ROM */ 6932029f493Smrgstatic error_t 6942029f493Smrgpci_device_x86_probe (struct pci_device *dev) 6952029f493Smrg{ 6962029f493Smrg error_t err; 6972029f493Smrg uint8_t hdrtype; 6982029f493Smrg int i; 6992029f493Smrg 7002029f493Smrg /* Probe BARs */ 7012029f493Smrg err = pci_device_cfg_read_u8 (dev, &hdrtype, PCI_HDRTYPE); 7022029f493Smrg if (err) 7032029f493Smrg return err; 7042029f493Smrg 7052029f493Smrg for (i = 0; i < pci_device_x86_get_num_regions (hdrtype); i++) 7062029f493Smrg { 7072029f493Smrg err = pci_device_x86_region_probe (dev, i); 7082029f493Smrg if (err) 7092029f493Smrg return err; 7102029f493Smrg 7112029f493Smrg if (dev->regions[i].is_64) 7122029f493Smrg /* Move the pointer one BAR ahead */ 7132029f493Smrg i++; 71428d65773Smrg } 71528d65773Smrg 7162029f493Smrg /* Probe ROM */ 7172029f493Smrg pci_device_x86_probe_rom(dev); 7182029f493Smrg 7192029f493Smrg return 0; 7202029f493Smrg} 7212029f493Smrg 7222029f493Smrg/* Recursively scan bus number `bus' */ 7232029f493Smrgstatic error_t 7242029f493Smrgpci_system_x86_scan_bus (uint8_t bus) 7252029f493Smrg{ 7262029f493Smrg error_t err; 7272029f493Smrg uint8_t dev, func, nfuncs, hdrtype, secbus; 7282029f493Smrg uint32_t reg; 7292029f493Smrg struct pci_device_private *d, *devices; 7302029f493Smrg struct pci_device scratchdev; 7312029f493Smrg 7322029f493Smrg scratchdev.bus = bus; 7332029f493Smrg 7342029f493Smrg for (dev = 0; dev < 32; dev++) 73528d65773Smrg { 7362029f493Smrg scratchdev.dev = dev; 7372029f493Smrg scratchdev.func = 0; 7382029f493Smrg err = pci_nfuncs (&scratchdev, &nfuncs); 7392029f493Smrg if (err) 7402029f493Smrg return err; 7412029f493Smrg 7422029f493Smrg for (func = 0; func < nfuncs; func++) 7432029f493Smrg { 7442029f493Smrg scratchdev.func = func; 7452029f493Smrg err = pci_device_cfg_read_u32 (&scratchdev, ®, PCI_VENDOR_ID); 7462029f493Smrg if (err) 7472029f493Smrg return err; 7482029f493Smrg 7492029f493Smrg if (PCI_VENDOR (reg) == PCI_VENDOR_INVALID || PCI_VENDOR (reg) == 0) 7502029f493Smrg continue; 7512029f493Smrg 7522029f493Smrg err = pci_device_cfg_read_u32 (&scratchdev, ®, PCI_CLASS); 7532029f493Smrg if (err) 7542029f493Smrg return err; 7552029f493Smrg 7562029f493Smrg err = pci_device_cfg_read_u8 (&scratchdev, &hdrtype, PCI_HDRTYPE); 7572029f493Smrg if (err) 7582029f493Smrg return err; 7592029f493Smrg 7602029f493Smrg devices = 7612029f493Smrg realloc (pci_sys->devices, 7622029f493Smrg (pci_sys->num_devices + 1) * sizeof (struct pci_device_private)); 7632029f493Smrg if (!devices) 7642029f493Smrg return ENOMEM; 7652029f493Smrg 7662029f493Smrg d = devices + pci_sys->num_devices; 7672029f493Smrg memset (d, 0, sizeof (struct pci_device_private)); 7682029f493Smrg 7692029f493Smrg /* Fixed values as PCI express is still not supported */ 7702029f493Smrg d->base.domain = 0; 7712029f493Smrg d->base.bus = bus; 7722029f493Smrg d->base.dev = dev; 7732029f493Smrg d->base.func = func; 7742029f493Smrg 7752029f493Smrg d->base.device_class = reg >> 8; 7762029f493Smrg 7772029f493Smrg err = pci_device_x86_probe (&d->base); 7782029f493Smrg if (err) 7792029f493Smrg return err; 7802029f493Smrg 7812029f493Smrg pci_sys->devices = devices; 7822029f493Smrg pci_sys->num_devices++; 7832029f493Smrg 7842029f493Smrg switch (hdrtype & 0x3) 7852029f493Smrg { 7862029f493Smrg case PCI_HDRTYPE_DEVICE: 7872029f493Smrg break; 7882029f493Smrg case PCI_HDRTYPE_BRIDGE: 7892029f493Smrg case PCI_HDRTYPE_CARDBUS: 7902029f493Smrg { 7912029f493Smrg err = pci_device_cfg_read_u8 (&scratchdev, &secbus, PCI_SECONDARY_BUS); 7922029f493Smrg if (err) 7932029f493Smrg return err; 7942029f493Smrg 7952029f493Smrg err = pci_system_x86_scan_bus (secbus); 7962029f493Smrg if (err) 7972029f493Smrg return err; 7982029f493Smrg 7992029f493Smrg break; 8002029f493Smrg } 8012029f493Smrg default: 8022029f493Smrg /* Unknown header, do nothing */ 8032029f493Smrg break; 8042029f493Smrg } 8052029f493Smrg } 80628d65773Smrg } 80728d65773Smrg 80828d65773Smrg return 0; 80928d65773Smrg} 81028d65773Smrg 8116a94483fSmrg#if defined(__CYGWIN__) 8126a94483fSmrg 8136a94483fSmrgstatic int 8146a94483fSmrgpci_device_x86_map_range(struct pci_device *dev, 8156a94483fSmrg struct pci_device_mapping *map) 8166a94483fSmrg{ 8176a94483fSmrg tagPhysStruct phys; 8186a94483fSmrg 8196a94483fSmrg phys.pvPhysAddress = (DWORD64)(DWORD32)map->base; 8206a94483fSmrg phys.dwPhysMemSizeInBytes = map->size; 8216a94483fSmrg 8226a94483fSmrg map->memory = (PDWORD)MapPhysToLin(&phys); 8236a94483fSmrg if (map->memory == NULL) 8246a94483fSmrg return EFAULT; 8256a94483fSmrg 8266a94483fSmrg return 0; 8276a94483fSmrg} 8286a94483fSmrg 8296a94483fSmrgstatic int 8306a94483fSmrgpci_device_x86_unmap_range(struct pci_device *dev, 8316a94483fSmrg struct pci_device_mapping *map) 8326a94483fSmrg{ 8336a94483fSmrg tagPhysStruct phys; 8346a94483fSmrg 8356a94483fSmrg phys.pvPhysAddress = (DWORD64)(DWORD32)map->base; 8366a94483fSmrg phys.dwPhysMemSizeInBytes = map->size; 8376a94483fSmrg 8386a94483fSmrg if (!UnmapPhysicalMemory(&phys)) 8396a94483fSmrg return EFAULT; 8406a94483fSmrg 8416a94483fSmrg return 0; 8426a94483fSmrg} 8436a94483fSmrg 8446a94483fSmrg#else 8456a94483fSmrg 8462029f493Smrgint 84728d65773Smrgpci_device_x86_map_range(struct pci_device *dev, 84828d65773Smrg struct pci_device_mapping *map) 84928d65773Smrg{ 850cad31331Smrg int memfd = open("/dev/mem", O_RDWR | O_CLOEXEC); 85128d65773Smrg int prot = PROT_READ; 85228d65773Smrg 85328d65773Smrg if (memfd == -1) 85428d65773Smrg return errno; 85528d65773Smrg 85628d65773Smrg if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE) 85728d65773Smrg prot |= PROT_WRITE; 85828d65773Smrg 85928d65773Smrg map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base); 86028d65773Smrg close(memfd); 86128d65773Smrg if (map->memory == MAP_FAILED) 86228d65773Smrg return errno; 86328d65773Smrg 86428d65773Smrg return 0; 86528d65773Smrg} 86628d65773Smrg 8672029f493Smrgint 8686a94483fSmrgpci_device_x86_unmap_range(struct pci_device *dev, 8696a94483fSmrg struct pci_device_mapping *map) 8706a94483fSmrg{ 8716a94483fSmrg return pci_device_generic_unmap_range(dev, map); 8726a94483fSmrg} 8736a94483fSmrg 8746a94483fSmrg#endif 8756a94483fSmrg 87628d65773Smrgstatic int 8772029f493Smrgpci_device_x86_read_conf1(struct pci_device *dev, void *data, 8782029f493Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) 8792029f493Smrg{ 8802029f493Smrg int err; 8812029f493Smrg 8822029f493Smrg *bytes_read = 0; 8832029f493Smrg while (size > 0) { 8842029f493Smrg int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); 8852029f493Smrg if (toread > size) 8862029f493Smrg toread = size; 8872029f493Smrg 8882029f493Smrg err = pci_system_x86_conf1_read(dev->bus, dev->dev, dev->func, offset, data, toread); 8892029f493Smrg if (err) 8902029f493Smrg return err; 8912029f493Smrg 8922029f493Smrg offset += toread; 8932029f493Smrg data = (char*)data + toread; 8942029f493Smrg size -= toread; 8952029f493Smrg *bytes_read += toread; 8962029f493Smrg } 8972029f493Smrg return 0; 8982029f493Smrg} 8992029f493Smrg 9002029f493Smrgstatic int 9012029f493Smrgpci_device_x86_read_conf2(struct pci_device *dev, void *data, 90228d65773Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) 90328d65773Smrg{ 90428d65773Smrg int err; 90528d65773Smrg 90628d65773Smrg *bytes_read = 0; 90728d65773Smrg while (size > 0) { 90828d65773Smrg int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); 90928d65773Smrg if (toread > size) 91028d65773Smrg toread = size; 91128d65773Smrg 9122029f493Smrg err = pci_system_x86_conf2_read(dev->bus, dev->dev, dev->func, offset, data, toread); 91328d65773Smrg if (err) 91428d65773Smrg return err; 91528d65773Smrg 91628d65773Smrg offset += toread; 91728d65773Smrg data = (char*)data + toread; 91828d65773Smrg size -= toread; 91928d65773Smrg *bytes_read += toread; 92028d65773Smrg } 92128d65773Smrg return 0; 92228d65773Smrg} 92328d65773Smrg 92428d65773Smrgstatic int 9252029f493Smrgpci_device_x86_write_conf1(struct pci_device *dev, const void *data, 9262029f493Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) 9272029f493Smrg{ 9282029f493Smrg int err; 9292029f493Smrg 9302029f493Smrg *bytes_written = 0; 9312029f493Smrg while (size > 0) { 9322029f493Smrg int towrite = 4; 9332029f493Smrg if (towrite > size) 9342029f493Smrg towrite = size; 9352029f493Smrg if (towrite > 4 - (offset & 0x3)) 9362029f493Smrg towrite = 4 - (offset & 0x3); 9372029f493Smrg 9382029f493Smrg err = pci_system_x86_conf1_write(dev->bus, dev->dev, dev->func, offset, data, towrite); 9392029f493Smrg if (err) 9402029f493Smrg return err; 9412029f493Smrg 9422029f493Smrg offset += towrite; 9432029f493Smrg data = (const char*)data + towrite; 9442029f493Smrg size -= towrite; 9452029f493Smrg *bytes_written += towrite; 9462029f493Smrg } 9472029f493Smrg return 0; 9482029f493Smrg} 9492029f493Smrg 9502029f493Smrgstatic int 9512029f493Smrgpci_device_x86_write_conf2(struct pci_device *dev, const void *data, 95228d65773Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) 95328d65773Smrg{ 95428d65773Smrg int err; 95528d65773Smrg 95628d65773Smrg *bytes_written = 0; 95728d65773Smrg while (size > 0) { 95828d65773Smrg int towrite = 4; 95928d65773Smrg if (towrite > size) 96028d65773Smrg towrite = size; 96128d65773Smrg if (towrite > 4 - (offset & 0x3)) 96228d65773Smrg towrite = 4 - (offset & 0x3); 96328d65773Smrg 9642029f493Smrg err = pci_system_x86_conf2_write(dev->bus, dev->dev, dev->func, offset, data, towrite); 96528d65773Smrg if (err) 96628d65773Smrg return err; 96728d65773Smrg 96828d65773Smrg offset += towrite; 96928d65773Smrg data = (const char*)data + towrite; 97028d65773Smrg size -= towrite; 97128d65773Smrg *bytes_written += towrite; 97228d65773Smrg } 97328d65773Smrg return 0; 97428d65773Smrg} 97528d65773Smrg 9762029f493Smrgvoid 97728d65773Smrgpci_system_x86_destroy(void) 97828d65773Smrg{ 97928d65773Smrg x86_disable_io(); 98028d65773Smrg} 98128d65773Smrg 9822029f493Smrgstruct pci_io_handle * 98386ea1d58Smrgpci_device_x86_open_legacy_io(struct pci_io_handle *ret, 98486ea1d58Smrg struct pci_device *dev, pciaddr_t base, pciaddr_t size) 98586ea1d58Smrg{ 98686ea1d58Smrg x86_enable_io(); 98786ea1d58Smrg 98886ea1d58Smrg ret->base = base; 98986ea1d58Smrg ret->size = size; 9906a94483fSmrg ret->is_legacy = 1; 99186ea1d58Smrg 99286ea1d58Smrg return ret; 99386ea1d58Smrg} 99486ea1d58Smrg 9952029f493Smrgvoid 99686ea1d58Smrgpci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle) 99786ea1d58Smrg{ 99886ea1d58Smrg /* Like in the Linux case, do not disable I/O, as it may be opened several 99986ea1d58Smrg * times, and closed fewer times. */ 100086ea1d58Smrg /* x86_disable_io(); */ 100186ea1d58Smrg} 100286ea1d58Smrg 10032029f493Smrguint32_t 100486ea1d58Smrgpci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg) 100586ea1d58Smrg{ 100686ea1d58Smrg return inl(reg + handle->base); 100786ea1d58Smrg} 100886ea1d58Smrg 10092029f493Smrguint16_t 101086ea1d58Smrgpci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg) 101186ea1d58Smrg{ 101286ea1d58Smrg return inw(reg + handle->base); 101386ea1d58Smrg} 101486ea1d58Smrg 10152029f493Smrguint8_t 101686ea1d58Smrgpci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg) 101786ea1d58Smrg{ 101886ea1d58Smrg return inb(reg + handle->base); 101986ea1d58Smrg} 102086ea1d58Smrg 10212029f493Smrgvoid 102286ea1d58Smrgpci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg, 102386ea1d58Smrg uint32_t data) 102486ea1d58Smrg{ 102586ea1d58Smrg outl(data, reg + handle->base); 102686ea1d58Smrg} 102786ea1d58Smrg 10282029f493Smrgvoid 102986ea1d58Smrgpci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg, 103086ea1d58Smrg uint16_t data) 103186ea1d58Smrg{ 103286ea1d58Smrg outw(data, reg + handle->base); 103386ea1d58Smrg} 103486ea1d58Smrg 10352029f493Smrgvoid 103686ea1d58Smrgpci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg, 103786ea1d58Smrg uint8_t data) 103886ea1d58Smrg{ 103986ea1d58Smrg outb(data, reg + handle->base); 104086ea1d58Smrg} 104186ea1d58Smrg 10422029f493Smrgint 104386ea1d58Smrgpci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base, 104486ea1d58Smrg pciaddr_t size, unsigned map_flags, void **addr) 104586ea1d58Smrg{ 104686ea1d58Smrg struct pci_device_mapping map; 104786ea1d58Smrg int err; 104886ea1d58Smrg 104986ea1d58Smrg map.base = base; 105086ea1d58Smrg map.size = size; 105186ea1d58Smrg map.flags = map_flags; 105286ea1d58Smrg err = pci_device_x86_map_range(dev, &map); 105386ea1d58Smrg *addr = map.memory; 105486ea1d58Smrg 105586ea1d58Smrg return err; 105686ea1d58Smrg} 105786ea1d58Smrg 10582029f493Smrgint 105986ea1d58Smrgpci_device_x86_unmap_legacy(struct pci_device *dev, void *addr, 106086ea1d58Smrg pciaddr_t size) 106186ea1d58Smrg{ 106286ea1d58Smrg struct pci_device_mapping map; 106386ea1d58Smrg 106486ea1d58Smrg map.size = size; 106586ea1d58Smrg map.flags = 0; 106686ea1d58Smrg map.memory = addr; 106786ea1d58Smrg 10686a94483fSmrg return pci_device_x86_unmap_range(dev, &map); 106986ea1d58Smrg} 107086ea1d58Smrg 10712029f493Smrgstatic const struct pci_system_methods x86_pci_method_conf1 = { 10722029f493Smrg .destroy = pci_system_x86_destroy, 10732029f493Smrg .read_rom = pci_device_x86_read_rom, 10742029f493Smrg .probe = pci_device_x86_probe, 10752029f493Smrg .map_range = pci_device_x86_map_range, 10762029f493Smrg .unmap_range = pci_device_x86_unmap_range, 10772029f493Smrg .read = pci_device_x86_read_conf1, 10782029f493Smrg .write = pci_device_x86_write_conf1, 10792029f493Smrg .fill_capabilities = pci_fill_capabilities_generic, 10802029f493Smrg .open_legacy_io = pci_device_x86_open_legacy_io, 10812029f493Smrg .close_io = pci_device_x86_close_io, 10822029f493Smrg .read32 = pci_device_x86_read32, 10832029f493Smrg .read16 = pci_device_x86_read16, 10842029f493Smrg .read8 = pci_device_x86_read8, 10852029f493Smrg .write32 = pci_device_x86_write32, 10862029f493Smrg .write16 = pci_device_x86_write16, 10872029f493Smrg .write8 = pci_device_x86_write8, 10882029f493Smrg .map_legacy = pci_device_x86_map_legacy, 10892029f493Smrg .unmap_legacy = pci_device_x86_unmap_legacy, 10902029f493Smrg}; 10912029f493Smrg 10922029f493Smrgstatic const struct pci_system_methods x86_pci_method_conf2 = { 109328d65773Smrg .destroy = pci_system_x86_destroy, 109428d65773Smrg .read_rom = pci_device_x86_read_rom, 109528d65773Smrg .probe = pci_device_x86_probe, 109628d65773Smrg .map_range = pci_device_x86_map_range, 10976a94483fSmrg .unmap_range = pci_device_x86_unmap_range, 10982029f493Smrg .read = pci_device_x86_read_conf2, 10992029f493Smrg .write = pci_device_x86_write_conf2, 110028d65773Smrg .fill_capabilities = pci_fill_capabilities_generic, 110186ea1d58Smrg .open_legacy_io = pci_device_x86_open_legacy_io, 110286ea1d58Smrg .close_io = pci_device_x86_close_io, 110386ea1d58Smrg .read32 = pci_device_x86_read32, 110486ea1d58Smrg .read16 = pci_device_x86_read16, 110586ea1d58Smrg .read8 = pci_device_x86_read8, 110686ea1d58Smrg .write32 = pci_device_x86_write32, 110786ea1d58Smrg .write16 = pci_device_x86_write16, 110886ea1d58Smrg .write8 = pci_device_x86_write8, 110986ea1d58Smrg .map_legacy = pci_device_x86_map_legacy, 111086ea1d58Smrg .unmap_legacy = pci_device_x86_unmap_legacy, 111128d65773Smrg}; 111228d65773Smrg 11132029f493Smrgstatic int pci_probe(void) 111428d65773Smrg{ 11152029f493Smrg pci_sys->methods = &x86_pci_method_conf1; 111628d65773Smrg if (pci_system_x86_conf1_probe() == 0) { 11172029f493Smrg if (pci_system_x86_check() == 0) 11182029f493Smrg return 1; 111928d65773Smrg } 112028d65773Smrg 11212029f493Smrg pci_sys->methods = &x86_pci_method_conf2; 112228d65773Smrg if (pci_system_x86_conf2_probe() == 0) { 11232029f493Smrg if (pci_system_x86_check() == 0) 11242029f493Smrg return 2; 112528d65773Smrg } 112628d65773Smrg 11272029f493Smrg pci_sys->methods = NULL; 11282029f493Smrg return 0; 112928d65773Smrg} 113028d65773Smrg 113128d65773Smrg_pci_hidden int 113228d65773Smrgpci_system_x86_create(void) 113328d65773Smrg{ 11342029f493Smrg error_t err; 11352029f493Smrg int confx; 113628d65773Smrg 11372029f493Smrg err = x86_enable_io (); 11382029f493Smrg if (err) 11392029f493Smrg return err; 114028d65773Smrg 11412029f493Smrg pci_sys = calloc (1, sizeof (struct pci_system)); 11422029f493Smrg if (pci_sys == NULL) 11432029f493Smrg { 11442029f493Smrg x86_disable_io (); 11452029f493Smrg return ENOMEM; 114628d65773Smrg } 114728d65773Smrg 11482029f493Smrg confx = pci_probe (); 11492029f493Smrg if (!confx) 11502029f493Smrg { 11512029f493Smrg x86_disable_io (); 11522029f493Smrg free (pci_sys); 11532029f493Smrg pci_sys = NULL; 11542029f493Smrg return ENODEV; 115528d65773Smrg } 11562029f493Smrg else if (confx == 1) 11572029f493Smrg pci_sys->methods = &x86_pci_method_conf1; 11582029f493Smrg else 11592029f493Smrg pci_sys->methods = &x86_pci_method_conf2; 116028d65773Smrg 11612029f493Smrg /* Recursive scan */ 11622029f493Smrg pci_sys->num_devices = 0; 11632029f493Smrg err = pci_system_x86_scan_bus (0); 11642029f493Smrg if (err) 11652029f493Smrg { 11662029f493Smrg x86_disable_io (); 11672029f493Smrg free (pci_sys); 11682029f493Smrg pci_sys = NULL; 11692029f493Smrg return err; 117028d65773Smrg } 117128d65773Smrg 117228d65773Smrg return 0; 117328d65773Smrg} 1174