x86_pci.c revision 48becaf0
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, &reg, 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, &reg, 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, &reg_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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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