diff options
author | Damien Zammit <damien@zamaudio.com> | 2019-11-03 21:35:57 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2019-11-03 21:37:57 +0100 |
commit | b160d6f3b3cdcd6a293c33cd89dcc46ab54c3264 (patch) | |
tree | babcc0b5db069672277131e914beef6d6b4dddc5 /pci-arbiter/x86_pci.c | |
parent | 084e5a86e5eca77cec49e08e0d83fe8266eca91b (diff) | |
download | hurd-b160d6f3b3cdcd6a293c33cd89dcc46ab54c3264.tar.gz hurd-b160d6f3b3cdcd6a293c33cd89dcc46ab54c3264.tar.bz2 hurd-b160d6f3b3cdcd6a293c33cd89dcc46ab54c3264.zip |
pci-arbiter: Use libpciaccess instead of embedding it
This patch removes all embedded pciaccess code from the arbiter
and instead uses the external pciaccess library.
* pci-arbiter/Makefile:
* Remove pci_access.c and x86_pci.c from the sources.
* pci-arbiter/func_files.c:
* io_config_file: Use a harcoded PCI config size.
* read_rom_file:
Grab the full rom first, then return the
requested amount.
* pci-arbiter/main.c:
* main: Call create_fs_tree() w/o pci_sys.
Since it's not part of the translator anymore.
* pci-arbiter/netfs_impl.c:
* netfs_attempt_read:
Send pci_device_cfg_read() as the read op.
* netfs_attempt_write:
Send pci_device_cfg_write() as the write op.
* pci-arbiter/pci-ops.c:
* S_pci_conf_read: Call libpciaccess' pci_device_cfg_read().
* S_pci_conf_write: Call libpciaccess' pci_device_cfg_write().
* S_pci_get_dev_rom:
Set rom.base_addr to zero for the moment, until
libpciaccess esposes it properly.
* pci-arbiter/pci_access.c: Deleted
* pci-arbiter/pci_access.h: Deleted
* pci-arbiter/pcifs.c:
* create_fs_tree:
Remove the pci_sys parameter.
Use libpciaccess' iterator.
Use a hardcoded config space size.
* pci-arbiter/pcifs.h: Definitions for changes in pcifs.c.
* pci-arbiter/x86_pci.c: Deleted.
* pci-arbiter/x86_pci.h: Deleted.
Diffstat (limited to 'pci-arbiter/x86_pci.c')
-rw-r--r-- | pci-arbiter/x86_pci.c | 843 |
1 files changed, 0 insertions, 843 deletions
diff --git a/pci-arbiter/x86_pci.c b/pci-arbiter/x86_pci.c deleted file mode 100644 index 9cf1f54a..00000000 --- a/pci-arbiter/x86_pci.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Copyright (c) 2017 Joan Lledó - * Copyright (c) 2009, 2012, 2018 Samuel Thibault - * Heavily inspired from the freebsd, netbsd, and openbsd backends - * (C) Copyright Eric Anholt 2006 - * (C) Copyright IBM Corporation 2006 - * Copyright (c) 2008 Juan Romero Pardines - * Copyright (c) 2008 Mark Kettenis - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * PCI backend for x86 (32 and 64 bit) architectures. - * - * Following code is borrowed from libpciaccess: - * https://cgit.freedesktop.org/xorg/lib/libpciaccess/ - */ - -#include "x86_pci.h" - -#include <unistd.h> -#include <stdlib.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/io.h> -#include <string.h> - -#include "pci_access.h" - -#define PCI_VENDOR(reg) ((reg) & 0xFFFF) -#define PCI_VENDOR_INVALID 0xFFFF - -#define PCI_VENDOR_ID 0x00 -#define PCI_VENDOR_ID_COMPAQ 0x0e11 -#define PCI_VENDOR_ID_INTEL 0x8086 - -#define PCI_CLASS 0x08 -#define PCI_CLASS_DEVICE 0x0a -#define PCI_CLASS_DISPLAY_VGA 0x0300 -#define PCI_CLASS_BRIDGE_HOST 0x0600 - -#define PCI_BAR_ADDR_0 0x10 -#define PCI_XROMBAR_ADDR_00 0x30 -#define PCI_XROMBAR_ADDR_01 0x38 - -#define PCI_HDRTYPE 0x0E -#define PCI_HDRTYPE_DEVICE 0x00 -#define PCI_HDRTYPE_BRIDGE 0x01 -#define PCI_HDRTYPE_CARDBUS 0x02 - -#define PCI_COMMAND 0x04 -#define PCI_SECONDARY_BUS 0x19 - -#define PCI_CONFIG_SIZE 256 - -static error_t -x86_enable_io (void) -{ - if (!ioperm (0, 0xffff, 1)) - return 0; - return errno; -} - -static error_t -x86_disable_io (void) -{ - if (!ioperm (0, 0xffff, 0)) - return 0; - return errno; -} - -static error_t -pci_system_x86_conf1_probe (void) -{ - unsigned long sav; - int res = ENODEV; - - outb (0x01, 0xCFB); - sav = inl (0xCF8); - outl (0x80000000, 0xCF8); - if (inl (0xCF8) == 0x80000000) - res = 0; - outl (sav, 0xCF8); - - return res; -} - -static error_t -pci_system_x86_conf1_read (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xCFC + (reg & 3); - unsigned long sav; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 - || size == 3) - return EIO; - - sav = inl (0xCF8); - outl (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), - 0xCF8); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - uint8_t *val = data; - *val = inb (addr); - break; - } - case 2: - { - uint16_t *val = data; - *val = inw (addr); - break; - } - case 4: - { - uint32_t *val = data; - *val = inl (addr); - break; - } - } - outl (sav, 0xCF8); - - return ret; -} - -static error_t -pci_system_x86_conf1_write (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xCFC + (reg & 3); - unsigned long sav; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 - || size == 3) - return EIO; - - sav = inl (0xCF8); - outl (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), - 0xCF8); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - const uint8_t *val = data; - outb (*val, addr); - break; - } - case 2: - { - const uint16_t *val = data; - outw (*val, addr); - break; - } - case 4: - { - const uint32_t *val = data; - outl (*val, addr); - break; - } - } - outl (sav, 0xCF8); - - return ret; -} - -static error_t -pci_system_x86_conf2_probe (void) -{ - outb (0, 0xCFB); - outb (0, 0xCF8); - outb (0, 0xCFA); - if (inb (0xCF8) == 0 && inb (0xCFA) == 0) - return 0; - - return ENODEV; -} - -static error_t -pci_system_x86_conf2_read (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xC000 | dev << 8 | reg; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) - return EIO; - - outb ((func << 1) | 0xF0, 0xCF8); - outb (bus, 0xCFA); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - uint8_t *val = data; - *val = inb (addr); - break; - } - case 2: - { - uint16_t *val = data; - *val = inw (addr); - break; - } - case 4: - { - uint32_t *val = data; - *val = inl (addr); - break; - } - default: - ret = EIO; - break; - } - outb (0, 0xCF8); - - return ret; -} - -static error_t -pci_system_x86_conf2_write (unsigned bus, unsigned dev, unsigned func, - pciaddr_t reg, void *data, unsigned size) -{ - unsigned addr = 0xC000 | dev << 8 | reg; - error_t ret = 0; - - if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100) - return EIO; - - outb ((func << 1) | 0xF0, 0xCF8); - outb (bus, 0xCFA); - /* NOTE: x86 is already LE */ - switch (size) - { - case 1: - { - const uint8_t *val = data; - outb (*val, addr); - break; - } - case 2: - { - const uint16_t *val = data; - outw (*val, addr); - break; - } - case 4: - { - const uint32_t *val = data; - outl (*val, addr); - break; - } - default: - ret = EIO; - break; - } - outb (0, 0xCF8); - - return ret; -} - -/* Returns the number of regions (base address registers) the device has */ -static int -pci_device_x86_get_num_regions (uint8_t header_type) -{ - switch (header_type & 0x7f) - { - case 0: - return 6; - case 1: - return 2; - case 2: - return 1; - default: - return 0; - } -} - -/* Masks out the flag bigs of the base address register value */ -static uint32_t -get_map_base (uint32_t val) -{ - if (val & 0x01) - return val & ~0x03; - else - return val & ~0x0f; -} - -/* Returns the size of a region based on the all-ones test value */ -static unsigned -get_test_val_size (uint32_t testval) -{ - unsigned size = 1; - - if (testval == 0) - return 0; - - /* Mask out the flag bits */ - testval = get_map_base (testval); - if (!testval) - return 0; - - while ((testval & 1) == 0) - { - size <<= 1; - testval >>= 1; - } - - return size; -} - -/* Read BAR `reg_num' in `dev' and map the data if any */ -static error_t -pci_device_x86_region_probe (struct pci_device *dev, int reg_num) -{ - error_t err; - uint8_t offset; - uint32_t reg, addr, testval; - int memfd; - - offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; - - /* Get the base address */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - /* Test write all ones to the register, then restore it. */ - reg = 0xffffffff; - err = pci_sys->write (dev->bus, dev->dev, dev->func, offset, ®, - sizeof (reg)); - if (err) - return err; - err = pci_sys->read (dev->bus, dev->dev, dev->func, offset, &testval, - sizeof (testval)); - if (err) - return err; - err = pci_sys->write (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - if (addr & 0x01) - dev->regions[reg_num].is_IO = 1; - if (addr & 0x04) - dev->regions[reg_num].is_64 = 1; - if (addr & 0x08) - dev->regions[reg_num].is_prefetchable = 1; - - /* Set the size */ - dev->regions[reg_num].size = get_test_val_size (testval); - - /* Set the base address value */ - dev->regions[reg_num].base_addr = get_map_base (addr); - - if (dev->regions[reg_num].is_64) - { - err = - pci_sys->read (dev->bus, dev->dev, dev->func, offset + 4, &addr, - sizeof (addr)); - if (err) - return err; - - dev->regions[reg_num].base_addr |= ((uint64_t) addr << 32); - } - - if (dev->regions[reg_num].is_IO) - { - /* Enable the I/O Space bit */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - - if (!(reg & 0x1)) - { - reg |= 0x1; - - err = - pci_sys->write (dev->bus, dev->dev, dev->func, PCI_COMMAND, - ®, sizeof (reg)); - if (err) - return err; - } - - /* Clear the map pointer */ - dev->regions[reg_num].memory = 0; - } - else if (dev->regions[reg_num].size > 0) - { - /* Enable the Memory Space bit */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - - if (!(reg & 0x2)) - { - reg |= 0x2; - - err = - pci_sys->write (dev->bus, dev->dev, dev->func, PCI_COMMAND, - ®, sizeof (reg)); - if (err) - return err; - } - - /* Map the region in our space */ - memfd = open ("/dev/mem", O_RDONLY | O_CLOEXEC); - if (memfd == -1) - return errno; - - dev->regions[reg_num].memory = - mmap (NULL, dev->regions[reg_num].size, PROT_READ | PROT_WRITE, 0, - memfd, dev->regions[reg_num].base_addr); - if (dev->regions[reg_num].memory == MAP_FAILED) - { - dev->regions[reg_num].memory = 0; - close (memfd); - return errno; - } - - close (memfd); - } - - return 0; -} - -/* Read the XROMBAR in `dev' and map the data if any */ -static error_t -pci_device_x86_rom_probe (struct pci_device *dev) -{ - error_t err; - uint8_t reg_8, xrombar_addr; - uint32_t reg, reg_back; - pciaddr_t rom_size; - pciaddr_t rom_base; - void *rom_mapped; - int memfd; - - /* First we need to know which type of header is this */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, PCI_HDRTYPE, ®_8, - sizeof (reg_8)); - if (err) - return err; - - /* Get the XROMBAR register address */ - switch (reg_8 & 0x3) - { - case PCI_HDRTYPE_DEVICE: - xrombar_addr = PCI_XROMBAR_ADDR_00; - break; - case PCI_HDRTYPE_BRIDGE: - xrombar_addr = PCI_XROMBAR_ADDR_01; - break; - default: - return -1; - } - - /* Get size and physical address */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, xrombar_addr, ®, - sizeof (reg)); - if (err) - return err; - - reg_back = reg; - reg = 0xFFFFF800; /* Base address: first 21 bytes */ - err = pci_sys->write (dev->bus, dev->dev, dev->func, xrombar_addr, ®, - sizeof (reg)); - if (err) - return err; - err = pci_sys->read (dev->bus, dev->dev, dev->func, xrombar_addr, ®, - sizeof (reg)); - if (err) - return err; - - rom_size = (~reg + 1); - rom_base = reg_back & reg; - - if (rom_size == 0) - return 0; - - /* Enable the address decoder and write the physical address back */ - reg_back |= 0x1; - err = pci_sys->write - (dev->bus, dev->dev, dev->func, xrombar_addr, ®_back, - sizeof (reg_back)); - if (err) - return err; - - /* Enable the Memory Space bit */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - - if (!(reg & 0x2)) - { - reg |= 0x2; - - err = - pci_sys->write (dev->bus, dev->dev, dev->func, PCI_COMMAND, ®, - sizeof (reg)); - if (err) - return err; - } - - /* Map the ROM in our space */ - memfd = open ("/dev/mem", O_RDONLY | O_CLOEXEC); - if (memfd == -1) - return errno; - - rom_mapped = mmap (NULL, rom_size, PROT_READ, 0, memfd, rom_base); - if (rom_mapped == MAP_FAILED) - { - close (memfd); - return errno; - } - - close (memfd); - - dev->rom_size = rom_size; - dev->rom_base = rom_base; - dev->rom_memory = rom_mapped; - - return 0; -} - -/* Configure BARs and ROM */ -static error_t -pci_device_x86_probe (struct pci_device *dev) -{ - error_t err; - uint8_t hdrtype; - int i; - - /* Probe BARs */ - err = pci_sys->read (dev->bus, dev->dev, dev->func, PCI_HDRTYPE, &hdrtype, - sizeof (hdrtype)); - if (err) - return err; - - for (i = 0; i < pci_device_x86_get_num_regions (hdrtype); i++) - { - err = pci_device_x86_region_probe (dev, i); - if (err) - return err; - - if (dev->regions[i].is_64) - /* Move the pointer one BAR ahead */ - i++; - } - - /* Probe ROM */ - err = pci_device_x86_rom_probe (dev); - if (err) - return err; - - return 0; -} - -/* - * Refresh the device. Check for updates in region `reg_num' - * or in ROM if `rom' = true. `reg_num' < 0 means no region check. - */ -static error_t -pci_device_x86_refresh (struct pci_device *dev, int reg_num, int rom) -{ - error_t err; - uint8_t offset, hdrtype; - uint32_t addr; - - if (reg_num >= 0 && dev->regions[reg_num].size > 0) - { - /* Read the BAR */ - offset = PCI_BAR_ADDR_0 + 0x4 * reg_num; - err = - pci_sys->read (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - /* Check whether the region is outdated, if so, the refresh it */ - if (dev->regions[reg_num].base_addr != get_map_base (addr)) - { - err = pci_device_x86_region_probe (dev, reg_num); - if (err) - return err; - } - } - - if (rom && dev->rom_size > 0) - { - /* Read the BAR */ - err = - pci_sys->read (dev->bus, dev->dev, dev->func, PCI_HDRTYPE, &hdrtype, - sizeof (hdrtype)); - if (err) - return err; - - switch (hdrtype & 0x3) - { - case PCI_HDRTYPE_DEVICE: - offset = PCI_XROMBAR_ADDR_00; - break; - case PCI_HDRTYPE_BRIDGE: - offset = PCI_XROMBAR_ADDR_01; - break; - default: - return -1; - } - - err = pci_sys->read (dev->bus, dev->dev, dev->func, offset, &addr, - sizeof (addr)); - if (err) - return err; - - /* Check whether the ROM is outdated, if so, the refresh it */ - if (dev->rom_base != (addr & 0xFFFFF800)) - { - err = pci_device_x86_rom_probe (dev); - if (err) - return err; - } - } - - return 0; -} - -/* Check that this really looks like a PCI configuration. */ -static error_t -pci_system_x86_check (struct pci_system *pci_sys) -{ - int dev; - uint16_t class, vendor; - - /* Look on bus 0 for a device that is a host bridge, a VGA card, - * or an intel or compaq device. */ - - for (dev = 0; dev < 32; dev++) - { - if (pci_sys->read (0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof (class))) - continue; - if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA) - return 0; - if (pci_sys->read (0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof (vendor))) - continue; - if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ) - return 0; - } - - return ENODEV; -} - -/* Find out which conf access method use */ -static error_t -pci_probe (struct pci_system *pci_sys) -{ - if (pci_system_x86_conf1_probe () == 0) - { - pci_sys->read = pci_system_x86_conf1_read; - pci_sys->write = pci_system_x86_conf1_write; - if (pci_system_x86_check (pci_sys) == 0) - return 0; - } - - if (pci_system_x86_conf2_probe () == 0) - { - pci_sys->read = pci_system_x86_conf2_read; - pci_sys->write = pci_system_x86_conf2_write; - if (pci_system_x86_check (pci_sys) == 0) - return 0; - } - - return ENODEV; -} - -static error_t -pci_nfuncs (struct pci_system *pci_sys, int bus, int dev, uint8_t * nfuncs) -{ - uint8_t hdrtype; - error_t err; - - err = pci_sys->read (bus, dev, 0, PCI_HDRTYPE, &hdrtype, sizeof (hdrtype)); - if (err) - return err; - - *nfuncs = hdrtype & 0x80 ? 8 : 1; - - return 0; -} - -/* Recursively scan bus number `bus' */ -static error_t -pci_system_x86_scan_bus (struct pci_system *pci_sys, uint8_t bus) -{ - error_t err; - uint8_t dev, func, nfuncs, hdrtype, secbus; - uint32_t reg; - struct pci_device *d, *devices; - - for (dev = 0; dev < 32; dev++) - { - err = pci_nfuncs (pci_sys, bus, dev, &nfuncs); - if (err) - return err; - - for (func = 0; func < nfuncs; func++) - { - err = - pci_sys->read (bus, dev, func, PCI_VENDOR_ID, ®, sizeof (reg)); - if (err) - return err; - - if (PCI_VENDOR (reg) == PCI_VENDOR_INVALID || PCI_VENDOR (reg) == 0) - continue; - - err = pci_sys->read (bus, dev, func, PCI_CLASS, ®, sizeof (reg)); - if (err) - return err; - - err = - pci_sys->read (bus, dev, func, PCI_HDRTYPE, &hdrtype, - sizeof (hdrtype)); - if (err) - return err; - - devices = - realloc (pci_sys->devices, - (pci_sys->num_devices + 1) * sizeof (struct pci_device)); - if (!devices) - return ENOMEM; - - d = devices + pci_sys->num_devices; - memset (d, 0, sizeof (struct pci_device)); - - /* Fixed values as PCI express is still not supported */ - d->domain = 0; - d->config_size = PCI_CONFIG_SIZE; - - d->bus = bus; - d->dev = dev; - d->func = func; - - d->device_class = reg >> 8; - - err = pci_device_x86_probe (d); - if (err) - return err; - - pci_sys->devices = devices; - pci_sys->num_devices++; - - switch (hdrtype & 0x3) - { - case PCI_HDRTYPE_DEVICE: - break; - case PCI_HDRTYPE_BRIDGE: - case PCI_HDRTYPE_CARDBUS: - { - err = - pci_sys->read (bus, dev, func, PCI_SECONDARY_BUS, &secbus, - sizeof (secbus)); - if (err) - return err; - - err = pci_system_x86_scan_bus (pci_sys, secbus); - if (err) - return err; - - break; - } - default: - /* Unknown header, do nothing */ - break; - } - } - } - - return 0; -} - -/* Initialize the x86 module */ -error_t -pci_system_x86_create (void) -{ - error_t err; - - err = x86_enable_io (); - if (err) - return err; - - pci_sys = calloc (1, sizeof (struct pci_system)); - if (pci_sys == NULL) - { - x86_disable_io (); - return ENOMEM; - } - - err = pci_probe (pci_sys); - if (err) - { - x86_disable_io (); - free (pci_sys); - return err; - } - pci_sys->device_refresh = pci_device_x86_refresh; - - /* Recursive scan */ - pci_sys->num_devices = 0; - err = pci_system_x86_scan_bus (pci_sys, 0); - if (err) - { - x86_disable_io (); - free (pci_sys); - pci_sys = NULL; - return err; - } - - return 0; -} |