blob: 599768e2d9608df054e264abc153d6c4e7ecd057 [file] [log] [blame]
pbrook502a5392006-05-13 16:11:23 +00001/*
2 * QEMU Ultrasparc APB PCI host
3 *
4 * Copyright (c) 2006 Fabrice Bellard
Artyom Tarasenko96250362013-04-27 07:55:12 +02005 * Copyright (c) 2012,2013 Artyom Tarasenko
ths5fafdf22007-09-16 21:08:06 +00006 *
pbrook502a5392006-05-13 16:11:23 +00007 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
pbrook80b3ada2006-09-24 17:01:44 +000025
blueswir1a94fd952009-01-09 20:53:30 +000026/* XXX This file and most of its contents are somewhat misnamed. The
pbrook80b3ada2006-09-24 17:01:44 +000027 Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
28 the secondary PCI bridge. */
29
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010030#include "hw/sysbus.h"
31#include "hw/pci/pci.h"
32#include "hw/pci/pci_host.h"
33#include "hw/pci/pci_bridge.h"
34#include "hw/pci/pci_bus.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010035#include "hw/pci-host/apb.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010036#include "sysemu/sysemu.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010037#include "exec/address-spaces.h"
blueswir1a94fd952009-01-09 20:53:30 +000038
39/* debug APB */
40//#define DEBUG_APB
41
42#ifdef DEBUG_APB
Blue Swirl001faf32009-05-13 17:53:17 +000043#define APB_DPRINTF(fmt, ...) \
44do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
blueswir1a94fd952009-01-09 20:53:30 +000045#else
Blue Swirl001faf32009-05-13 17:53:17 +000046#define APB_DPRINTF(fmt, ...)
blueswir1a94fd952009-01-09 20:53:30 +000047#endif
48
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +010049/* debug IOMMU */
50//#define DEBUG_IOMMU
51
52#ifdef DEBUG_IOMMU
53#define IOMMU_DPRINTF(fmt, ...) \
54do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
55#else
56#define IOMMU_DPRINTF(fmt, ...)
57#endif
58
Blue Swirl930f3fe2009-10-13 18:56:27 +000059/*
60 * Chipset docs:
61 * PBM: "UltraSPARC IIi User's Manual",
62 * http://www.sun.com/processors/manuals/805-0087.pdf
63 *
64 * APB: "Advanced PCI Bridge (APB) User's Manual",
65 * http://www.sun.com/processors/manuals/805-1251.pdf
66 */
67
Blue Swirl95819af2010-01-30 19:48:12 +000068#define PBM_PCI_IMR_MASK 0x7fffffff
69#define PBM_PCI_IMR_ENABLED 0x80000000
70
Peter Maydellaf239062014-03-17 16:00:41 +000071#define POR (1U << 31)
72#define SOFT_POR (1U << 30)
73#define SOFT_XIR (1U << 29)
74#define BTN_POR (1U << 28)
75#define BTN_XIR (1U << 27)
Blue Swirl95819af2010-01-30 19:48:12 +000076#define RESET_MASK 0xf8000000
77#define RESET_WCMASK 0x98000000
78#define RESET_WMASK 0x60000000
79
Artyom Tarasenko852e82f2013-04-27 07:55:11 +020080#define MAX_IVEC 0x40
Artyom Tarasenko96250362013-04-27 07:55:12 +020081#define NO_IRQ_REQUEST (MAX_IVEC + 1)
Blue Swirl361dea42012-03-10 20:37:00 +000082
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +010083#define IOMMU_PAGE_SIZE_8K (1ULL << 13)
84#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
85#define IOMMU_PAGE_SIZE_64K (1ULL << 16)
86#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
87
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +010088#define IOMMU_NREGS 3
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +010089
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +010090#define IOMMU_CTRL 0x0
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +010091#define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
92#define IOMMU_CTRL_MMU_EN (1ULL)
93
94#define IOMMU_CTRL_TSB_SHIFT 16
95
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +010096#define IOMMU_BASE 0x8
Mark Cave-Aylandb87b0642014-08-11 12:22:52 +010097#define IOMMU_FLUSH 0x10
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +010098
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +010099#define IOMMU_TTE_DATA_V (1ULL << 63)
100#define IOMMU_TTE_DATA_SIZE (1ULL << 61)
101#define IOMMU_TTE_DATA_W (1ULL << 1)
102
Stefan Weild1180c12014-06-07 20:54:42 +0200103#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
104#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +0100105
106#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
107#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
108#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
109#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
110#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
111#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
112#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
113#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
114
115#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
116#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
117#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
118#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
119#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
120#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
121
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100122typedef struct IOMMUState {
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +0100123 AddressSpace iommu_as;
124 MemoryRegion iommu;
125
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +0100126 uint64_t regs[IOMMU_NREGS];
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100127} IOMMUState;
128
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200129#define TYPE_APB "pbm"
130
131#define APB_DEVICE(obj) \
132 OBJECT_CHECK(APBState, (obj), TYPE_APB)
133
Blue Swirl72f44c82009-07-21 08:36:37 +0000134typedef struct APBState {
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200135 PCIHostState parent_obj;
136
Avi Kivity3812ed02011-08-15 17:17:15 +0300137 MemoryRegion apb_config;
138 MemoryRegion pci_config;
Blue Swirlf69539b2011-09-03 16:38:02 +0000139 MemoryRegion pci_mmio;
Avi Kivity3812ed02011-08-15 17:17:15 +0300140 MemoryRegion pci_ioport;
Artyom Tarasenko96250362013-04-27 07:55:12 +0200141 uint64_t pci_irq_in;
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100142 IOMMUState iommu;
Blue Swirl95819af2010-01-30 19:48:12 +0000143 uint32_t pci_control[16];
144 uint32_t pci_irq_map[8];
Mark Cave-Aylandde739df2014-09-05 14:50:56 +0100145 uint32_t pci_err_irq_map[4];
Blue Swirl95819af2010-01-30 19:48:12 +0000146 uint32_t obio_irq_map[32];
Blue Swirl361dea42012-03-10 20:37:00 +0000147 qemu_irq *pbm_irqs;
148 qemu_irq *ivec_irqs;
Artyom Tarasenko96250362013-04-27 07:55:12 +0200149 unsigned int irq_request;
Blue Swirl95819af2010-01-30 19:48:12 +0000150 uint32_t reset_control;
Blue Swirl9c0afd02010-05-12 19:27:23 +0000151 unsigned int nr_resets;
Blue Swirl72f44c82009-07-21 08:36:37 +0000152} APBState;
pbrook502a5392006-05-13 16:11:23 +0000153
Artyom Tarasenko96250362013-04-27 07:55:12 +0200154static inline void pbm_set_request(APBState *s, unsigned int irq_num)
155{
156 APB_DPRINTF("%s: request irq %d\n", __func__, irq_num);
157
158 s->irq_request = irq_num;
159 qemu_set_irq(s->ivec_irqs[irq_num], 1);
160}
161
162static inline void pbm_check_irqs(APBState *s)
163{
164
165 unsigned int i;
166
167 /* Previous request is not acknowledged, resubmit */
168 if (s->irq_request != NO_IRQ_REQUEST) {
169 pbm_set_request(s, s->irq_request);
170 return;
171 }
172 /* no request pending */
173 if (s->pci_irq_in == 0ULL) {
174 return;
175 }
176 for (i = 0; i < 32; i++) {
177 if (s->pci_irq_in & (1ULL << i)) {
178 if (s->pci_irq_map[i >> 2] & PBM_PCI_IMR_ENABLED) {
179 pbm_set_request(s, i);
180 return;
181 }
182 }
183 }
184 for (i = 32; i < 64; i++) {
185 if (s->pci_irq_in & (1ULL << i)) {
186 if (s->obio_irq_map[i - 32] & PBM_PCI_IMR_ENABLED) {
187 pbm_set_request(s, i);
188 break;
189 }
190 }
191 }
192}
193
194static inline void pbm_clear_request(APBState *s, unsigned int irq_num)
195{
196 APB_DPRINTF("%s: clear request irq %d\n", __func__, irq_num);
197 qemu_set_irq(s->ivec_irqs[irq_num], 0);
198 s->irq_request = NO_IRQ_REQUEST;
199}
Artyom Tarasenko94d19912012-05-12 11:15:23 +0200200
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +0100201static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
202{
203 IOMMUState *is = opaque;
204
205 return &is->iommu_as;
206}
207
Paolo Bonzini79e2b9a2015-01-21 12:09:14 +0100208/* Called from RCU critical section */
Le Tan8d7b8cb2014-08-16 13:55:37 +0800209static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
210 bool is_write)
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +0100211{
212 IOMMUState *is = container_of(iommu, IOMMUState, iommu);
213 hwaddr baseaddr, offset;
214 uint64_t tte;
215 uint32_t tsbsize;
216 IOMMUTLBEntry ret = {
217 .target_as = &address_space_memory,
218 .iova = 0,
219 .translated_addr = 0,
220 .addr_mask = ~(hwaddr)0,
221 .perm = IOMMU_NONE,
222 };
223
224 if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) {
225 /* IOMMU disabled, passthrough using standard 8K page */
226 ret.iova = addr & IOMMU_PAGE_MASK_8K;
227 ret.translated_addr = addr;
228 ret.addr_mask = IOMMU_PAGE_MASK_8K;
229 ret.perm = IOMMU_RW;
230
231 return ret;
232 }
233
234 baseaddr = is->regs[IOMMU_BASE >> 3];
235 tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7;
236
237 if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) {
238 /* 64K */
239 switch (tsbsize) {
240 case 0:
241 offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13;
242 break;
243 case 1:
244 offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13;
245 break;
246 case 2:
247 offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13;
248 break;
249 case 3:
250 offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13;
251 break;
252 case 4:
253 offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13;
254 break;
255 case 5:
256 offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13;
257 break;
258 default:
259 /* Not implemented, error */
260 return ret;
261 }
262 } else {
263 /* 8K */
264 switch (tsbsize) {
265 case 0:
266 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10;
267 break;
268 case 1:
269 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10;
270 break;
271 case 2:
272 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10;
273 break;
274 case 3:
275 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10;
276 break;
277 case 4:
278 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10;
279 break;
280 case 5:
281 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10;
282 break;
283 case 6:
284 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10;
285 break;
286 case 7:
287 offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10;
288 break;
289 }
290 }
291
Peter Maydell42874d32015-04-26 16:49:24 +0100292 tte = address_space_ldq_be(&address_space_memory, baseaddr + offset,
293 MEMTXATTRS_UNSPECIFIED, NULL);
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +0100294
295 if (!(tte & IOMMU_TTE_DATA_V)) {
296 /* Invalid mapping */
297 return ret;
298 }
299
300 if (tte & IOMMU_TTE_DATA_W) {
301 /* Writeable */
302 ret.perm = IOMMU_RW;
303 } else {
304 ret.perm = IOMMU_RO;
305 }
306
307 /* Extract phys */
308 if (tte & IOMMU_TTE_DATA_SIZE) {
309 /* 64K */
310 ret.iova = addr & IOMMU_PAGE_MASK_64K;
311 ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K;
312 ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1);
313 } else {
314 /* 8K */
315 ret.iova = addr & IOMMU_PAGE_MASK_8K;
316 ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K;
317 ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1);
318 }
319
320 return ret;
321}
322
323static MemoryRegionIOMMUOps pbm_iommu_ops = {
324 .translate = pbm_translate_iommu,
325};
326
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +0100327static void iommu_config_write(void *opaque, hwaddr addr,
328 uint64_t val, unsigned size)
329{
330 IOMMUState *is = opaque;
331
332 IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64
333 " size: %d\n", addr, val, size);
334
335 switch (addr) {
336 case IOMMU_CTRL:
337 if (size == 4) {
338 is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL;
339 is->regs[IOMMU_CTRL >> 3] |= val << 32;
340 } else {
Stefan Weil68716da2014-06-09 16:19:29 +0200341 is->regs[IOMMU_CTRL >> 3] = val;
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +0100342 }
343 break;
344 case IOMMU_CTRL + 0x4:
345 is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL;
346 is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL;
347 break;
348 case IOMMU_BASE:
349 if (size == 4) {
350 is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL;
351 is->regs[IOMMU_BASE >> 3] |= val << 32;
352 } else {
Stefan Weil68716da2014-06-09 16:19:29 +0200353 is->regs[IOMMU_BASE >> 3] = val;
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +0100354 }
355 break;
356 case IOMMU_BASE + 0x4:
357 is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
358 is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
359 break;
Mark Cave-Aylandb87b0642014-08-11 12:22:52 +0100360 case IOMMU_FLUSH:
361 case IOMMU_FLUSH + 0x4:
362 break;
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +0100363 default:
364 qemu_log_mask(LOG_UNIMP,
365 "apb iommu: Unimplemented register write "
366 "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
367 addr, size, val);
368 break;
369 }
370}
371
372static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size)
373{
374 IOMMUState *is = opaque;
375 uint64_t val;
376
377 switch (addr) {
378 case IOMMU_CTRL:
379 if (size == 4) {
380 val = is->regs[IOMMU_CTRL >> 3] >> 32;
381 } else {
382 val = is->regs[IOMMU_CTRL >> 3];
383 }
384 break;
385 case IOMMU_CTRL + 0x4:
386 val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL;
387 break;
388 case IOMMU_BASE:
389 if (size == 4) {
390 val = is->regs[IOMMU_BASE >> 3] >> 32;
391 } else {
392 val = is->regs[IOMMU_BASE >> 3];
393 }
394 break;
395 case IOMMU_BASE + 0x4:
396 val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
397 break;
Mark Cave-Aylandb87b0642014-08-11 12:22:52 +0100398 case IOMMU_FLUSH:
399 case IOMMU_FLUSH + 0x4:
400 val = 0;
401 break;
Mark Cave-Aylandf38b1612014-05-28 08:28:22 +0100402 default:
403 qemu_log_mask(LOG_UNIMP,
404 "apb iommu: Unimplemented register read "
405 "reg 0x%" HWADDR_PRIx " size 0x%x\n",
406 addr, size);
407 val = 0;
408 break;
409 }
410
411 IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64
412 " size: %d\n", addr, val, size);
413
414 return val;
415}
416
Avi Kivitya8170e52012-10-23 12:30:10 +0200417static void apb_config_writel (void *opaque, hwaddr addr,
Avi Kivity3812ed02011-08-15 17:17:15 +0300418 uint64_t val, unsigned size)
pbrook502a5392006-05-13 16:11:23 +0000419{
Blue Swirl95819af2010-01-30 19:48:12 +0000420 APBState *s = opaque;
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100421 IOMMUState *is = &s->iommu;
pbrook502a5392006-05-13 16:11:23 +0000422
Paolo Bonzinic0907c92013-02-05 15:06:20 +0100423 APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
Blue Swirl95819af2010-01-30 19:48:12 +0000424
425 switch (addr & 0xffff) {
426 case 0x30 ... 0x4f: /* DMA error registers */
427 /* XXX: not implemented yet */
428 break;
Mark Cave-Aylandfd7fbc82014-05-28 08:28:21 +0100429 case 0x200 ... 0x217: /* IOMMU */
Mark Cave-Aylandb87b0642014-08-11 12:22:52 +0100430 iommu_config_write(is, (addr & 0x1f), val, size);
Blue Swirl95819af2010-01-30 19:48:12 +0000431 break;
Blue Swirl95819af2010-01-30 19:48:12 +0000432 case 0xc00 ... 0xc3f: /* PCI interrupt control */
433 if (addr & 4) {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200434 unsigned int ino = (addr & 0x3f) >> 3;
435 s->pci_irq_map[ino] &= PBM_PCI_IMR_MASK;
436 s->pci_irq_map[ino] |= val & ~PBM_PCI_IMR_MASK;
437 if ((s->irq_request == ino) && !(val & ~PBM_PCI_IMR_MASK)) {
438 pbm_clear_request(s, ino);
439 }
440 pbm_check_irqs(s);
Blue Swirl95819af2010-01-30 19:48:12 +0000441 }
442 break;
Mark Cave-Aylandde739df2014-09-05 14:50:56 +0100443 case 0x1000 ... 0x107f: /* OBIO interrupt control */
Blue Swirl361dea42012-03-10 20:37:00 +0000444 if (addr & 4) {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200445 unsigned int ino = ((addr & 0xff) >> 3);
446 s->obio_irq_map[ino] &= PBM_PCI_IMR_MASK;
447 s->obio_irq_map[ino] |= val & ~PBM_PCI_IMR_MASK;
448 if ((s->irq_request == (ino | 0x20))
449 && !(val & ~PBM_PCI_IMR_MASK)) {
450 pbm_clear_request(s, ino | 0x20);
451 }
452 pbm_check_irqs(s);
Blue Swirl361dea42012-03-10 20:37:00 +0000453 }
454 break;
Artyom Tarasenko96250362013-04-27 07:55:12 +0200455 case 0x1400 ... 0x14ff: /* PCI interrupt clear */
Artyom Tarasenko94d19912012-05-12 11:15:23 +0200456 if (addr & 4) {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200457 unsigned int ino = (addr & 0xff) >> 5;
458 if ((s->irq_request / 4) == ino) {
459 pbm_clear_request(s, s->irq_request);
460 pbm_check_irqs(s);
461 }
Artyom Tarasenko94d19912012-05-12 11:15:23 +0200462 }
463 break;
464 case 0x1800 ... 0x1860: /* OBIO interrupt clear */
465 if (addr & 4) {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200466 unsigned int ino = ((addr & 0xff) >> 3) | 0x20;
467 if (s->irq_request == ino) {
468 pbm_clear_request(s, ino);
469 pbm_check_irqs(s);
470 }
Artyom Tarasenko94d19912012-05-12 11:15:23 +0200471 }
472 break;
Blue Swirl95819af2010-01-30 19:48:12 +0000473 case 0x2000 ... 0x202f: /* PCI control */
474 s->pci_control[(addr & 0x3f) >> 2] = val;
475 break;
476 case 0xf020 ... 0xf027: /* Reset control */
477 if (addr & 4) {
478 val &= RESET_MASK;
479 s->reset_control &= ~(val & RESET_WCMASK);
480 s->reset_control |= val & RESET_WMASK;
481 if (val & SOFT_POR) {
Blue Swirl9c0afd02010-05-12 19:27:23 +0000482 s->nr_resets = 0;
Blue Swirl95819af2010-01-30 19:48:12 +0000483 qemu_system_reset_request();
484 } else if (val & SOFT_XIR) {
485 qemu_system_reset_request();
486 }
487 }
488 break;
489 case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
490 case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
491 case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
492 case 0xf000 ... 0xf01f: /* FFB config, memory control */
493 /* we don't care */
pbrook502a5392006-05-13 16:11:23 +0000494 default:
blueswir1f930d072007-10-06 11:28:21 +0000495 break;
pbrook502a5392006-05-13 16:11:23 +0000496 }
497}
498
Avi Kivity3812ed02011-08-15 17:17:15 +0300499static uint64_t apb_config_readl (void *opaque,
Avi Kivitya8170e52012-10-23 12:30:10 +0200500 hwaddr addr, unsigned size)
pbrook502a5392006-05-13 16:11:23 +0000501{
Blue Swirl95819af2010-01-30 19:48:12 +0000502 APBState *s = opaque;
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100503 IOMMUState *is = &s->iommu;
pbrook502a5392006-05-13 16:11:23 +0000504 uint32_t val;
505
Blue Swirl95819af2010-01-30 19:48:12 +0000506 switch (addr & 0xffff) {
507 case 0x30 ... 0x4f: /* DMA error registers */
508 val = 0;
509 /* XXX: not implemented yet */
510 break;
Mark Cave-Aylandfd7fbc82014-05-28 08:28:21 +0100511 case 0x200 ... 0x217: /* IOMMU */
Mark Cave-Aylandb87b0642014-08-11 12:22:52 +0100512 val = iommu_config_read(is, (addr & 0x1f), size);
Blue Swirl95819af2010-01-30 19:48:12 +0000513 break;
Blue Swirl95819af2010-01-30 19:48:12 +0000514 case 0xc00 ... 0xc3f: /* PCI interrupt control */
515 if (addr & 4) {
516 val = s->pci_irq_map[(addr & 0x3f) >> 3];
517 } else {
518 val = 0;
519 }
520 break;
Mark Cave-Aylandde739df2014-09-05 14:50:56 +0100521 case 0x1000 ... 0x107f: /* OBIO interrupt control */
Blue Swirl361dea42012-03-10 20:37:00 +0000522 if (addr & 4) {
523 val = s->obio_irq_map[(addr & 0xff) >> 3];
524 } else {
525 val = 0;
526 }
527 break;
Mark Cave-Aylandde739df2014-09-05 14:50:56 +0100528 case 0x1080 ... 0x108f: /* PCI bus error */
529 if (addr & 4) {
530 val = s->pci_err_irq_map[(addr & 0xf) >> 3];
531 } else {
532 val = 0;
533 }
534 break;
Blue Swirl95819af2010-01-30 19:48:12 +0000535 case 0x2000 ... 0x202f: /* PCI control */
536 val = s->pci_control[(addr & 0x3f) >> 2];
537 break;
538 case 0xf020 ... 0xf027: /* Reset control */
539 if (addr & 4) {
540 val = s->reset_control;
541 } else {
542 val = 0;
543 }
544 break;
545 case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
546 case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
547 case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
548 case 0xf000 ... 0xf01f: /* FFB config, memory control */
549 /* we don't care */
pbrook502a5392006-05-13 16:11:23 +0000550 default:
blueswir1f930d072007-10-06 11:28:21 +0000551 val = 0;
552 break;
pbrook502a5392006-05-13 16:11:23 +0000553 }
Paolo Bonzinic0907c92013-02-05 15:06:20 +0100554 APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, val);
Blue Swirl95819af2010-01-30 19:48:12 +0000555
pbrook502a5392006-05-13 16:11:23 +0000556 return val;
557}
558
Avi Kivity3812ed02011-08-15 17:17:15 +0300559static const MemoryRegionOps apb_config_ops = {
560 .read = apb_config_readl,
561 .write = apb_config_writel,
562 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook502a5392006-05-13 16:11:23 +0000563};
564
Avi Kivitya8170e52012-10-23 12:30:10 +0200565static void apb_pci_config_write(void *opaque, hwaddr addr,
Avi Kivity3812ed02011-08-15 17:17:15 +0300566 uint64_t val, unsigned size)
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000567{
Avi Kivity3812ed02011-08-15 17:17:15 +0300568 APBState *s = opaque;
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200569 PCIHostState *phb = PCI_HOST_BRIDGE(s);
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200570
571 val = qemu_bswap_len(val, size);
Paolo Bonzinic0907c92013-02-05 15:06:20 +0100572 APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200573 pci_data_write(phb->bus, addr, val, size);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000574}
575
Avi Kivitya8170e52012-10-23 12:30:10 +0200576static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
Avi Kivity3812ed02011-08-15 17:17:15 +0300577 unsigned size)
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000578{
579 uint32_t ret;
Avi Kivity3812ed02011-08-15 17:17:15 +0300580 APBState *s = opaque;
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200581 PCIHostState *phb = PCI_HOST_BRIDGE(s);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000582
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200583 ret = pci_data_read(phb->bus, addr, size);
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200584 ret = qemu_bswap_len(ret, size);
Paolo Bonzinic0907c92013-02-05 15:06:20 +0100585 APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000586 return ret;
587}
588
pbrook80b3ada2006-09-24 17:01:44 +0000589/* The APB host has an IRQ line for each IRQ line of each slot. */
pbrookd2b59312006-09-24 00:16:34 +0000590static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
pbrook502a5392006-05-13 16:11:23 +0000591{
pbrook80b3ada2006-09-24 17:01:44 +0000592 return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
593}
594
595static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
596{
597 int bus_offset;
598 if (pci_dev->devfn & 1)
599 bus_offset = 16;
600 else
601 bus_offset = 0;
Artyom Tarasenko903ce9f2013-04-27 07:55:13 +0200602 return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
pbrookd2b59312006-09-24 00:16:34 +0000603}
604
Juan Quintela5d4e84c2009-08-28 15:28:17 +0200605static void pci_apb_set_irq(void *opaque, int irq_num, int level)
pbrookd2b59312006-09-24 00:16:34 +0000606{
Blue Swirl95819af2010-01-30 19:48:12 +0000607 APBState *s = opaque;
Juan Quintela5d4e84c2009-08-28 15:28:17 +0200608
Artyom Tarasenko96250362013-04-27 07:55:12 +0200609 APB_DPRINTF("%s: set irq_in %d level %d\n", __func__, irq_num, level);
pbrook80b3ada2006-09-24 17:01:44 +0000610 /* PCI IRQ map onto the first 32 INO. */
Blue Swirl95819af2010-01-30 19:48:12 +0000611 if (irq_num < 32) {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200612 if (level) {
613 s->pci_irq_in |= 1ULL << irq_num;
614 if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
615 pbm_set_request(s, irq_num);
616 }
Blue Swirl95819af2010-01-30 19:48:12 +0000617 } else {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200618 s->pci_irq_in &= ~(1ULL << irq_num);
Blue Swirl361dea42012-03-10 20:37:00 +0000619 }
620 } else {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200621 /* OBIO IRQ map onto the next 32 INO. */
622 if (level) {
Blue Swirl361dea42012-03-10 20:37:00 +0000623 APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
Artyom Tarasenko96250362013-04-27 07:55:12 +0200624 s->pci_irq_in |= 1ULL << irq_num;
625 if ((s->irq_request == NO_IRQ_REQUEST)
626 && (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED)) {
627 pbm_set_request(s, irq_num);
628 }
Blue Swirl361dea42012-03-10 20:37:00 +0000629 } else {
Artyom Tarasenko96250362013-04-27 07:55:12 +0200630 s->pci_irq_in &= ~(1ULL << irq_num);
Blue Swirl95819af2010-01-30 19:48:12 +0000631 }
632 }
pbrook502a5392006-05-13 16:11:23 +0000633}
634
Isaku Yamahata68f79992010-07-13 13:01:42 +0900635static int apb_pci_bridge_initfn(PCIDevice *dev)
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200636{
Isaku Yamahata68f79992010-07-13 13:01:42 +0900637 int rc;
638
Alex Williamson60a0e442013-03-14 16:01:11 -0600639 rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
Isaku Yamahata68f79992010-07-13 13:01:42 +0900640 if (rc < 0) {
641 return rc;
642 }
643
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200644 /*
645 * command register:
646 * According to PCI bridge spec, after reset
647 * bus master bit is off
648 * memory space enable bit is off
649 * According to manual (805-1251.pdf).
650 * the reset value should be zero unless the boot pin is tied high
651 * (which is true) and thus it should be PCI_COMMAND_MEMORY.
652 */
653 pci_set_word(dev->config + PCI_COMMAND,
Blue Swirl9fe52c72010-02-14 08:27:19 +0000654 PCI_COMMAND_MEMORY);
655 pci_set_word(dev->config + PCI_STATUS,
656 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
657 PCI_STATUS_DEVSEL_MEDIUM);
Isaku Yamahata68f79992010-07-13 13:01:42 +0900658 return 0;
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200659}
660
Avi Kivitya8170e52012-10-23 12:30:10 +0200661PCIBus *pci_apb_init(hwaddr special_base,
662 hwaddr mem_base,
Blue Swirl361dea42012-03-10 20:37:00 +0000663 qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
664 qemu_irq **pbm_irqs)
pbrook502a5392006-05-13 16:11:23 +0000665{
Blue Swirl72f44c82009-07-21 08:36:37 +0000666 DeviceState *dev;
667 SysBusDevice *s;
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200668 PCIHostState *phb;
Blue Swirl72f44c82009-07-21 08:36:37 +0000669 APBState *d;
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100670 IOMMUState *is;
Isaku Yamahata68f79992010-07-13 13:01:42 +0900671 PCIDevice *pci_dev;
672 PCIBridge *br;
Blue Swirl72f44c82009-07-21 08:36:37 +0000673
674 /* Ultrasparc PBM main bus */
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200675 dev = qdev_create(NULL, TYPE_APB);
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200676 qdev_init_nofail(dev);
Andreas Färber1356b982013-01-20 02:47:33 +0100677 s = SYS_BUS_DEVICE(dev);
Blue Swirl72f44c82009-07-21 08:36:37 +0000678 /* apb_config */
Blue Swirlbae7b512010-01-10 18:25:48 +0000679 sysbus_mmio_map(s, 0, special_base);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400680 /* PCI configuration space */
681 sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
Blue Swirl72f44c82009-07-21 08:36:37 +0000682 /* pci_ioport */
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400683 sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200684 d = APB_DEVICE(dev);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400685
Paolo Bonzini40c5dce2013-06-06 21:25:08 -0400686 memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
Blue Swirlf69539b2011-09-03 16:38:02 +0000687 memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
688
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200689 phb = PCI_HOST_BRIDGE(dev);
690 phb->bus = pci_register_bus(DEVICE(phb), "pci",
691 pci_apb_set_irq, pci_pbm_map_irq, d,
692 &d->pci_mmio,
693 get_system_io(),
694 0, 32, TYPE_PCI_BUS);
Blue Swirlf6b6f1b2009-12-27 20:52:39 +0000695
Blue Swirl361dea42012-03-10 20:37:00 +0000696 *pbm_irqs = d->pbm_irqs;
697 d->ivec_irqs = ivec_irqs;
Blue Swirl95819af2010-01-30 19:48:12 +0000698
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200699 pci_create_simple(phb->bus, 0, "pbm-pci");
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400700
Mark Cave-Aylandea9a6602014-05-28 08:28:21 +0100701 /* APB IOMMU */
702 is = &d->iommu;
703 memset(is, 0, sizeof(IOMMUState));
704
Mark Cave-Aylandae74bbe2014-05-28 08:28:22 +0100705 memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops,
706 "iommu-apb", UINT64_MAX);
707 address_space_init(&is->iommu_as, &is->iommu, "pbm-as");
708 pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
709
Blue Swirl72f44c82009-07-21 08:36:37 +0000710 /* APB secondary busses */
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200711 pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
Isaku Yamahata68f79992010-07-13 13:01:42 +0900712 "pbm-bridge");
Andreas Färberf055e962013-07-11 17:13:43 +0200713 br = PCI_BRIDGE(pci_dev);
Isaku Yamahata68f79992010-07-13 13:01:42 +0900714 pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
715 pci_apb_map_irq);
716 qdev_init_nofail(&pci_dev->qdev);
717 *bus2 = pci_bridge_get_sec_bus(br);
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200718
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200719 pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true,
Isaku Yamahata68f79992010-07-13 13:01:42 +0900720 "pbm-bridge");
Andreas Färberf055e962013-07-11 17:13:43 +0200721 br = PCI_BRIDGE(pci_dev);
Isaku Yamahata68f79992010-07-13 13:01:42 +0900722 pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
723 pci_apb_map_irq);
724 qdev_init_nofail(&pci_dev->qdev);
725 *bus3 = pci_bridge_get_sec_bus(br);
Blue Swirl72f44c82009-07-21 08:36:37 +0000726
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200727 return phb->bus;
Blue Swirl72f44c82009-07-21 08:36:37 +0000728}
729
Blue Swirl95819af2010-01-30 19:48:12 +0000730static void pci_pbm_reset(DeviceState *d)
731{
732 unsigned int i;
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200733 APBState *s = APB_DEVICE(d);
Blue Swirl95819af2010-01-30 19:48:12 +0000734
735 for (i = 0; i < 8; i++) {
736 s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
737 }
Artyom Tarasenkod1d80052012-05-12 11:15:22 +0200738 for (i = 0; i < 32; i++) {
739 s->obio_irq_map[i] &= PBM_PCI_IMR_MASK;
740 }
Blue Swirl95819af2010-01-30 19:48:12 +0000741
Artyom Tarasenko96250362013-04-27 07:55:12 +0200742 s->irq_request = NO_IRQ_REQUEST;
743 s->pci_irq_in = 0ULL;
744
Blue Swirl9c0afd02010-05-12 19:27:23 +0000745 if (s->nr_resets++ == 0) {
Blue Swirl95819af2010-01-30 19:48:12 +0000746 /* Power on reset */
747 s->reset_control = POR;
748 }
749}
750
Avi Kivity3812ed02011-08-15 17:17:15 +0300751static const MemoryRegionOps pci_config_ops = {
752 .read = apb_pci_config_read,
753 .write = apb_pci_config_write,
754 .endianness = DEVICE_NATIVE_ENDIAN,
755};
756
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200757static int pci_pbm_init_device(SysBusDevice *dev)
Blue Swirl72f44c82009-07-21 08:36:37 +0000758{
pbrook502a5392006-05-13 16:11:23 +0000759 APBState *s;
Blue Swirl95819af2010-01-30 19:48:12 +0000760 unsigned int i;
pbrook502a5392006-05-13 16:11:23 +0000761
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200762 s = APB_DEVICE(dev);
Blue Swirl95819af2010-01-30 19:48:12 +0000763 for (i = 0; i < 8; i++) {
764 s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
765 }
Mark Cave-Aylandde739df2014-09-05 14:50:56 +0100766 for (i = 0; i < 2; i++) {
767 s->pci_err_irq_map[i] = (0x1f << 6) | 0x30;
768 }
Artyom Tarasenkod1d80052012-05-12 11:15:22 +0200769 for (i = 0; i < 32; i++) {
770 s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
771 }
Blue Swirl361dea42012-03-10 20:37:00 +0000772 s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
Artyom Tarasenko96250362013-04-27 07:55:12 +0200773 s->irq_request = NO_IRQ_REQUEST;
774 s->pci_irq_in = 0ULL;
Blue Swirl95819af2010-01-30 19:48:12 +0000775
Blue Swirl72f44c82009-07-21 08:36:37 +0000776 /* apb_config */
Paolo Bonzini40c5dce2013-06-06 21:25:08 -0400777 memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s,
778 "apb-config", 0x10000);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400779 /* at region 0 */
Avi Kivity750ecd42011-11-27 11:38:10 +0200780 sysbus_init_mmio(dev, &s->apb_config);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400781
Paolo Bonzini40c5dce2013-06-06 21:25:08 -0400782 memory_region_init_io(&s->pci_config, OBJECT(s), &pci_config_ops, s,
783 "apb-pci-config", 0x1000000);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400784 /* at region 1 */
Avi Kivity750ecd42011-11-27 11:38:10 +0200785 sysbus_init_mmio(dev, &s->pci_config);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400786
787 /* pci_ioport */
Paolo Bonzini5519ad02013-07-22 15:54:22 +0200788 memory_region_init_alias(&s->pci_ioport, OBJECT(s), "apb-pci-ioport",
789 get_system_io(), 0, 0x10000);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400790 /* at region 2 */
Avi Kivity750ecd42011-11-27 11:38:10 +0200791 sysbus_init_mmio(dev, &s->pci_ioport);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400792
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200793 return 0;
Blue Swirl72f44c82009-07-21 08:36:37 +0000794}
pbrook502a5392006-05-13 16:11:23 +0000795
Markus Armbruster9af21db2015-01-19 15:52:30 +0100796static void pbm_pci_host_realize(PCIDevice *d, Error **errp)
Blue Swirl72f44c82009-07-21 08:36:37 +0000797{
Blue Swirl9fe52c72010-02-14 08:27:19 +0000798 pci_set_word(d->config + PCI_COMMAND,
799 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
800 pci_set_word(d->config + PCI_STATUS,
801 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
802 PCI_STATUS_DEVSEL_MEDIUM);
pbrook502a5392006-05-13 16:11:23 +0000803}
Blue Swirl72f44c82009-07-21 08:36:37 +0000804
Anthony Liguori40021f02011-12-04 12:22:06 -0600805static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
806{
807 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
Markus Armbruster08c58f92013-11-28 17:26:58 +0100808 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600809
Markus Armbruster9af21db2015-01-19 15:52:30 +0100810 k->realize = pbm_pci_host_realize;
Anthony Liguori40021f02011-12-04 12:22:06 -0600811 k->vendor_id = PCI_VENDOR_ID_SUN;
812 k->device_id = PCI_DEVICE_ID_SUN_SABRE;
813 k->class_id = PCI_CLASS_BRIDGE_HOST;
Markus Armbruster08c58f92013-11-28 17:26:58 +0100814 /*
815 * PCI-facing part of the host bridge, not usable without the
816 * host-facing part, which can't be device_add'ed, yet.
817 */
818 dc->cannot_instantiate_with_device_add_yet = true;
Anthony Liguori40021f02011-12-04 12:22:06 -0600819}
820
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100821static const TypeInfo pbm_pci_host_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600822 .name = "pbm-pci",
823 .parent = TYPE_PCI_DEVICE,
824 .instance_size = sizeof(PCIDevice),
825 .class_init = pbm_pci_host_class_init,
Blue Swirl72f44c82009-07-21 08:36:37 +0000826};
827
Anthony Liguori999e12b2012-01-24 13:12:29 -0600828static void pbm_host_class_init(ObjectClass *klass, void *data)
829{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600830 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600831 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
832
833 k->init = pci_pbm_init_device;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300834 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600835 dc->reset = pci_pbm_reset;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600836}
837
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100838static const TypeInfo pbm_host_info = {
Paolo Bonzini2b8fbcd2013-07-22 15:54:30 +0200839 .name = TYPE_APB,
840 .parent = TYPE_PCI_HOST_BRIDGE,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600841 .instance_size = sizeof(APBState),
842 .class_init = pbm_host_class_init,
Blue Swirl95819af2010-01-30 19:48:12 +0000843};
Isaku Yamahata68f79992010-07-13 13:01:42 +0900844
Anthony Liguori40021f02011-12-04 12:22:06 -0600845static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
846{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600847 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600848 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
849
850 k->init = apb_pci_bridge_initfn;
851 k->exit = pci_bridge_exitfn;
852 k->vendor_id = PCI_VENDOR_ID_SUN;
853 k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
854 k->revision = 0x11;
855 k->config_write = pci_bridge_write_config;
856 k->is_bridge = 1;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300857 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600858 dc->reset = pci_bridge_reset;
859 dc->vmsd = &vmstate_pci_device;
Anthony Liguori40021f02011-12-04 12:22:06 -0600860}
861
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100862static const TypeInfo pbm_pci_bridge_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600863 .name = "pbm-bridge",
Andreas Färberf055e962013-07-11 17:13:43 +0200864 .parent = TYPE_PCI_BRIDGE,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600865 .class_init = pbm_pci_bridge_class_init,
Isaku Yamahata68f79992010-07-13 13:01:42 +0900866};
867
Andreas Färber83f7d432012-02-09 15:20:55 +0100868static void pbm_register_types(void)
Blue Swirl72f44c82009-07-21 08:36:37 +0000869{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600870 type_register_static(&pbm_host_info);
871 type_register_static(&pbm_pci_host_info);
872 type_register_static(&pbm_pci_bridge_info);
Blue Swirl72f44c82009-07-21 08:36:37 +0000873}
874
Andreas Färber83f7d432012-02-09 15:20:55 +0100875type_init(pbm_register_types)