qemu/tests/libqos/pci-pc.c
<<
>>
Prefs
   1/*
   2 * libqos PCI bindings for PC
   3 *
   4 * Copyright IBM, Corp. 2012-2013
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "libqtest.h"
  14#include "libqos/pci-pc.h"
  15
  16#include "hw/pci/pci_regs.h"
  17
  18#include "qemu-common.h"
  19#include "qemu/host-utils.h"
  20
  21#include <glib.h>
  22
  23typedef struct QPCIBusPC
  24{
  25    QPCIBus bus;
  26
  27    uint32_t pci_hole_start;
  28    uint32_t pci_hole_size;
  29    uint32_t pci_hole_alloc;
  30
  31    uint16_t pci_iohole_start;
  32    uint16_t pci_iohole_size;
  33    uint16_t pci_iohole_alloc;
  34} QPCIBusPC;
  35
  36static uint8_t qpci_pc_io_readb(QPCIBus *bus, void *addr)
  37{
  38    uintptr_t port = (uintptr_t)addr;
  39    uint8_t value;
  40
  41    if (port < 0x10000) {
  42        value = inb(port);
  43    } else {
  44        memread(port, &value, sizeof(value));
  45    }
  46
  47    return value;
  48}
  49
  50static uint16_t qpci_pc_io_readw(QPCIBus *bus, void *addr)
  51{
  52    uintptr_t port = (uintptr_t)addr;
  53    uint16_t value;
  54
  55    if (port < 0x10000) {
  56        value = inw(port);
  57    } else {
  58        memread(port, &value, sizeof(value));
  59    }
  60
  61    return value;
  62}
  63
  64static uint32_t qpci_pc_io_readl(QPCIBus *bus, void *addr)
  65{
  66    uintptr_t port = (uintptr_t)addr;
  67    uint32_t value;
  68
  69    if (port < 0x10000) {
  70        value = inl(port);
  71    } else {
  72        memread(port, &value, sizeof(value));
  73    }
  74
  75    return value;
  76}
  77
  78static void qpci_pc_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
  79{
  80    uintptr_t port = (uintptr_t)addr;
  81
  82    if (port < 0x10000) {
  83        outb(port, value);
  84    } else {
  85        memwrite(port, &value, sizeof(value));
  86    }
  87}
  88
  89static void qpci_pc_io_writew(QPCIBus *bus, void *addr, uint16_t value)
  90{
  91    uintptr_t port = (uintptr_t)addr;
  92
  93    if (port < 0x10000) {
  94        outw(port, value);
  95    } else {
  96        memwrite(port, &value, sizeof(value));
  97    }
  98}
  99
 100static void qpci_pc_io_writel(QPCIBus *bus, void *addr, uint32_t value)
 101{
 102    uintptr_t port = (uintptr_t)addr;
 103
 104    if (port < 0x10000) {
 105        outl(port, value);
 106    } else {
 107        memwrite(port, &value, sizeof(value));
 108    }
 109}
 110
 111static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
 112{
 113    outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
 114    return inb(0xcfc);
 115}
 116
 117static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
 118{
 119    outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
 120    return inw(0xcfc);
 121}
 122
 123static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
 124{
 125    outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
 126    return inl(0xcfc);
 127}
 128
 129static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value)
 130{
 131    outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
 132    outb(0xcfc, value);
 133}
 134
 135static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value)
 136{
 137    outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
 138    outw(0xcfc, value);
 139}
 140
 141static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value)
 142{
 143    outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
 144    outl(0xcfc, value);
 145}
 146
 147static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno)
 148{
 149    QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
 150    static const int bar_reg_map[] = {
 151        PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
 152        PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
 153    };
 154    int bar_reg;
 155    uint32_t addr;
 156    uint64_t size;
 157    uint32_t io_type;
 158
 159    g_assert(barno >= 0 && barno <= 5);
 160    bar_reg = bar_reg_map[barno];
 161
 162    qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
 163    addr = qpci_config_readl(dev, bar_reg);
 164
 165    io_type = addr & PCI_BASE_ADDRESS_SPACE;
 166    if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
 167        addr &= PCI_BASE_ADDRESS_IO_MASK;
 168    } else {
 169        addr &= PCI_BASE_ADDRESS_MEM_MASK;
 170    }
 171
 172    size = (1ULL << ctzl(addr));
 173    if (size == 0) {
 174        return NULL;
 175    }
 176
 177    if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
 178        uint16_t loc;
 179
 180        g_assert((s->pci_iohole_alloc + size) <= s->pci_iohole_size);
 181        loc = s->pci_iohole_start + s->pci_iohole_alloc;
 182        s->pci_iohole_alloc += size;
 183
 184        qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
 185
 186        return (void *)(intptr_t)loc;
 187    } else {
 188        uint64_t loc;
 189
 190        g_assert((s->pci_hole_alloc + size) <= s->pci_hole_size);
 191        loc = s->pci_hole_start + s->pci_hole_alloc;
 192        s->pci_hole_alloc += size;
 193
 194        qpci_config_writel(dev, bar_reg, loc);
 195
 196        return (void *)(intptr_t)loc;
 197    }
 198}
 199
 200static void qpci_pc_iounmap(QPCIBus *bus, void *data)
 201{
 202    /* FIXME */
 203}
 204
 205QPCIBus *qpci_init_pc(void)
 206{
 207    QPCIBusPC *ret;
 208
 209    ret = g_malloc(sizeof(*ret));
 210
 211    ret->bus.io_readb = qpci_pc_io_readb;
 212    ret->bus.io_readw = qpci_pc_io_readw;
 213    ret->bus.io_readl = qpci_pc_io_readl;
 214
 215    ret->bus.io_writeb = qpci_pc_io_writeb;
 216    ret->bus.io_writew = qpci_pc_io_writew;
 217    ret->bus.io_writel = qpci_pc_io_writel;
 218
 219    ret->bus.config_readb = qpci_pc_config_readb;
 220    ret->bus.config_readw = qpci_pc_config_readw;
 221    ret->bus.config_readl = qpci_pc_config_readl;
 222
 223    ret->bus.config_writeb = qpci_pc_config_writeb;
 224    ret->bus.config_writew = qpci_pc_config_writew;
 225    ret->bus.config_writel = qpci_pc_config_writel;
 226
 227    ret->bus.iomap = qpci_pc_iomap;
 228    ret->bus.iounmap = qpci_pc_iounmap;
 229
 230    ret->pci_hole_start = 0xE0000000;
 231    ret->pci_hole_size = 0x20000000;
 232    ret->pci_hole_alloc = 0;
 233
 234    ret->pci_iohole_start = 0xc000;
 235    ret->pci_iohole_size = 0x4000;
 236    ret->pci_iohole_alloc = 0;
 237
 238    return &ret->bus;
 239}
 240