128d65773Smrg/* 22029f493Smrg * Copyright (c) 2018 Damien Zammit 32029f493Smrg * Copyright (c) 2017 Joan Lledó 448becaf0Smrg * Copyright (c) 2009, 2012, 2020 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 21448becaf0Smrgstatic int cmp_devices(const void *dev1, const void *dev2) 21548becaf0Smrg{ 21648becaf0Smrg const struct pci_device *d1 = dev1; 21748becaf0Smrg const struct pci_device *d2 = dev2; 21848becaf0Smrg 21948becaf0Smrg if (d1->bus != d2->bus) { 22048becaf0Smrg return (d1->bus > d2->bus) ? 1 : -1; 22148becaf0Smrg } 22248becaf0Smrg 22348becaf0Smrg if (d1->dev != d2->dev) { 22448becaf0Smrg return (d1->dev > d2->dev) ? 1 : -1; 22548becaf0Smrg } 22648becaf0Smrg 22748becaf0Smrg return (d1->func > d2->func) ? 1 : -1; 22848becaf0Smrg} 22948becaf0Smrg 23048becaf0Smrgstatic void 23148becaf0Smrgsort_devices(void) 23248becaf0Smrg{ 23348becaf0Smrg qsort(pci_sys->devices, pci_sys->num_devices, 23448becaf0Smrg sizeof (pci_sys->devices[0]), &cmp_devices); 23548becaf0Smrg} 23648becaf0Smrg 23748becaf0Smrg#if defined(__GNU__) 23848becaf0Smrg#include <mach.h> 23948becaf0Smrg#include <hurd.h> 24048becaf0Smrg#include <device/device.h> 24148becaf0Smrg#endif 24248becaf0Smrg 24348becaf0Smrgint 24448becaf0Smrgpci_system_x86_map_dev_mem(void **dest, size_t mem_offset, size_t mem_size, int write) 24548becaf0Smrg{ 24648becaf0Smrg#if defined(__GNU__) 24748becaf0Smrg int err; 24848becaf0Smrg mach_port_t master_device; 24948becaf0Smrg mach_port_t devmem; 25048becaf0Smrg mach_port_t pager; 25148becaf0Smrg dev_mode_t mode = D_READ; 25248becaf0Smrg vm_prot_t prot = VM_PROT_READ; 25348becaf0Smrg int pagesize; 25448becaf0Smrg 25548becaf0Smrg if (get_privileged_ports (NULL, &master_device)) { 25648becaf0Smrg *dest = 0; 25748becaf0Smrg return EPERM; 25848becaf0Smrg } 25948becaf0Smrg 26048becaf0Smrg if (write) { 26148becaf0Smrg mode |= D_WRITE; 26248becaf0Smrg prot |= VM_PROT_WRITE; 26348becaf0Smrg } 26448becaf0Smrg 26548becaf0Smrg err = device_open (master_device, mode, "mem", &devmem); 26648becaf0Smrg mach_port_deallocate (mach_task_self (), master_device); 26748becaf0Smrg if (err) 26848becaf0Smrg return err; 26948becaf0Smrg 27048becaf0Smrg pagesize = getpagesize(); 27148becaf0Smrg if (mem_size % pagesize) 27248becaf0Smrg mem_size += pagesize - (mem_size % pagesize); 27348becaf0Smrg 27448becaf0Smrg err = device_map (devmem, prot, mem_offset, mem_size, &pager, 0); 27548becaf0Smrg device_close (devmem); 27648becaf0Smrg mach_port_deallocate (mach_task_self (), devmem); 27748becaf0Smrg if (err) 27848becaf0Smrg return err; 27948becaf0Smrg 28048becaf0Smrg err = vm_map (mach_task_self (), (vm_address_t *)dest, mem_size, 28148becaf0Smrg (vm_address_t) 0, /* mask */ 28248becaf0Smrg 1, /* anywhere? */ 28348becaf0Smrg pager, 0, 28448becaf0Smrg 0, /* copy */ 28548becaf0Smrg prot, VM_PROT_ALL, VM_INHERIT_SHARE); 28648becaf0Smrg mach_port_deallocate (mach_task_self (), pager); 28748becaf0Smrg if (err) 28848becaf0Smrg return err; 28948becaf0Smrg 29048becaf0Smrg return err; 29148becaf0Smrg#else 29248becaf0Smrg int prot = PROT_READ; 29348becaf0Smrg int flags = O_RDONLY; 29448becaf0Smrg int memfd; 29548becaf0Smrg 29648becaf0Smrg if (write) { 29748becaf0Smrg prot |= PROT_WRITE; 29848becaf0Smrg flags = O_RDWR; 29948becaf0Smrg } 30048becaf0Smrg memfd = open("/dev/mem", flags | O_CLOEXEC); 30148becaf0Smrg if (memfd == -1) 30248becaf0Smrg return errno; 30348becaf0Smrg 30448becaf0Smrg *dest = mmap(NULL, mem_size, prot, MAP_SHARED, memfd, mem_offset); 30548becaf0Smrg if (*dest == MAP_FAILED) { 30648becaf0Smrg close(memfd); 30748becaf0Smrg *dest = NULL; 30848becaf0Smrg return errno; 30948becaf0Smrg } 31048becaf0Smrg 31148becaf0Smrg close(memfd); 31248becaf0Smrg return 0; 31348becaf0Smrg#endif 31448becaf0Smrg} 31548becaf0Smrg 31628d65773Smrgstatic int 31728d65773Smrgpci_system_x86_conf1_probe(void) 31828d65773Smrg{ 31928d65773Smrg unsigned long sav; 32028d65773Smrg int res = ENODEV; 32128d65773Smrg 32228d65773Smrg outb(0x01, 0xCFB); 32328d65773Smrg sav = inl(0xCF8); 32428d65773Smrg outl(0x80000000, 0xCF8); 32528d65773Smrg if (inl(0xCF8) == 0x80000000) 32628d65773Smrg res = 0; 32728d65773Smrg outl(sav, 0xCF8); 32828d65773Smrg 32928d65773Smrg return res; 33028d65773Smrg} 33128d65773Smrg 33228d65773Smrgstatic int 33328d65773Smrgpci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size) 33428d65773Smrg{ 33528d65773Smrg unsigned addr = 0xCFC + (reg & 3); 33628d65773Smrg unsigned long sav; 33728d65773Smrg int ret = 0; 33828d65773Smrg 33928d65773Smrg if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3) 34028d65773Smrg return EIO; 34128d65773Smrg 34228d65773Smrg sav = inl(0xCF8); 34328d65773Smrg outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8); 34428d65773Smrg /* NOTE: x86 is already LE */ 34528d65773Smrg switch (size) { 34628d65773Smrg case 1: { 34728d65773Smrg uint8_t *val = data; 34828d65773Smrg *val = inb(addr); 34928d65773Smrg break; 35028d65773Smrg } 35128d65773Smrg case 2: { 35228d65773Smrg uint16_t *val = data; 35328d65773Smrg *val = inw(addr); 35428d65773Smrg break; 35528d65773Smrg } 35628d65773Smrg case 4: { 35728d65773Smrg uint32_t *val = data; 35828d65773Smrg *val = inl(addr); 35928d65773Smrg break; 36028d65773Smrg } 36128d65773Smrg } 36228d65773Smrg outl(sav, 0xCF8); 36328d65773Smrg 36428d65773Smrg return ret; 36528d65773Smrg} 36628d65773Smrg 36728d65773Smrgstatic int 36828d65773Smrgpci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size) 36928d65773Smrg{ 37028d65773Smrg unsigned addr = 0xCFC + (reg & 3); 37128d65773Smrg unsigned long sav; 37228d65773Smrg int ret = 0; 37328d65773Smrg 37428d65773Smrg if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3) 37528d65773Smrg return EIO; 37628d65773Smrg 37728d65773Smrg sav = inl(0xCF8); 37828d65773Smrg outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8); 37928d65773Smrg /* NOTE: x86 is already LE */ 38028d65773Smrg switch (size) { 38128d65773Smrg case 1: { 38228d65773Smrg const uint8_t *val = data; 38328d65773Smrg outb(*val, addr); 38428d65773Smrg break; 38528d65773Smrg } 38628d65773Smrg case 2: { 38728d65773Smrg const uint16_t *val = data; 38828d65773Smrg outw(*val, addr); 38928d65773Smrg break; 39028d65773Smrg } 39128d65773Smrg case 4: { 39228d65773Smrg const uint32_t *val = data; 39328d65773Smrg outl(*val, addr); 39428d65773Smrg break; 39528d65773Smrg } 39628d65773Smrg } 39728d65773Smrg outl(sav, 0xCF8); 39828d65773Smrg 39928d65773Smrg return ret; 40028d65773Smrg} 40128d65773Smrg 40228d65773Smrgstatic int 40328d65773Smrgpci_system_x86_conf2_probe(void) 40428d65773Smrg{ 40528d65773Smrg outb(0, 0xCFB); 40628d65773Smrg outb(0, 0xCF8); 40728d65773Smrg outb(0, 0xCFA); 40828d65773Smrg if (inb(0xCF8) == 0 && inb(0xCFA) == 0) 40928d65773Smrg return 0; 41028d65773Smrg 41128d65773Smrg return ENODEV; 41228d65773Smrg} 41328d65773Smrg 41428d65773Smrgstatic int 41528d65773Smrgpci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size) 41628d65773Smrg{ 41728d65773Smrg unsigned addr = 0xC000 | dev << 8 | reg; 41828d65773Smrg int ret = 0; 41928d65773Smrg 42028d65773Smrg if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) 42128d65773Smrg return EIO; 42228d65773Smrg 42328d65773Smrg outb((func << 1) | 0xF0, 0xCF8); 42428d65773Smrg outb(bus, 0xCFA); 42528d65773Smrg /* NOTE: x86 is already LE */ 42628d65773Smrg switch (size) { 42728d65773Smrg case 1: { 42828d65773Smrg uint8_t *val = data; 42928d65773Smrg *val = inb(addr); 43028d65773Smrg break; 43128d65773Smrg } 43228d65773Smrg case 2: { 43328d65773Smrg uint16_t *val = data; 43428d65773Smrg *val = inw(addr); 43528d65773Smrg break; 43628d65773Smrg } 43728d65773Smrg case 4: { 43828d65773Smrg uint32_t *val = data; 43928d65773Smrg *val = inl(addr); 44028d65773Smrg break; 44128d65773Smrg } 44228d65773Smrg default: 44328d65773Smrg ret = EIO; 44428d65773Smrg break; 44528d65773Smrg } 44628d65773Smrg outb(0, 0xCF8); 44728d65773Smrg 44828d65773Smrg return ret; 44928d65773Smrg} 45028d65773Smrg 45128d65773Smrgstatic int 45228d65773Smrgpci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size) 45328d65773Smrg{ 45428d65773Smrg unsigned addr = 0xC000 | dev << 8 | reg; 45528d65773Smrg int ret = 0; 45628d65773Smrg 45728d65773Smrg if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) 45828d65773Smrg return EIO; 45928d65773Smrg 46028d65773Smrg outb((func << 1) | 0xF0, 0xCF8); 46128d65773Smrg outb(bus, 0xCFA); 46228d65773Smrg /* NOTE: x86 is already LE */ 46328d65773Smrg switch (size) { 46428d65773Smrg case 1: { 46528d65773Smrg const uint8_t *val = data; 46628d65773Smrg outb(*val, addr); 46728d65773Smrg break; 46828d65773Smrg } 46928d65773Smrg case 2: { 47028d65773Smrg const uint16_t *val = data; 47128d65773Smrg outw(*val, addr); 47228d65773Smrg break; 47328d65773Smrg } 47428d65773Smrg case 4: { 47528d65773Smrg const uint32_t *val = data; 47628d65773Smrg outl(*val, addr); 47728d65773Smrg break; 47828d65773Smrg } 47928d65773Smrg default: 48028d65773Smrg ret = EIO; 48128d65773Smrg break; 48228d65773Smrg } 48328d65773Smrg outb(0, 0xCF8); 48428d65773Smrg 48528d65773Smrg return ret; 48628d65773Smrg} 48728d65773Smrg 48828d65773Smrg/* Check that this really looks like a PCI configuration. */ 4892029f493Smrgstatic error_t 4902029f493Smrgpci_system_x86_check (void) 49128d65773Smrg{ 49228d65773Smrg int dev; 49328d65773Smrg uint16_t class, vendor; 4942029f493Smrg struct pci_device tmpdev = { 0 }; 49528d65773Smrg 49628d65773Smrg /* Look on bus 0 for a device that is a host bridge, a VGA card, 49728d65773Smrg * or an intel or compaq device. */ 4982029f493Smrg tmpdev.bus = 0; 4992029f493Smrg tmpdev.func = 0; 5002029f493Smrg class = 0; 5012029f493Smrg vendor = 0; 50228d65773Smrg 50328d65773Smrg for (dev = 0; dev < 32; dev++) { 5042029f493Smrg tmpdev.dev = dev; 5052029f493Smrg if (pci_device_cfg_read_u16 (&tmpdev, &class, PCI_CLASS_DEVICE)) 5062029f493Smrg continue; 5072029f493Smrg if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) 5082029f493Smrg return 0; 5092029f493Smrg if (pci_device_cfg_read_u16 (&tmpdev, &vendor, PCI_VENDOR_ID)) 5102029f493Smrg continue; 5112029f493Smrg if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) 5122029f493Smrg return 0; 51328d65773Smrg } 51428d65773Smrg 51528d65773Smrg return ENODEV; 51628d65773Smrg} 51728d65773Smrg 51828d65773Smrgstatic int 5192029f493Smrgpci_nfuncs(struct pci_device *dev, uint8_t *nfuncs) 52028d65773Smrg{ 52128d65773Smrg uint8_t hdr; 52228d65773Smrg int err; 5232029f493Smrg struct pci_device tmpdev = *dev; 52428d65773Smrg 5252029f493Smrg tmpdev.func = 0; 5262029f493Smrg 5272029f493Smrg err = pci_device_cfg_read_u8 (&tmpdev, &hdr, PCI_HDRTYPE); 52828d65773Smrg 52928d65773Smrg if (err) 53028d65773Smrg return err; 53128d65773Smrg 5322029f493Smrg *nfuncs = hdr & 0x80 ? 8 : 1; 5332029f493Smrg return err; 53428d65773Smrg} 53528d65773Smrg 53628d65773Smrg/** 5372029f493Smrg * Read a PCI rom. 53828d65773Smrg */ 5392029f493Smrgstatic error_t 54028d65773Smrgpci_device_x86_read_rom(struct pci_device *dev, void *buffer) 54128d65773Smrg{ 54248becaf0Smrg void *bios = NULL; 5432029f493Smrg struct pci_device_private *d = (struct pci_device_private *)dev; 54428d65773Smrg 54548becaf0Smrg int err; 54648becaf0Smrg if ( (err = pci_system_x86_map_dev_mem(&bios, d->rom_base, dev->rom_size, 0)) ) 54748becaf0Smrg return err; 54828d65773Smrg 54928d65773Smrg memcpy(buffer, bios, dev->rom_size); 55028d65773Smrg munmap(bios, dev->rom_size); 55128d65773Smrg return 0; 55228d65773Smrg} 55328d65773Smrg 55428d65773Smrg/** Returns the number of regions (base address registers) the device has */ 55528d65773Smrgstatic int 55628d65773Smrgpci_device_x86_get_num_regions(uint8_t header_type) 55728d65773Smrg{ 55828d65773Smrg switch (header_type & 0x7f) { 55928d65773Smrg case 0: 56028d65773Smrg return 6; 56128d65773Smrg case 1: 56228d65773Smrg return 2; 56328d65773Smrg case 2: 56428d65773Smrg return 1; 56528d65773Smrg default: 56628d65773Smrg fprintf(stderr,"unknown header type %02x\n", header_type); 56728d65773Smrg return 0; 56828d65773Smrg } 56928d65773Smrg} 57028d65773Smrg 57128d65773Smrg/** Masks out the flag bigs of the base address register value */ 57228d65773Smrgstatic uint32_t 57328d65773Smrgget_map_base( uint32_t val ) 57428d65773Smrg{ 57528d65773Smrg if (val & 0x01) 57628d65773Smrg return val & ~0x03; 57728d65773Smrg else 57828d65773Smrg return val & ~0x0f; 57928d65773Smrg} 58028d65773Smrg 58128d65773Smrg/** Returns the size of a region based on the all-ones test value */ 58228d65773Smrgstatic unsigned 58328d65773Smrgget_test_val_size( uint32_t testval ) 58428d65773Smrg{ 58528d65773Smrg unsigned size = 1; 58628d65773Smrg 58728d65773Smrg if (testval == 0) 58828d65773Smrg return 0; 58928d65773Smrg 59028d65773Smrg /* Mask out the flag bits */ 59128d65773Smrg testval = get_map_base( testval ); 59228d65773Smrg if (!testval) 59328d65773Smrg return 0; 59428d65773Smrg 59528d65773Smrg while ((testval & 1) == 0) { 59628d65773Smrg size <<= 1; 59728d65773Smrg testval >>= 1; 59828d65773Smrg } 59928d65773Smrg 60028d65773Smrg return size; 60128d65773Smrg} 60228d65773Smrg 6032029f493Smrg/* Read BAR `reg_num' in `dev' and map the data if any */ 6042029f493Smrgstatic error_t 6052029f493Smrgpci_device_x86_region_probe (struct pci_device *dev, int reg_num) 60628d65773Smrg{ 6072029f493Smrg error_t err; 6082029f493Smrg uint8_t offset; 6092029f493Smrg uint32_t reg, addr, testval; 61028d65773Smrg 6112029f493Smrg offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; 61228d65773Smrg 6132029f493Smrg /* Get the base address */ 6142029f493Smrg err = pci_device_cfg_read_u32 (dev, &addr, offset); 61528d65773Smrg if (err) 6162029f493Smrg return err; 61728d65773Smrg 6182029f493Smrg /* Test write all ones to the register, then restore it. */ 6192029f493Smrg reg = 0xffffffff; 6202029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, offset); 62128d65773Smrg if (err) 6222029f493Smrg return err; 6232029f493Smrg err = pci_device_cfg_read_u32 (dev, &testval, offset); 6242029f493Smrg if (err) 6252029f493Smrg return err; 6262029f493Smrg err = pci_device_cfg_write_u32 (dev, addr, offset); 6272029f493Smrg if (err) 6282029f493Smrg return err; 62928d65773Smrg 6302029f493Smrg if (addr & 0x01) 6312029f493Smrg dev->regions[reg_num].is_IO = 1; 6322029f493Smrg if (addr & 0x04) 6332029f493Smrg dev->regions[reg_num].is_64 = 1; 6342029f493Smrg if (addr & 0x08) 6352029f493Smrg dev->regions[reg_num].is_prefetchable = 1; 6362029f493Smrg 6372029f493Smrg /* Set the size */ 6382029f493Smrg dev->regions[reg_num].size = get_test_val_size (testval); 6392029f493Smrg 6402029f493Smrg /* Set the base address value */ 6412029f493Smrg dev->regions[reg_num].base_addr = get_map_base (addr); 6422029f493Smrg 6432029f493Smrg if (dev->regions[reg_num].is_64) 6442029f493Smrg { 6452029f493Smrg err = pci_device_cfg_read_u32 (dev, &addr, offset + 4); 6462029f493Smrg if (err) 6472029f493Smrg return err; 6482029f493Smrg 6492029f493Smrg dev->regions[reg_num].base_addr |= ((uint64_t) addr << 32); 6502029f493Smrg } 6512029f493Smrg 6522029f493Smrg if (dev->regions[reg_num].is_IO) 6532029f493Smrg { 6542029f493Smrg /* Enable the I/O Space bit */ 6552029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); 6562029f493Smrg if (err) 6572029f493Smrg return err; 6582029f493Smrg 6592029f493Smrg if (!(reg & 0x1)) 6602029f493Smrg { 6612029f493Smrg reg |= 0x1; 6622029f493Smrg 6632029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); 6642029f493Smrg if (err) 6652029f493Smrg return err; 6662029f493Smrg } 6672029f493Smrg } 6682029f493Smrg else if (dev->regions[reg_num].size > 0) 6692029f493Smrg { 6702029f493Smrg /* Enable the Memory Space bit */ 6712029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); 6722029f493Smrg if (err) 6732029f493Smrg return err; 6742029f493Smrg 6752029f493Smrg if (!(reg & 0x2)) 6762029f493Smrg { 6772029f493Smrg reg |= 0x2; 6782029f493Smrg 6792029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); 6802029f493Smrg if (err) 6812029f493Smrg return err; 6822029f493Smrg } 6832029f493Smrg } 6842029f493Smrg 68548becaf0Smrg /* Clear the map pointer */ 68648becaf0Smrg dev->regions[reg_num].memory = 0; 68748becaf0Smrg 6882029f493Smrg return 0; 6892029f493Smrg} 6902029f493Smrg 6912029f493Smrg/* Read the XROMBAR in `dev' and save the rom size and rom base */ 6922029f493Smrgstatic error_t 6932029f493Smrgpci_device_x86_probe_rom (struct pci_device *dev) 6942029f493Smrg{ 6952029f493Smrg error_t err; 6962029f493Smrg uint8_t reg_8, xrombar_addr; 6972029f493Smrg uint32_t reg, reg_back; 6982029f493Smrg pciaddr_t rom_size; 6992029f493Smrg pciaddr_t rom_base; 7002029f493Smrg struct pci_device_private *d = (struct pci_device_private *)dev; 7012029f493Smrg 7022029f493Smrg /* First we need to know which type of header is this */ 7032029f493Smrg err = pci_device_cfg_read_u8 (dev, ®_8, PCI_HDRTYPE); 7042029f493Smrg if (err) 7052029f493Smrg return err; 7062029f493Smrg 7072029f493Smrg /* Get the XROMBAR register address */ 7082029f493Smrg switch (reg_8 & 0x3) 7092029f493Smrg { 7102029f493Smrg case PCI_HDRTYPE_DEVICE: 7112029f493Smrg xrombar_addr = PCI_XROMBAR_ADDR_00; 7122029f493Smrg break; 7132029f493Smrg case PCI_HDRTYPE_BRIDGE: 7142029f493Smrg xrombar_addr = PCI_XROMBAR_ADDR_01; 7152029f493Smrg break; 7162029f493Smrg default: 7172029f493Smrg return -1; 7182029f493Smrg } 7192029f493Smrg 7202029f493Smrg /* Get size and physical address */ 7212029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, xrombar_addr); 7222029f493Smrg if (err) 7232029f493Smrg return err; 7242029f493Smrg 7252029f493Smrg reg_back = reg; 7262029f493Smrg reg = 0xFFFFF800; /* Base address: first 21 bytes */ 7272029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, xrombar_addr); 7282029f493Smrg if (err) 7292029f493Smrg return err; 7302029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, xrombar_addr); 7312029f493Smrg if (err) 7322029f493Smrg return err; 7332029f493Smrg 7342029f493Smrg rom_size = (~reg + 1); 7352029f493Smrg rom_base = reg_back & reg; 7362029f493Smrg 7372029f493Smrg if (rom_size == 0) 7382029f493Smrg return 0; 7392029f493Smrg 7402029f493Smrg /* Enable the address decoder and write the physical address back */ 7412029f493Smrg reg_back |= 0x1; 7422029f493Smrg err = pci_device_cfg_write_u32 (dev, reg_back, xrombar_addr); 7432029f493Smrg if (err) 7442029f493Smrg return err; 7452029f493Smrg 7462029f493Smrg /* Enable the Memory Space bit */ 7472029f493Smrg err = pci_device_cfg_read_u32 (dev, ®, PCI_COMMAND); 7482029f493Smrg if (err) 7492029f493Smrg return err; 7502029f493Smrg 7512029f493Smrg if (!(reg & 0x2)) 7522029f493Smrg { 7532029f493Smrg reg |= 0x2; 7542029f493Smrg 7552029f493Smrg err = pci_device_cfg_write_u32 (dev, reg, PCI_COMMAND); 7562029f493Smrg if (err) 7572029f493Smrg return err; 7582029f493Smrg } 7592029f493Smrg 7602029f493Smrg dev->rom_size = rom_size; 7612029f493Smrg d->rom_base = rom_base; 7622029f493Smrg 7632029f493Smrg return 0; 7642029f493Smrg} 7652029f493Smrg 7662029f493Smrg/* Configure BARs and ROM */ 7672029f493Smrgstatic error_t 7682029f493Smrgpci_device_x86_probe (struct pci_device *dev) 7692029f493Smrg{ 7702029f493Smrg error_t err; 7712029f493Smrg uint8_t hdrtype; 7722029f493Smrg int i; 7732029f493Smrg 7742029f493Smrg /* Probe BARs */ 7752029f493Smrg err = pci_device_cfg_read_u8 (dev, &hdrtype, PCI_HDRTYPE); 7762029f493Smrg if (err) 7772029f493Smrg return err; 7782029f493Smrg 7792029f493Smrg for (i = 0; i < pci_device_x86_get_num_regions (hdrtype); i++) 7802029f493Smrg { 7812029f493Smrg err = pci_device_x86_region_probe (dev, i); 7822029f493Smrg if (err) 7832029f493Smrg return err; 7842029f493Smrg 7852029f493Smrg if (dev->regions[i].is_64) 7862029f493Smrg /* Move the pointer one BAR ahead */ 7872029f493Smrg i++; 78828d65773Smrg } 78928d65773Smrg 7902029f493Smrg /* Probe ROM */ 7912029f493Smrg pci_device_x86_probe_rom(dev); 7922029f493Smrg 7932029f493Smrg return 0; 7942029f493Smrg} 7952029f493Smrg 7962029f493Smrg/* Recursively scan bus number `bus' */ 7972029f493Smrgstatic error_t 7982029f493Smrgpci_system_x86_scan_bus (uint8_t bus) 7992029f493Smrg{ 8002029f493Smrg error_t err; 8012029f493Smrg uint8_t dev, func, nfuncs, hdrtype, secbus; 8022029f493Smrg uint32_t reg; 8032029f493Smrg struct pci_device_private *d, *devices; 8042029f493Smrg struct pci_device scratchdev; 8052029f493Smrg 8062029f493Smrg scratchdev.bus = bus; 8072029f493Smrg 8082029f493Smrg for (dev = 0; dev < 32; dev++) 80928d65773Smrg { 8102029f493Smrg scratchdev.dev = dev; 8112029f493Smrg scratchdev.func = 0; 8122029f493Smrg err = pci_nfuncs (&scratchdev, &nfuncs); 8132029f493Smrg if (err) 8142029f493Smrg return err; 8152029f493Smrg 8162029f493Smrg for (func = 0; func < nfuncs; func++) 8172029f493Smrg { 8182029f493Smrg scratchdev.func = func; 8192029f493Smrg err = pci_device_cfg_read_u32 (&scratchdev, ®, PCI_VENDOR_ID); 8202029f493Smrg if (err) 8212029f493Smrg return err; 8222029f493Smrg 8232029f493Smrg if (PCI_VENDOR (reg) == PCI_VENDOR_INVALID || PCI_VENDOR (reg) == 0) 8242029f493Smrg continue; 8252029f493Smrg 8262029f493Smrg err = pci_device_cfg_read_u32 (&scratchdev, ®, PCI_CLASS); 8272029f493Smrg if (err) 8282029f493Smrg return err; 8292029f493Smrg 8302029f493Smrg err = pci_device_cfg_read_u8 (&scratchdev, &hdrtype, PCI_HDRTYPE); 8312029f493Smrg if (err) 8322029f493Smrg return err; 8332029f493Smrg 8342029f493Smrg devices = 8352029f493Smrg realloc (pci_sys->devices, 8362029f493Smrg (pci_sys->num_devices + 1) * sizeof (struct pci_device_private)); 8372029f493Smrg if (!devices) 8382029f493Smrg return ENOMEM; 8392029f493Smrg 8402029f493Smrg d = devices + pci_sys->num_devices; 8412029f493Smrg memset (d, 0, sizeof (struct pci_device_private)); 8422029f493Smrg 8432029f493Smrg /* Fixed values as PCI express is still not supported */ 8442029f493Smrg d->base.domain = 0; 8452029f493Smrg d->base.bus = bus; 8462029f493Smrg d->base.dev = dev; 8472029f493Smrg d->base.func = func; 8482029f493Smrg 8492029f493Smrg d->base.device_class = reg >> 8; 8502029f493Smrg 8512029f493Smrg pci_sys->devices = devices; 8522029f493Smrg pci_sys->num_devices++; 8532029f493Smrg 8542029f493Smrg switch (hdrtype & 0x3) 8552029f493Smrg { 8562029f493Smrg case PCI_HDRTYPE_DEVICE: 8572029f493Smrg break; 8582029f493Smrg case PCI_HDRTYPE_BRIDGE: 8592029f493Smrg case PCI_HDRTYPE_CARDBUS: 8602029f493Smrg { 8612029f493Smrg err = pci_device_cfg_read_u8 (&scratchdev, &secbus, PCI_SECONDARY_BUS); 8622029f493Smrg if (err) 8632029f493Smrg return err; 8642029f493Smrg 8652029f493Smrg err = pci_system_x86_scan_bus (secbus); 8662029f493Smrg if (err) 8672029f493Smrg return err; 8682029f493Smrg 8692029f493Smrg break; 8702029f493Smrg } 8712029f493Smrg default: 8722029f493Smrg /* Unknown header, do nothing */ 8732029f493Smrg break; 8742029f493Smrg } 8752029f493Smrg } 87628d65773Smrg } 87728d65773Smrg 87828d65773Smrg return 0; 87928d65773Smrg} 88028d65773Smrg 8816a94483fSmrg#if defined(__CYGWIN__) 8826a94483fSmrg 8836a94483fSmrgstatic int 8846a94483fSmrgpci_device_x86_map_range(struct pci_device *dev, 8856a94483fSmrg struct pci_device_mapping *map) 8866a94483fSmrg{ 8876a94483fSmrg tagPhysStruct phys; 8886a94483fSmrg 8896a94483fSmrg phys.pvPhysAddress = (DWORD64)(DWORD32)map->base; 8906a94483fSmrg phys.dwPhysMemSizeInBytes = map->size; 8916a94483fSmrg 8926a94483fSmrg map->memory = (PDWORD)MapPhysToLin(&phys); 8936a94483fSmrg if (map->memory == NULL) 8946a94483fSmrg return EFAULT; 8956a94483fSmrg 8966a94483fSmrg return 0; 8976a94483fSmrg} 8986a94483fSmrg 8996a94483fSmrgstatic int 9006a94483fSmrgpci_device_x86_unmap_range(struct pci_device *dev, 9016a94483fSmrg struct pci_device_mapping *map) 9026a94483fSmrg{ 9036a94483fSmrg tagPhysStruct phys; 9046a94483fSmrg 9056a94483fSmrg phys.pvPhysAddress = (DWORD64)(DWORD32)map->base; 9066a94483fSmrg phys.dwPhysMemSizeInBytes = map->size; 9076a94483fSmrg 9086a94483fSmrg if (!UnmapPhysicalMemory(&phys)) 9096a94483fSmrg return EFAULT; 9106a94483fSmrg 9116a94483fSmrg return 0; 9126a94483fSmrg} 9136a94483fSmrg 9146a94483fSmrg#else 9156a94483fSmrg 91648becaf0Smrgstatic int 91728d65773Smrgpci_device_x86_map_range(struct pci_device *dev, 91828d65773Smrg struct pci_device_mapping *map) 91928d65773Smrg{ 92048becaf0Smrg int err; 92148becaf0Smrg if ( (err = pci_system_x86_map_dev_mem(&map->memory, map->base, map->size, 92248becaf0Smrg map->flags & PCI_DEV_MAP_FLAG_WRITABLE))) 92348becaf0Smrg return err; 92428d65773Smrg 92528d65773Smrg return 0; 92628d65773Smrg} 92728d65773Smrg 92848becaf0Smrgstatic int 9296a94483fSmrgpci_device_x86_unmap_range(struct pci_device *dev, 9306a94483fSmrg struct pci_device_mapping *map) 9316a94483fSmrg{ 93248becaf0Smrg int err; 93348becaf0Smrg err = pci_device_generic_unmap_range(dev, map); 93448becaf0Smrg map->memory = NULL; 93548becaf0Smrg 93648becaf0Smrg return err; 9376a94483fSmrg} 9386a94483fSmrg 9396a94483fSmrg#endif 9406a94483fSmrg 94128d65773Smrgstatic int 9422029f493Smrgpci_device_x86_read_conf1(struct pci_device *dev, void *data, 9432029f493Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) 9442029f493Smrg{ 9452029f493Smrg int err; 9462029f493Smrg 9472029f493Smrg *bytes_read = 0; 9482029f493Smrg while (size > 0) { 9492029f493Smrg int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); 9502029f493Smrg if (toread > size) 9512029f493Smrg toread = size; 9522029f493Smrg 9532029f493Smrg err = pci_system_x86_conf1_read(dev->bus, dev->dev, dev->func, offset, data, toread); 9542029f493Smrg if (err) 9552029f493Smrg return err; 9562029f493Smrg 9572029f493Smrg offset += toread; 9582029f493Smrg data = (char*)data + toread; 9592029f493Smrg size -= toread; 9602029f493Smrg *bytes_read += toread; 9612029f493Smrg } 9622029f493Smrg return 0; 9632029f493Smrg} 9642029f493Smrg 9652029f493Smrgstatic int 9662029f493Smrgpci_device_x86_read_conf2(struct pci_device *dev, void *data, 96728d65773Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) 96828d65773Smrg{ 96928d65773Smrg int err; 97028d65773Smrg 97128d65773Smrg *bytes_read = 0; 97228d65773Smrg while (size > 0) { 97328d65773Smrg int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); 97428d65773Smrg if (toread > size) 97528d65773Smrg toread = size; 97628d65773Smrg 9772029f493Smrg err = pci_system_x86_conf2_read(dev->bus, dev->dev, dev->func, offset, data, toread); 97828d65773Smrg if (err) 97928d65773Smrg return err; 98028d65773Smrg 98128d65773Smrg offset += toread; 98228d65773Smrg data = (char*)data + toread; 98328d65773Smrg size -= toread; 98428d65773Smrg *bytes_read += toread; 98528d65773Smrg } 98628d65773Smrg return 0; 98728d65773Smrg} 98828d65773Smrg 98928d65773Smrgstatic int 9902029f493Smrgpci_device_x86_write_conf1(struct pci_device *dev, const void *data, 9912029f493Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) 9922029f493Smrg{ 9932029f493Smrg int err; 9942029f493Smrg 9952029f493Smrg *bytes_written = 0; 9962029f493Smrg while (size > 0) { 9972029f493Smrg int towrite = 4; 9982029f493Smrg if (towrite > size) 9992029f493Smrg towrite = size; 10002029f493Smrg if (towrite > 4 - (offset & 0x3)) 10012029f493Smrg towrite = 4 - (offset & 0x3); 10022029f493Smrg 10032029f493Smrg err = pci_system_x86_conf1_write(dev->bus, dev->dev, dev->func, offset, data, towrite); 10042029f493Smrg if (err) 10052029f493Smrg return err; 10062029f493Smrg 10072029f493Smrg offset += towrite; 10082029f493Smrg data = (const char*)data + towrite; 10092029f493Smrg size -= towrite; 10102029f493Smrg *bytes_written += towrite; 10112029f493Smrg } 10122029f493Smrg return 0; 10132029f493Smrg} 10142029f493Smrg 10152029f493Smrgstatic int 10162029f493Smrgpci_device_x86_write_conf2(struct pci_device *dev, const void *data, 101728d65773Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) 101828d65773Smrg{ 101928d65773Smrg int err; 102028d65773Smrg 102128d65773Smrg *bytes_written = 0; 102228d65773Smrg while (size > 0) { 102328d65773Smrg int towrite = 4; 102428d65773Smrg if (towrite > size) 102528d65773Smrg towrite = size; 102628d65773Smrg if (towrite > 4 - (offset & 0x3)) 102728d65773Smrg towrite = 4 - (offset & 0x3); 102828d65773Smrg 10292029f493Smrg err = pci_system_x86_conf2_write(dev->bus, dev->dev, dev->func, offset, data, towrite); 103028d65773Smrg if (err) 103128d65773Smrg return err; 103228d65773Smrg 103328d65773Smrg offset += towrite; 103428d65773Smrg data = (const char*)data + towrite; 103528d65773Smrg size -= towrite; 103628d65773Smrg *bytes_written += towrite; 103728d65773Smrg } 103828d65773Smrg return 0; 103928d65773Smrg} 104028d65773Smrg 10412029f493Smrgvoid 104228d65773Smrgpci_system_x86_destroy(void) 104328d65773Smrg{ 104428d65773Smrg x86_disable_io(); 104528d65773Smrg} 104628d65773Smrg 10472029f493Smrgstruct pci_io_handle * 104886ea1d58Smrgpci_device_x86_open_legacy_io(struct pci_io_handle *ret, 104986ea1d58Smrg struct pci_device *dev, pciaddr_t base, pciaddr_t size) 105086ea1d58Smrg{ 105186ea1d58Smrg x86_enable_io(); 105286ea1d58Smrg 105386ea1d58Smrg ret->base = base; 105486ea1d58Smrg ret->size = size; 10556a94483fSmrg ret->is_legacy = 1; 105686ea1d58Smrg 105786ea1d58Smrg return ret; 105886ea1d58Smrg} 105986ea1d58Smrg 10602029f493Smrgvoid 106186ea1d58Smrgpci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle) 106286ea1d58Smrg{ 106386ea1d58Smrg /* Like in the Linux case, do not disable I/O, as it may be opened several 106486ea1d58Smrg * times, and closed fewer times. */ 106586ea1d58Smrg /* x86_disable_io(); */ 106686ea1d58Smrg} 106786ea1d58Smrg 10682029f493Smrguint32_t 106986ea1d58Smrgpci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg) 107086ea1d58Smrg{ 107186ea1d58Smrg return inl(reg + handle->base); 107286ea1d58Smrg} 107386ea1d58Smrg 10742029f493Smrguint16_t 107586ea1d58Smrgpci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg) 107686ea1d58Smrg{ 107786ea1d58Smrg return inw(reg + handle->base); 107886ea1d58Smrg} 107986ea1d58Smrg 10802029f493Smrguint8_t 108186ea1d58Smrgpci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg) 108286ea1d58Smrg{ 108386ea1d58Smrg return inb(reg + handle->base); 108486ea1d58Smrg} 108586ea1d58Smrg 10862029f493Smrgvoid 108786ea1d58Smrgpci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg, 108886ea1d58Smrg uint32_t data) 108986ea1d58Smrg{ 109086ea1d58Smrg outl(data, reg + handle->base); 109186ea1d58Smrg} 109286ea1d58Smrg 10932029f493Smrgvoid 109486ea1d58Smrgpci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg, 109586ea1d58Smrg uint16_t data) 109686ea1d58Smrg{ 109786ea1d58Smrg outw(data, reg + handle->base); 109886ea1d58Smrg} 109986ea1d58Smrg 11002029f493Smrgvoid 110186ea1d58Smrgpci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg, 110286ea1d58Smrg uint8_t data) 110386ea1d58Smrg{ 110486ea1d58Smrg outb(data, reg + handle->base); 110586ea1d58Smrg} 110686ea1d58Smrg 110748becaf0Smrgstatic int 110886ea1d58Smrgpci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base, 110986ea1d58Smrg pciaddr_t size, unsigned map_flags, void **addr) 111086ea1d58Smrg{ 111186ea1d58Smrg struct pci_device_mapping map; 111286ea1d58Smrg int err; 111386ea1d58Smrg 111486ea1d58Smrg map.base = base; 111586ea1d58Smrg map.size = size; 111686ea1d58Smrg map.flags = map_flags; 111786ea1d58Smrg err = pci_device_x86_map_range(dev, &map); 111886ea1d58Smrg *addr = map.memory; 111986ea1d58Smrg 112086ea1d58Smrg return err; 112186ea1d58Smrg} 112286ea1d58Smrg 112348becaf0Smrgstatic int 112486ea1d58Smrgpci_device_x86_unmap_legacy(struct pci_device *dev, void *addr, 112586ea1d58Smrg pciaddr_t size) 112686ea1d58Smrg{ 112786ea1d58Smrg struct pci_device_mapping map; 112886ea1d58Smrg 112986ea1d58Smrg map.size = size; 113086ea1d58Smrg map.flags = 0; 113186ea1d58Smrg map.memory = addr; 113286ea1d58Smrg 11336a94483fSmrg return pci_device_x86_unmap_range(dev, &map); 113486ea1d58Smrg} 113586ea1d58Smrg 11362029f493Smrgstatic const struct pci_system_methods x86_pci_method_conf1 = { 11372029f493Smrg .destroy = pci_system_x86_destroy, 11382029f493Smrg .read_rom = pci_device_x86_read_rom, 11392029f493Smrg .probe = pci_device_x86_probe, 11402029f493Smrg .map_range = pci_device_x86_map_range, 11412029f493Smrg .unmap_range = pci_device_x86_unmap_range, 11422029f493Smrg .read = pci_device_x86_read_conf1, 11432029f493Smrg .write = pci_device_x86_write_conf1, 11442029f493Smrg .fill_capabilities = pci_fill_capabilities_generic, 11452029f493Smrg .open_legacy_io = pci_device_x86_open_legacy_io, 11462029f493Smrg .close_io = pci_device_x86_close_io, 11472029f493Smrg .read32 = pci_device_x86_read32, 11482029f493Smrg .read16 = pci_device_x86_read16, 11492029f493Smrg .read8 = pci_device_x86_read8, 11502029f493Smrg .write32 = pci_device_x86_write32, 11512029f493Smrg .write16 = pci_device_x86_write16, 11522029f493Smrg .write8 = pci_device_x86_write8, 11532029f493Smrg .map_legacy = pci_device_x86_map_legacy, 11542029f493Smrg .unmap_legacy = pci_device_x86_unmap_legacy, 11552029f493Smrg}; 11562029f493Smrg 11572029f493Smrgstatic const struct pci_system_methods x86_pci_method_conf2 = { 115828d65773Smrg .destroy = pci_system_x86_destroy, 115928d65773Smrg .read_rom = pci_device_x86_read_rom, 116028d65773Smrg .probe = pci_device_x86_probe, 116128d65773Smrg .map_range = pci_device_x86_map_range, 11626a94483fSmrg .unmap_range = pci_device_x86_unmap_range, 11632029f493Smrg .read = pci_device_x86_read_conf2, 11642029f493Smrg .write = pci_device_x86_write_conf2, 116528d65773Smrg .fill_capabilities = pci_fill_capabilities_generic, 116686ea1d58Smrg .open_legacy_io = pci_device_x86_open_legacy_io, 116786ea1d58Smrg .close_io = pci_device_x86_close_io, 116886ea1d58Smrg .read32 = pci_device_x86_read32, 116986ea1d58Smrg .read16 = pci_device_x86_read16, 117086ea1d58Smrg .read8 = pci_device_x86_read8, 117186ea1d58Smrg .write32 = pci_device_x86_write32, 117286ea1d58Smrg .write16 = pci_device_x86_write16, 117386ea1d58Smrg .write8 = pci_device_x86_write8, 117486ea1d58Smrg .map_legacy = pci_device_x86_map_legacy, 117586ea1d58Smrg .unmap_legacy = pci_device_x86_unmap_legacy, 117628d65773Smrg}; 117728d65773Smrg 11782029f493Smrgstatic int pci_probe(void) 117928d65773Smrg{ 11802029f493Smrg pci_sys->methods = &x86_pci_method_conf1; 118128d65773Smrg if (pci_system_x86_conf1_probe() == 0) { 11822029f493Smrg if (pci_system_x86_check() == 0) 11832029f493Smrg return 1; 118428d65773Smrg } 118528d65773Smrg 11862029f493Smrg pci_sys->methods = &x86_pci_method_conf2; 118728d65773Smrg if (pci_system_x86_conf2_probe() == 0) { 11882029f493Smrg if (pci_system_x86_check() == 0) 11892029f493Smrg return 2; 119028d65773Smrg } 119128d65773Smrg 11922029f493Smrg pci_sys->methods = NULL; 11932029f493Smrg return 0; 119428d65773Smrg} 119528d65773Smrg 119628d65773Smrg_pci_hidden int 119728d65773Smrgpci_system_x86_create(void) 119828d65773Smrg{ 11992029f493Smrg error_t err; 12002029f493Smrg int confx; 120128d65773Smrg 12022029f493Smrg err = x86_enable_io (); 12032029f493Smrg if (err) 12042029f493Smrg return err; 120528d65773Smrg 12062029f493Smrg pci_sys = calloc (1, sizeof (struct pci_system)); 12072029f493Smrg if (pci_sys == NULL) 12082029f493Smrg { 12092029f493Smrg x86_disable_io (); 12102029f493Smrg return ENOMEM; 121128d65773Smrg } 121228d65773Smrg 12132029f493Smrg confx = pci_probe (); 12142029f493Smrg if (!confx) 12152029f493Smrg { 12162029f493Smrg x86_disable_io (); 12172029f493Smrg free (pci_sys); 12182029f493Smrg pci_sys = NULL; 12192029f493Smrg return ENODEV; 122028d65773Smrg } 12212029f493Smrg else if (confx == 1) 12222029f493Smrg pci_sys->methods = &x86_pci_method_conf1; 12232029f493Smrg else 12242029f493Smrg pci_sys->methods = &x86_pci_method_conf2; 122528d65773Smrg 12262029f493Smrg /* Recursive scan */ 12272029f493Smrg pci_sys->num_devices = 0; 12282029f493Smrg err = pci_system_x86_scan_bus (0); 12292029f493Smrg if (err) 12302029f493Smrg { 12312029f493Smrg x86_disable_io (); 123248becaf0Smrg if (pci_sys->num_devices) 123348becaf0Smrg { 123448becaf0Smrg free (pci_sys->devices); 123548becaf0Smrg } 12362029f493Smrg free (pci_sys); 12372029f493Smrg pci_sys = NULL; 12382029f493Smrg return err; 123928d65773Smrg } 124028d65773Smrg 124148becaf0Smrg sort_devices (); 124228d65773Smrg return 0; 124328d65773Smrg} 1244