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, &reg, 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, &reg, 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, &reg_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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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