2 * libqos PCI bindings for SPAPR
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.
8 #include "qemu/osdep.h"
10 #include "libqos/pci-spapr.h"
11 #include "libqos/rtas.h"
13 #include "hw/pci/pci_regs.h"
15 #include "qemu-common.h"
16 #include "qemu/host-utils.h"
19 /* From include/hw/pci-host/spapr.h */
21 #define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
23 #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
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
33 /* index is the phb index */
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)
41 typedef struct QPCIBusSPAPR
{
43 QGuestAllocator
*alloc
;
45 uint64_t pci_hole_start
;
46 uint64_t pci_hole_size
;
47 uint64_t pci_hole_alloc
;
49 uint32_t pci_iohole_start
;
50 uint32_t pci_iohole_size
;
51 uint32_t pci_iohole_alloc
;
55 * PCI devices are always little-endian
56 * SPAPR by default is big-endian
57 * so PCI accessors need to swap data endianness
60 static uint8_t qpci_spapr_io_readb(QPCIBus
*bus
, void *addr
)
62 uint64_t port
= (uintptr_t)addr
;
64 if (port
< SPAPR_PCI_IO_WIN_SIZE
) {
65 v
= readb(IOBASE(0) + port
);
67 v
= readb(MMIOBASE(0) + port
);
72 static uint16_t qpci_spapr_io_readw(QPCIBus
*bus
, void *addr
)
74 uint64_t port
= (uintptr_t)addr
;
76 if (port
< SPAPR_PCI_IO_WIN_SIZE
) {
77 v
= readw(IOBASE(0) + port
);
79 v
= readw(MMIOBASE(0) + port
);
84 static uint32_t qpci_spapr_io_readl(QPCIBus
*bus
, void *addr
)
86 uint64_t port
= (uintptr_t)addr
;
88 if (port
< SPAPR_PCI_IO_WIN_SIZE
) {
89 v
= readl(IOBASE(0) + port
);
91 v
= readl(MMIOBASE(0) + port
);
96 static void qpci_spapr_io_writeb(QPCIBus
*bus
, void *addr
, uint8_t value
)
98 uint64_t port
= (uintptr_t)addr
;
99 if (port
< SPAPR_PCI_IO_WIN_SIZE
) {
100 writeb(IOBASE(0) + port
, value
);
102 writeb(MMIOBASE(0) + port
, value
);
106 static void qpci_spapr_io_writew(QPCIBus
*bus
, void *addr
, uint16_t value
)
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
);
113 writew(MMIOBASE(0) + port
, value
);
117 static void qpci_spapr_io_writel(QPCIBus
*bus
, void *addr
, uint32_t value
)
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
);
124 writel(MMIOBASE(0) + port
, value
);
128 static uint8_t qpci_spapr_config_readb(QPCIBus
*bus
, int devfn
, uint8_t offset
)
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),
136 static uint16_t qpci_spapr_config_readw(QPCIBus
*bus
, int devfn
, uint8_t offset
)
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),
144 static uint32_t qpci_spapr_config_readl(QPCIBus
*bus
, int devfn
, uint8_t offset
)
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),
152 static void qpci_spapr_config_writeb(QPCIBus
*bus
, int devfn
, uint8_t offset
,
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
);
161 static void qpci_spapr_config_writew(QPCIBus
*bus
, int devfn
, uint8_t offset
,
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
);
170 static void qpci_spapr_config_writel(QPCIBus
*bus
, int devfn
, uint8_t offset
,
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
);
179 static void *qpci_spapr_iomap(QPCIBus
*bus
, QPCIDevice
*dev
, int barno
,
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
,
192 g_assert(barno
>= 0 && barno
<= 5);
193 bar_reg
= bar_reg_map
[barno
];
195 qpci_config_writel(dev
, bar_reg
, 0xFFFFFFFF);
196 addr
= qpci_config_readl(dev
, bar_reg
);
198 io_type
= addr
& PCI_BASE_ADDRESS_SPACE
;
199 if (io_type
== PCI_BASE_ADDRESS_SPACE_IO
) {
200 addr
&= PCI_BASE_ADDRESS_IO_MASK
;
202 addr
&= PCI_BASE_ADDRESS_MEM_MASK
;
205 size
= (1ULL << ctzl(addr
));
213 if (io_type
== PCI_BASE_ADDRESS_SPACE_IO
) {
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
;
222 qpci_config_writel(dev
, bar_reg
, loc
| PCI_BASE_ADDRESS_SPACE_IO
);
224 return (void *)(unsigned long)loc
;
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
;
234 qpci_config_writel(dev
, bar_reg
, loc
);
236 return (void *)(unsigned long)loc
;
240 static void qpci_spapr_iounmap(QPCIBus
*bus
, void *data
)
245 QPCIBus
*qpci_init_spapr(QGuestAllocator
*alloc
)
249 ret
= g_malloc(sizeof(*ret
));
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
;
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
;
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
;
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
;
269 ret
->bus
.iomap
= qpci_spapr_iomap
;
270 ret
->bus
.iounmap
= qpci_spapr_iounmap
;
272 ret
->pci_hole_start
= 0xC0000000;
273 ret
->pci_hole_size
= SPAPR_PCI_MMIO_WIN_SIZE
;
274 ret
->pci_hole_alloc
= 0;
276 ret
->pci_iohole_start
= 0xc000;
277 ret
->pci_iohole_size
= SPAPR_PCI_IO_WIN_SIZE
;
278 ret
->pci_iohole_alloc
= 0;
283 void qpci_free_spapr(QPCIBus
*bus
)
285 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);