qemu/hw/pci_host.c
<<
>>
Prefs
   1/*
   2 * pci_host.c
   3 *
   4 * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
   5 *                    VA Linux Systems Japan K.K.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16
  17 * You should have received a copy of the GNU General Public License along
  18 * with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "pci.h"
  22#include "pci_host.h"
  23
  24/* debug PCI */
  25//#define DEBUG_PCI
  26
  27#ifdef DEBUG_PCI
  28#define PCI_DPRINTF(fmt, ...) \
  29do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
  30#else
  31#define PCI_DPRINTF(fmt, ...)
  32#endif
  33
  34/*
  35 * PCI address
  36 * bit 16 - 24: bus number
  37 * bit  8 - 15: devfun number
  38 * bit  0 -  7: offset in configuration space of a given pci device
  39 */
  40
  41/* the helper functio to get a PCIDeice* for a given pci address */
  42static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
  43{
  44    uint8_t bus_num = addr >> 16;
  45    uint8_t devfn = addr >> 8;
  46
  47    return pci_find_device(bus, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
  48}
  49
  50void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
  51{
  52    PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
  53    uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
  54
  55    if (!pci_dev)
  56        return;
  57
  58    PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
  59                __func__, pci_dev->name, config_addr, val, len);
  60    pci_dev->config_write(pci_dev, config_addr, val, len);
  61}
  62
  63uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
  64{
  65    PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
  66    uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
  67    uint32_t val;
  68
  69    assert(len == 1 || len == 2 || len == 4);
  70    if (!pci_dev) {
  71        return ~0x0;
  72    }
  73
  74    val = pci_dev->config_read(pci_dev, config_addr, len);
  75    PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
  76                __func__, pci_dev->name, config_addr, val, len);
  77
  78    return val;
  79}
  80
  81static void pci_host_config_write_swap(ReadWriteHandler *handler,
  82                                       pcibus_t addr, uint32_t val, int len)
  83{
  84    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
  85
  86    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
  87                __func__, addr, len, val);
  88    val = qemu_bswap_len(val, len);
  89    s->config_reg = val;
  90}
  91
  92static uint32_t pci_host_config_read_swap(ReadWriteHandler *handler,
  93                                          pcibus_t addr, int len)
  94{
  95    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
  96    uint32_t val = s->config_reg;
  97
  98    val = qemu_bswap_len(val, len);
  99    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
 100                __func__, addr, len, val);
 101    return val;
 102}
 103
 104static void pci_host_config_write_noswap(ReadWriteHandler *handler,
 105                                         pcibus_t addr, uint32_t val, int len)
 106{
 107    PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
 108
 109    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
 110                __func__, addr, len, val);
 111    s->config_reg = val;
 112}
 113
 114static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler,
 115                                            pcibus_t addr, int len)
 116{
 117    PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
 118    uint32_t val = s->config_reg;
 119
 120    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
 121                __func__, addr, len, val);
 122    return val;
 123}
 124
 125static void pci_host_data_write_swap(ReadWriteHandler *handler,
 126                                     pcibus_t addr, uint32_t val, int len)
 127{
 128    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
 129
 130    val = qemu_bswap_len(val, len);
 131    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
 132                addr, len, val);
 133    if (s->config_reg & (1u << 31))
 134        pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
 135}
 136
 137static uint32_t pci_host_data_read_swap(ReadWriteHandler *handler,
 138                                        pcibus_t addr, int len)
 139{
 140    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
 141    uint32_t val;
 142    if (!(s->config_reg & (1 << 31)))
 143        return 0xffffffff;
 144    val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
 145    PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
 146                addr, len, val);
 147    val = qemu_bswap_len(val, len);
 148    return val;
 149}
 150
 151static void pci_host_data_write_noswap(ReadWriteHandler *handler,
 152                                       pcibus_t addr, uint32_t val, int len)
 153{
 154    PCIHostState *s = container_of(handler, PCIHostState, data_noswap_handler);
 155    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
 156                addr, len, val);
 157    if (s->config_reg & (1u << 31))
 158        pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
 159}
 160
 161static uint32_t pci_host_data_read_noswap(ReadWriteHandler *handler,
 162                                          pcibus_t addr, int len)
 163{
 164    PCIHostState *s = container_of(handler, PCIHostState, data_noswap_handler);
 165    uint32_t val;
 166    if (!(s->config_reg & (1 << 31)))
 167        return 0xffffffff;
 168    val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
 169    PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
 170                addr, len, val);
 171    return val;
 172}
 173
 174static void pci_host_init(PCIHostState *s)
 175{
 176    s->conf_handler.write = pci_host_config_write_swap;
 177    s->conf_handler.read = pci_host_config_read_swap;
 178    s->conf_noswap_handler.write = pci_host_config_write_noswap;
 179    s->conf_noswap_handler.read = pci_host_config_read_noswap;
 180    s->data_handler.write = pci_host_data_write_swap;
 181    s->data_handler.read = pci_host_data_read_swap;
 182    s->data_noswap_handler.write = pci_host_data_write_noswap;
 183    s->data_noswap_handler.read = pci_host_data_read_noswap;
 184}
 185
 186int pci_host_conf_register_mmio(PCIHostState *s, int swap)
 187{
 188    pci_host_init(s);
 189    if (swap) {
 190        return cpu_register_io_memory_simple(&s->conf_handler);
 191    } else {
 192        return cpu_register_io_memory_simple(&s->conf_noswap_handler);
 193    }
 194}
 195
 196void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
 197{
 198    pci_host_init(s);
 199    register_ioport_simple(&s->conf_noswap_handler, ioport, 4, 4);
 200}
 201
 202int pci_host_data_register_mmio(PCIHostState *s, int swap)
 203{
 204    pci_host_init(s);
 205    if (swap) {
 206        return cpu_register_io_memory_simple(&s->data_handler);
 207    } else {
 208        return cpu_register_io_memory_simple(&s->data_noswap_handler);
 209    }
 210}
 211
 212void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
 213{
 214    pci_host_init(s);
 215    register_ioport_simple(&s->data_noswap_handler, ioport, 4, 1);
 216    register_ioport_simple(&s->data_noswap_handler, ioport, 4, 2);
 217    register_ioport_simple(&s->data_noswap_handler, ioport, 4, 4);
 218}
 219