pci: implement pci bridge filtering.
[qemu.git] / hw / apb_pci.c
blob39998791f226e72f73ed268fdbf4ca7ee464bfd9
1 /*
2 * QEMU Ultrasparc APB PCI host
4 * Copyright (c) 2006 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
25 /* XXX This file and most of its contents are somewhat misnamed. The
26 Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
27 the secondary PCI bridge. */
29 #include "sysbus.h"
30 #include "pci.h"
31 #include "pci_host.h"
33 /* debug APB */
34 //#define DEBUG_APB
36 #ifdef DEBUG_APB
37 #define APB_DPRINTF(fmt, ...) \
38 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
39 #else
40 #define APB_DPRINTF(fmt, ...)
41 #endif
44 * Chipset docs:
45 * PBM: "UltraSPARC IIi User's Manual",
46 * http://www.sun.com/processors/manuals/805-0087.pdf
48 * APB: "Advanced PCI Bridge (APB) User's Manual",
49 * http://www.sun.com/processors/manuals/805-1251.pdf
52 typedef struct APBState {
53 SysBusDevice busdev;
54 PCIHostState host_state;
55 } APBState;
57 static void apb_config_writel (void *opaque, target_phys_addr_t addr,
58 uint32_t val)
60 //PCIBus *s = opaque;
62 switch (addr & 0x3f) {
63 case 0x00: // Control/Status
64 case 0x10: // AFSR
65 case 0x18: // AFAR
66 case 0x20: // Diagnostic
67 case 0x28: // Target address space
68 // XXX
69 default:
70 break;
74 static uint32_t apb_config_readl (void *opaque,
75 target_phys_addr_t addr)
77 //PCIBus *s = opaque;
78 uint32_t val;
80 switch (addr & 0x3f) {
81 case 0x00: // Control/Status
82 case 0x10: // AFSR
83 case 0x18: // AFAR
84 case 0x20: // Diagnostic
85 case 0x28: // Target address space
86 // XXX
87 default:
88 val = 0;
89 break;
91 return val;
94 static CPUWriteMemoryFunc * const apb_config_write[] = {
95 &apb_config_writel,
96 &apb_config_writel,
97 &apb_config_writel,
100 static CPUReadMemoryFunc * const apb_config_read[] = {
101 &apb_config_readl,
102 &apb_config_readl,
103 &apb_config_readl,
106 static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
107 uint32_t val)
109 cpu_outb(addr & IOPORTS_MASK, val);
112 static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
113 uint32_t val)
115 cpu_outw(addr & IOPORTS_MASK, val);
118 static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
119 uint32_t val)
121 cpu_outl(addr & IOPORTS_MASK, val);
124 static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
126 uint32_t val;
128 val = cpu_inb(addr & IOPORTS_MASK);
129 return val;
132 static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
134 uint32_t val;
136 val = cpu_inw(addr & IOPORTS_MASK);
137 return val;
140 static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
142 uint32_t val;
144 val = cpu_inl(addr & IOPORTS_MASK);
145 return val;
148 static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
149 &pci_apb_iowriteb,
150 &pci_apb_iowritew,
151 &pci_apb_iowritel,
154 static CPUReadMemoryFunc * const pci_apb_ioread[] = {
155 &pci_apb_ioreadb,
156 &pci_apb_ioreadw,
157 &pci_apb_ioreadl,
160 /* The APB host has an IRQ line for each IRQ line of each slot. */
161 static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
163 return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
166 static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
168 int bus_offset;
169 if (pci_dev->devfn & 1)
170 bus_offset = 16;
171 else
172 bus_offset = 0;
173 return bus_offset + irq_num;
176 static void pci_apb_set_irq(void *opaque, int irq_num, int level)
178 qemu_irq *pic = opaque;
180 /* PCI IRQ map onto the first 32 INO. */
181 qemu_set_irq(pic[irq_num], level);
184 PCIBus *pci_apb_init(target_phys_addr_t special_base,
185 target_phys_addr_t mem_base,
186 qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
188 DeviceState *dev;
189 SysBusDevice *s;
190 APBState *d;
192 /* Ultrasparc PBM main bus */
193 dev = qdev_create(NULL, "pbm");
194 qdev_init_nofail(dev);
195 s = sysbus_from_qdev(dev);
196 /* apb_config */
197 sysbus_mmio_map(s, 0, special_base + 0x2000ULL);
198 /* pci_ioport */
199 sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
200 /* mem_config: XXX size should be 4G-prom */
201 sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
202 /* mem_data */
203 sysbus_mmio_map(s, 3, mem_base);
204 d = FROM_SYSBUS(APBState, s);
205 d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
206 pci_apb_set_irq, pci_pbm_map_irq, pic,
207 0, 32);
208 pci_create_simple(d->host_state.bus, 0, "pbm");
209 /* APB secondary busses */
210 *bus2 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 0),
211 PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
212 pci_apb_map_irq,
213 "Advanced PCI Bus secondary bridge 1");
214 *bus3 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 1),
215 PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
216 pci_apb_map_irq,
217 "Advanced PCI Bus secondary bridge 2");
219 return d->host_state.bus;
222 static int pci_pbm_init_device(SysBusDevice *dev)
225 APBState *s;
226 int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
228 s = FROM_SYSBUS(APBState, dev);
229 /* apb_config */
230 apb_config = cpu_register_io_memory(apb_config_read,
231 apb_config_write, s);
232 sysbus_init_mmio(dev, 0x40ULL, apb_config);
233 /* pci_ioport */
234 pci_ioport = cpu_register_io_memory(pci_apb_ioread,
235 pci_apb_iowrite, s);
236 sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
237 /* mem_config */
238 pci_mem_config = pci_host_config_register_io_memory(&s->host_state);
239 sysbus_init_mmio(dev, 0x10ULL, pci_mem_config);
240 /* mem_data */
241 pci_mem_data = pci_host_data_register_io_memory(&s->host_state);
242 sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
243 return 0;
246 static int pbm_pci_host_init(PCIDevice *d)
248 pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
249 pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
250 d->config[0x04] = 0x06; // command = bus master, pci mem
251 d->config[0x05] = 0x00;
252 d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
253 d->config[0x07] = 0x03; // status = medium devsel
254 d->config[0x08] = 0x00; // revision
255 d->config[0x09] = 0x00; // programming i/f
256 pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
257 d->config[0x0D] = 0x10; // latency_timer
258 d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
259 return 0;
262 static PCIDeviceInfo pbm_pci_host_info = {
263 .qdev.name = "pbm",
264 .qdev.size = sizeof(PCIDevice),
265 .init = pbm_pci_host_init,
268 static void pbm_register_devices(void)
270 sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
271 pci_qdev_register(&pbm_pci_host_info);
274 device_init(pbm_register_devices)