xref: /qemu/tests/qtest/libqos/pci-spapr.c (revision 3df72d1c5500347eac0b5b6d9894713dc443a079)
1cf716b31SLaurent Vivier /*
2cf716b31SLaurent Vivier  * libqos PCI bindings for SPAPR
3cf716b31SLaurent Vivier  *
4cf716b31SLaurent Vivier  * This work is licensed under the terms of the GNU GPL, version 2 or later.
5cf716b31SLaurent Vivier  * See the COPYING file in the top-level directory.
6cf716b31SLaurent Vivier  */
7cf716b31SLaurent Vivier 
8cf716b31SLaurent Vivier #include "qemu/osdep.h"
9907b5105SMarc-André Lureau #include "../libqtest.h"
10a2ce7dbdSPaolo Bonzini #include "pci-spapr.h"
11a2ce7dbdSPaolo Bonzini #include "rtas.h"
12a2ce7dbdSPaolo Bonzini #include "qgraph.h"
13cf716b31SLaurent Vivier 
14cf716b31SLaurent Vivier #include "hw/pci/pci_regs.h"
15cf716b31SLaurent Vivier 
16cf716b31SLaurent Vivier #include "qemu/host-utils.h"
170b8fa32fSMarkus Armbruster #include "qemu/module.h"
18cf716b31SLaurent Vivier 
19cf716b31SLaurent Vivier /*
20cf716b31SLaurent Vivier  * PCI devices are always little-endian
21cf716b31SLaurent Vivier  * SPAPR by default is big-endian
22cf716b31SLaurent Vivier  * so PCI accessors need to swap data endianness
23cf716b31SLaurent Vivier  */
24cf716b31SLaurent Vivier 
qpci_spapr_pio_readb(QPCIBus * bus,uint32_t addr)25a795fc08SDavid Gibson static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr)
26cf716b31SLaurent Vivier {
27cd1b354eSDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
28d786f782SThomas Huth     return qtest_readb(bus->qts, s->pio_cpu_base + addr);
29cf716b31SLaurent Vivier }
30cf716b31SLaurent Vivier 
qpci_spapr_pio_writeb(QPCIBus * bus,uint32_t addr,uint8_t val)31a795fc08SDavid Gibson static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val)
32cf716b31SLaurent Vivier {
33cd1b354eSDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
34d786f782SThomas Huth     qtest_writeb(bus->qts, s->pio_cpu_base + addr, val);
35cf716b31SLaurent Vivier }
36cf716b31SLaurent Vivier 
qpci_spapr_pio_readw(QPCIBus * bus,uint32_t addr)37a795fc08SDavid Gibson static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr)
38cf716b31SLaurent Vivier {
39cd1b354eSDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
40d786f782SThomas Huth     return bswap16(qtest_readw(bus->qts, s->pio_cpu_base + addr));
41cf716b31SLaurent Vivier }
42cf716b31SLaurent Vivier 
qpci_spapr_pio_writew(QPCIBus * bus,uint32_t addr,uint16_t val)43a795fc08SDavid Gibson static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val)
44a795fc08SDavid Gibson {
45a795fc08SDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
46d786f782SThomas Huth     qtest_writew(bus->qts, s->pio_cpu_base + addr, bswap16(val));
47a795fc08SDavid Gibson }
48a795fc08SDavid Gibson 
qpci_spapr_pio_readl(QPCIBus * bus,uint32_t addr)49a795fc08SDavid Gibson static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr)
50a795fc08SDavid Gibson {
51a795fc08SDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
52d786f782SThomas Huth     return bswap32(qtest_readl(bus->qts, s->pio_cpu_base + addr));
53a795fc08SDavid Gibson }
54a795fc08SDavid Gibson 
qpci_spapr_pio_writel(QPCIBus * bus,uint32_t addr,uint32_t val)55a795fc08SDavid Gibson static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val)
56a795fc08SDavid Gibson {
57a795fc08SDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
58d786f782SThomas Huth     qtest_writel(bus->qts, s->pio_cpu_base + addr, bswap32(val));
59a795fc08SDavid Gibson }
60a795fc08SDavid Gibson 
qpci_spapr_pio_readq(QPCIBus * bus,uint32_t addr)61f775f45aSDavid Gibson static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr)
62f775f45aSDavid Gibson {
63f775f45aSDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
64d786f782SThomas Huth     return bswap64(qtest_readq(bus->qts, s->pio_cpu_base + addr));
65f775f45aSDavid Gibson }
66f775f45aSDavid Gibson 
qpci_spapr_pio_writeq(QPCIBus * bus,uint32_t addr,uint64_t val)67f775f45aSDavid Gibson static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val)
68f775f45aSDavid Gibson {
69f775f45aSDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
70d786f782SThomas Huth     qtest_writeq(bus->qts, s->pio_cpu_base + addr, bswap64(val));
71f775f45aSDavid Gibson }
72f775f45aSDavid Gibson 
qpci_spapr_memread(QPCIBus * bus,uint32_t addr,void * buf,size_t len)739a84f889SDavid Gibson static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr,
749a84f889SDavid Gibson                                void *buf, size_t len)
759a84f889SDavid Gibson {
769a84f889SDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
77d786f782SThomas Huth     qtest_memread(bus->qts, s->mmio32_cpu_base + addr, buf, len);
789a84f889SDavid Gibson }
799a84f889SDavid Gibson 
qpci_spapr_memwrite(QPCIBus * bus,uint32_t addr,const void * buf,size_t len)809a84f889SDavid Gibson static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr,
819a84f889SDavid Gibson                                 const void *buf, size_t len)
829a84f889SDavid Gibson {
839a84f889SDavid Gibson     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
84d786f782SThomas Huth     qtest_memwrite(bus->qts, s->mmio32_cpu_base + addr, buf, len);
859a84f889SDavid Gibson }
869a84f889SDavid Gibson 
qpci_spapr_config_readb(QPCIBus * bus,int devfn,uint8_t offset)87cf716b31SLaurent Vivier static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
88cf716b31SLaurent Vivier {
89cf716b31SLaurent Vivier     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
90cf716b31SLaurent Vivier     uint32_t config_addr = (devfn << 8) | offset;
919b67af76SEric Blake     return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid,
929b67af76SEric Blake                                      config_addr, 1);
93cf716b31SLaurent Vivier }
94cf716b31SLaurent Vivier 
qpci_spapr_config_readw(QPCIBus * bus,int devfn,uint8_t offset)95cf716b31SLaurent Vivier static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
96cf716b31SLaurent Vivier {
97cf716b31SLaurent Vivier     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
98cf716b31SLaurent Vivier     uint32_t config_addr = (devfn << 8) | offset;
999b67af76SEric Blake     return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid,
1009b67af76SEric Blake                                      config_addr, 2);
101cf716b31SLaurent Vivier }
102cf716b31SLaurent Vivier 
qpci_spapr_config_readl(QPCIBus * bus,int devfn,uint8_t offset)103cf716b31SLaurent Vivier static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
104cf716b31SLaurent Vivier {
105cf716b31SLaurent Vivier     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
106cf716b31SLaurent Vivier     uint32_t config_addr = (devfn << 8) | offset;
1079b67af76SEric Blake     return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid,
1089b67af76SEric Blake                                      config_addr, 4);
109cf716b31SLaurent Vivier }
110cf716b31SLaurent Vivier 
qpci_spapr_config_writeb(QPCIBus * bus,int devfn,uint8_t offset,uint8_t value)111cf716b31SLaurent Vivier static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
112cf716b31SLaurent Vivier                                      uint8_t value)
113cf716b31SLaurent Vivier {
114cf716b31SLaurent Vivier     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
115cf716b31SLaurent Vivier     uint32_t config_addr = (devfn << 8) | offset;
1169b67af76SEric Blake     qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid,
1179b67af76SEric Blake                                config_addr, 1, value);
118cf716b31SLaurent Vivier }
119cf716b31SLaurent Vivier 
qpci_spapr_config_writew(QPCIBus * bus,int devfn,uint8_t offset,uint16_t value)120cf716b31SLaurent Vivier static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
121cf716b31SLaurent Vivier                                      uint16_t value)
122cf716b31SLaurent Vivier {
123cf716b31SLaurent Vivier     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
124cf716b31SLaurent Vivier     uint32_t config_addr = (devfn << 8) | offset;
1259b67af76SEric Blake     qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid,
1269b67af76SEric Blake                                config_addr, 2, value);
127cf716b31SLaurent Vivier }
128cf716b31SLaurent Vivier 
qpci_spapr_config_writel(QPCIBus * bus,int devfn,uint8_t offset,uint32_t value)129cf716b31SLaurent Vivier static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
130cf716b31SLaurent Vivier                                      uint32_t value)
131cf716b31SLaurent Vivier {
132cf716b31SLaurent Vivier     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
133cf716b31SLaurent Vivier     uint32_t config_addr = (devfn << 8) | offset;
1349b67af76SEric Blake     qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid,
1359b67af76SEric Blake                                config_addr, 4, value);
136cf716b31SLaurent Vivier }
137cf716b31SLaurent Vivier 
138357d1e3bSDavid Gibson #define SPAPR_PCI_BASE               (1ULL << 45)
139357d1e3bSDavid Gibson 
1408360544aSDavid Gibson #define SPAPR_PCI_MMIO32_WIN_SIZE    0x80000000 /* 2 GiB */
141cd1b354eSDavid Gibson #define SPAPR_PCI_IO_WIN_SIZE        0x10000
142cd1b354eSDavid Gibson 
qpci_spapr_get_driver(void * obj,const char * interface)143b8782d2aSEmanuele Giuseppe Esposito static void *qpci_spapr_get_driver(void *obj, const char *interface)
144cf716b31SLaurent Vivier {
145b8782d2aSEmanuele Giuseppe Esposito     QPCIBusSPAPR *qpci = obj;
146b8782d2aSEmanuele Giuseppe Esposito     if (!g_strcmp0(interface, "pci-bus")) {
147b8782d2aSEmanuele Giuseppe Esposito         return &qpci->bus;
148b8782d2aSEmanuele Giuseppe Esposito     }
149b8782d2aSEmanuele Giuseppe Esposito     fprintf(stderr, "%s not present in pci-bus-spapr", interface);
150b8782d2aSEmanuele Giuseppe Esposito     g_assert_not_reached();
151b8782d2aSEmanuele Giuseppe Esposito }
152cf716b31SLaurent Vivier 
qpci_init_spapr(QPCIBusSPAPR * qpci,QTestState * qts,QGuestAllocator * alloc)153b8782d2aSEmanuele Giuseppe Esposito void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts,
154b8782d2aSEmanuele Giuseppe Esposito                      QGuestAllocator *alloc)
155b8782d2aSEmanuele Giuseppe Esposito {
156e5d1730dSEric Blake     assert(qts);
157cf716b31SLaurent Vivier 
15892bbafc7SEmanuele Giuseppe Esposito     /* tests cannot use spapr, needs to be fixed first */
159c098aac7SJafar Abdi     qpci->bus.has_buggy_msi = true;
16092bbafc7SEmanuele Giuseppe Esposito 
161b8782d2aSEmanuele Giuseppe Esposito     qpci->alloc = alloc;
162cf716b31SLaurent Vivier 
163b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_readb = qpci_spapr_pio_readb;
164b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_readw = qpci_spapr_pio_readw;
165b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_readl = qpci_spapr_pio_readl;
166b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_readq = qpci_spapr_pio_readq;
167cf716b31SLaurent Vivier 
168b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_writeb = qpci_spapr_pio_writeb;
169b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_writew = qpci_spapr_pio_writew;
170b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_writel = qpci_spapr_pio_writel;
171b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_writeq = qpci_spapr_pio_writeq;
172a795fc08SDavid Gibson 
173b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.memread = qpci_spapr_memread;
174b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.memwrite = qpci_spapr_memwrite;
1759a84f889SDavid Gibson 
176b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.config_readb = qpci_spapr_config_readb;
177b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.config_readw = qpci_spapr_config_readw;
178b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.config_readl = qpci_spapr_config_readl;
179cf716b31SLaurent Vivier 
180b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.config_writeb = qpci_spapr_config_writeb;
181b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.config_writew = qpci_spapr_config_writew;
182b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.config_writel = qpci_spapr_config_writel;
183cf716b31SLaurent Vivier 
184cd1b354eSDavid Gibson     /* FIXME: We assume the default location of the PHB for now.
185cd1b354eSDavid Gibson      * Ideally we'd parse the device tree deposited in the guest to
186cd1b354eSDavid Gibson      * get the window locations */
187b8782d2aSEmanuele Giuseppe Esposito     qpci->buid = 0x800000020000000ULL;
188cd1b354eSDavid Gibson 
189b8782d2aSEmanuele Giuseppe Esposito     qpci->pio_cpu_base = SPAPR_PCI_BASE;
190b8782d2aSEmanuele Giuseppe Esposito     qpci->pio.pci_base = 0;
191b8782d2aSEmanuele Giuseppe Esposito     qpci->pio.size = SPAPR_PCI_IO_WIN_SIZE;
192cd1b354eSDavid Gibson 
1938360544aSDavid Gibson     /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */
194b8782d2aSEmanuele Giuseppe Esposito     qpci->mmio32_cpu_base = SPAPR_PCI_BASE;
195b8782d2aSEmanuele Giuseppe Esposito     qpci->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE;
196b8782d2aSEmanuele Giuseppe Esposito     qpci->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE;
197cd1b354eSDavid Gibson 
198b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.qts = qts;
199b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.pio_alloc_ptr = 0xc000;
200*3df72d1cSEric Auger     qpci->bus.pio_limit = 0x10000;
201b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base;
202b8782d2aSEmanuele Giuseppe Esposito     qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size;
203cf716b31SLaurent Vivier 
204b8782d2aSEmanuele Giuseppe Esposito     qpci->obj.get_driver = qpci_spapr_get_driver;
205b8782d2aSEmanuele Giuseppe Esposito }
206b8782d2aSEmanuele Giuseppe Esposito 
qpci_new_spapr(QTestState * qts,QGuestAllocator * alloc)207b8782d2aSEmanuele Giuseppe Esposito QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc)
208b8782d2aSEmanuele Giuseppe Esposito {
209b8782d2aSEmanuele Giuseppe Esposito     QPCIBusSPAPR *qpci = g_new0(QPCIBusSPAPR, 1);
210b8782d2aSEmanuele Giuseppe Esposito     qpci_init_spapr(qpci, qts, alloc);
211b8782d2aSEmanuele Giuseppe Esposito 
212b8782d2aSEmanuele Giuseppe Esposito     return &qpci->bus;
213cf716b31SLaurent Vivier }
214cf716b31SLaurent Vivier 
qpci_free_spapr(QPCIBus * bus)215cf716b31SLaurent Vivier void qpci_free_spapr(QPCIBus *bus)
216cf716b31SLaurent Vivier {
217b8782d2aSEmanuele Giuseppe Esposito     QPCIBusSPAPR *s;
218b8782d2aSEmanuele Giuseppe Esposito 
219b8782d2aSEmanuele Giuseppe Esposito     if (!bus) {
220b8782d2aSEmanuele Giuseppe Esposito         return;
221b8782d2aSEmanuele Giuseppe Esposito     }
222b8782d2aSEmanuele Giuseppe Esposito     s = container_of(bus, QPCIBusSPAPR, bus);
223cf716b31SLaurent Vivier 
224cf716b31SLaurent Vivier     g_free(s);
225cf716b31SLaurent Vivier }
226b8782d2aSEmanuele Giuseppe Esposito 
qpci_spapr_register_nodes(void)227b8782d2aSEmanuele Giuseppe Esposito static void qpci_spapr_register_nodes(void)
228b8782d2aSEmanuele Giuseppe Esposito {
229b8782d2aSEmanuele Giuseppe Esposito     qos_node_create_driver("pci-bus-spapr", NULL);
230b8782d2aSEmanuele Giuseppe Esposito     qos_node_produces("pci-bus-spapr", "pci-bus");
231b8782d2aSEmanuele Giuseppe Esposito }
232b8782d2aSEmanuele Giuseppe Esposito 
233b8782d2aSEmanuele Giuseppe Esposito libqos_init(qpci_spapr_register_nodes);
234