qemu/hw/pci-host/xilinx_axipcie.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the Xilinx AXI_PCIE Controller
   3 *
   4 * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@xilinx.com>
   5 * Copyright (C) 2012 Xilinx Inc.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "hw/sysbus.h"
  28#include "sysemu/sysemu.h"
  29#include "qemu/log.h"
  30#include "hw/pci/pci.h"
  31#include "exec/memory.h"
  32#include "exec/address-spaces.h"
  33
  34#include "hw/fdt_generic_util.h"
  35
  36#define XILINX_AXI_PCIE_DEBUG 1
  37
  38#ifndef XILINX_AXI_PCIE_DEBUG
  39#define XILINX_AXI_PCIE_DEBUG 0
  40#endif
  41#define DB_PRINT(fmt, args...) do {\
  42    if (XILINX_AXI_PCIE_DEBUG) {\
  43        fprintf(stderr, "XILINX_AXI_PCIE: %s:" fmt, __func__, ## args);\
  44    } \
  45} while (0);
  46
  47#define R_ADDR_TO_IDX(x) (((x) - 0x130) / 4)
  48
  49#define R_BR_INFO       R_ADDR_TO_IDX(0x130)
  50#define R_BR_SCR        R_ADDR_TO_IDX(0x134)
  51#define R_IDR           R_ADDR_TO_IDX(0x138)
  52#define R_IMR           R_ADDR_TO_IDX(0x13c)
  53#define R_BUS_LOC       R_ADDR_TO_IDX(0x140)
  54#define R_PHY_SCR       R_ADDR_TO_IDX(0x144)
  55#define R_RP_MSI_1      R_ADDR_TO_IDX(0x14c)
  56#define R_RP_MSI_2      R_ADDR_TO_IDX(0x150)
  57#define R_RP_ERR_FIFO   R_ADDR_TO_IDX(0x154)
  58#define R_RP_INT_FIFO1  R_ADDR_TO_IDX(0x158)
  59#define R_RP_INT_FIFO2  R_ADDR_TO_IDX(0x15c)
  60
  61#define R_MAX ((0x160 - 0x130)/4)
  62
  63/* FIXME: this struct defintion is generic, may belong in bitops or somewhere
  64 * like that
  65 */
  66
  67typedef struct XilinxAXIPCIERegInfo {
  68    const char *name;
  69    uint32_t ro;
  70    uint32_t wtc;
  71    uint32_t reset;
  72    int width;
  73}  XilinxAXIPCIERegInfo;
  74
  75static const XilinxAXIPCIERegInfo xilinx_axi_pcie_reg_info[] = {
  76    [R_BR_INFO]        = {.name = "BRIDGE INFO", .width = 19, .reset = 0x70007,
  77                          .ro = ~0 },
  78    [R_BR_SCR]         = {.name = "BRIDGE STATUS CONTROL", .width = 18,
  79                          .ro = 0x0FEFF },
  80    [R_IDR]            = {.name = "INTERRUPT DECODE", .width = 29,
  81                          .wtc = 0x1FF30FEF, .ro = 0xCF010 },
  82    [R_IMR]            = {.name = "INTERRUPT MASK", .width = 29,
  83                          .ro = 0xCF010 },
  84    [R_BUS_LOC]        = {.name = "BUS LOCATION", .width = 24 },
  85    [R_PHY_SCR]        = {.name = "PHY STATUS CONTROL", .width = 22,
  86                          .ro = 0xFFFF, .reset = 0x800 },
  87    [R_RP_MSI_1]       = {.name = "ROOT PORT MSI BASE 1", .width = 32 },
  88    [R_RP_MSI_2]       = {.name = "ROOT PORT MSI BASE 2", .width = 32 },
  89    [R_MAX]            = {.name = NULL }
  90};
  91
  92#define MAX_AXI_TO_PCI_BARS 6
  93#define MAX_PCI_TO_AXI_BARS 3
  94
  95typedef struct XilinxACIPCIEMapping {
  96    hwaddr src;
  97    hwaddr dst;
  98    hwaddr size;
  99    uint8_t size2;
 100} XilinxACIPCIEMapping;
 101
 102typedef struct XilinxAXIPCIE {
 103    SysBusDevice busdev;
 104    PCIBus *pci_bus;
 105
 106    MemoryRegion container;
 107    MemoryRegion config;
 108    MemoryRegion mmio;
 109    MemoryRegion pci_space;
 110
 111    MemoryRegion axi_to_pci_bar[MAX_AXI_TO_PCI_BARS];
 112    MemoryRegion pci_to_axi_bar[MAX_PCI_TO_AXI_BARS];
 113
 114    PCIBus *bus;
 115
 116    qemu_irq irq;
 117    int irqline;
 118
 119    uint32_t regs[R_MAX];
 120} XilinxAXIPCIE;
 121
 122static inline void xilinx_axi_pcie_update_irq(XilinxAXIPCIE *s)
 123{
 124    int new_irqline = !!(s->regs[R_IDR] & s->regs[R_IMR]);
 125    
 126    if (new_irqline != s->irqline) {
 127        DB_PRINT("irq state: %d\n", new_irqline);
 128        qemu_set_irq(s->irq, new_irqline);
 129        s->irqline = new_irqline;
 130    }
 131}
 132
 133static void xilinx_axi_pcie_do_reset(XilinxAXIPCIE *s)
 134{
 135    int i;
 136    memset(s->regs, 0, sizeof(s->regs));
 137
 138    for (i = 0; i < ARRAY_SIZE(s->regs); ++i) {
 139        if (xilinx_axi_pcie_reg_info[i].name) {
 140            s->regs[i] = xilinx_axi_pcie_reg_info[i].reset;
 141        }
 142    }
 143
 144    xilinx_axi_pcie_update_irq(s);
 145}
 146
 147static void xilinx_axi_pcie_reset(DeviceState *d)
 148{
 149    /* FIXME: implement QOM cast macro */
 150    xilinx_axi_pcie_do_reset((XilinxAXIPCIE *)d);
 151}
 152
 153static inline void xilinx_axi_pcie_check_reg_access(hwaddr offset, uint32_t val,
 154                                                bool rnw)
 155{
 156    if (!xilinx_axi_pcie_reg_info[offset >> 2].name) {
 157        qemu_log_mask(LOG_UNIMP, "Xilinx AXI PCIE: %s offset %x\n",
 158                      rnw ? "read from" : "write to", (unsigned)offset);
 159        DB_PRINT("Unimplemented %s offset %x\n",
 160                 rnw ? "read from" : "write to", (unsigned)offset);
 161    } else {
 162        DB_PRINT("%s %s [%#02x] %s %#08x\n", rnw ? "read" : "write",
 163                 xilinx_axi_pcie_reg_info[offset >> 2].name, (unsigned) offset,
 164                 rnw ? "->" : "<-", val);
 165    }
 166}
 167
 168static uint64_t xilinx_axi_pcie_config_read(void *opaque, hwaddr offset,
 169                                            unsigned int size)
 170{
 171    XilinxAXIPCIE *s = opaque;
 172    PCIDevice *pci_dev = pci_find_device(s->pci_bus, 0, 0);
 173    uint64_t ret = pci_dev ? pci_dev->config_read(pci_dev, offset, size) : 0;
 174
 175    DB_PRINT("PCI config read device :%s offset: %x data: %x size: %d\n",
 176             pci_dev ? object_get_canonical_path(OBJECT(pci_dev)) : "(none)",
 177             (unsigned)offset, (unsigned)ret, size);
 178
 179    return ret;
 180}
 181
 182static void xilinx_axi_pcie_config_write(void *opaque, hwaddr offset,
 183                                         uint64_t value, unsigned int size)
 184{
 185    XilinxAXIPCIE *s = opaque;
 186    PCIDevice *pci_dev = pci_find_device(s->pci_bus, 0, 0);
 187
 188    DB_PRINT("PCI config write device :%s offset: %x data: %x size: %d\n",
 189             pci_dev ? object_get_canonical_path(OBJECT(pci_dev)) : "(none)",
 190             (unsigned)offset, (unsigned)value, size);
 191
 192    if (pci_dev) {
 193        pci_dev->config_write(pci_dev, offset, value, size);
 194    }
 195}
 196
 197static const MemoryRegionOps xilinx_axi_pcie_config_ops = {
 198    .read = xilinx_axi_pcie_config_read,
 199    .write = xilinx_axi_pcie_config_write,
 200    .endianness = DEVICE_NATIVE_ENDIAN,
 201    .valid = {
 202        .min_access_size = 1,
 203        .max_access_size = 4
 204    }
 205};
 206
 207static uint64_t xilinx_axi_pcie_read(void *opaque, hwaddr offset,
 208                                     unsigned int size)
 209{
 210    XilinxAXIPCIE *s = opaque;
 211    uint32_t ret = s->regs[offset >> 2];
 212
 213    xilinx_axi_pcie_check_reg_access(offset, ret, true);
 214    return ret;    
 215}
 216
 217static void xilinx_axi_pcie_write(void *opaque, hwaddr offset, uint64_t value,
 218                                  unsigned int size)
 219{
 220    XilinxAXIPCIE *s = opaque;
 221    const XilinxAXIPCIERegInfo *info = &xilinx_axi_pcie_reg_info[offset >> 2];
 222    uint32_t new_value = value;
 223    uint32_t ro_mask;
 224
 225    xilinx_axi_pcie_check_reg_access(offset, value, false);
 226    if (!info->name) {
 227        return;
 228    }
 229
 230    offset >>= 2;
 231    assert(!(info->wtc & info->ro));
 232    /* preserve read-only and write to clear bits */
 233    ro_mask = info->ro | info->wtc | ~((1ull << info->width) - 1);
 234    new_value &= ~ro_mask;
 235    new_value |= ro_mask & s->regs[offset];
 236    /* do write to clear */
 237    new_value &= ~(value & info->wtc);
 238    s->regs[offset] = new_value;
 239    
 240    xilinx_axi_pcie_update_irq(s);
 241}
 242
 243static const MemoryRegionOps xilinx_axi_pcie_ops = {
 244    .read = xilinx_axi_pcie_read,
 245    .write = xilinx_axi_pcie_write,
 246    .endianness = DEVICE_NATIVE_ENDIAN,
 247    .valid = {
 248        .min_access_size = 4,
 249        .max_access_size = 4
 250    }
 251};
 252
 253static int xilinx_axi_pcie_init(SysBusDevice *dev)
 254{
 255#if 0
 256    XilinxAXIPCIE *s = (XilinxAXIPCIE *)dev;
 257
 258    DB_PRINT("\n");
 259
 260    /*FIXME: Parameterise BAR size */
 261    memory_region_init(&s->pci_space, OBJECT(dev), "xilinx-pci-bar", 1ull << 32);
 262    s->pci_bus = pci_register_bus(DEVICE(dev), "xilinx-pci",
 263                                  NULL, NULL, s->irq,
 264                                  &s->pci_space, get_system_io(),
 265                                  0 , 1, TYPE_PCI_BUS);
 266
 267    /*memory_region_init_alias(&s->axi_to_pci_bar[0], "foo", &s->pci_space,
 268                             0x40000000, 0x10000000);*/
 269    memory_region_init_io(&s->config, OBJECT(dev), &razwi_unimp_ops, s,
 270                          "xilinx-axi_pcie_bar", 0x10000000);
 271    memory_region_add_subregion(get_system_memory(), 0x70000000,
 272                                &s->axi_to_pci_bar[0]);
 273
 274    memory_region_init_alias(&s->pci_to_axi_bar[0], OBJECT(dev), "bar", get_system_memory(),
 275                             0x50000000, 0x10000000);
 276    memory_region_add_subregion(&s->pci_space, 0x50000000,
 277                                &s->pci_to_axi_bar[0]);
 278
 279    sysbus_init_irq(dev, &s->irq);
 280    memory_region_init(&s->container, OBJECT(dev), "a9mp-priv-container", 16 << 20);
 281    memory_region_init_io(&s->mmio, OBJECT(dev), &xilinx_axi_pcie_ops, s,
 282                          "xilinx-axi_pcie_mmio", R_MAX * 4);
 283    memory_region_add_subregion(&s->container, 0x130, &s->mmio);
 284    
 285    memory_region_init_io(&s->config, OBJECT(dev), &xilinx_axi_pcie_config_ops, s,
 286                          "xilinx-axi_pcie_mmio", 0x130);
 287    memory_region_add_subregion(&s->container, 0, &s->config);
 288
 289    sysbus_init_mmio(dev, &s->container);
 290
 291    s->irqline = -1;
 292#endif
 293    return 0;
 294}
 295
 296static const VMStateDescription vmstate_xilinx_axi_pcie = {
 297    .name = "xlnx.axi-pcie",
 298    .version_id = 1,
 299    .minimum_version_id = 1,
 300    .minimum_version_id_old = 1,
 301    .fields = (VMStateField[]) {
 302        VMSTATE_UINT32_ARRAY(regs, XilinxAXIPCIE, R_MAX),
 303        VMSTATE_END_OF_LIST()
 304    }
 305};
 306
 307static Property xilinx_axi_pcie_properties[] = {
 308    DEFINE_PROP_END_OF_LIST(),
 309};
 310
 311static void xilinx_axi_pcie_class_init(ObjectClass *klass, void *data)
 312{
 313    DeviceClass *dc = DEVICE_CLASS(klass);
 314    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 315
 316    k->init = xilinx_axi_pcie_init;
 317    dc->reset = xilinx_axi_pcie_reset;
 318    dc->props = xilinx_axi_pcie_properties;
 319    dc->vmsd = &vmstate_xilinx_axi_pcie;
 320}
 321
 322static TypeInfo xilinx_axi_pcie_info = {
 323    .name           = "xlnx.axi-pcie",
 324    .parent         = TYPE_SYS_BUS_DEVICE,
 325    .instance_size  = sizeof(XilinxAXIPCIE),
 326    .class_init     = xilinx_axi_pcie_class_init,
 327};
 328
 329static void xilinx_axi_pcie_register_types(void)
 330{
 331    type_register_static(&xilinx_axi_pcie_info);
 332}
 333
 334type_init(xilinx_axi_pcie_register_types)
 335