xref: /qemu/tests/qtest/libqos/pci-spapr.c (revision cf716b31cba278a6dbff585d58fa29d1ae2fe334)
1 /*
2  * libqos PCI bindings for SPAPR
3  *
4  * This work is licensed under the terms of the GNU GPL, version 2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7 
8 #include "qemu/osdep.h"
9 #include "libqtest.h"
10 #include "libqos/pci-spapr.h"
11 #include "libqos/rtas.h"
12 
13 #include "hw/pci/pci_regs.h"
14 
15 #include "qemu-common.h"
16 #include "qemu/host-utils.h"
17 
18 
19 /* From include/hw/pci-host/spapr.h */
20 
21 #define SPAPR_PCI_BASE_BUID          0x800000020000000ULL
22 
23 #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
24 
25 #define SPAPR_PCI_WINDOW_BASE        0x10000000000ULL
26 #define SPAPR_PCI_WINDOW_SPACING     0x1000000000ULL
27 #define SPAPR_PCI_MMIO_WIN_OFF       0xA0000000
28 #define SPAPR_PCI_MMIO_WIN_SIZE      (SPAPR_PCI_WINDOW_SPACING - \
29                                      SPAPR_PCI_MEM_WIN_BUS_OFFSET)
30 #define SPAPR_PCI_IO_WIN_OFF         0x80000000
31 #define SPAPR_PCI_IO_WIN_SIZE        0x10000
32 
33 /* index is the phb index */
34 
35 #define BUIDBASE(index)              (SPAPR_PCI_BASE_BUID + (index))
36 #define PCIBASE(index)               (SPAPR_PCI_WINDOW_BASE + \
37                                       (index) * SPAPR_PCI_WINDOW_SPACING)
38 #define IOBASE(index)                (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF)
39 #define MMIOBASE(index)              (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF)
40 
41 typedef struct QPCIBusSPAPR {
42     QPCIBus bus;
43     QGuestAllocator *alloc;
44 
45     uint64_t pci_hole_start;
46     uint64_t pci_hole_size;
47     uint64_t pci_hole_alloc;
48 
49     uint32_t pci_iohole_start;
50     uint32_t pci_iohole_size;
51     uint32_t pci_iohole_alloc;
52 } QPCIBusSPAPR;
53 
54 /*
55  * PCI devices are always little-endian
56  * SPAPR by default is big-endian
57  * so PCI accessors need to swap data endianness
58  */
59 
60 static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
61 {
62     uint64_t port = (uintptr_t)addr;
63     uint8_t v;
64     if (port < SPAPR_PCI_IO_WIN_SIZE) {
65         v = readb(IOBASE(0) + port);
66     } else {
67         v = readb(MMIOBASE(0) + port);
68     }
69     return v;
70 }
71 
72 static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr)
73 {
74     uint64_t port = (uintptr_t)addr;
75     uint16_t v;
76     if (port < SPAPR_PCI_IO_WIN_SIZE) {
77         v = readw(IOBASE(0) + port);
78     } else {
79         v = readw(MMIOBASE(0) + port);
80     }
81     return bswap16(v);
82 }
83 
84 static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr)
85 {
86     uint64_t port = (uintptr_t)addr;
87     uint32_t v;
88     if (port < SPAPR_PCI_IO_WIN_SIZE) {
89         v = readl(IOBASE(0) + port);
90     } else {
91         v = readl(MMIOBASE(0) + port);
92     }
93     return bswap32(v);
94 }
95 
96 static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
97 {
98     uint64_t port = (uintptr_t)addr;
99     if (port < SPAPR_PCI_IO_WIN_SIZE) {
100         writeb(IOBASE(0) + port, value);
101     } else {
102         writeb(MMIOBASE(0) + port, value);
103     }
104 }
105 
106 static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value)
107 {
108     uint64_t port = (uintptr_t)addr;
109     value = bswap16(value);
110     if (port < SPAPR_PCI_IO_WIN_SIZE) {
111         writew(IOBASE(0) + port, value);
112     } else {
113         writew(MMIOBASE(0) + port, value);
114     }
115 }
116 
117 static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value)
118 {
119     uint64_t port = (uintptr_t)addr;
120     value = bswap32(value);
121     if (port < SPAPR_PCI_IO_WIN_SIZE) {
122         writel(IOBASE(0) + port, value);
123     } else {
124         writel(MMIOBASE(0) + port, value);
125     }
126 }
127 
128 static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
129 {
130     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
131     uint32_t config_addr = (devfn << 8) | offset;
132     return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
133                                      config_addr, 1);
134 }
135 
136 static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
137 {
138     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
139     uint32_t config_addr = (devfn << 8) | offset;
140     return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
141                                      config_addr, 2);
142 }
143 
144 static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
145 {
146     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
147     uint32_t config_addr = (devfn << 8) | offset;
148     return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
149                                      config_addr, 4);
150 }
151 
152 static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
153                                      uint8_t value)
154 {
155     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
156     uint32_t config_addr = (devfn << 8) | offset;
157     qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
158                                config_addr, 1, value);
159 }
160 
161 static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
162                                      uint16_t value)
163 {
164     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
165     uint32_t config_addr = (devfn << 8) | offset;
166     qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
167                                config_addr, 2, value);
168 }
169 
170 static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
171                                      uint32_t value)
172 {
173     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
174     uint32_t config_addr = (devfn << 8) | offset;
175     qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
176                                config_addr, 4, value);
177 }
178 
179 static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno,
180                               uint64_t *sizeptr)
181 {
182     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
183     static const int bar_reg_map[] = {
184         PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
185         PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
186     };
187     int bar_reg;
188     uint32_t addr;
189     uint64_t size;
190     uint32_t io_type;
191 
192     g_assert(barno >= 0 && barno <= 5);
193     bar_reg = bar_reg_map[barno];
194 
195     qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
196     addr = qpci_config_readl(dev, bar_reg);
197 
198     io_type = addr & PCI_BASE_ADDRESS_SPACE;
199     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
200         addr &= PCI_BASE_ADDRESS_IO_MASK;
201     } else {
202         addr &= PCI_BASE_ADDRESS_MEM_MASK;
203     }
204 
205     size = (1ULL << ctzl(addr));
206     if (size == 0) {
207         return NULL;
208     }
209     if (sizeptr) {
210         *sizeptr = size;
211     }
212 
213     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
214         uint16_t loc;
215 
216         g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size
217                  <= s->pci_iohole_size);
218         s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size);
219         loc = s->pci_iohole_start + s->pci_iohole_alloc;
220         s->pci_iohole_alloc += size;
221 
222         qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
223 
224         return (void *)(unsigned long)loc;
225     } else {
226         uint64_t loc;
227 
228         g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size
229                  <= s->pci_hole_size);
230         s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size);
231         loc = s->pci_hole_start + s->pci_hole_alloc;
232         s->pci_hole_alloc += size;
233 
234         qpci_config_writel(dev, bar_reg, loc);
235 
236         return (void *)(unsigned long)loc;
237     }
238 }
239 
240 static void qpci_spapr_iounmap(QPCIBus *bus, void *data)
241 {
242     /* FIXME */
243 }
244 
245 QPCIBus *qpci_init_spapr(QGuestAllocator *alloc)
246 {
247     QPCIBusSPAPR *ret;
248 
249     ret = g_malloc(sizeof(*ret));
250 
251     ret->alloc = alloc;
252 
253     ret->bus.io_readb = qpci_spapr_io_readb;
254     ret->bus.io_readw = qpci_spapr_io_readw;
255     ret->bus.io_readl = qpci_spapr_io_readl;
256 
257     ret->bus.io_writeb = qpci_spapr_io_writeb;
258     ret->bus.io_writew = qpci_spapr_io_writew;
259     ret->bus.io_writel = qpci_spapr_io_writel;
260 
261     ret->bus.config_readb = qpci_spapr_config_readb;
262     ret->bus.config_readw = qpci_spapr_config_readw;
263     ret->bus.config_readl = qpci_spapr_config_readl;
264 
265     ret->bus.config_writeb = qpci_spapr_config_writeb;
266     ret->bus.config_writew = qpci_spapr_config_writew;
267     ret->bus.config_writel = qpci_spapr_config_writel;
268 
269     ret->bus.iomap = qpci_spapr_iomap;
270     ret->bus.iounmap = qpci_spapr_iounmap;
271 
272     ret->pci_hole_start = 0xC0000000;
273     ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE;
274     ret->pci_hole_alloc = 0;
275 
276     ret->pci_iohole_start = 0xc000;
277     ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE;
278     ret->pci_iohole_alloc = 0;
279 
280     return &ret->bus;
281 }
282 
283 void qpci_free_spapr(QPCIBus *bus)
284 {
285     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
286 
287     g_free(s);
288 }
289