xio3130_downstream.c 6.4 KB
Newer Older
I
Isaku Yamahata 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * x3130_downstream.c
 * TI X3130 pci express downstream port switch
 *
 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
 *                    VA Linux Systems Japan K.K.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, see <http://www.gnu.org/licenses/>.
 */

22 23 24 25
#include "hw/pci/pci_ids.h"
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "hw/xio3130_downstream.h"
I
Isaku Yamahata 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

#define PCI_DEVICE_ID_TI_XIO3130D       0x8233  /* downstream port */
#define XIO3130_REVISION                0x1
#define XIO3130_MSI_OFFSET              0x70
#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
#define XIO3130_MSI_NR_VECTOR           1
#define XIO3130_SSVID_OFFSET            0x80
#define XIO3130_SSVID_SVID              0
#define XIO3130_SSVID_SSID              0
#define XIO3130_EXP_OFFSET              0x90
#define XIO3130_AER_OFFSET              0x100

static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
                                         uint32_t val, int len)
{
    pci_bridge_write_config(d, address, val, len);
    pcie_cap_flr_write_config(d, address, val, len);
43
    pcie_cap_slot_write_config(d, address, val, len);
I
Isaku Yamahata 已提交
44
    pcie_aer_write_config(d, address, val, len);
I
Isaku Yamahata 已提交
45 46 47 48
}

static void xio3130_downstream_reset(DeviceState *qdev)
{
49
    PCIDevice *d = PCI_DEVICE(qdev);
50

I
Isaku Yamahata 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63
    pcie_cap_deverr_reset(d);
    pcie_cap_slot_reset(d);
    pcie_cap_ari_reset(d);
    pci_bridge_reset(qdev);
}

static int xio3130_downstream_initfn(PCIDevice *d)
{
    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
    int rc;

64
    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
I
Isaku Yamahata 已提交
65 66 67 68 69 70 71 72 73 74
    if (rc < 0) {
        return rc;
    }

    pcie_port_init_reg(d);

    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
    if (rc < 0) {
I
Isaku Yamahata 已提交
75
        goto err_bridge;
I
Isaku Yamahata 已提交
76 77 78 79
    }
    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
    if (rc < 0) {
I
Isaku Yamahata 已提交
80
        goto err_bridge;
I
Isaku Yamahata 已提交
81 82 83 84
    }
    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
                       p->port);
    if (rc < 0) {
I
Isaku Yamahata 已提交
85
        goto err_msi;
I
Isaku Yamahata 已提交
86
    }
I
Isaku Yamahata 已提交
87
    pcie_cap_flr_init(d);
I
Isaku Yamahata 已提交
88 89 90 91 92
    pcie_cap_deverr_init(d);
    pcie_cap_slot_init(d, s->slot);
    pcie_chassis_create(s->chassis);
    rc = pcie_chassis_add_slot(s);
    if (rc < 0) {
I
Isaku Yamahata 已提交
93
        goto err_pcie_cap;
I
Isaku Yamahata 已提交
94 95
    }
    pcie_cap_ari_init(d);
I
Isaku Yamahata 已提交
96 97 98 99
    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
    if (rc < 0) {
        goto err;
    }
I
Isaku Yamahata 已提交
100 101

    return 0;
I
Isaku Yamahata 已提交
102 103 104 105 106 107 108 109

err:
    pcie_chassis_del_slot(s);
err_pcie_cap:
    pcie_cap_exit(d);
err_msi:
    msi_uninit(d);
err_bridge:
110
    pci_bridge_exitfn(d);
I
Isaku Yamahata 已提交
111
    return rc;
I
Isaku Yamahata 已提交
112 113
}

114
static void xio3130_downstream_exitfn(PCIDevice *d)
I
Isaku Yamahata 已提交
115
{
I
Isaku Yamahata 已提交
116 117 118 119 120 121
    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);

    pcie_aer_exit(d);
    pcie_chassis_del_slot(s);
I
Isaku Yamahata 已提交
122
    pcie_cap_exit(d);
I
Isaku Yamahata 已提交
123
    msi_uninit(d);
124
    pci_bridge_exitfn(d);
I
Isaku Yamahata 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
}

PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
                                  const char *bus_name, pci_map_irq_fn map_irq,
                                  uint8_t port, uint8_t chassis,
                                  uint16_t slot)
{
    PCIDevice *d;
    PCIBridge *br;
    DeviceState *qdev;

    d = pci_create_multifunction(bus, devfn, multifunction,
                                 "xio3130-downstream");
    if (!d) {
        return NULL;
    }
    br = DO_UPCAST(PCIBridge, dev, d);

    qdev = &br->dev.qdev;
    pci_bridge_map_irq(br, bus_name, map_irq);
    qdev_prop_set_uint8(qdev, "port", port);
    qdev_prop_set_uint8(qdev, "chassis", chassis);
    qdev_prop_set_uint16(qdev, "slot", slot);
    qdev_init_nofail(qdev);

    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
}

static const VMStateDescription vmstate_xio3130_downstream = {
    .name = "xio3130-express-downstream-port",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
158
    .post_load = pcie_cap_slot_post_load,
I
Isaku Yamahata 已提交
159 160
    .fields = (VMStateField[]) {
        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
I
Isaku Yamahata 已提交
161 162
        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
                       vmstate_pcie_aer_log, PCIEAERLog),
I
Isaku Yamahata 已提交
163 164 165 166
        VMSTATE_END_OF_LIST()
    }
};

167 168 169 170 171 172 173 174 175 176 177 178
static Property xio3130_downstream_properties[] = {
    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
    port.br.dev.exp.aer_log.log_max,
    PCIE_AER_LOG_MAX_DEFAULT),
    DEFINE_PROP_END_OF_LIST(),
};

static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
{
179
    DeviceClass *dc = DEVICE_CLASS(klass);
180 181 182 183 184 185 186 187 188 189
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->is_express = 1;
    k->is_bridge = 1;
    k->config_write = xio3130_downstream_write_config;
    k->init = xio3130_downstream_initfn;
    k->exit = xio3130_downstream_exitfn;
    k->vendor_id = PCI_VENDOR_ID_TI;
    k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
    k->revision = XIO3130_REVISION;
190 191 192 193
    dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
    dc->reset = xio3130_downstream_reset;
    dc->vmsd = &vmstate_xio3130_downstream;
    dc->props = xio3130_downstream_properties;
194 195
}

196
static const TypeInfo xio3130_downstream_info = {
197 198 199 200
    .name          = "xio3130-downstream",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(PCIESlot),
    .class_init    = xio3130_downstream_class_init,
I
Isaku Yamahata 已提交
201 202
};

A
Andreas Färber 已提交
203
static void xio3130_downstream_register_types(void)
I
Isaku Yamahata 已提交
204
{
205
    type_register_static(&xio3130_downstream_info);
I
Isaku Yamahata 已提交
206 207
}

A
Andreas Färber 已提交
208
type_init(xio3130_downstream_register_types)
I
Isaku Yamahata 已提交
209 210 211 212 213 214 215 216 217

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 8
 *  indent-tab-mode: nil
 * End:
 */