]>
Commit | Line | Data |
---|---|---|
cf716b31 LV |
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 | ||
cd1b354e DG |
21 | typedef struct QPCIWindow { |
22 | uint64_t pci_base; /* window address in PCI space */ | |
23 | uint64_t size; /* window size */ | |
24 | } QPCIWindow; | |
cf716b31 LV |
25 | |
26 | typedef struct QPCIBusSPAPR { | |
27 | QPCIBus bus; | |
28 | QGuestAllocator *alloc; | |
29 | ||
cd1b354e DG |
30 | uint64_t buid; |
31 | ||
32 | uint64_t pio_cpu_base; | |
33 | QPCIWindow pio; | |
34 | ||
8360544a DG |
35 | uint64_t mmio32_cpu_base; |
36 | QPCIWindow mmio32; | |
cf716b31 LV |
37 | } QPCIBusSPAPR; |
38 | ||
39 | /* | |
40 | * PCI devices are always little-endian | |
41 | * SPAPR by default is big-endian | |
42 | * so PCI accessors need to swap data endianness | |
43 | */ | |
44 | ||
a795fc08 | 45 | static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr) |
cf716b31 | 46 | { |
cd1b354e | 47 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); |
d786f782 | 48 | return qtest_readb(bus->qts, s->pio_cpu_base + addr); |
cf716b31 LV |
49 | } |
50 | ||
a795fc08 | 51 | static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) |
cf716b31 | 52 | { |
cd1b354e | 53 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); |
d786f782 | 54 | qtest_writeb(bus->qts, s->pio_cpu_base + addr, val); |
cf716b31 LV |
55 | } |
56 | ||
a795fc08 | 57 | static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr) |
cf716b31 | 58 | { |
cd1b354e | 59 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); |
d786f782 | 60 | return bswap16(qtest_readw(bus->qts, s->pio_cpu_base + addr)); |
cf716b31 LV |
61 | } |
62 | ||
a795fc08 DG |
63 | static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) |
64 | { | |
65 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 66 | qtest_writew(bus->qts, s->pio_cpu_base + addr, bswap16(val)); |
a795fc08 DG |
67 | } |
68 | ||
a795fc08 DG |
69 | static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr) |
70 | { | |
71 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 72 | return bswap32(qtest_readl(bus->qts, s->pio_cpu_base + addr)); |
a795fc08 DG |
73 | } |
74 | ||
a795fc08 DG |
75 | static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) |
76 | { | |
77 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 78 | qtest_writel(bus->qts, s->pio_cpu_base + addr, bswap32(val)); |
a795fc08 DG |
79 | } |
80 | ||
f775f45a DG |
81 | static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr) |
82 | { | |
83 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 84 | return bswap64(qtest_readq(bus->qts, s->pio_cpu_base + addr)); |
f775f45a DG |
85 | } |
86 | ||
87 | static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) | |
88 | { | |
89 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 90 | qtest_writeq(bus->qts, s->pio_cpu_base + addr, bswap64(val)); |
f775f45a DG |
91 | } |
92 | ||
9a84f889 DG |
93 | static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, |
94 | void *buf, size_t len) | |
95 | { | |
96 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 97 | qtest_memread(bus->qts, s->mmio32_cpu_base + addr, buf, len); |
9a84f889 DG |
98 | } |
99 | ||
100 | static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr, | |
101 | const void *buf, size_t len) | |
102 | { | |
103 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
d786f782 | 104 | qtest_memwrite(bus->qts, s->mmio32_cpu_base + addr, buf, len); |
9a84f889 DG |
105 | } |
106 | ||
cf716b31 LV |
107 | static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) |
108 | { | |
109 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
110 | uint32_t config_addr = (devfn << 8) | offset; | |
9b67af76 EB |
111 | return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, |
112 | config_addr, 1); | |
cf716b31 LV |
113 | } |
114 | ||
115 | static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) | |
116 | { | |
117 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
118 | uint32_t config_addr = (devfn << 8) | offset; | |
9b67af76 EB |
119 | return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, |
120 | config_addr, 2); | |
cf716b31 LV |
121 | } |
122 | ||
123 | static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) | |
124 | { | |
125 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
126 | uint32_t config_addr = (devfn << 8) | offset; | |
9b67af76 EB |
127 | return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, |
128 | config_addr, 4); | |
cf716b31 LV |
129 | } |
130 | ||
131 | static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, | |
132 | uint8_t value) | |
133 | { | |
134 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
135 | uint32_t config_addr = (devfn << 8) | offset; | |
9b67af76 EB |
136 | qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, |
137 | config_addr, 1, value); | |
cf716b31 LV |
138 | } |
139 | ||
140 | static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, | |
141 | uint16_t value) | |
142 | { | |
143 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
144 | uint32_t config_addr = (devfn << 8) | offset; | |
9b67af76 EB |
145 | qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, |
146 | config_addr, 2, value); | |
cf716b31 LV |
147 | } |
148 | ||
149 | static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, | |
150 | uint32_t value) | |
151 | { | |
152 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
153 | uint32_t config_addr = (devfn << 8) | offset; | |
9b67af76 EB |
154 | qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, |
155 | config_addr, 4, value); | |
cf716b31 LV |
156 | } |
157 | ||
357d1e3b DG |
158 | #define SPAPR_PCI_BASE (1ULL << 45) |
159 | ||
8360544a | 160 | #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ |
cd1b354e DG |
161 | #define SPAPR_PCI_IO_WIN_SIZE 0x10000 |
162 | ||
143e6db6 | 163 | QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc) |
cf716b31 | 164 | { |
e5d1730d | 165 | QPCIBusSPAPR *ret = g_new0(QPCIBusSPAPR, 1); |
cf716b31 | 166 | |
e5d1730d | 167 | assert(qts); |
cf716b31 LV |
168 | |
169 | ret->alloc = alloc; | |
170 | ||
a795fc08 DG |
171 | ret->bus.pio_readb = qpci_spapr_pio_readb; |
172 | ret->bus.pio_readw = qpci_spapr_pio_readw; | |
173 | ret->bus.pio_readl = qpci_spapr_pio_readl; | |
f775f45a | 174 | ret->bus.pio_readq = qpci_spapr_pio_readq; |
a795fc08 DG |
175 | |
176 | ret->bus.pio_writeb = qpci_spapr_pio_writeb; | |
177 | ret->bus.pio_writew = qpci_spapr_pio_writew; | |
178 | ret->bus.pio_writel = qpci_spapr_pio_writel; | |
f775f45a | 179 | ret->bus.pio_writeq = qpci_spapr_pio_writeq; |
a795fc08 | 180 | |
9a84f889 DG |
181 | ret->bus.memread = qpci_spapr_memread; |
182 | ret->bus.memwrite = qpci_spapr_memwrite; | |
183 | ||
cf716b31 LV |
184 | ret->bus.config_readb = qpci_spapr_config_readb; |
185 | ret->bus.config_readw = qpci_spapr_config_readw; | |
186 | ret->bus.config_readl = qpci_spapr_config_readl; | |
187 | ||
188 | ret->bus.config_writeb = qpci_spapr_config_writeb; | |
189 | ret->bus.config_writew = qpci_spapr_config_writew; | |
190 | ret->bus.config_writel = qpci_spapr_config_writel; | |
191 | ||
cd1b354e DG |
192 | /* FIXME: We assume the default location of the PHB for now. |
193 | * Ideally we'd parse the device tree deposited in the guest to | |
194 | * get the window locations */ | |
195 | ret->buid = 0x800000020000000ULL; | |
196 | ||
357d1e3b | 197 | ret->pio_cpu_base = SPAPR_PCI_BASE; |
cd1b354e DG |
198 | ret->pio.pci_base = 0; |
199 | ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; | |
200 | ||
8360544a | 201 | /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ |
b8454169 LV |
202 | ret->mmio32_cpu_base = SPAPR_PCI_BASE; |
203 | ret->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE; | |
8360544a | 204 | ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; |
cd1b354e | 205 | |
e5d1730d | 206 | ret->bus.qts = qts; |
b8cc4d02 DG |
207 | ret->bus.pio_alloc_ptr = 0xc000; |
208 | ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base; | |
209 | ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size; | |
cf716b31 LV |
210 | |
211 | return &ret->bus; | |
212 | } | |
213 | ||
214 | void qpci_free_spapr(QPCIBus *bus) | |
215 | { | |
216 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
217 | ||
218 | g_free(s); | |
219 | } |