x86_pci.c revision 86ea1d58
128d65773Smrg/* 286ea1d58Smrg * Copyright (c) 2009, 2012 Samuel Thibault 328d65773Smrg * Heavily inspired from the freebsd, netbsd, and openbsd backends 428d65773Smrg * (C) Copyright Eric Anholt 2006 528d65773Smrg * (C) Copyright IBM Corporation 2006 628d65773Smrg * Copyright (c) 2008 Juan Romero Pardines 728d65773Smrg * Copyright (c) 2008 Mark Kettenis 828d65773Smrg * 928d65773Smrg * Permission to use, copy, modify, and distribute this software for any 1028d65773Smrg * purpose with or without fee is hereby granted, provided that the above 1128d65773Smrg * copyright notice and this permission notice appear in all copies. 1228d65773Smrg * 1328d65773Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1428d65773Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1528d65773Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1628d65773Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1728d65773Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1828d65773Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1928d65773Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2028d65773Smrg */ 2128d65773Smrg 2228d65773Smrg#define _GNU_SOURCE 2328d65773Smrg#include <unistd.h> 2428d65773Smrg#include <stdio.h> 2528d65773Smrg#include <stdlib.h> 2628d65773Smrg#include <errno.h> 2728d65773Smrg#include <fcntl.h> 2828d65773Smrg#include <sys/mman.h> 2928d65773Smrg#include <string.h> 3028d65773Smrg#include <strings.h> 3128d65773Smrg 3228d65773Smrg#include "pciaccess.h" 3328d65773Smrg#include "pciaccess_private.h" 3428d65773Smrg 3528d65773Smrg#if defined(__GNU__) 3628d65773Smrg 3728d65773Smrg#include <sys/io.h> 3828d65773Smrg 3928d65773Smrgstatic int 4028d65773Smrgx86_enable_io(void) 4128d65773Smrg{ 4228d65773Smrg if (!ioperm(0, 0xffff, 1)) 4328d65773Smrg return 0; 4428d65773Smrg return errno; 4528d65773Smrg} 4628d65773Smrg 4728d65773Smrgstatic int 4828d65773Smrgx86_disable_io(void) 4928d65773Smrg{ 5028d65773Smrg if (!ioperm(0, 0xffff, 0)) 5128d65773Smrg return 0; 5228d65773Smrg return errno; 5328d65773Smrg} 5428d65773Smrg 5528d65773Smrg#elif defined(__GLIBC__) 5628d65773Smrg 5728d65773Smrg#include <sys/io.h> 5828d65773Smrg 5928d65773Smrgstatic int 6028d65773Smrgx86_enable_io(void) 6128d65773Smrg{ 6228d65773Smrg if (!iopl(3)) 6328d65773Smrg return 0; 6428d65773Smrg return errno; 6528d65773Smrg} 6628d65773Smrg 6728d65773Smrgstatic int 6828d65773Smrgx86_disable_io(void) 6928d65773Smrg{ 7028d65773Smrg if (!iopl(0)) 7128d65773Smrg return 0; 7228d65773Smrg return errno; 7328d65773Smrg} 7428d65773Smrg 7528d65773Smrg#else 7628d65773Smrg 7728d65773Smrg#error How to enable IO ports on this system? 7828d65773Smrg 7928d65773Smrg#endif 8028d65773Smrg 8128d65773Smrg#define PCI_VENDOR(reg) ((reg) & 0xFFFF) 8228d65773Smrg#define PCI_VENDOR_INVALID 0xFFFF 8328d65773Smrg 8428d65773Smrg#define PCI_VENDOR_ID 0x00 8528d65773Smrg#define PCI_SUB_VENDOR_ID 0x2c 8628d65773Smrg#define PCI_VENDOR_ID_COMPAQ 0x0e11 8728d65773Smrg#define PCI_VENDOR_ID_INTEL 0x8086 8828d65773Smrg 8928d65773Smrg#define PCI_DEVICE(reg) (((reg) >> 16) & 0xFFFF) 9028d65773Smrg#define PCI_DEVICE_INVALID 0xFFFF 9128d65773Smrg 9228d65773Smrg#define PCI_CLASS 0x08 9328d65773Smrg#define PCI_CLASS_DEVICE 0x0a 9428d65773Smrg#define PCI_CLASS_DISPLAY_VGA 0x0300 9528d65773Smrg#define PCI_CLASS_BRIDGE_HOST 0x0600 9628d65773Smrg 9728d65773Smrg#define PCIC_DISPLAY 0x03 9828d65773Smrg#define PCIS_DISPLAY_VGA 0x00 9928d65773Smrg 10028d65773Smrg#define PCI_HDRTYPE 0x0E 10128d65773Smrg#define PCI_IRQ 0x3C 10228d65773Smrg 10328d65773Smrgstruct pci_system_x86 { 10428d65773Smrg struct pci_system system; 10528d65773Smrg int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size); 10628d65773Smrg int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size); 10728d65773Smrg}; 10828d65773Smrg 10928d65773Smrgstatic int 11028d65773Smrgpci_system_x86_conf1_probe(void) 11128d65773Smrg{ 11228d65773Smrg unsigned long sav; 11328d65773Smrg int res = ENODEV; 11428d65773Smrg 11528d65773Smrg outb(0x01, 0xCFB); 11628d65773Smrg sav = inl(0xCF8); 11728d65773Smrg outl(0x80000000, 0xCF8); 11828d65773Smrg if (inl(0xCF8) == 0x80000000) 11928d65773Smrg res = 0; 12028d65773Smrg outl(sav, 0xCF8); 12128d65773Smrg 12228d65773Smrg return res; 12328d65773Smrg} 12428d65773Smrg 12528d65773Smrgstatic int 12628d65773Smrgpci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size) 12728d65773Smrg{ 12828d65773Smrg unsigned addr = 0xCFC + (reg & 3); 12928d65773Smrg unsigned long sav; 13028d65773Smrg int ret = 0; 13128d65773Smrg 13228d65773Smrg if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3) 13328d65773Smrg return EIO; 13428d65773Smrg 13528d65773Smrg sav = inl(0xCF8); 13628d65773Smrg outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8); 13728d65773Smrg /* NOTE: x86 is already LE */ 13828d65773Smrg switch (size) { 13928d65773Smrg case 1: { 14028d65773Smrg uint8_t *val = data; 14128d65773Smrg *val = inb(addr); 14228d65773Smrg break; 14328d65773Smrg } 14428d65773Smrg case 2: { 14528d65773Smrg uint16_t *val = data; 14628d65773Smrg *val = inw(addr); 14728d65773Smrg break; 14828d65773Smrg } 14928d65773Smrg case 4: { 15028d65773Smrg uint32_t *val = data; 15128d65773Smrg *val = inl(addr); 15228d65773Smrg break; 15328d65773Smrg } 15428d65773Smrg } 15528d65773Smrg outl(sav, 0xCF8); 15628d65773Smrg 15728d65773Smrg return ret; 15828d65773Smrg} 15928d65773Smrg 16028d65773Smrgstatic int 16128d65773Smrgpci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size) 16228d65773Smrg{ 16328d65773Smrg unsigned addr = 0xCFC + (reg & 3); 16428d65773Smrg unsigned long sav; 16528d65773Smrg int ret = 0; 16628d65773Smrg 16728d65773Smrg if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3) 16828d65773Smrg return EIO; 16928d65773Smrg 17028d65773Smrg sav = inl(0xCF8); 17128d65773Smrg outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8); 17228d65773Smrg /* NOTE: x86 is already LE */ 17328d65773Smrg switch (size) { 17428d65773Smrg case 1: { 17528d65773Smrg const uint8_t *val = data; 17628d65773Smrg outb(*val, addr); 17728d65773Smrg break; 17828d65773Smrg } 17928d65773Smrg case 2: { 18028d65773Smrg const uint16_t *val = data; 18128d65773Smrg outw(*val, addr); 18228d65773Smrg break; 18328d65773Smrg } 18428d65773Smrg case 4: { 18528d65773Smrg const uint32_t *val = data; 18628d65773Smrg outl(*val, addr); 18728d65773Smrg break; 18828d65773Smrg } 18928d65773Smrg } 19028d65773Smrg outl(sav, 0xCF8); 19128d65773Smrg 19228d65773Smrg return ret; 19328d65773Smrg} 19428d65773Smrg 19528d65773Smrgstatic int 19628d65773Smrgpci_system_x86_conf2_probe(void) 19728d65773Smrg{ 19828d65773Smrg outb(0, 0xCFB); 19928d65773Smrg outb(0, 0xCF8); 20028d65773Smrg outb(0, 0xCFA); 20128d65773Smrg if (inb(0xCF8) == 0 && inb(0xCFA) == 0) 20228d65773Smrg return 0; 20328d65773Smrg 20428d65773Smrg return ENODEV; 20528d65773Smrg} 20628d65773Smrg 20728d65773Smrgstatic int 20828d65773Smrgpci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size) 20928d65773Smrg{ 21028d65773Smrg unsigned addr = 0xC000 | dev << 8 | reg; 21128d65773Smrg int ret = 0; 21228d65773Smrg 21328d65773Smrg if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) 21428d65773Smrg return EIO; 21528d65773Smrg 21628d65773Smrg outb((func << 1) | 0xF0, 0xCF8); 21728d65773Smrg outb(bus, 0xCFA); 21828d65773Smrg /* NOTE: x86 is already LE */ 21928d65773Smrg switch (size) { 22028d65773Smrg case 1: { 22128d65773Smrg uint8_t *val = data; 22228d65773Smrg *val = inb(addr); 22328d65773Smrg break; 22428d65773Smrg } 22528d65773Smrg case 2: { 22628d65773Smrg uint16_t *val = data; 22728d65773Smrg *val = inw(addr); 22828d65773Smrg break; 22928d65773Smrg } 23028d65773Smrg case 4: { 23128d65773Smrg uint32_t *val = data; 23228d65773Smrg *val = inl(addr); 23328d65773Smrg break; 23428d65773Smrg } 23528d65773Smrg default: 23628d65773Smrg ret = EIO; 23728d65773Smrg break; 23828d65773Smrg } 23928d65773Smrg outb(0, 0xCF8); 24028d65773Smrg 24128d65773Smrg return ret; 24228d65773Smrg} 24328d65773Smrg 24428d65773Smrgstatic int 24528d65773Smrgpci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size) 24628d65773Smrg{ 24728d65773Smrg unsigned addr = 0xC000 | dev << 8 | reg; 24828d65773Smrg int ret = 0; 24928d65773Smrg 25028d65773Smrg if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) 25128d65773Smrg return EIO; 25228d65773Smrg 25328d65773Smrg outb((func << 1) | 0xF0, 0xCF8); 25428d65773Smrg outb(bus, 0xCFA); 25528d65773Smrg /* NOTE: x86 is already LE */ 25628d65773Smrg switch (size) { 25728d65773Smrg case 1: { 25828d65773Smrg const uint8_t *val = data; 25928d65773Smrg outb(*val, addr); 26028d65773Smrg break; 26128d65773Smrg } 26228d65773Smrg case 2: { 26328d65773Smrg const uint16_t *val = data; 26428d65773Smrg outw(*val, addr); 26528d65773Smrg break; 26628d65773Smrg } 26728d65773Smrg case 4: { 26828d65773Smrg const uint32_t *val = data; 26928d65773Smrg outl(*val, addr); 27028d65773Smrg break; 27128d65773Smrg } 27228d65773Smrg default: 27328d65773Smrg ret = EIO; 27428d65773Smrg break; 27528d65773Smrg } 27628d65773Smrg outb(0, 0xCF8); 27728d65773Smrg 27828d65773Smrg return ret; 27928d65773Smrg} 28028d65773Smrg 28128d65773Smrg/* Check that this really looks like a PCI configuration. */ 28228d65773Smrgstatic int 28328d65773Smrgpci_system_x86_check(struct pci_system_x86 *pci_sys_x86) 28428d65773Smrg{ 28528d65773Smrg int dev; 28628d65773Smrg uint16_t class, vendor; 28728d65773Smrg 28828d65773Smrg /* Look on bus 0 for a device that is a host bridge, a VGA card, 28928d65773Smrg * or an intel or compaq device. */ 29028d65773Smrg 29128d65773Smrg for (dev = 0; dev < 32; dev++) { 29228d65773Smrg if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class))) 29328d65773Smrg continue; 29428d65773Smrg if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) 29528d65773Smrg return 0; 29628d65773Smrg if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor))) 29728d65773Smrg continue; 29828d65773Smrg if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) 29928d65773Smrg return 0; 30028d65773Smrg } 30128d65773Smrg 30228d65773Smrg return ENODEV; 30328d65773Smrg} 30428d65773Smrg 30528d65773Smrgstatic int 30628d65773Smrgpci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev) 30728d65773Smrg{ 30828d65773Smrg uint8_t hdr; 30928d65773Smrg int err; 31028d65773Smrg 31128d65773Smrg err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr)); 31228d65773Smrg 31328d65773Smrg if (err) 31428d65773Smrg return err; 31528d65773Smrg 31628d65773Smrg return hdr & 0x80 ? 8 : 1; 31728d65773Smrg} 31828d65773Smrg 31928d65773Smrg/** 32028d65773Smrg * Read a VGA rom using the 0xc0000 mapping. 32128d65773Smrg */ 32228d65773Smrgstatic int 32328d65773Smrgpci_device_x86_read_rom(struct pci_device *dev, void *buffer) 32428d65773Smrg{ 32528d65773Smrg void *bios; 32628d65773Smrg int memfd; 32728d65773Smrg 32828d65773Smrg if ((dev->device_class & 0x00ffff00) != 32928d65773Smrg ((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) { 33028d65773Smrg return ENOSYS; 33128d65773Smrg } 33228d65773Smrg 333cad31331Smrg memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC); 33428d65773Smrg if (memfd == -1) 33528d65773Smrg return errno; 33628d65773Smrg 33728d65773Smrg bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000); 33828d65773Smrg if (bios == MAP_FAILED) { 33928d65773Smrg close(memfd); 34028d65773Smrg return errno; 34128d65773Smrg } 34228d65773Smrg 34328d65773Smrg memcpy(buffer, bios, dev->rom_size); 34428d65773Smrg 34528d65773Smrg munmap(bios, dev->rom_size); 34628d65773Smrg close(memfd); 34728d65773Smrg 34828d65773Smrg return 0; 34928d65773Smrg} 35028d65773Smrg 35128d65773Smrg/** Returns the number of regions (base address registers) the device has */ 35228d65773Smrgstatic int 35328d65773Smrgpci_device_x86_get_num_regions(uint8_t header_type) 35428d65773Smrg{ 35528d65773Smrg switch (header_type & 0x7f) { 35628d65773Smrg case 0: 35728d65773Smrg return 6; 35828d65773Smrg case 1: 35928d65773Smrg return 2; 36028d65773Smrg case 2: 36128d65773Smrg return 1; 36228d65773Smrg default: 36328d65773Smrg fprintf(stderr,"unknown header type %02x\n", header_type); 36428d65773Smrg return 0; 36528d65773Smrg } 36628d65773Smrg} 36728d65773Smrg 36828d65773Smrg/** Masks out the flag bigs of the base address register value */ 36928d65773Smrgstatic uint32_t 37028d65773Smrgget_map_base( uint32_t val ) 37128d65773Smrg{ 37228d65773Smrg if (val & 0x01) 37328d65773Smrg return val & ~0x03; 37428d65773Smrg else 37528d65773Smrg return val & ~0x0f; 37628d65773Smrg} 37728d65773Smrg 37828d65773Smrg/** Returns the size of a region based on the all-ones test value */ 37928d65773Smrgstatic unsigned 38028d65773Smrgget_test_val_size( uint32_t testval ) 38128d65773Smrg{ 38228d65773Smrg unsigned size = 1; 38328d65773Smrg 38428d65773Smrg if (testval == 0) 38528d65773Smrg return 0; 38628d65773Smrg 38728d65773Smrg /* Mask out the flag bits */ 38828d65773Smrg testval = get_map_base( testval ); 38928d65773Smrg if (!testval) 39028d65773Smrg return 0; 39128d65773Smrg 39228d65773Smrg while ((testval & 1) == 0) { 39328d65773Smrg size <<= 1; 39428d65773Smrg testval >>= 1; 39528d65773Smrg } 39628d65773Smrg 39728d65773Smrg return size; 39828d65773Smrg} 39928d65773Smrg 40028d65773Smrgstatic int 40128d65773Smrgpci_device_x86_probe(struct pci_device *dev) 40228d65773Smrg{ 40328d65773Smrg uint8_t irq, hdrtype; 40428d65773Smrg int err, i, bar; 40528d65773Smrg 40628d65773Smrg /* Many of the fields were filled in during initial device enumeration. 40728d65773Smrg * At this point, we need to fill in regions, rom_size, and irq. 40828d65773Smrg */ 40928d65773Smrg 41028d65773Smrg err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ); 41128d65773Smrg if (err) 41228d65773Smrg return err; 41328d65773Smrg dev->irq = irq; 41428d65773Smrg 41528d65773Smrg err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE); 41628d65773Smrg if (err) 41728d65773Smrg return err; 41828d65773Smrg 41928d65773Smrg bar = 0x10; 42028d65773Smrg for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) { 42128d65773Smrg uint32_t addr, testval; 42228d65773Smrg 42328d65773Smrg /* Get the base address */ 42428d65773Smrg err = pci_device_cfg_read_u32(dev, &addr, bar); 42528d65773Smrg if (err != 0) 42628d65773Smrg continue; 42728d65773Smrg 42828d65773Smrg /* Test write all ones to the register, then restore it. */ 42928d65773Smrg err = pci_device_cfg_write_u32(dev, 0xffffffff, bar); 43028d65773Smrg if (err != 0) 43128d65773Smrg continue; 43228d65773Smrg pci_device_cfg_read_u32(dev, &testval, bar); 43328d65773Smrg err = pci_device_cfg_write_u32(dev, addr, bar); 43428d65773Smrg 43528d65773Smrg if (addr & 0x01) 43628d65773Smrg dev->regions[i].is_IO = 1; 43728d65773Smrg if (addr & 0x04) 43828d65773Smrg dev->regions[i].is_64 = 1; 43928d65773Smrg if (addr & 0x08) 44028d65773Smrg dev->regions[i].is_prefetchable = 1; 44128d65773Smrg 44228d65773Smrg /* Set the size */ 44328d65773Smrg dev->regions[i].size = get_test_val_size(testval); 44428d65773Smrg 44528d65773Smrg /* Set the base address value */ 44628d65773Smrg if (dev->regions[i].is_64) { 44728d65773Smrg uint32_t top; 44828d65773Smrg 44928d65773Smrg err = pci_device_cfg_read_u32(dev, &top, bar + 4); 45028d65773Smrg if (err != 0) 45128d65773Smrg continue; 45228d65773Smrg 45328d65773Smrg dev->regions[i].base_addr = ((uint64_t)top << 32) | 45428d65773Smrg get_map_base(addr); 45528d65773Smrg bar += 4; 45628d65773Smrg i++; 45728d65773Smrg } else { 45828d65773Smrg dev->regions[i].base_addr = get_map_base(addr); 45928d65773Smrg } 46028d65773Smrg } 46128d65773Smrg 46228d65773Smrg /* If it's a VGA device, set up the rom size for read_rom using the 46328d65773Smrg * 0xc0000 mapping. 46428d65773Smrg */ 46528d65773Smrg if ((dev->device_class & 0x00ffff00) == 46628d65773Smrg ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8))) 46728d65773Smrg { 46828d65773Smrg dev->rom_size = 64 * 1024; 46928d65773Smrg } 47028d65773Smrg 47128d65773Smrg return 0; 47228d65773Smrg} 47328d65773Smrg 47428d65773Smrgstatic int 47528d65773Smrgpci_device_x86_map_range(struct pci_device *dev, 47628d65773Smrg struct pci_device_mapping *map) 47728d65773Smrg{ 478cad31331Smrg int memfd = open("/dev/mem", O_RDWR | O_CLOEXEC); 47928d65773Smrg int prot = PROT_READ; 48028d65773Smrg 48128d65773Smrg if (memfd == -1) 48228d65773Smrg return errno; 48328d65773Smrg 48428d65773Smrg if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE) 48528d65773Smrg prot |= PROT_WRITE; 48628d65773Smrg 48728d65773Smrg map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base); 48828d65773Smrg close(memfd); 48928d65773Smrg if (map->memory == MAP_FAILED) 49028d65773Smrg return errno; 49128d65773Smrg 49228d65773Smrg return 0; 49328d65773Smrg} 49428d65773Smrg 49528d65773Smrgstatic int 49628d65773Smrgpci_device_x86_read(struct pci_device *dev, void *data, 49728d65773Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read) 49828d65773Smrg{ 49928d65773Smrg struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys; 50028d65773Smrg int err; 50128d65773Smrg 50228d65773Smrg *bytes_read = 0; 50328d65773Smrg while (size > 0) { 50428d65773Smrg int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1); 50528d65773Smrg if (toread > size) 50628d65773Smrg toread = size; 50728d65773Smrg 50828d65773Smrg err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread); 50928d65773Smrg if (err) 51028d65773Smrg return err; 51128d65773Smrg 51228d65773Smrg offset += toread; 51328d65773Smrg data = (char*)data + toread; 51428d65773Smrg size -= toread; 51528d65773Smrg *bytes_read += toread; 51628d65773Smrg } 51728d65773Smrg return 0; 51828d65773Smrg} 51928d65773Smrg 52028d65773Smrgstatic int 52128d65773Smrgpci_device_x86_write(struct pci_device *dev, const void *data, 52228d65773Smrg pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written) 52328d65773Smrg{ 52428d65773Smrg struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys; 52528d65773Smrg int err; 52628d65773Smrg 52728d65773Smrg *bytes_written = 0; 52828d65773Smrg while (size > 0) { 52928d65773Smrg int towrite = 4; 53028d65773Smrg if (towrite > size) 53128d65773Smrg towrite = size; 53228d65773Smrg if (towrite > 4 - (offset & 0x3)) 53328d65773Smrg towrite = 4 - (offset & 0x3); 53428d65773Smrg 53528d65773Smrg err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite); 53628d65773Smrg if (err) 53728d65773Smrg return err; 53828d65773Smrg 53928d65773Smrg offset += towrite; 54028d65773Smrg data = (const char*)data + towrite; 54128d65773Smrg size -= towrite; 54228d65773Smrg *bytes_written += towrite; 54328d65773Smrg } 54428d65773Smrg return 0; 54528d65773Smrg} 54628d65773Smrg 54728d65773Smrgstatic void 54828d65773Smrgpci_system_x86_destroy(void) 54928d65773Smrg{ 55028d65773Smrg x86_disable_io(); 55128d65773Smrg} 55228d65773Smrg 55386ea1d58Smrgstatic struct pci_io_handle * 55486ea1d58Smrgpci_device_x86_open_legacy_io(struct pci_io_handle *ret, 55586ea1d58Smrg struct pci_device *dev, pciaddr_t base, pciaddr_t size) 55686ea1d58Smrg{ 55786ea1d58Smrg x86_enable_io(); 55886ea1d58Smrg 55986ea1d58Smrg ret->base = base; 56086ea1d58Smrg ret->size = size; 56186ea1d58Smrg 56286ea1d58Smrg return ret; 56386ea1d58Smrg} 56486ea1d58Smrg 56586ea1d58Smrgstatic void 56686ea1d58Smrgpci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle) 56786ea1d58Smrg{ 56886ea1d58Smrg /* Like in the Linux case, do not disable I/O, as it may be opened several 56986ea1d58Smrg * times, and closed fewer times. */ 57086ea1d58Smrg /* x86_disable_io(); */ 57186ea1d58Smrg} 57286ea1d58Smrg 57386ea1d58Smrgstatic uint32_t 57486ea1d58Smrgpci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg) 57586ea1d58Smrg{ 57686ea1d58Smrg return inl(reg + handle->base); 57786ea1d58Smrg} 57886ea1d58Smrg 57986ea1d58Smrgstatic uint16_t 58086ea1d58Smrgpci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg) 58186ea1d58Smrg{ 58286ea1d58Smrg return inw(reg + handle->base); 58386ea1d58Smrg} 58486ea1d58Smrg 58586ea1d58Smrgstatic uint8_t 58686ea1d58Smrgpci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg) 58786ea1d58Smrg{ 58886ea1d58Smrg return inb(reg + handle->base); 58986ea1d58Smrg} 59086ea1d58Smrg 59186ea1d58Smrgstatic void 59286ea1d58Smrgpci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg, 59386ea1d58Smrg uint32_t data) 59486ea1d58Smrg{ 59586ea1d58Smrg outl(data, reg + handle->base); 59686ea1d58Smrg} 59786ea1d58Smrg 59886ea1d58Smrgstatic void 59986ea1d58Smrgpci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg, 60086ea1d58Smrg uint16_t data) 60186ea1d58Smrg{ 60286ea1d58Smrg outw(data, reg + handle->base); 60386ea1d58Smrg} 60486ea1d58Smrg 60586ea1d58Smrgstatic void 60686ea1d58Smrgpci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg, 60786ea1d58Smrg uint8_t data) 60886ea1d58Smrg{ 60986ea1d58Smrg outb(data, reg + handle->base); 61086ea1d58Smrg} 61186ea1d58Smrg 61286ea1d58Smrgstatic int 61386ea1d58Smrgpci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base, 61486ea1d58Smrg pciaddr_t size, unsigned map_flags, void **addr) 61586ea1d58Smrg{ 61686ea1d58Smrg struct pci_device_mapping map; 61786ea1d58Smrg int err; 61886ea1d58Smrg 61986ea1d58Smrg map.base = base; 62086ea1d58Smrg map.size = size; 62186ea1d58Smrg map.flags = map_flags; 62286ea1d58Smrg err = pci_device_x86_map_range(dev, &map); 62386ea1d58Smrg *addr = map.memory; 62486ea1d58Smrg 62586ea1d58Smrg return err; 62686ea1d58Smrg} 62786ea1d58Smrg 62886ea1d58Smrgstatic int 62986ea1d58Smrgpci_device_x86_unmap_legacy(struct pci_device *dev, void *addr, 63086ea1d58Smrg pciaddr_t size) 63186ea1d58Smrg{ 63286ea1d58Smrg struct pci_device_mapping map; 63386ea1d58Smrg 63486ea1d58Smrg map.size = size; 63586ea1d58Smrg map.flags = 0; 63686ea1d58Smrg map.memory = addr; 63786ea1d58Smrg 63886ea1d58Smrg return pci_device_generic_unmap_range(dev, &map); 63986ea1d58Smrg} 64086ea1d58Smrg 64128d65773Smrgstatic const struct pci_system_methods x86_pci_methods = { 64228d65773Smrg .destroy = pci_system_x86_destroy, 64328d65773Smrg .read_rom = pci_device_x86_read_rom, 64428d65773Smrg .probe = pci_device_x86_probe, 64528d65773Smrg .map_range = pci_device_x86_map_range, 64628d65773Smrg .unmap_range = pci_device_generic_unmap_range, 64728d65773Smrg .read = pci_device_x86_read, 64828d65773Smrg .write = pci_device_x86_write, 64928d65773Smrg .fill_capabilities = pci_fill_capabilities_generic, 65086ea1d58Smrg .open_legacy_io = pci_device_x86_open_legacy_io, 65186ea1d58Smrg .close_io = pci_device_x86_close_io, 65286ea1d58Smrg .read32 = pci_device_x86_read32, 65386ea1d58Smrg .read16 = pci_device_x86_read16, 65486ea1d58Smrg .read8 = pci_device_x86_read8, 65586ea1d58Smrg .write32 = pci_device_x86_write32, 65686ea1d58Smrg .write16 = pci_device_x86_write16, 65786ea1d58Smrg .write8 = pci_device_x86_write8, 65886ea1d58Smrg .map_legacy = pci_device_x86_map_legacy, 65986ea1d58Smrg .unmap_legacy = pci_device_x86_unmap_legacy, 66028d65773Smrg}; 66128d65773Smrg 66228d65773Smrgstatic int pci_probe(struct pci_system_x86 *pci_sys_x86) 66328d65773Smrg{ 66428d65773Smrg if (pci_system_x86_conf1_probe() == 0) { 66528d65773Smrg pci_sys_x86->read = pci_system_x86_conf1_read; 66628d65773Smrg pci_sys_x86->write = pci_system_x86_conf1_write; 66728d65773Smrg if (pci_system_x86_check(pci_sys_x86) == 0) 66828d65773Smrg return 0; 66928d65773Smrg } 67028d65773Smrg 67128d65773Smrg if (pci_system_x86_conf2_probe() == 0) { 67228d65773Smrg pci_sys_x86->read = pci_system_x86_conf2_read; 67328d65773Smrg pci_sys_x86->write = pci_system_x86_conf2_write; 67428d65773Smrg if (pci_system_x86_check(pci_sys_x86) == 0) 67528d65773Smrg return 0; 67628d65773Smrg } 67728d65773Smrg 67828d65773Smrg return ENODEV; 67928d65773Smrg} 68028d65773Smrg 68128d65773Smrg_pci_hidden int 68228d65773Smrgpci_system_x86_create(void) 68328d65773Smrg{ 68428d65773Smrg struct pci_device_private *device; 68528d65773Smrg int ret, bus, dev, ndevs, func, nfuncs; 68628d65773Smrg struct pci_system_x86 *pci_sys_x86; 68728d65773Smrg uint32_t reg; 68828d65773Smrg 68928d65773Smrg ret = x86_enable_io(); 69028d65773Smrg if (ret) 69128d65773Smrg return ret; 69228d65773Smrg 69328d65773Smrg pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86)); 69428d65773Smrg if (pci_sys_x86 == NULL) { 69528d65773Smrg x86_disable_io(); 69628d65773Smrg return ENOMEM; 69728d65773Smrg } 69828d65773Smrg pci_sys = &pci_sys_x86->system; 69928d65773Smrg 70028d65773Smrg ret = pci_probe(pci_sys_x86); 70128d65773Smrg if (ret) { 70228d65773Smrg x86_disable_io(); 70328d65773Smrg free(pci_sys_x86); 70428d65773Smrg pci_sys = NULL; 70528d65773Smrg return ret; 70628d65773Smrg } 70728d65773Smrg 70828d65773Smrg pci_sys->methods = &x86_pci_methods; 70928d65773Smrg 71028d65773Smrg ndevs = 0; 71128d65773Smrg for (bus = 0; bus < 256; bus++) { 71228d65773Smrg for (dev = 0; dev < 32; dev++) { 71328d65773Smrg nfuncs = pci_nfuncs(pci_sys_x86, bus, dev); 71428d65773Smrg for (func = 0; func < nfuncs; func++) { 71528d65773Smrg if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, ®, sizeof(reg)) != 0) 71628d65773Smrg continue; 71728d65773Smrg if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || 71828d65773Smrg PCI_VENDOR(reg) == 0) 71928d65773Smrg continue; 72028d65773Smrg ndevs++; 72128d65773Smrg } 72228d65773Smrg } 72328d65773Smrg } 72428d65773Smrg 72528d65773Smrg pci_sys->num_devices = ndevs; 72628d65773Smrg pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private)); 72728d65773Smrg if (pci_sys->devices == NULL) { 72828d65773Smrg x86_disable_io(); 72928d65773Smrg free(pci_sys_x86); 73028d65773Smrg pci_sys = NULL; 73128d65773Smrg return ENOMEM; 73228d65773Smrg } 73328d65773Smrg 73428d65773Smrg device = pci_sys->devices; 73528d65773Smrg for (bus = 0; bus < 256; bus++) { 73628d65773Smrg for (dev = 0; dev < 32; dev++) { 73728d65773Smrg nfuncs = pci_nfuncs(pci_sys_x86, bus, dev); 73828d65773Smrg for (func = 0; func < nfuncs; func++) { 73928d65773Smrg if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, ®, sizeof(reg)) != 0) 74028d65773Smrg continue; 74128d65773Smrg if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || 74228d65773Smrg PCI_VENDOR(reg) == 0) 74328d65773Smrg continue; 74428d65773Smrg device->base.domain = 0; 74528d65773Smrg device->base.bus = bus; 74628d65773Smrg device->base.dev = dev; 74728d65773Smrg device->base.func = func; 74828d65773Smrg device->base.vendor_id = PCI_VENDOR(reg); 74928d65773Smrg device->base.device_id = PCI_DEVICE(reg); 75028d65773Smrg 75128d65773Smrg if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, ®, sizeof(reg)) != 0) 75228d65773Smrg continue; 75328d65773Smrg device->base.device_class = reg >> 8; 75428d65773Smrg device->base.revision = reg & 0xFF; 75528d65773Smrg 75628d65773Smrg if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, ®, sizeof(reg)) != 0) 75728d65773Smrg continue; 75828d65773Smrg device->base.subvendor_id = PCI_VENDOR(reg); 75928d65773Smrg device->base.subdevice_id = PCI_DEVICE(reg); 76028d65773Smrg 76128d65773Smrg device++; 76228d65773Smrg } 76328d65773Smrg } 76428d65773Smrg } 76528d65773Smrg 76628d65773Smrg return 0; 76728d65773Smrg} 768