]> Git Repo - qemu.git/blame - hw/pci-host/designware.c
Include hw/irq.h a lot less
[qemu.git] / hw / pci-host / designware.c
CommitLineData
d64e5eab
AS
1/*
2 * Copyright (c) 2018, Impinj, Inc.
3 *
4 * Designware PCIe IP block emulation
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21#include "qemu/osdep.h"
22#include "qapi/error.h"
0b8fa32f 23#include "qemu/module.h"
d64e5eab
AS
24#include "hw/pci/msi.h"
25#include "hw/pci/pci_bridge.h"
26#include "hw/pci/pci_host.h"
27#include "hw/pci/pcie_port.h"
64552b6b 28#include "hw/irq.h"
d64e5eab
AS
29#include "hw/pci-host/designware.h"
30
31#define DESIGNWARE_PCIE_PORT_LINK_CONTROL 0x710
32#define DESIGNWARE_PCIE_PHY_DEBUG_R1 0x72C
33#define DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP BIT(4)
34#define DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
35#define DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE BIT(17)
36#define DESIGNWARE_PCIE_MSI_ADDR_LO 0x820
37#define DESIGNWARE_PCIE_MSI_ADDR_HI 0x824
38#define DESIGNWARE_PCIE_MSI_INTR0_ENABLE 0x828
39#define DESIGNWARE_PCIE_MSI_INTR0_MASK 0x82C
40#define DESIGNWARE_PCIE_MSI_INTR0_STATUS 0x830
41#define DESIGNWARE_PCIE_ATU_VIEWPORT 0x900
42#define DESIGNWARE_PCIE_ATU_REGION_INBOUND BIT(31)
43#define DESIGNWARE_PCIE_ATU_CR1 0x904
44#define DESIGNWARE_PCIE_ATU_TYPE_MEM (0x0 << 0)
45#define DESIGNWARE_PCIE_ATU_CR2 0x908
46#define DESIGNWARE_PCIE_ATU_ENABLE BIT(31)
47#define DESIGNWARE_PCIE_ATU_LOWER_BASE 0x90C
48#define DESIGNWARE_PCIE_ATU_UPPER_BASE 0x910
49#define DESIGNWARE_PCIE_ATU_LIMIT 0x914
50#define DESIGNWARE_PCIE_ATU_LOWER_TARGET 0x918
51#define DESIGNWARE_PCIE_ATU_BUS(x) (((x) >> 24) & 0xff)
52#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
53#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
54
01b96ec8
AS
55#define DESIGNWARE_PCIE_IRQ_MSI 3
56
d64e5eab
AS
57static DesignwarePCIEHost *
58designware_pcie_root_to_host(DesignwarePCIERoot *root)
59{
60 BusState *bus = qdev_get_parent_bus(DEVICE(root));
61 return DESIGNWARE_PCIE_HOST(bus->parent);
62}
63
64static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
65 uint64_t val, unsigned len)
66{
67 DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(opaque);
68 DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
69
70 root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
71
72 if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
01b96ec8 73 qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
d64e5eab
AS
74 }
75}
76
77static const MemoryRegionOps designware_pci_host_msi_ops = {
78 .write = designware_pcie_root_msi_write,
79 .endianness = DEVICE_LITTLE_ENDIAN,
80 .valid = {
81 .min_access_size = 4,
82 .max_access_size = 4,
83 },
84};
85
86static void designware_pcie_root_update_msi_mapping(DesignwarePCIERoot *root)
87
88{
89 MemoryRegion *mem = &root->msi.iomem;
90 const uint64_t base = root->msi.base;
91 const bool enable = root->msi.intr[0].enable;
92
93 memory_region_set_address(mem, base);
94 memory_region_set_enabled(mem, enable);
95}
96
97static DesignwarePCIEViewport *
98designware_pcie_root_get_current_viewport(DesignwarePCIERoot *root)
99{
100 const unsigned int idx = root->atu_viewport & 0xF;
101 const unsigned int dir =
102 !!(root->atu_viewport & DESIGNWARE_PCIE_ATU_REGION_INBOUND);
103 return &root->viewports[dir][idx];
104}
105
106static uint32_t
107designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len)
108{
109 DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
110 DesignwarePCIEViewport *viewport =
111 designware_pcie_root_get_current_viewport(root);
112
113 uint32_t val;
114
115 switch (address) {
116 case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
117 /*
118 * Linux guest uses this register only to configure number of
119 * PCIE lane (which in our case is irrelevant) and doesn't
120 * really care about the value it reads from this register
121 */
122 val = 0xDEADBEEF;
123 break;
124
125 case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
126 /*
127 * To make sure that any code in guest waiting for speed
128 * change does not time out we always report
129 * PORT_LOGIC_SPEED_CHANGE as set
130 */
131 val = DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE;
132 break;
133
134 case DESIGNWARE_PCIE_MSI_ADDR_LO:
135 val = root->msi.base;
136 break;
137
138 case DESIGNWARE_PCIE_MSI_ADDR_HI:
139 val = root->msi.base >> 32;
140 break;
141
142 case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
143 val = root->msi.intr[0].enable;
144 break;
145
146 case DESIGNWARE_PCIE_MSI_INTR0_MASK:
147 val = root->msi.intr[0].mask;
148 break;
149
150 case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
151 val = root->msi.intr[0].status;
152 break;
153
154 case DESIGNWARE_PCIE_PHY_DEBUG_R1:
155 val = DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
156 break;
157
158 case DESIGNWARE_PCIE_ATU_VIEWPORT:
159 val = root->atu_viewport;
160 break;
161
162 case DESIGNWARE_PCIE_ATU_LOWER_BASE:
163 val = viewport->base;
164 break;
165
166 case DESIGNWARE_PCIE_ATU_UPPER_BASE:
167 val = viewport->base >> 32;
168 break;
169
170 case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
171 val = viewport->target;
172 break;
173
174 case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
175 val = viewport->target >> 32;
176 break;
177
178 case DESIGNWARE_PCIE_ATU_LIMIT:
179 val = viewport->limit;
180 break;
181
182 case DESIGNWARE_PCIE_ATU_CR1:
183 case DESIGNWARE_PCIE_ATU_CR2: /* FALLTHROUGH */
184 val = viewport->cr[(address - DESIGNWARE_PCIE_ATU_CR1) /
185 sizeof(uint32_t)];
186 break;
187
188 default:
189 val = pci_default_read_config(d, address, len);
190 break;
191 }
192
193 return val;
194}
195
196static uint64_t designware_pcie_root_data_access(void *opaque, hwaddr addr,
197 uint64_t *val, unsigned len)
198{
199 DesignwarePCIEViewport *viewport = opaque;
200 DesignwarePCIERoot *root = viewport->root;
201
202 const uint8_t busnum = DESIGNWARE_PCIE_ATU_BUS(viewport->target);
203 const uint8_t devfn = DESIGNWARE_PCIE_ATU_DEVFN(viewport->target);
204 PCIBus *pcibus = pci_get_bus(PCI_DEVICE(root));
205 PCIDevice *pcidev = pci_find_device(pcibus, busnum, devfn);
206
207 if (pcidev) {
208 addr &= pci_config_size(pcidev) - 1;
209
210 if (val) {
211 pci_host_config_write_common(pcidev, addr,
212 pci_config_size(pcidev),
213 *val, len);
214 } else {
215 return pci_host_config_read_common(pcidev, addr,
216 pci_config_size(pcidev),
217 len);
218 }
219 }
220
221 return UINT64_MAX;
222}
223
224static uint64_t designware_pcie_root_data_read(void *opaque, hwaddr addr,
225 unsigned len)
226{
227 return designware_pcie_root_data_access(opaque, addr, NULL, len);
228}
229
230static void designware_pcie_root_data_write(void *opaque, hwaddr addr,
231 uint64_t val, unsigned len)
232{
233 designware_pcie_root_data_access(opaque, addr, &val, len);
234}
235
236static const MemoryRegionOps designware_pci_host_conf_ops = {
237 .read = designware_pcie_root_data_read,
238 .write = designware_pcie_root_data_write,
239 .endianness = DEVICE_LITTLE_ENDIAN,
240 .valid = {
241 .min_access_size = 1,
242 .max_access_size = 4,
243 },
244};
245
246static void designware_pcie_update_viewport(DesignwarePCIERoot *root,
247 DesignwarePCIEViewport *viewport)
248{
249 const uint64_t target = viewport->target;
250 const uint64_t base = viewport->base;
251 const uint64_t size = (uint64_t)viewport->limit - base + 1;
252 const bool enabled = viewport->cr[1] & DESIGNWARE_PCIE_ATU_ENABLE;
253
254 MemoryRegion *current, *other;
255
256 if (viewport->cr[0] == DESIGNWARE_PCIE_ATU_TYPE_MEM) {
257 current = &viewport->mem;
258 other = &viewport->cfg;
259 memory_region_set_alias_offset(current, target);
260 } else {
261 current = &viewport->cfg;
262 other = &viewport->mem;
263 }
264
265 /*
266 * An outbound viewport can be reconfigure from being MEM to CFG,
267 * to account for that we disable the "other" memory region that
268 * becomes unused due to that fact.
269 */
270 memory_region_set_enabled(other, false);
271 if (enabled) {
272 memory_region_set_size(current, size);
273 memory_region_set_address(current, base);
274 }
275 memory_region_set_enabled(current, enabled);
276}
277
278static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
279 uint32_t val, int len)
280{
281 DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
282 DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
283 DesignwarePCIEViewport *viewport =
284 designware_pcie_root_get_current_viewport(root);
285
286 switch (address) {
287 case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
288 case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
289 case DESIGNWARE_PCIE_PHY_DEBUG_R1:
290 /* No-op */
291 break;
292
293 case DESIGNWARE_PCIE_MSI_ADDR_LO:
294 root->msi.base &= 0xFFFFFFFF00000000ULL;
295 root->msi.base |= val;
97b7e29b 296 designware_pcie_root_update_msi_mapping(root);
d64e5eab
AS
297 break;
298
299 case DESIGNWARE_PCIE_MSI_ADDR_HI:
300 root->msi.base &= 0x00000000FFFFFFFFULL;
301 root->msi.base |= (uint64_t)val << 32;
97b7e29b 302 designware_pcie_root_update_msi_mapping(root);
d64e5eab
AS
303 break;
304
4eb42b81 305 case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
d64e5eab 306 root->msi.intr[0].enable = val;
4eb42b81 307 designware_pcie_root_update_msi_mapping(root);
d64e5eab 308 break;
d64e5eab
AS
309
310 case DESIGNWARE_PCIE_MSI_INTR0_MASK:
311 root->msi.intr[0].mask = val;
312 break;
313
314 case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
315 root->msi.intr[0].status ^= val;
316 if (!root->msi.intr[0].status) {
01b96ec8 317 qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
d64e5eab
AS
318 }
319 break;
320
321 case DESIGNWARE_PCIE_ATU_VIEWPORT:
322 root->atu_viewport = val;
323 break;
324
325 case DESIGNWARE_PCIE_ATU_LOWER_BASE:
326 viewport->base &= 0xFFFFFFFF00000000ULL;
327 viewport->base |= val;
328 break;
329
330 case DESIGNWARE_PCIE_ATU_UPPER_BASE:
331 viewport->base &= 0x00000000FFFFFFFFULL;
332 viewport->base |= (uint64_t)val << 32;
333 break;
334
335 case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
336 viewport->target &= 0xFFFFFFFF00000000ULL;
337 viewport->target |= val;
338 break;
339
340 case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
341 viewport->target &= 0x00000000FFFFFFFFULL;
342 viewport->target |= val;
343 break;
344
345 case DESIGNWARE_PCIE_ATU_LIMIT:
346 viewport->limit = val;
347 break;
348
349 case DESIGNWARE_PCIE_ATU_CR1:
350 viewport->cr[0] = val;
351 break;
352 case DESIGNWARE_PCIE_ATU_CR2:
353 viewport->cr[1] = val;
354 designware_pcie_update_viewport(root, viewport);
355 break;
356
357 default:
358 pci_bridge_write_config(d, address, val, len);
359 break;
360 }
361}
362
363static char *designware_pcie_viewport_name(const char *direction,
364 unsigned int i,
365 const char *type)
366{
367 return g_strdup_printf("PCI %s Viewport %u [%s]",
368 direction, i, type);
369}
370
371static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
372{
373 DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev);
374 DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
375 MemoryRegion *address_space = &host->pci.memory;
376 PCIBridge *br = PCI_BRIDGE(dev);
377 DesignwarePCIEViewport *viewport;
378 /*
379 * Dummy values used for initial configuration of MemoryRegions
380 * that belong to a given viewport
381 */
382 const hwaddr dummy_offset = 0;
383 const uint64_t dummy_size = 4;
384 size_t i;
385
386 br->bus_name = "dw-pcie";
387
388 pci_set_word(dev->config + PCI_COMMAND,
389 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
390
391 pci_config_set_interrupt_pin(dev->config, 1);
392 pci_bridge_initfn(dev, TYPE_PCIE_BUS);
393
394 pcie_port_init_reg(dev);
395
396 pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT,
397 0, &error_fatal);
398
399 msi_nonbroken = true;
400 msi_init(dev, 0x50, 32, true, true, &error_fatal);
401
402 for (i = 0; i < DESIGNWARE_PCIE_NUM_VIEWPORTS; i++) {
403 MemoryRegion *source, *destination, *mem;
404 const char *direction;
405 char *name;
406
407 viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][i];
408 viewport->inbound = true;
409 viewport->base = 0x0000000000000000ULL;
410 viewport->target = 0x0000000000000000ULL;
411 viewport->limit = UINT32_MAX;
412 viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM;
413
414 source = &host->pci.address_space_root;
415 destination = get_system_memory();
416 direction = "Inbound";
417
418 /*
419 * Configure MemoryRegion implementing PCI -> CPU memory
420 * access
421 */
422 mem = &viewport->mem;
423 name = designware_pcie_viewport_name(direction, i, "MEM");
424 memory_region_init_alias(mem, OBJECT(root), name, destination,
425 dummy_offset, dummy_size);
426 memory_region_add_subregion_overlap(source, dummy_offset, mem, -1);
427 memory_region_set_enabled(mem, false);
428 g_free(name);
429
430 viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_OUTBOUND][i];
431 viewport->root = root;
432 viewport->inbound = false;
433 viewport->base = 0x0000000000000000ULL;
434 viewport->target = 0x0000000000000000ULL;
435 viewport->limit = UINT32_MAX;
436 viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM;
437
438 destination = &host->pci.memory;
439 direction = "Outbound";
440 source = get_system_memory();
441
442 /*
443 * Configure MemoryRegion implementing CPU -> PCI memory
444 * access
445 */
446 mem = &viewport->mem;
447 name = designware_pcie_viewport_name(direction, i, "MEM");
448 memory_region_init_alias(mem, OBJECT(root), name, destination,
449 dummy_offset, dummy_size);
450 memory_region_add_subregion(source, dummy_offset, mem);
451 memory_region_set_enabled(mem, false);
452 g_free(name);
453
454 /*
455 * Configure MemoryRegion implementing access to configuration
456 * space
457 */
458 mem = &viewport->cfg;
459 name = designware_pcie_viewport_name(direction, i, "CFG");
460 memory_region_init_io(&viewport->cfg, OBJECT(root),
461 &designware_pci_host_conf_ops,
462 viewport, name, dummy_size);
463 memory_region_add_subregion(source, dummy_offset, mem);
464 memory_region_set_enabled(mem, false);
465 g_free(name);
466 }
467
468 /*
469 * If no inbound iATU windows are configured, HW defaults to
470 * letting inbound TLPs to pass in. We emulate that by exlicitly
471 * configuring first inbound window to cover all of target's
472 * address space.
473 *
474 * NOTE: This will not work correctly for the case when first
475 * configured inbound window is window 0
476 */
477 viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][0];
478 viewport->cr[1] = DESIGNWARE_PCIE_ATU_ENABLE;
479 designware_pcie_update_viewport(root, viewport);
480
481 memory_region_init_io(&root->msi.iomem, OBJECT(root),
482 &designware_pci_host_msi_ops,
483 root, "pcie-msi", 0x4);
484 /*
485 * We initially place MSI interrupt I/O region a adress 0 and
486 * disable it. It'll be later moved to correct offset and enabled
487 * in designware_pcie_root_update_msi_mapping() as a part of
488 * initialization done by guest OS
489 */
490 memory_region_add_subregion(address_space, dummy_offset, &root->msi.iomem);
491 memory_region_set_enabled(&root->msi.iomem, false);
492}
493
494static void designware_pcie_set_irq(void *opaque, int irq_num, int level)
495{
496 DesignwarePCIEHost *host = DESIGNWARE_PCIE_HOST(opaque);
497
498 qemu_set_irq(host->pci.irqs[irq_num], level);
499}
500
501static const char *
502designware_pcie_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus)
503{
504 return "0000:00";
505}
506
507static const VMStateDescription vmstate_designware_pcie_msi_bank = {
508 .name = "designware-pcie-msi-bank",
509 .version_id = 1,
510 .minimum_version_id = 1,
511 .fields = (VMStateField[]) {
512 VMSTATE_UINT32(enable, DesignwarePCIEMSIBank),
513 VMSTATE_UINT32(mask, DesignwarePCIEMSIBank),
514 VMSTATE_UINT32(status, DesignwarePCIEMSIBank),
515 VMSTATE_END_OF_LIST()
516 }
517};
518
519static const VMStateDescription vmstate_designware_pcie_msi = {
520 .name = "designware-pcie-msi",
521 .version_id = 1,
522 .minimum_version_id = 1,
523 .fields = (VMStateField[]) {
524 VMSTATE_UINT64(base, DesignwarePCIEMSI),
525 VMSTATE_STRUCT_ARRAY(intr,
526 DesignwarePCIEMSI,
527 DESIGNWARE_PCIE_NUM_MSI_BANKS,
528 1,
529 vmstate_designware_pcie_msi_bank,
530 DesignwarePCIEMSIBank),
531 VMSTATE_END_OF_LIST()
532 }
533};
534
535static const VMStateDescription vmstate_designware_pcie_viewport = {
536 .name = "designware-pcie-viewport",
537 .version_id = 1,
538 .minimum_version_id = 1,
539 .fields = (VMStateField[]) {
540 VMSTATE_UINT64(base, DesignwarePCIEViewport),
541 VMSTATE_UINT64(target, DesignwarePCIEViewport),
542 VMSTATE_UINT32(limit, DesignwarePCIEViewport),
543 VMSTATE_UINT32_ARRAY(cr, DesignwarePCIEViewport, 2),
544 VMSTATE_END_OF_LIST()
545 }
546};
547
548static const VMStateDescription vmstate_designware_pcie_root = {
549 .name = "designware-pcie-root",
550 .version_id = 1,
551 .minimum_version_id = 1,
552 .fields = (VMStateField[]) {
553 VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
554 VMSTATE_UINT32(atu_viewport, DesignwarePCIERoot),
555 VMSTATE_STRUCT_2DARRAY(viewports,
556 DesignwarePCIERoot,
557 2,
558 DESIGNWARE_PCIE_NUM_VIEWPORTS,
559 1,
560 vmstate_designware_pcie_viewport,
561 DesignwarePCIEViewport),
562 VMSTATE_STRUCT(msi,
563 DesignwarePCIERoot,
564 1,
565 vmstate_designware_pcie_msi,
566 DesignwarePCIEMSI),
567 VMSTATE_END_OF_LIST()
568 }
569};
570
571static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
572{
573 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
574 DeviceClass *dc = DEVICE_CLASS(klass);
575
576 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
577
578 k->vendor_id = PCI_VENDOR_ID_SYNOPSYS;
579 k->device_id = 0xABCD;
580 k->revision = 0;
581 k->class_id = PCI_CLASS_BRIDGE_PCI;
582 k->is_bridge = true;
583 k->exit = pci_bridge_exitfn;
584 k->realize = designware_pcie_root_realize;
585 k->config_read = designware_pcie_root_config_read;
586 k->config_write = designware_pcie_root_config_write;
587
588 dc->reset = pci_bridge_reset;
589 /*
590 * PCI-facing part of the host bridge, not usable without the
591 * host-facing part, which can't be device_add'ed, yet.
592 */
593 dc->user_creatable = false;
594 dc->vmsd = &vmstate_designware_pcie_root;
595}
596
597static uint64_t designware_pcie_host_mmio_read(void *opaque, hwaddr addr,
598 unsigned int size)
599{
600 PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
601 PCIDevice *device = pci_find_device(pci->bus, 0, 0);
602
603 return pci_host_config_read_common(device,
604 addr,
605 pci_config_size(device),
606 size);
607}
608
609static void designware_pcie_host_mmio_write(void *opaque, hwaddr addr,
610 uint64_t val, unsigned int size)
611{
612 PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
613 PCIDevice *device = pci_find_device(pci->bus, 0, 0);
614
615 return pci_host_config_write_common(device,
616 addr,
617 pci_config_size(device),
618 val, size);
619}
620
621static const MemoryRegionOps designware_pci_mmio_ops = {
622 .read = designware_pcie_host_mmio_read,
623 .write = designware_pcie_host_mmio_write,
624 .endianness = DEVICE_LITTLE_ENDIAN,
625 .impl = {
626 /*
627 * Our device would not work correctly if the guest was doing
628 * unaligned access. This might not be a limitation on the real
629 * device but in practice there is no reason for a guest to access
630 * this device unaligned.
631 */
632 .min_access_size = 4,
633 .max_access_size = 4,
634 .unaligned = false,
635 },
636};
637
638static AddressSpace *designware_pcie_host_set_iommu(PCIBus *bus, void *opaque,
639 int devfn)
640{
641 DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(opaque);
642
643 return &s->pci.address_space;
644}
645
646static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
647{
648 PCIHostState *pci = PCI_HOST_BRIDGE(dev);
649 DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(dev);
650 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
651 size_t i;
652
653 for (i = 0; i < ARRAY_SIZE(s->pci.irqs); i++) {
654 sysbus_init_irq(sbd, &s->pci.irqs[i]);
655 }
656
657 memory_region_init_io(&s->mmio,
658 OBJECT(s),
659 &designware_pci_mmio_ops,
660 s,
661 "pcie.reg", 4 * 1024);
662 sysbus_init_mmio(sbd, &s->mmio);
663
664 memory_region_init(&s->pci.io, OBJECT(s), "pcie-pio", 16);
665 memory_region_init(&s->pci.memory, OBJECT(s),
666 "pcie-bus-memory",
667 UINT64_MAX);
668
669 pci->bus = pci_register_root_bus(dev, "pcie",
670 designware_pcie_set_irq,
671 pci_swizzle_map_irq_fn,
672 s,
673 &s->pci.memory,
674 &s->pci.io,
675 0, 4,
676 TYPE_PCIE_BUS);
677
678 memory_region_init(&s->pci.address_space_root,
679 OBJECT(s),
680 "pcie-bus-address-space-root",
681 UINT64_MAX);
682 memory_region_add_subregion(&s->pci.address_space_root,
683 0x0, &s->pci.memory);
684 address_space_init(&s->pci.address_space,
685 &s->pci.address_space_root,
686 "pcie-bus-address-space");
687 pci_setup_iommu(pci->bus, designware_pcie_host_set_iommu, s);
688
689 qdev_set_parent_bus(DEVICE(&s->root), BUS(pci->bus));
690 qdev_init_nofail(DEVICE(&s->root));
691}
692
693static const VMStateDescription vmstate_designware_pcie_host = {
694 .name = "designware-pcie-host",
695 .version_id = 1,
696 .minimum_version_id = 1,
697 .fields = (VMStateField[]) {
698 VMSTATE_STRUCT(root,
699 DesignwarePCIEHost,
700 1,
701 vmstate_designware_pcie_root,
702 DesignwarePCIERoot),
703 VMSTATE_END_OF_LIST()
704 }
705};
706
707static void designware_pcie_host_class_init(ObjectClass *klass, void *data)
708{
709 DeviceClass *dc = DEVICE_CLASS(klass);
710 PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
711
712 hc->root_bus_path = designware_pcie_host_root_bus_path;
713 dc->realize = designware_pcie_host_realize;
714 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
715 dc->fw_name = "pci";
716 dc->vmsd = &vmstate_designware_pcie_host;
717}
718
719static void designware_pcie_host_init(Object *obj)
720{
721 DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(obj);
722 DesignwarePCIERoot *root = &s->root;
723
aff39be0
TH
724 object_initialize_child(obj, "root", root, sizeof(*root),
725 TYPE_DESIGNWARE_PCIE_ROOT, &error_abort, NULL);
d64e5eab
AS
726 qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
727 qdev_prop_set_bit(DEVICE(root), "multifunction", false);
728}
729
730static const TypeInfo designware_pcie_root_info = {
731 .name = TYPE_DESIGNWARE_PCIE_ROOT,
732 .parent = TYPE_PCI_BRIDGE,
733 .instance_size = sizeof(DesignwarePCIERoot),
734 .class_init = designware_pcie_root_class_init,
735 .interfaces = (InterfaceInfo[]) {
736 { INTERFACE_PCIE_DEVICE },
737 { }
738 },
739};
740
741static const TypeInfo designware_pcie_host_info = {
742 .name = TYPE_DESIGNWARE_PCIE_HOST,
743 .parent = TYPE_PCI_HOST_BRIDGE,
744 .instance_size = sizeof(DesignwarePCIEHost),
745 .instance_init = designware_pcie_host_init,
746 .class_init = designware_pcie_host_class_init,
747};
748
749static void designware_pcie_register(void)
750{
751 type_register_static(&designware_pcie_root_info);
752 type_register_static(&designware_pcie_host_info);
753}
754type_init(designware_pcie_register)
This page took 0.202942 seconds and 4 git commands to generate.