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 typedef struct QPCIWindow
{
22 uint64_t pci_base
; /* window address in PCI space */
23 uint64_t size
; /* window size */
26 typedef struct QPCIBusSPAPR
{
28 QGuestAllocator
*alloc
;
32 uint64_t pio_cpu_base
;
35 uint64_t mmio32_cpu_base
;
40 * PCI devices are always little-endian
41 * SPAPR by default is big-endian
42 * so PCI accessors need to swap data endianness
45 static uint8_t qpci_spapr_pio_readb(QPCIBus
*bus
, uint32_t addr
)
47 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
48 return readb(s
->pio_cpu_base
+ addr
);
51 static void qpci_spapr_pio_writeb(QPCIBus
*bus
, uint32_t addr
, uint8_t val
)
53 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
54 writeb(s
->pio_cpu_base
+ addr
, val
);
57 static uint16_t qpci_spapr_pio_readw(QPCIBus
*bus
, uint32_t addr
)
59 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
60 return bswap16(readw(s
->pio_cpu_base
+ addr
));
63 static void qpci_spapr_pio_writew(QPCIBus
*bus
, uint32_t addr
, uint16_t val
)
65 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
66 writew(s
->pio_cpu_base
+ addr
, bswap16(val
));
69 static uint32_t qpci_spapr_pio_readl(QPCIBus
*bus
, uint32_t addr
)
71 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
72 return bswap32(readl(s
->pio_cpu_base
+ addr
));
75 static void qpci_spapr_pio_writel(QPCIBus
*bus
, uint32_t addr
, uint32_t val
)
77 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
78 writel(s
->pio_cpu_base
+ addr
, bswap32(val
));
81 static uint64_t qpci_spapr_pio_readq(QPCIBus
*bus
, uint32_t addr
)
83 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
84 return bswap64(readq(s
->pio_cpu_base
+ addr
));
87 static void qpci_spapr_pio_writeq(QPCIBus
*bus
, uint32_t addr
, uint64_t val
)
89 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
90 writeq(s
->pio_cpu_base
+ addr
, bswap64(val
));
93 static void qpci_spapr_memread(QPCIBus
*bus
, uint32_t addr
,
94 void *buf
, size_t len
)
96 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
97 memread(s
->mmio32_cpu_base
+ addr
, buf
, len
);
100 static void qpci_spapr_memwrite(QPCIBus
*bus
, uint32_t addr
,
101 const void *buf
, size_t len
)
103 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
104 memwrite(s
->mmio32_cpu_base
+ addr
, buf
, len
);
107 static uint8_t qpci_spapr_config_readb(QPCIBus
*bus
, int devfn
, uint8_t offset
)
109 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
110 uint32_t config_addr
= (devfn
<< 8) | offset
;
111 return qrtas_ibm_read_pci_config(s
->alloc
, s
->buid
, config_addr
, 1);
114 static uint16_t qpci_spapr_config_readw(QPCIBus
*bus
, int devfn
, uint8_t offset
)
116 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
117 uint32_t config_addr
= (devfn
<< 8) | offset
;
118 return qrtas_ibm_read_pci_config(s
->alloc
, s
->buid
, config_addr
, 2);
121 static uint32_t qpci_spapr_config_readl(QPCIBus
*bus
, int devfn
, uint8_t offset
)
123 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
124 uint32_t config_addr
= (devfn
<< 8) | offset
;
125 return qrtas_ibm_read_pci_config(s
->alloc
, s
->buid
, config_addr
, 4);
128 static void qpci_spapr_config_writeb(QPCIBus
*bus
, int devfn
, uint8_t offset
,
131 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
132 uint32_t config_addr
= (devfn
<< 8) | offset
;
133 qrtas_ibm_write_pci_config(s
->alloc
, s
->buid
, config_addr
, 1, value
);
136 static void qpci_spapr_config_writew(QPCIBus
*bus
, int devfn
, uint8_t offset
,
139 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
140 uint32_t config_addr
= (devfn
<< 8) | offset
;
141 qrtas_ibm_write_pci_config(s
->alloc
, s
->buid
, config_addr
, 2, value
);
144 static void qpci_spapr_config_writel(QPCIBus
*bus
, int devfn
, uint8_t offset
,
147 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);
148 uint32_t config_addr
= (devfn
<< 8) | offset
;
149 qrtas_ibm_write_pci_config(s
->alloc
, s
->buid
, config_addr
, 4, value
);
152 #define SPAPR_PCI_BASE (1ULL << 45)
154 #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */
155 #define SPAPR_PCI_IO_WIN_SIZE 0x10000
157 QPCIBus
*qpci_init_spapr(QGuestAllocator
*alloc
)
161 ret
= g_malloc(sizeof(*ret
));
165 ret
->bus
.pio_readb
= qpci_spapr_pio_readb
;
166 ret
->bus
.pio_readw
= qpci_spapr_pio_readw
;
167 ret
->bus
.pio_readl
= qpci_spapr_pio_readl
;
168 ret
->bus
.pio_readq
= qpci_spapr_pio_readq
;
170 ret
->bus
.pio_writeb
= qpci_spapr_pio_writeb
;
171 ret
->bus
.pio_writew
= qpci_spapr_pio_writew
;
172 ret
->bus
.pio_writel
= qpci_spapr_pio_writel
;
173 ret
->bus
.pio_writeq
= qpci_spapr_pio_writeq
;
175 ret
->bus
.memread
= qpci_spapr_memread
;
176 ret
->bus
.memwrite
= qpci_spapr_memwrite
;
178 ret
->bus
.config_readb
= qpci_spapr_config_readb
;
179 ret
->bus
.config_readw
= qpci_spapr_config_readw
;
180 ret
->bus
.config_readl
= qpci_spapr_config_readl
;
182 ret
->bus
.config_writeb
= qpci_spapr_config_writeb
;
183 ret
->bus
.config_writew
= qpci_spapr_config_writew
;
184 ret
->bus
.config_writel
= qpci_spapr_config_writel
;
186 /* FIXME: We assume the default location of the PHB for now.
187 * Ideally we'd parse the device tree deposited in the guest to
188 * get the window locations */
189 ret
->buid
= 0x800000020000000ULL
;
191 ret
->pio_cpu_base
= SPAPR_PCI_BASE
;
192 ret
->pio
.pci_base
= 0;
193 ret
->pio
.size
= SPAPR_PCI_IO_WIN_SIZE
;
195 /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */
196 ret
->mmio32_cpu_base
= SPAPR_PCI_BASE
;
197 ret
->mmio32
.pci_base
= SPAPR_PCI_MMIO32_WIN_SIZE
;
198 ret
->mmio32
.size
= SPAPR_PCI_MMIO32_WIN_SIZE
;
200 ret
->bus
.pio_alloc_ptr
= 0xc000;
201 ret
->bus
.mmio_alloc_ptr
= ret
->mmio32
.pci_base
;
202 ret
->bus
.mmio_limit
= ret
->mmio32
.pci_base
+ ret
->mmio32
.size
;
207 void qpci_free_spapr(QPCIBus
*bus
)
209 QPCIBusSPAPR
*s
= container_of(bus
, QPCIBusSPAPR
, bus
);