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