]> Git Repo - qemu.git/blob - hw/pci-host/prep.c
raven: Implement non-contiguous I/O region
[qemu.git] / hw / pci-host / prep.c
1 /*
2  * QEMU PREP PCI host
3  *
4  * Copyright (c) 2006 Fabrice Bellard
5  * Copyright (c) 2011-2013 Andreas Färber
6  *
7  * 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  */
25
26 #include "hw/hw.h"
27 #include "hw/pci/pci.h"
28 #include "hw/pci/pci_bus.h"
29 #include "hw/pci/pci_host.h"
30 #include "hw/i386/pc.h"
31 #include "hw/loader.h"
32 #include "exec/address-spaces.h"
33 #include "elf.h"
34
35 #define TYPE_RAVEN_PCI_DEVICE "raven"
36 #define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
37
38 #define RAVEN_PCI_DEVICE(obj) \
39     OBJECT_CHECK(RavenPCIState, (obj), TYPE_RAVEN_PCI_DEVICE)
40
41 typedef struct RavenPCIState {
42     PCIDevice dev;
43
44     uint32_t elf_machine;
45     char *bios_name;
46     MemoryRegion bios;
47 } RavenPCIState;
48
49 #define RAVEN_PCI_HOST_BRIDGE(obj) \
50     OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE)
51
52 typedef struct PRePPCIState {
53     PCIHostState parent_obj;
54
55     qemu_irq irq[PCI_NUM_PINS];
56     PCIBus pci_bus;
57     AddressSpace pci_io_as;
58     MemoryRegion pci_io_non_contiguous;
59     MemoryRegion pci_intack;
60     RavenPCIState pci_dev;
61
62     int contiguous_map;
63 } PREPPCIState;
64
65 #define BIOS_SIZE (1024 * 1024)
66
67 static inline uint32_t PPC_PCIIO_config(hwaddr addr)
68 {
69     int i;
70
71     for (i = 0; i < 11; i++) {
72         if ((addr & (1 << (11 + i))) != 0) {
73             break;
74         }
75     }
76     return (addr & 0x7ff) |  (i << 11);
77 }
78
79 static void ppc_pci_io_write(void *opaque, hwaddr addr,
80                              uint64_t val, unsigned int size)
81 {
82     PREPPCIState *s = opaque;
83     PCIHostState *phb = PCI_HOST_BRIDGE(s);
84     pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
85 }
86
87 static uint64_t ppc_pci_io_read(void *opaque, hwaddr addr,
88                                 unsigned int size)
89 {
90     PREPPCIState *s = opaque;
91     PCIHostState *phb = PCI_HOST_BRIDGE(s);
92     return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
93 }
94
95 static const MemoryRegionOps PPC_PCIIO_ops = {
96     .read = ppc_pci_io_read,
97     .write = ppc_pci_io_write,
98     .endianness = DEVICE_LITTLE_ENDIAN,
99 };
100
101 static uint64_t ppc_intack_read(void *opaque, hwaddr addr,
102                                 unsigned int size)
103 {
104     return pic_read_irq(isa_pic);
105 }
106
107 static const MemoryRegionOps PPC_intack_ops = {
108     .read = ppc_intack_read,
109     .valid = {
110         .max_access_size = 1,
111     },
112 };
113
114 static inline hwaddr raven_io_address(PREPPCIState *s,
115                                       hwaddr addr)
116 {
117     if (s->contiguous_map == 0) {
118         /* 64 KB contiguous space for IOs */
119         addr &= 0xFFFF;
120     } else {
121         /* 8 MB non-contiguous space for IOs */
122         addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
123     }
124
125     /* FIXME: handle endianness switch */
126
127     return addr;
128 }
129
130 static uint64_t raven_io_read(void *opaque, hwaddr addr,
131                               unsigned int size)
132 {
133     PREPPCIState *s = opaque;
134     uint8_t buf[4];
135
136     addr = raven_io_address(s, addr);
137     address_space_read(&s->pci_io_as, addr, buf, size);
138
139     if (size == 1) {
140         return buf[0];
141     } else if (size == 2) {
142         return lduw_p(buf);
143     } else if (size == 4) {
144         return ldl_p(buf);
145     } else {
146         g_assert_not_reached();
147     }
148 }
149
150 static void raven_io_write(void *opaque, hwaddr addr,
151                            uint64_t val, unsigned int size)
152 {
153     PREPPCIState *s = opaque;
154     uint8_t buf[4];
155
156     addr = raven_io_address(s, addr);
157
158     if (size == 1) {
159         buf[0] = val;
160     } else if (size == 2) {
161         stw_p(buf, val);
162     } else if (size == 4) {
163         stl_p(buf, val);
164     } else {
165         g_assert_not_reached();
166     }
167
168     address_space_write(&s->pci_io_as, addr, buf, size);
169 }
170
171 static const MemoryRegionOps raven_io_ops = {
172     .read = raven_io_read,
173     .write = raven_io_write,
174     .endianness = DEVICE_LITTLE_ENDIAN,
175     .impl.max_access_size = 4,
176     .valid.unaligned = true,
177 };
178
179 static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
180 {
181     return (irq_num + (pci_dev->devfn >> 3)) & 1;
182 }
183
184 static void prep_set_irq(void *opaque, int irq_num, int level)
185 {
186     qemu_irq *pic = opaque;
187
188     qemu_set_irq(pic[irq_num] , level);
189 }
190
191 static void raven_change_gpio(void *opaque, int n, int level)
192 {
193     PREPPCIState *s = opaque;
194
195     s->contiguous_map = level;
196 }
197
198 static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
199 {
200     SysBusDevice *dev = SYS_BUS_DEVICE(d);
201     PCIHostState *h = PCI_HOST_BRIDGE(dev);
202     PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
203     MemoryRegion *address_space_mem = get_system_memory();
204     int i;
205
206     isa_mem_base = 0xc0000000;
207
208     for (i = 0; i < PCI_NUM_PINS; i++) {
209         sysbus_init_irq(dev, &s->irq[i]);
210     }
211
212     qdev_init_gpio_in(d, raven_change_gpio, 1);
213
214     pci_bus_irqs(&s->pci_bus, prep_set_irq, prep_map_irq, s->irq, PCI_NUM_PINS);
215
216     memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_be_ops, s,
217                           "pci-conf-idx", 1);
218     sysbus_add_io(dev, 0xcf8, &h->conf_mem);
219     sysbus_init_ioports(&h->busdev, 0xcf8, 1);
220
221     memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_be_ops, s,
222                           "pci-conf-data", 1);
223     sysbus_add_io(dev, 0xcfc, &h->data_mem);
224     sysbus_init_ioports(&h->busdev, 0xcfc, 1);
225
226     memory_region_init_io(&h->mmcfg, OBJECT(s), &PPC_PCIIO_ops, s, "pciio", 0x00400000);
227     memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
228
229     memory_region_init_io(&s->pci_intack, OBJECT(s), &PPC_intack_ops, s,
230                           "pci-intack", 1);
231     memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
232
233     /* TODO Remove once realize propagates to child devices. */
234     object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
235 }
236
237 static void raven_pcihost_initfn(Object *obj)
238 {
239     PCIHostState *h = PCI_HOST_BRIDGE(obj);
240     PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
241     MemoryRegion *address_space_mem = get_system_memory();
242     MemoryRegion *address_space_io = get_system_io();
243     DeviceState *pci_dev;
244
245     memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
246                           "pci-io-non-contiguous", 0x00800000);
247     address_space_init(&s->pci_io_as, get_system_io(), "raven-io");
248
249     /* CPU address space */
250     memory_region_add_subregion_overlap(address_space_mem, 0x80000000,
251                                         &s->pci_io_non_contiguous, 1);
252     pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
253                         address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
254     h->bus = &s->pci_bus;
255
256     object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
257     pci_dev = DEVICE(&s->pci_dev);
258     qdev_set_parent_bus(pci_dev, BUS(&s->pci_bus));
259     object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr",
260                             NULL);
261     qdev_prop_set_bit(pci_dev, "multifunction", false);
262 }
263
264 static int raven_init(PCIDevice *d)
265 {
266     RavenPCIState *s = RAVEN_PCI_DEVICE(d);
267     char *filename;
268     int bios_size = -1;
269
270     d->config[0x0C] = 0x08; // cache_line_size
271     d->config[0x0D] = 0x10; // latency_timer
272     d->config[0x34] = 0x00; // capabilities_pointer
273
274     memory_region_init_ram(&s->bios, OBJECT(s), "bios", BIOS_SIZE);
275     memory_region_set_readonly(&s->bios, true);
276     memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
277                                 &s->bios);
278     vmstate_register_ram_global(&s->bios);
279     if (s->bios_name) {
280         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
281         if (filename) {
282             if (s->elf_machine != EM_NONE) {
283                 bios_size = load_elf(filename, NULL, NULL, NULL,
284                                      NULL, NULL, 1, s->elf_machine, 0);
285             }
286             if (bios_size < 0) {
287                 bios_size = get_image_size(filename);
288                 if (bios_size > 0 && bios_size <= BIOS_SIZE) {
289                     hwaddr bios_addr;
290                     bios_size = (bios_size + 0xfff) & ~0xfff;
291                     bios_addr = (uint32_t)(-BIOS_SIZE);
292                     bios_size = load_image_targphys(filename, bios_addr,
293                                                     bios_size);
294                 }
295             }
296         }
297         if (bios_size < 0 || bios_size > BIOS_SIZE) {
298             hw_error("qemu: could not load bios image '%s'\n", s->bios_name);
299         }
300         if (filename) {
301             g_free(filename);
302         }
303     }
304
305     return 0;
306 }
307
308 static const VMStateDescription vmstate_raven = {
309     .name = "raven",
310     .version_id = 0,
311     .minimum_version_id = 0,
312     .fields = (VMStateField[]) {
313         VMSTATE_PCI_DEVICE(dev, RavenPCIState),
314         VMSTATE_END_OF_LIST()
315     },
316 };
317
318 static void raven_class_init(ObjectClass *klass, void *data)
319 {
320     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
321     DeviceClass *dc = DEVICE_CLASS(klass);
322
323     k->init = raven_init;
324     k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
325     k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
326     k->revision = 0x00;
327     k->class_id = PCI_CLASS_BRIDGE_HOST;
328     dc->desc = "PReP Host Bridge - Motorola Raven";
329     dc->vmsd = &vmstate_raven;
330     /*
331      * PCI-facing part of the host bridge, not usable without the
332      * host-facing part, which can't be device_add'ed, yet.
333      */
334     dc->cannot_instantiate_with_device_add_yet = true;
335 }
336
337 static const TypeInfo raven_info = {
338     .name = TYPE_RAVEN_PCI_DEVICE,
339     .parent = TYPE_PCI_DEVICE,
340     .instance_size = sizeof(RavenPCIState),
341     .class_init = raven_class_init,
342 };
343
344 static Property raven_pcihost_properties[] = {
345     DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
346                        EM_NONE),
347     DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
348     DEFINE_PROP_END_OF_LIST()
349 };
350
351 static void raven_pcihost_class_init(ObjectClass *klass, void *data)
352 {
353     DeviceClass *dc = DEVICE_CLASS(klass);
354
355     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
356     dc->realize = raven_pcihost_realizefn;
357     dc->props = raven_pcihost_properties;
358     dc->fw_name = "pci";
359 }
360
361 static const TypeInfo raven_pcihost_info = {
362     .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
363     .parent = TYPE_PCI_HOST_BRIDGE,
364     .instance_size = sizeof(PREPPCIState),
365     .instance_init = raven_pcihost_initfn,
366     .class_init = raven_pcihost_class_init,
367 };
368
369 static void raven_register_types(void)
370 {
371     type_register_static(&raven_pcihost_info);
372     type_register_static(&raven_info);
373 }
374
375 type_init(raven_register_types)
This page took 0.045353 seconds and 4 git commands to generate.