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