]>
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); |
a795fc08 | 48 | return readb(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); |
a795fc08 | 54 | writeb(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); |
a795fc08 | 60 | return bswap16(readw(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); | |
66 | writew(s->pio_cpu_base + addr, bswap16(val)); | |
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); | |
72 | return bswap32(readl(s->pio_cpu_base + addr)); | |
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); | |
78 | writel(s->pio_cpu_base + addr, bswap32(val)); | |
79 | } | |
80 | ||
9a84f889 DG |
81 | static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, |
82 | void *buf, size_t len) | |
83 | { | |
84 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
85 | memread(s->mmio32_cpu_base + addr, buf, len); | |
86 | } | |
87 | ||
88 | static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr, | |
89 | const void *buf, size_t len) | |
90 | { | |
91 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
92 | memwrite(s->mmio32_cpu_base + addr, buf, len); | |
93 | } | |
94 | ||
cf716b31 LV |
95 | static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) |
96 | { | |
97 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
98 | uint32_t config_addr = (devfn << 8) | offset; | |
cd1b354e | 99 | return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 1); |
cf716b31 LV |
100 | } |
101 | ||
102 | static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) | |
103 | { | |
104 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
105 | uint32_t config_addr = (devfn << 8) | offset; | |
cd1b354e | 106 | return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 2); |
cf716b31 LV |
107 | } |
108 | ||
109 | static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) | |
110 | { | |
111 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
112 | uint32_t config_addr = (devfn << 8) | offset; | |
cd1b354e | 113 | return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 4); |
cf716b31 LV |
114 | } |
115 | ||
116 | static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, | |
117 | uint8_t value) | |
118 | { | |
119 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
120 | uint32_t config_addr = (devfn << 8) | offset; | |
cd1b354e | 121 | qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 1, value); |
cf716b31 LV |
122 | } |
123 | ||
124 | static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, | |
125 | uint16_t value) | |
126 | { | |
127 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
128 | uint32_t config_addr = (devfn << 8) | offset; | |
cd1b354e | 129 | qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 2, value); |
cf716b31 LV |
130 | } |
131 | ||
132 | static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, | |
133 | uint32_t value) | |
134 | { | |
135 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
136 | uint32_t config_addr = (devfn << 8) | offset; | |
cd1b354e | 137 | qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value); |
cf716b31 LV |
138 | } |
139 | ||
357d1e3b DG |
140 | #define SPAPR_PCI_BASE (1ULL << 45) |
141 | ||
8360544a | 142 | #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ |
cd1b354e DG |
143 | #define SPAPR_PCI_IO_WIN_SIZE 0x10000 |
144 | ||
cf716b31 LV |
145 | QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) |
146 | { | |
147 | QPCIBusSPAPR *ret; | |
148 | ||
149 | ret = g_malloc(sizeof(*ret)); | |
150 | ||
151 | ret->alloc = alloc; | |
152 | ||
a795fc08 DG |
153 | ret->bus.pio_readb = qpci_spapr_pio_readb; |
154 | ret->bus.pio_readw = qpci_spapr_pio_readw; | |
155 | ret->bus.pio_readl = qpci_spapr_pio_readl; | |
156 | ||
157 | ret->bus.pio_writeb = qpci_spapr_pio_writeb; | |
158 | ret->bus.pio_writew = qpci_spapr_pio_writew; | |
159 | ret->bus.pio_writel = qpci_spapr_pio_writel; | |
160 | ||
9a84f889 DG |
161 | ret->bus.memread = qpci_spapr_memread; |
162 | ret->bus.memwrite = qpci_spapr_memwrite; | |
163 | ||
cf716b31 LV |
164 | ret->bus.config_readb = qpci_spapr_config_readb; |
165 | ret->bus.config_readw = qpci_spapr_config_readw; | |
166 | ret->bus.config_readl = qpci_spapr_config_readl; | |
167 | ||
168 | ret->bus.config_writeb = qpci_spapr_config_writeb; | |
169 | ret->bus.config_writew = qpci_spapr_config_writew; | |
170 | ret->bus.config_writel = qpci_spapr_config_writel; | |
171 | ||
cd1b354e DG |
172 | /* FIXME: We assume the default location of the PHB for now. |
173 | * Ideally we'd parse the device tree deposited in the guest to | |
174 | * get the window locations */ | |
175 | ret->buid = 0x800000020000000ULL; | |
176 | ||
357d1e3b | 177 | ret->pio_cpu_base = SPAPR_PCI_BASE; |
cd1b354e DG |
178 | ret->pio.pci_base = 0; |
179 | ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; | |
180 | ||
8360544a | 181 | /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ |
357d1e3b | 182 | ret->mmio32_cpu_base = SPAPR_PCI_BASE + SPAPR_PCI_MMIO32_WIN_SIZE; |
8360544a DG |
183 | ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ |
184 | ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; | |
cd1b354e | 185 | |
b8cc4d02 DG |
186 | ret->bus.pio_alloc_ptr = 0xc000; |
187 | ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base; | |
188 | ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size; | |
cf716b31 LV |
189 | |
190 | return &ret->bus; | |
191 | } | |
192 | ||
193 | void qpci_free_spapr(QPCIBus *bus) | |
194 | { | |
195 | QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); | |
196 | ||
197 | g_free(s); | |
198 | } |