qemu/hw/pci-bridge/ioh3420.c
<<
>>
Prefs
   1/*
   2 * ioh3420.c
   3 * Intel X58 north bridge IOH
   4 * PCI Express root port device id 3420
   5 *
   6 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
   7 *                    VA Linux Systems Japan K.K.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License along
  20 * with this program; if not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#include "hw/pci/pci_ids.h"
  24#include "hw/pci/msi.h"
  25#include "hw/pci/pcie.h"
  26#include "ioh3420.h"
  27
  28#define PCI_DEVICE_ID_IOH_EPORT         0x3420  /* D0:F0 express mode */
  29#define PCI_DEVICE_ID_IOH_REV           0x2
  30#define IOH_EP_SSVID_OFFSET             0x40
  31#define IOH_EP_SSVID_SVID               PCI_VENDOR_ID_INTEL
  32#define IOH_EP_SSVID_SSID               0
  33#define IOH_EP_MSI_OFFSET               0x60
  34#define IOH_EP_MSI_SUPPORTED_FLAGS      PCI_MSI_FLAGS_MASKBIT
  35#define IOH_EP_MSI_NR_VECTOR            2
  36#define IOH_EP_EXP_OFFSET               0x90
  37#define IOH_EP_AER_OFFSET               0x100
  38
  39/*
  40 * If two MSI vector are allocated, Advanced Error Interrupt Message Number
  41 * is 1. otherwise 0.
  42 * 17.12.5.10 RPERRSTS,  32:27 bit Advanced Error Interrupt Message Number.
  43 */
  44static uint8_t ioh3420_aer_vector(const PCIDevice *d)
  45{
  46    switch (msi_nr_vectors_allocated(d)) {
  47    case 1:
  48        return 0;
  49    case 2:
  50        return 1;
  51    case 4:
  52    case 8:
  53    case 16:
  54    case 32:
  55    default:
  56        break;
  57    }
  58    abort();
  59    return 0;
  60}
  61
  62static void ioh3420_aer_vector_update(PCIDevice *d)
  63{
  64    pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
  65}
  66
  67static void ioh3420_write_config(PCIDevice *d,
  68                                   uint32_t address, uint32_t val, int len)
  69{
  70    uint32_t root_cmd =
  71        pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
  72
  73    pci_bridge_write_config(d, address, val, len);
  74    ioh3420_aer_vector_update(d);
  75    pcie_cap_slot_write_config(d, address, val, len);
  76    pcie_aer_write_config(d, address, val, len);
  77    pcie_aer_root_write_config(d, address, val, len, root_cmd);
  78}
  79
  80static void ioh3420_reset(DeviceState *qdev)
  81{
  82    PCIDevice *d = PCI_DEVICE(qdev);
  83
  84    ioh3420_aer_vector_update(d);
  85    pcie_cap_root_reset(d);
  86    pcie_cap_deverr_reset(d);
  87    pcie_cap_slot_reset(d);
  88    pcie_aer_root_reset(d);
  89    pci_bridge_reset(qdev);
  90    pci_bridge_disable_base_limit(d);
  91}
  92
  93static int ioh3420_initfn(PCIDevice *d)
  94{
  95    PCIEPort *p = PCIE_PORT(d);
  96    PCIESlot *s = PCIE_SLOT(d);
  97    int rc;
  98
  99    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
 100    if (rc < 0) {
 101        return rc;
 102    }
 103
 104    pcie_port_init_reg(d);
 105
 106    rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
 107                               IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
 108    if (rc < 0) {
 109        goto err_bridge;
 110    }
 111    rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
 112                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
 113                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
 114    if (rc < 0) {
 115        goto err_bridge;
 116    }
 117    rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
 118    if (rc < 0) {
 119        goto err_msi;
 120    }
 121    pcie_cap_deverr_init(d);
 122    pcie_cap_slot_init(d, s->slot);
 123    pcie_chassis_create(s->chassis);
 124    rc = pcie_chassis_add_slot(s);
 125    if (rc < 0) {
 126        goto err_pcie_cap;
 127    }
 128    pcie_cap_root_init(d);
 129    rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
 130    if (rc < 0) {
 131        goto err;
 132    }
 133    pcie_aer_root_init(d);
 134    ioh3420_aer_vector_update(d);
 135    return 0;
 136
 137err:
 138    pcie_chassis_del_slot(s);
 139err_pcie_cap:
 140    pcie_cap_exit(d);
 141err_msi:
 142    msi_uninit(d);
 143err_bridge:
 144    pci_bridge_exitfn(d);
 145    return rc;
 146}
 147
 148static void ioh3420_exitfn(PCIDevice *d)
 149{
 150    PCIESlot *s = PCIE_SLOT(d);
 151
 152    pcie_aer_exit(d);
 153    pcie_chassis_del_slot(s);
 154    pcie_cap_exit(d);
 155    msi_uninit(d);
 156    pci_bridge_exitfn(d);
 157}
 158
 159PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
 160                         const char *bus_name, pci_map_irq_fn map_irq,
 161                         uint8_t port, uint8_t chassis, uint16_t slot)
 162{
 163    PCIDevice *d;
 164    PCIBridge *br;
 165    DeviceState *qdev;
 166
 167    d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
 168    if (!d) {
 169        return NULL;
 170    }
 171    br = PCI_BRIDGE(d);
 172
 173    qdev = DEVICE(d);
 174    pci_bridge_map_irq(br, bus_name, map_irq);
 175    qdev_prop_set_uint8(qdev, "port", port);
 176    qdev_prop_set_uint8(qdev, "chassis", chassis);
 177    qdev_prop_set_uint16(qdev, "slot", slot);
 178    qdev_init_nofail(qdev);
 179
 180    return PCIE_SLOT(d);
 181}
 182
 183static const VMStateDescription vmstate_ioh3420 = {
 184    .name = "ioh-3240-express-root-port",
 185    .version_id = 1,
 186    .minimum_version_id = 1,
 187    .minimum_version_id_old = 1,
 188    .post_load = pcie_cap_slot_post_load,
 189    .fields = (VMStateField[]) {
 190        VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
 191        VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
 192                       PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
 193        VMSTATE_END_OF_LIST()
 194    }
 195};
 196
 197static void ioh3420_class_init(ObjectClass *klass, void *data)
 198{
 199    DeviceClass *dc = DEVICE_CLASS(klass);
 200    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 201
 202    k->is_express = 1;
 203    k->is_bridge = 1;
 204    k->config_write = ioh3420_write_config;
 205    k->init = ioh3420_initfn;
 206    k->exit = ioh3420_exitfn;
 207    k->vendor_id = PCI_VENDOR_ID_INTEL;
 208    k->device_id = PCI_DEVICE_ID_IOH_EPORT;
 209    k->revision = PCI_DEVICE_ID_IOH_REV;
 210    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 211    dc->desc = "Intel IOH device id 3420 PCIE Root Port";
 212    dc->reset = ioh3420_reset;
 213    dc->vmsd = &vmstate_ioh3420;
 214}
 215
 216static const TypeInfo ioh3420_info = {
 217    .name          = "ioh3420",
 218    .parent        = TYPE_PCIE_SLOT,
 219    .class_init    = ioh3420_class_init,
 220};
 221
 222static void ioh3420_register_types(void)
 223{
 224    type_register_static(&ioh3420_info);
 225}
 226
 227type_init(ioh3420_register_types)
 228
 229/*
 230 * Local variables:
 231 *  c-indent-level: 4
 232 *  c-basic-offset: 4
 233 *  tab-width: 8
 234 *  indent-tab-mode: nil
 235 * End:
 236 */
 237