xref: /qemu/hw/pci-bridge/gen_pcie_root_port.c (revision f7d6f3fac8dd7b1d1ecb2662b1751e0ed3fef727)
1*f7d6f3faSMarcel Apfelbaum /*
2*f7d6f3faSMarcel Apfelbaum  * Generic PCI Express Root Port emulation
3*f7d6f3faSMarcel Apfelbaum  *
4*f7d6f3faSMarcel Apfelbaum  * Copyright (C) 2017 Red Hat Inc
5*f7d6f3faSMarcel Apfelbaum  *
6*f7d6f3faSMarcel Apfelbaum  * Authors:
7*f7d6f3faSMarcel Apfelbaum  *   Marcel Apfelbaum <marcel@redhat.com>
8*f7d6f3faSMarcel Apfelbaum  *
9*f7d6f3faSMarcel Apfelbaum  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10*f7d6f3faSMarcel Apfelbaum  * See the COPYING file in the top-level directory.
11*f7d6f3faSMarcel Apfelbaum  */
12*f7d6f3faSMarcel Apfelbaum 
13*f7d6f3faSMarcel Apfelbaum #include "qemu/osdep.h"
14*f7d6f3faSMarcel Apfelbaum #include "qapi/error.h"
15*f7d6f3faSMarcel Apfelbaum #include "hw/pci/msix.h"
16*f7d6f3faSMarcel Apfelbaum #include "hw/pci/pcie_port.h"
17*f7d6f3faSMarcel Apfelbaum 
18*f7d6f3faSMarcel Apfelbaum #define TYPE_GEN_PCIE_ROOT_PORT                "pcie-root-port"
19*f7d6f3faSMarcel Apfelbaum 
20*f7d6f3faSMarcel Apfelbaum #define GEN_PCIE_ROOT_PORT_AER_OFFSET           0x100
21*f7d6f3faSMarcel Apfelbaum #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR       1
22*f7d6f3faSMarcel Apfelbaum 
23*f7d6f3faSMarcel Apfelbaum static uint8_t gen_rp_aer_vector(const PCIDevice *d)
24*f7d6f3faSMarcel Apfelbaum {
25*f7d6f3faSMarcel Apfelbaum     return 0;
26*f7d6f3faSMarcel Apfelbaum }
27*f7d6f3faSMarcel Apfelbaum 
28*f7d6f3faSMarcel Apfelbaum static int gen_rp_interrupts_init(PCIDevice *d, Error **errp)
29*f7d6f3faSMarcel Apfelbaum {
30*f7d6f3faSMarcel Apfelbaum     int rc;
31*f7d6f3faSMarcel Apfelbaum 
32*f7d6f3faSMarcel Apfelbaum     rc = msix_init_exclusive_bar(d, GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR, 0);
33*f7d6f3faSMarcel Apfelbaum 
34*f7d6f3faSMarcel Apfelbaum     if (rc < 0) {
35*f7d6f3faSMarcel Apfelbaum         assert(rc == -ENOTSUP);
36*f7d6f3faSMarcel Apfelbaum         error_setg(errp, "Unable to init msix vectors");
37*f7d6f3faSMarcel Apfelbaum     } else {
38*f7d6f3faSMarcel Apfelbaum         msix_vector_use(d, 0);
39*f7d6f3faSMarcel Apfelbaum     }
40*f7d6f3faSMarcel Apfelbaum 
41*f7d6f3faSMarcel Apfelbaum     return rc;
42*f7d6f3faSMarcel Apfelbaum }
43*f7d6f3faSMarcel Apfelbaum 
44*f7d6f3faSMarcel Apfelbaum static void gen_rp_interrupts_uninit(PCIDevice *d)
45*f7d6f3faSMarcel Apfelbaum {
46*f7d6f3faSMarcel Apfelbaum     msix_uninit_exclusive_bar(d);
47*f7d6f3faSMarcel Apfelbaum }
48*f7d6f3faSMarcel Apfelbaum 
49*f7d6f3faSMarcel Apfelbaum static const VMStateDescription vmstate_rp_dev = {
50*f7d6f3faSMarcel Apfelbaum     .name = "pcie-root-port",
51*f7d6f3faSMarcel Apfelbaum     .version_id = 1,
52*f7d6f3faSMarcel Apfelbaum     .minimum_version_id = 1,
53*f7d6f3faSMarcel Apfelbaum     .post_load = pcie_cap_slot_post_load,
54*f7d6f3faSMarcel Apfelbaum     .fields = (VMStateField[]) {
55*f7d6f3faSMarcel Apfelbaum         VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
56*f7d6f3faSMarcel Apfelbaum         VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
57*f7d6f3faSMarcel Apfelbaum                        PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
58*f7d6f3faSMarcel Apfelbaum         VMSTATE_END_OF_LIST()
59*f7d6f3faSMarcel Apfelbaum     }
60*f7d6f3faSMarcel Apfelbaum };
61*f7d6f3faSMarcel Apfelbaum 
62*f7d6f3faSMarcel Apfelbaum static void gen_rp_dev_class_init(ObjectClass *klass, void *data)
63*f7d6f3faSMarcel Apfelbaum {
64*f7d6f3faSMarcel Apfelbaum     DeviceClass *dc = DEVICE_CLASS(klass);
65*f7d6f3faSMarcel Apfelbaum     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
66*f7d6f3faSMarcel Apfelbaum     PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
67*f7d6f3faSMarcel Apfelbaum 
68*f7d6f3faSMarcel Apfelbaum     k->vendor_id = PCI_VENDOR_ID_REDHAT;
69*f7d6f3faSMarcel Apfelbaum     k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP;
70*f7d6f3faSMarcel Apfelbaum     dc->desc = "PCI Express Root Port";
71*f7d6f3faSMarcel Apfelbaum     dc->vmsd = &vmstate_rp_dev;
72*f7d6f3faSMarcel Apfelbaum     rpc->aer_vector = gen_rp_aer_vector;
73*f7d6f3faSMarcel Apfelbaum     rpc->interrupts_init = gen_rp_interrupts_init;
74*f7d6f3faSMarcel Apfelbaum     rpc->interrupts_uninit = gen_rp_interrupts_uninit;
75*f7d6f3faSMarcel Apfelbaum     rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
76*f7d6f3faSMarcel Apfelbaum }
77*f7d6f3faSMarcel Apfelbaum 
78*f7d6f3faSMarcel Apfelbaum static const TypeInfo gen_rp_dev_info = {
79*f7d6f3faSMarcel Apfelbaum     .name          = TYPE_GEN_PCIE_ROOT_PORT,
80*f7d6f3faSMarcel Apfelbaum     .parent        = TYPE_PCIE_ROOT_PORT,
81*f7d6f3faSMarcel Apfelbaum     .class_init    = gen_rp_dev_class_init,
82*f7d6f3faSMarcel Apfelbaum };
83*f7d6f3faSMarcel Apfelbaum 
84*f7d6f3faSMarcel Apfelbaum  static void gen_rp_register_types(void)
85*f7d6f3faSMarcel Apfelbaum  {
86*f7d6f3faSMarcel Apfelbaum     type_register_static(&gen_rp_dev_info);
87*f7d6f3faSMarcel Apfelbaum  }
88*f7d6f3faSMarcel Apfelbaum  type_init(gen_rp_register_types)
89