]>
Commit | Line | Data |
---|---|---|
f7d6f3fa MA |
1 | /* |
2 | * Generic PCI Express Root Port emulation | |
3 | * | |
4 | * Copyright (C) 2017 Red Hat Inc | |
5 | * | |
6 | * Authors: | |
7 | * Marcel Apfelbaum <marcel@redhat.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
10 | * See the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
13 | #include "qemu/osdep.h" | |
14 | #include "qapi/error.h" | |
15 | #include "hw/pci/msix.h" | |
16 | #include "hw/pci/pcie_port.h" | |
17 | ||
18 | #define TYPE_GEN_PCIE_ROOT_PORT "pcie-root-port" | |
226263fb AB |
19 | #define GEN_PCIE_ROOT_PORT(obj) \ |
20 | OBJECT_CHECK(GenPCIERootPort, (obj), TYPE_GEN_PCIE_ROOT_PORT) | |
f7d6f3fa MA |
21 | |
22 | #define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 | |
e07fb4b5 KO |
23 | #define GEN_PCIE_ROOT_PORT_ACS_OFFSET \ |
24 | (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF) | |
25 | ||
f7d6f3fa MA |
26 | #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1 |
27 | ||
bc277a52 MA |
28 | typedef struct GenPCIERootPort { |
29 | /*< private >*/ | |
30 | PCIESlot parent_obj; | |
31 | /*< public >*/ | |
32 | ||
33 | bool migrate_msix; | |
226263fb | 34 | |
9e899399 JL |
35 | /* additional resources to reserve */ |
36 | PCIResReserve res_reserve; | |
bc277a52 MA |
37 | } GenPCIERootPort; |
38 | ||
f7d6f3fa MA |
39 | static uint8_t gen_rp_aer_vector(const PCIDevice *d) |
40 | { | |
41 | return 0; | |
42 | } | |
43 | ||
44 | static int gen_rp_interrupts_init(PCIDevice *d, Error **errp) | |
45 | { | |
46 | int rc; | |
47 | ||
ee640c62 | 48 | rc = msix_init_exclusive_bar(d, GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR, 0, errp); |
f7d6f3fa MA |
49 | |
50 | if (rc < 0) { | |
51 | assert(rc == -ENOTSUP); | |
f7d6f3fa MA |
52 | } else { |
53 | msix_vector_use(d, 0); | |
54 | } | |
55 | ||
56 | return rc; | |
57 | } | |
58 | ||
59 | static void gen_rp_interrupts_uninit(PCIDevice *d) | |
60 | { | |
61 | msix_uninit_exclusive_bar(d); | |
62 | } | |
63 | ||
bc277a52 MA |
64 | static bool gen_rp_test_migrate_msix(void *opaque, int version_id) |
65 | { | |
66 | GenPCIERootPort *rp = opaque; | |
67 | ||
68 | return rp->migrate_msix; | |
69 | } | |
70 | ||
226263fb AB |
71 | static void gen_rp_realize(DeviceState *dev, Error **errp) |
72 | { | |
73 | PCIDevice *d = PCI_DEVICE(dev); | |
74 | GenPCIERootPort *grp = GEN_PCIE_ROOT_PORT(d); | |
75 | PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d); | |
fced4d00 | 76 | Error *local_err = NULL; |
226263fb | 77 | |
fced4d00 MA |
78 | rpc->parent_realize(dev, &local_err); |
79 | if (local_err) { | |
80 | error_propagate(errp, local_err); | |
81 | return; | |
82 | } | |
226263fb | 83 | |
9e899399 JL |
84 | int rc = pci_bridge_qemu_reserve_cap_init(d, 0, |
85 | grp->res_reserve, errp); | |
226263fb AB |
86 | |
87 | if (rc < 0) { | |
88 | rpc->parent_class.exit(d); | |
89 | return; | |
90 | } | |
8e36c336 | 91 | |
9e899399 | 92 | if (!grp->res_reserve.io) { |
8e36c336 MA |
93 | pci_word_test_and_clear_mask(d->wmask + PCI_COMMAND, |
94 | PCI_COMMAND_IO); | |
95 | d->wmask[PCI_IO_BASE] = 0; | |
96 | d->wmask[PCI_IO_LIMIT] = 0; | |
97 | } | |
226263fb AB |
98 | } |
99 | ||
f7d6f3fa MA |
100 | static const VMStateDescription vmstate_rp_dev = { |
101 | .name = "pcie-root-port", | |
9d6b9db1 | 102 | .priority = MIG_PRI_PCI_BUS, |
f7d6f3fa MA |
103 | .version_id = 1, |
104 | .minimum_version_id = 1, | |
105 | .post_load = pcie_cap_slot_post_load, | |
106 | .fields = (VMStateField[]) { | |
107 | VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), | |
108 | VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, | |
109 | PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), | |
bc277a52 MA |
110 | VMSTATE_MSIX_TEST(parent_obj.parent_obj.parent_obj.parent_obj, |
111 | GenPCIERootPort, | |
112 | gen_rp_test_migrate_msix), | |
f7d6f3fa MA |
113 | VMSTATE_END_OF_LIST() |
114 | } | |
115 | }; | |
116 | ||
bc277a52 | 117 | static Property gen_rp_props[] = { |
9e899399 JL |
118 | DEFINE_PROP_BOOL("x-migrate-msix", GenPCIERootPort, |
119 | migrate_msix, true), | |
120 | DEFINE_PROP_UINT32("bus-reserve", GenPCIERootPort, | |
121 | res_reserve.bus, -1), | |
122 | DEFINE_PROP_SIZE("io-reserve", GenPCIERootPort, | |
123 | res_reserve.io, -1), | |
124 | DEFINE_PROP_SIZE("mem-reserve", GenPCIERootPort, | |
125 | res_reserve.mem_non_pref, -1), | |
126 | DEFINE_PROP_SIZE("pref32-reserve", GenPCIERootPort, | |
127 | res_reserve.mem_pref_32, -1), | |
128 | DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort, | |
129 | res_reserve.mem_pref_64, -1), | |
c2a490e3 | 130 | DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot, |
a09d2038 | 131 | speed, PCIE_LINK_SPEED_16), |
c2a490e3 | 132 | DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot, |
a09d2038 | 133 | width, PCIE_LINK_WIDTH_32), |
bc277a52 MA |
134 | DEFINE_PROP_END_OF_LIST() |
135 | }; | |
136 | ||
f7d6f3fa MA |
137 | static void gen_rp_dev_class_init(ObjectClass *klass, void *data) |
138 | { | |
139 | DeviceClass *dc = DEVICE_CLASS(klass); | |
140 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
141 | PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass); | |
142 | ||
143 | k->vendor_id = PCI_VENDOR_ID_REDHAT; | |
144 | k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP; | |
145 | dc->desc = "PCI Express Root Port"; | |
146 | dc->vmsd = &vmstate_rp_dev; | |
bc277a52 | 147 | dc->props = gen_rp_props; |
226263fb | 148 | |
bf853881 | 149 | device_class_set_parent_realize(dc, gen_rp_realize, &rpc->parent_realize); |
226263fb | 150 | |
f7d6f3fa MA |
151 | rpc->aer_vector = gen_rp_aer_vector; |
152 | rpc->interrupts_init = gen_rp_interrupts_init; | |
153 | rpc->interrupts_uninit = gen_rp_interrupts_uninit; | |
154 | rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET; | |
e07fb4b5 | 155 | rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET; |
f7d6f3fa MA |
156 | } |
157 | ||
158 | static const TypeInfo gen_rp_dev_info = { | |
159 | .name = TYPE_GEN_PCIE_ROOT_PORT, | |
160 | .parent = TYPE_PCIE_ROOT_PORT, | |
bc277a52 | 161 | .instance_size = sizeof(GenPCIERootPort), |
f7d6f3fa MA |
162 | .class_init = gen_rp_dev_class_init, |
163 | }; | |
164 | ||
165 | static void gen_rp_register_types(void) | |
166 | { | |
167 | type_register_static(&gen_rp_dev_info); | |
168 | } | |
169 | type_init(gen_rp_register_types) |