1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "sysemu/sysemu.h"
12#include "qemu/log.h"
13#include "qapi/qmp/qerror.h"
14#include "qapi/error.h"
15#include "hw/pci/pci.h"
16#include "hw/pci/msi.h"
17#include "hw/pci/msix.h"
18#include "hw/sysbus.h"
19#include "migration/vmstate.h"
20#include "hw/qdev-properties.h"
21
22#include "hw/remote-port.h"
23#include "hw/remote-port-device.h"
24#include "hw/remote-port-memory-master.h"
25#include "hw/remote-port-memory-slave.h"
26
27#include "hw/fdt_generic_util.h"
28
29#ifndef REMOTE_PORT_ERR_DEBUG
30#define REMOTE_PORT_DEBUG_LEVEL 0
31#else
32#define REMOTE_PORT_DEBUG_LEVEL 1
33#endif
34
35#define DB_PRINT_L(level, ...) do { \
36 if (REMOTE_PORT_DEBUG_LEVEL > level) { \
37 fprintf(stderr, ": %s: ", __func__); \
38 fprintf(stderr, ## __VA_ARGS__); \
39 } \
40} while (0);
41
42#define TYPE_REMOTE_PORT_PCI_DEVICE "remote-port-pci-device"
43#define REMOTE_PORT_PCI_DEVICE(obj) \
44 OBJECT_CHECK(RemotePortPCIDevice, (obj), \
45 TYPE_REMOTE_PORT_PCI_DEVICE)
46
47#define REMOTE_PORT_PCI_DEVICE_PARENT_CLASS \
48 object_class_get_parent( \
49 object_class_by_name(TYPE_REMOTE_PORT_PCI_DEVICE))
50
51
52
53
54
55
56
57
58
59
60
61
62
63#define RPDEV_PCI_CONFIG 0
64#define RPDEV_PCI_LEGACY_IRQ 1
65#define RPDEV_PCI_MESSAGES 2
66#define RPDEV_PCI_DMA 3
67#define RPDEV_PCI_BAR_BASE 10
68
69typedef struct RemotePortPCIDevice RemotePortPCIDevice;
70
71struct RemotePortPCIDevice {
72
73 PCIDevice parent_obj;
74
75 RemotePortMemorySlave *rp_dma;
76
77
78 RemotePortMap *maps;
79
80 struct {
81 uint32_t rp_dev;
82 uint32_t nr_io_bars;
83 uint32_t nr_mm_bars;
84 uint64_t bar_size[6];
85 uint32_t nr_devs;
86 uint32_t vendor_id;
87 uint32_t device_id;
88 uint32_t revision;
89 uint32_t class_id;
90 uint8_t prog_if;
91 uint8_t irq_pin;
92
93
94 bool remote_config;
95
96 bool msi;
97 bool msix;
98 } cfg;
99 struct RemotePort *rp;
100 struct rp_peer_state *peer;
101};
102
103static void rp_io_access(MemoryTransaction *tr)
104{
105 RemotePortMap *map = tr->opaque;
106 RemotePortPCIDevice *s = map->parent;
107
108 rp_mm_access(s->rp, map->rp_dev, s->peer, tr, true, 0);
109}
110
111static const MemoryRegionOps rp_ops = {
112 .access = rp_io_access,
113 .endianness = DEVICE_LITTLE_ENDIAN,
114};
115
116static uint32_t rp_pci_read_config(PCIDevice *pci_dev, uint32_t addr, int size)
117{
118 RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
119 MemoryTransaction tr = {
120 .addr = addr,
121 .rw = false,
122 .size = size,
123 .attr = MEMTXATTRS_UNSPECIFIED
124 };
125
126 rp_mm_access(s->rp, s->cfg.rp_dev, s->peer, &tr, true, 0);
127 DB_PRINT_L(0, "addr: %x data: %x\n", addr, (uint32_t) tr.data.u64);
128 return tr.data.u64;
129}
130
131static void rp_pci_write_config(PCIDevice *pci_dev, uint32_t addr,
132 uint32_t value, int size)
133{
134 RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
135 MemoryTransaction tr = {
136 .addr = addr,
137 .rw = true,
138 .size = size,
139 .data.u64 = value,
140 .attr = MEMTXATTRS_UNSPECIFIED
141 };
142
143 DB_PRINT_L(0, "addr: %x data: %x\n", addr, value);
144 rp_mm_access(s->rp, s->cfg.rp_dev, s->peer, &tr, true, 0);
145 pci_default_write_config(pci_dev, addr, value, size);
146 DB_PRINT_L(1, "\n");
147}
148
149static void rp_gpio_interrupt(RemotePortDevice *rpd, struct rp_pkt *pkt)
150{
151 RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(rpd);
152 PCIDevice *d = PCI_DEVICE(s);
153 int irq = pkt->interrupt.line;
154 int level = pkt->interrupt.val;
155
156 DB_PRINT_L(0, "%s: irq[%d]=%d\n", __func__, irq, level);
157
158
159
160
161
162 if (s->cfg.msix && msix_enabled(d)) {
163 if (level) {
164 msix_notify(d, 0);
165 }
166 } else if (s->cfg.msi && msi_enabled(d)) {
167 if (level) {
168 msi_notify(d, 0);
169 }
170 } else {
171 pci_set_irq(d, level);
172 }
173}
174
175static void rp_pci_realize(PCIDevice *pci_dev, Error **errp)
176{
177 RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
178 AddressSpace *as;
179 int i;
180
181 assert(s->rp);
182 s->peer = rp_get_peer(s->rp);
183
184
185 pci_config_set_vendor_id(pci_dev->config, s->cfg.vendor_id);
186 pci_config_set_device_id(pci_dev->config, s->cfg.device_id);
187 pci_config_set_revision(pci_dev->config, s->cfg.revision);
188 pci_config_set_class(pci_dev->config, s->cfg.class_id);
189 pci_dev->config[PCI_CLASS_PROG] = s->cfg.prog_if;
190 pci_dev->config[PCI_INTERRUPT_PIN] = s->cfg.irq_pin;
191
192 if (s->cfg.remote_config) {
193 pci_dev->config_read = rp_pci_read_config;
194 }
195
196 pci_dev->config_write = rp_pci_write_config;
197
198 if (s->cfg.msi) {
199 msi_init(pci_dev, 0x60, 1, true, false, &error_fatal);
200 }
201
202
203 s->maps = g_new0(typeof(*s->maps), s->cfg.nr_io_bars + s->cfg.nr_mm_bars);
204
205 for (i = 0; i < s->cfg.nr_io_bars + s->cfg.nr_mm_bars; i++) {
206 bool io_bar = i < s->cfg.nr_io_bars;
207 char *name = g_strdup_printf("rp-pci-%s-%d", io_bar ? "io" : "mmio", i);
208 uint8_t attr = io_bar ?
209 PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
210
211 memory_region_init_io(&s->maps[i].iomem, OBJECT(s), &rp_ops,
212 &s->maps[i], name, s->cfg.bar_size[i]);
213 pci_register_bar(pci_dev, i, attr, &s->maps[i].iomem);
214 s->maps[i].rp_dev = RPDEV_PCI_BAR_BASE + i;
215 s->maps[i].parent = s;
216 g_free(name);
217 }
218
219 if (s->cfg.msix) {
220 msix_init_exclusive_bar(pci_dev, 1,
221 s->cfg.nr_io_bars + s->cfg.nr_mm_bars,
222 NULL);
223 msix_vector_use(pci_dev, 0);
224 }
225
226
227 rp_device_attach(OBJECT(s->rp), OBJECT(s->rp_dma), 0,
228 s->cfg.rp_dev + RPDEV_PCI_DMA, &error_abort);
229
230 as = pci_get_address_space(pci_dev);
231 object_property_set_link(OBJECT(s->rp_dma), OBJECT(as->root), "mr",
232 &error_abort);
233
234 object_property_set_bool(OBJECT(s->rp_dma), true, "realized", &error_abort);
235}
236
237static void rp_pci_exit(PCIDevice *pci_dev)
238{
239 RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
240
241
242 rp_device_detach(OBJECT(s->rp), OBJECT(s->rp_dma), 0,
243 s->cfg.rp_dev + RPDEV_PCI_DMA, &error_abort);
244 rp_device_detach(OBJECT(s->rp), OBJECT(s), 0,
245 s->cfg.rp_dev, &error_abort);
246
247
248
249
250
251 object_unparent(OBJECT(s->rp_dma));
252}
253
254static void rp_pci_init(Object *obj)
255{
256 RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(obj);
257 Object *tmp_obj;
258
259 object_property_add_link(obj, "rp-adaptor0", "remote-port",
260 (Object **)&s->rp,
261 qdev_prop_allow_set_link,
262 OBJ_PROP_LINK_STRONG);
263
264
265 tmp_obj = object_new(TYPE_REMOTE_PORT_MEMORY_SLAVE);
266 s->rp_dma = REMOTE_PORT_MEMORY_SLAVE(tmp_obj);
267
268 object_property_add_child(obj, "rp-dma", tmp_obj);
269
270 object_unref(tmp_obj);
271}
272
273static Property rp_properties[] = {
274 DEFINE_PROP_UINT32("rp-chan0", RemotePortPCIDevice, cfg.rp_dev, 0),
275 DEFINE_PROP_UINT32("nr-io-bars", RemotePortPCIDevice, cfg.nr_io_bars, 0),
276 DEFINE_PROP_UINT32("nr-mm-bars", RemotePortPCIDevice, cfg.nr_mm_bars, 0),
277 DEFINE_PROP_UINT32("vendor-id", RemotePortPCIDevice, cfg.vendor_id, 0),
278 DEFINE_PROP_UINT32("device-id", RemotePortPCIDevice, cfg.device_id, 0),
279 DEFINE_PROP_UINT32("revision", RemotePortPCIDevice, cfg.revision, 0),
280 DEFINE_PROP_UINT32("class-id", RemotePortPCIDevice, cfg.class_id, 0),
281 DEFINE_PROP_UINT8("prog-if", RemotePortPCIDevice, cfg.prog_if, 1),
282 DEFINE_PROP_UINT8("irq-pin", RemotePortPCIDevice, cfg.irq_pin, 1),
283
284 DEFINE_PROP_UINT64("bar-size0", RemotePortPCIDevice,
285 cfg.bar_size[0], 0x1000),
286 DEFINE_PROP_UINT64("bar-size1", RemotePortPCIDevice,
287 cfg.bar_size[1], 0x1000),
288 DEFINE_PROP_UINT64("bar-size2", RemotePortPCIDevice,
289 cfg.bar_size[2], 0x1000),
290 DEFINE_PROP_UINT64("bar-size3", RemotePortPCIDevice,
291 cfg.bar_size[3], 0x1000),
292 DEFINE_PROP_UINT64("bar-size4", RemotePortPCIDevice,
293 cfg.bar_size[4], 0x1000),
294 DEFINE_PROP_UINT64("bar-size5", RemotePortPCIDevice,
295 cfg.bar_size[5], 0x1000),
296
297 DEFINE_PROP_BOOL("remote-config", RemotePortPCIDevice,
298 cfg.remote_config, false),
299 DEFINE_PROP_BOOL("msi", RemotePortPCIDevice, cfg.msi, false),
300 DEFINE_PROP_BOOL("msix", RemotePortPCIDevice, cfg.msix, false),
301
302
303 DEFINE_PROP_UINT32("nr-devs", RemotePortPCIDevice, cfg.nr_devs, 20),
304 DEFINE_PROP_END_OF_LIST()
305};
306
307static void rp_pci_class_init(ObjectClass *oc, void *data)
308{
309 RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
310 DeviceClass *dc = DEVICE_CLASS(oc);
311 PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
312
313 dc->desc = "Remote-Port PCI Device";
314 device_class_set_props(dc, rp_properties);
315
316 rpdc->ops[RP_CMD_interrupt] = rp_gpio_interrupt;
317 k->realize = rp_pci_realize;
318 k->exit = rp_pci_exit;
319 k->vendor_id = PCI_VENDOR_ID_XILINX;
320 k->device_id = 0;
321 k->revision = 0;
322 k->class_id = PCI_CLASS_NETWORK_ETHERNET;
323 set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
324}
325
326static const TypeInfo rp_info = {
327 .name = TYPE_REMOTE_PORT_PCI_DEVICE,
328 .parent = TYPE_PCI_DEVICE,
329 .instance_size = sizeof(RemotePortPCIDevice),
330 .instance_init = rp_pci_init,
331 .class_init = rp_pci_class_init,
332 .interfaces = (InterfaceInfo[]) {
333 { TYPE_REMOTE_PORT_DEVICE },
334 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
335 { },
336 },
337};
338
339static void rp_register_types(void)
340{
341 type_register_static(&rp_info);
342}
343
344type_init(rp_register_types)
345