114a026ddSPhilippe Mathieu-Daudé /*
214a026ddSPhilippe Mathieu-Daudé * QEMU PIIX PCI ISA Bridge Emulation
314a026ddSPhilippe Mathieu-Daudé *
414a026ddSPhilippe Mathieu-Daudé * Copyright (c) 2006 Fabrice Bellard
516971899SBernhard Beschow * Copyright (c) 2018 Hervé Poussineau
614a026ddSPhilippe Mathieu-Daudé *
714a026ddSPhilippe Mathieu-Daudé * Permission is hereby granted, free of charge, to any person obtaining a copy
814a026ddSPhilippe Mathieu-Daudé * of this software and associated documentation files (the "Software"), to deal
914a026ddSPhilippe Mathieu-Daudé * in the Software without restriction, including without limitation the rights
1014a026ddSPhilippe Mathieu-Daudé * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1114a026ddSPhilippe Mathieu-Daudé * copies of the Software, and to permit persons to whom the Software is
1214a026ddSPhilippe Mathieu-Daudé * furnished to do so, subject to the following conditions:
1314a026ddSPhilippe Mathieu-Daudé *
1414a026ddSPhilippe Mathieu-Daudé * The above copyright notice and this permission notice shall be included in
1514a026ddSPhilippe Mathieu-Daudé * all copies or substantial portions of the Software.
1614a026ddSPhilippe Mathieu-Daudé *
1714a026ddSPhilippe Mathieu-Daudé * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1814a026ddSPhilippe Mathieu-Daudé * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1914a026ddSPhilippe Mathieu-Daudé * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2014a026ddSPhilippe Mathieu-Daudé * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2114a026ddSPhilippe Mathieu-Daudé * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2214a026ddSPhilippe Mathieu-Daudé * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2314a026ddSPhilippe Mathieu-Daudé * THE SOFTWARE.
2414a026ddSPhilippe Mathieu-Daudé */
2514a026ddSPhilippe Mathieu-Daudé
2614a026ddSPhilippe Mathieu-Daudé #include "qemu/osdep.h"
2714a026ddSPhilippe Mathieu-Daudé #include "qemu/range.h"
28fe3055d2SBernhard Beschow #include "qapi/error.h"
29503a35e7SBernhard Beschow #include "hw/dma/i8257.h"
3014a026ddSPhilippe Mathieu-Daudé #include "hw/southbridge/piix.h"
3116971899SBernhard Beschow #include "hw/timer/i8254.h"
3214a026ddSPhilippe Mathieu-Daudé #include "hw/irq.h"
33f0bc6bf7SBernhard Beschow #include "hw/qdev-properties.h"
34e47e5a5bSBernhard Beschow #include "hw/ide/piix.h"
3516971899SBernhard Beschow #include "hw/intc/i8259.h"
3614a026ddSPhilippe Mathieu-Daudé #include "hw/isa/isa.h"
3732cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h"
3814a026ddSPhilippe Mathieu-Daudé #include "migration/vmstate.h"
3992ea7fb3SIgor Mammedov #include "hw/acpi/acpi_aml_interface.h"
4014a026ddSPhilippe Mathieu-Daudé
piix_set_irq_pic(PIIXState * s,int pic_irq)412a62c479SBernhard Beschow static void piix_set_irq_pic(PIIXState *s, int pic_irq)
4214a026ddSPhilippe Mathieu-Daudé {
432a62c479SBernhard Beschow qemu_set_irq(s->isa_irqs_in[pic_irq],
442a62c479SBernhard Beschow !!(s->pic_levels &
4514a026ddSPhilippe Mathieu-Daudé (((1ULL << PIIX_NUM_PIRQS) - 1) <<
4614a026ddSPhilippe Mathieu-Daudé (pic_irq * PIIX_NUM_PIRQS))));
4714a026ddSPhilippe Mathieu-Daudé }
4814a026ddSPhilippe Mathieu-Daudé
piix_set_pci_irq_level_internal(PIIXState * s,int pirq,int level)492a62c479SBernhard Beschow static void piix_set_pci_irq_level_internal(PIIXState *s, int pirq, int level)
5014a026ddSPhilippe Mathieu-Daudé {
5114a026ddSPhilippe Mathieu-Daudé int pic_irq;
5214a026ddSPhilippe Mathieu-Daudé uint64_t mask;
5314a026ddSPhilippe Mathieu-Daudé
542a62c479SBernhard Beschow pic_irq = s->dev.config[PIIX_PIRQCA + pirq];
5532f29b26SBernhard Beschow if (pic_irq >= ISA_NUM_IRQS) {
5614a026ddSPhilippe Mathieu-Daudé return;
5714a026ddSPhilippe Mathieu-Daudé }
5814a026ddSPhilippe Mathieu-Daudé
5914a026ddSPhilippe Mathieu-Daudé mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
602a62c479SBernhard Beschow s->pic_levels &= ~mask;
612a62c479SBernhard Beschow s->pic_levels |= mask * !!level;
6214a026ddSPhilippe Mathieu-Daudé }
6314a026ddSPhilippe Mathieu-Daudé
piix_set_pci_irq_level(PIIXState * s,int pirq,int level)642a62c479SBernhard Beschow static void piix_set_pci_irq_level(PIIXState *s, int pirq, int level)
6514a026ddSPhilippe Mathieu-Daudé {
6614a026ddSPhilippe Mathieu-Daudé int pic_irq;
6714a026ddSPhilippe Mathieu-Daudé
682a62c479SBernhard Beschow pic_irq = s->dev.config[PIIX_PIRQCA + pirq];
6932f29b26SBernhard Beschow if (pic_irq >= ISA_NUM_IRQS) {
7014a026ddSPhilippe Mathieu-Daudé return;
7114a026ddSPhilippe Mathieu-Daudé }
7214a026ddSPhilippe Mathieu-Daudé
732a62c479SBernhard Beschow piix_set_pci_irq_level_internal(s, pirq, level);
7414a026ddSPhilippe Mathieu-Daudé
752a62c479SBernhard Beschow piix_set_irq_pic(s, pic_irq);
7614a026ddSPhilippe Mathieu-Daudé }
7714a026ddSPhilippe Mathieu-Daudé
piix_set_pci_irq(void * opaque,int pirq,int level)782a62c479SBernhard Beschow static void piix_set_pci_irq(void *opaque, int pirq, int level)
7914a026ddSPhilippe Mathieu-Daudé {
802a62c479SBernhard Beschow PIIXState *s = opaque;
812a62c479SBernhard Beschow piix_set_pci_irq_level(s, pirq, level);
8214a026ddSPhilippe Mathieu-Daudé }
8314a026ddSPhilippe Mathieu-Daudé
piix_request_i8259_irq(void * opaque,int irq,int level)842d7630f5SBernhard Beschow static void piix_request_i8259_irq(void *opaque, int irq, int level)
8516971899SBernhard Beschow {
867d6f2659SBernhard Beschow PIIXState *s = opaque;
8716971899SBernhard Beschow qemu_set_irq(s->cpu_intr, level);
8816971899SBernhard Beschow }
8916971899SBernhard Beschow
piix_route_intx_pin_to_irq(void * opaque,int pin)902a62c479SBernhard Beschow static PCIINTxRoute piix_route_intx_pin_to_irq(void *opaque, int pin)
9114a026ddSPhilippe Mathieu-Daudé {
922a62c479SBernhard Beschow PCIDevice *pci_dev = opaque;
932a62c479SBernhard Beschow int irq = pci_dev->config[PIIX_PIRQCA + pin];
9414a026ddSPhilippe Mathieu-Daudé PCIINTxRoute route;
9514a026ddSPhilippe Mathieu-Daudé
9632f29b26SBernhard Beschow if (irq < ISA_NUM_IRQS) {
9714a026ddSPhilippe Mathieu-Daudé route.mode = PCI_INTX_ENABLED;
9814a026ddSPhilippe Mathieu-Daudé route.irq = irq;
9914a026ddSPhilippe Mathieu-Daudé } else {
10014a026ddSPhilippe Mathieu-Daudé route.mode = PCI_INTX_DISABLED;
10114a026ddSPhilippe Mathieu-Daudé route.irq = -1;
10214a026ddSPhilippe Mathieu-Daudé }
10314a026ddSPhilippe Mathieu-Daudé return route;
10414a026ddSPhilippe Mathieu-Daudé }
10514a026ddSPhilippe Mathieu-Daudé
10614a026ddSPhilippe Mathieu-Daudé /* irq routing is changed. so rebuild bitmap */
piix_update_pci_irq_levels(PIIXState * s)1072a62c479SBernhard Beschow static void piix_update_pci_irq_levels(PIIXState *s)
10814a026ddSPhilippe Mathieu-Daudé {
1092a62c479SBernhard Beschow PCIBus *bus = pci_get_bus(&s->dev);
11014a026ddSPhilippe Mathieu-Daudé int pirq;
11114a026ddSPhilippe Mathieu-Daudé
1122a62c479SBernhard Beschow s->pic_levels = 0;
11314a026ddSPhilippe Mathieu-Daudé for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
1142a62c479SBernhard Beschow piix_set_pci_irq_level(s, pirq, pci_bus_get_irq_level(bus, pirq));
11514a026ddSPhilippe Mathieu-Daudé }
11614a026ddSPhilippe Mathieu-Daudé }
11714a026ddSPhilippe Mathieu-Daudé
piix_write_config(PCIDevice * dev,uint32_t address,uint32_t val,int len)1182a62c479SBernhard Beschow static void piix_write_config(PCIDevice *dev, uint32_t address, uint32_t val,
1192a62c479SBernhard Beschow int len)
12014a026ddSPhilippe Mathieu-Daudé {
12114a026ddSPhilippe Mathieu-Daudé pci_default_write_config(dev, address, val, len);
12214a026ddSPhilippe Mathieu-Daudé if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) {
1232a62c479SBernhard Beschow PIIXState *s = PIIX_PCI_DEVICE(dev);
12414a026ddSPhilippe Mathieu-Daudé int pic_irq;
12514a026ddSPhilippe Mathieu-Daudé
1262a62c479SBernhard Beschow pci_bus_fire_intx_routing_notifier(pci_get_bus(&s->dev));
1272a62c479SBernhard Beschow piix_update_pci_irq_levels(s);
12832f29b26SBernhard Beschow for (pic_irq = 0; pic_irq < ISA_NUM_IRQS; pic_irq++) {
1292a62c479SBernhard Beschow piix_set_irq_pic(s, pic_irq);
13014a026ddSPhilippe Mathieu-Daudé }
13114a026ddSPhilippe Mathieu-Daudé }
13214a026ddSPhilippe Mathieu-Daudé }
13314a026ddSPhilippe Mathieu-Daudé
piix_reset(DeviceState * dev)1347d6f2659SBernhard Beschow static void piix_reset(DeviceState *dev)
13514a026ddSPhilippe Mathieu-Daudé {
1367d6f2659SBernhard Beschow PIIXState *d = PIIX_PCI_DEVICE(dev);
13714a026ddSPhilippe Mathieu-Daudé uint8_t *pci_conf = d->dev.config;
13814a026ddSPhilippe Mathieu-Daudé
13914a026ddSPhilippe Mathieu-Daudé pci_conf[0x04] = 0x07; /* master, memory and I/O */
14014a026ddSPhilippe Mathieu-Daudé pci_conf[0x05] = 0x00;
14114a026ddSPhilippe Mathieu-Daudé pci_conf[0x06] = 0x00;
14214a026ddSPhilippe Mathieu-Daudé pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
14314a026ddSPhilippe Mathieu-Daudé pci_conf[0x4c] = 0x4d;
14414a026ddSPhilippe Mathieu-Daudé pci_conf[0x4e] = 0x03;
14514a026ddSPhilippe Mathieu-Daudé pci_conf[0x4f] = 0x00;
14614a026ddSPhilippe Mathieu-Daudé pci_conf[0x60] = 0x80;
14714a026ddSPhilippe Mathieu-Daudé pci_conf[0x61] = 0x80;
14814a026ddSPhilippe Mathieu-Daudé pci_conf[0x62] = 0x80;
14914a026ddSPhilippe Mathieu-Daudé pci_conf[0x63] = 0x80;
15014a026ddSPhilippe Mathieu-Daudé pci_conf[0x69] = 0x02;
15114a026ddSPhilippe Mathieu-Daudé pci_conf[0x70] = 0x80;
15214a026ddSPhilippe Mathieu-Daudé pci_conf[0x76] = 0x0c;
15314a026ddSPhilippe Mathieu-Daudé pci_conf[0x77] = 0x0c;
15414a026ddSPhilippe Mathieu-Daudé pci_conf[0x78] = 0x02;
15514a026ddSPhilippe Mathieu-Daudé pci_conf[0x79] = 0x00;
15614a026ddSPhilippe Mathieu-Daudé pci_conf[0x80] = 0x00;
15714a026ddSPhilippe Mathieu-Daudé pci_conf[0x82] = 0x00;
15814a026ddSPhilippe Mathieu-Daudé pci_conf[0xa0] = 0x08;
15914a026ddSPhilippe Mathieu-Daudé pci_conf[0xa2] = 0x00;
16014a026ddSPhilippe Mathieu-Daudé pci_conf[0xa3] = 0x00;
16114a026ddSPhilippe Mathieu-Daudé pci_conf[0xa4] = 0x00;
16214a026ddSPhilippe Mathieu-Daudé pci_conf[0xa5] = 0x00;
16314a026ddSPhilippe Mathieu-Daudé pci_conf[0xa6] = 0x00;
16414a026ddSPhilippe Mathieu-Daudé pci_conf[0xa7] = 0x00;
16514a026ddSPhilippe Mathieu-Daudé pci_conf[0xa8] = 0x0f;
16614a026ddSPhilippe Mathieu-Daudé pci_conf[0xaa] = 0x00;
16714a026ddSPhilippe Mathieu-Daudé pci_conf[0xab] = 0x00;
16814a026ddSPhilippe Mathieu-Daudé pci_conf[0xac] = 0x00;
16914a026ddSPhilippe Mathieu-Daudé pci_conf[0xae] = 0x00;
17014a026ddSPhilippe Mathieu-Daudé
17114a026ddSPhilippe Mathieu-Daudé d->pic_levels = 0;
17214a026ddSPhilippe Mathieu-Daudé d->rcr = 0;
17314a026ddSPhilippe Mathieu-Daudé }
17414a026ddSPhilippe Mathieu-Daudé
piix_post_load(void * opaque,int version_id)1752a62c479SBernhard Beschow static int piix_post_load(void *opaque, int version_id)
17614a026ddSPhilippe Mathieu-Daudé {
1772a62c479SBernhard Beschow PIIXState *s = opaque;
17814a026ddSPhilippe Mathieu-Daudé int pirq;
17914a026ddSPhilippe Mathieu-Daudé
18014a026ddSPhilippe Mathieu-Daudé /*
18114a026ddSPhilippe Mathieu-Daudé * Because the i8259 has not been deserialized yet, qemu_irq_raise
18214a026ddSPhilippe Mathieu-Daudé * might bring the system to a different state than the saved one;
18314a026ddSPhilippe Mathieu-Daudé * for example, the interrupt could be masked but the i8259 would
18414a026ddSPhilippe Mathieu-Daudé * not know that yet and would trigger an interrupt in the CPU.
18514a026ddSPhilippe Mathieu-Daudé *
18614a026ddSPhilippe Mathieu-Daudé * Here, we update irq levels without raising the interrupt.
18714a026ddSPhilippe Mathieu-Daudé * Interrupt state will be deserialized separately through the i8259.
18814a026ddSPhilippe Mathieu-Daudé */
1892a62c479SBernhard Beschow s->pic_levels = 0;
19014a026ddSPhilippe Mathieu-Daudé for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
1912a62c479SBernhard Beschow piix_set_pci_irq_level_internal(s, pirq,
1922a62c479SBernhard Beschow pci_bus_get_irq_level(pci_get_bus(&s->dev), pirq));
19314a026ddSPhilippe Mathieu-Daudé }
19414a026ddSPhilippe Mathieu-Daudé return 0;
19514a026ddSPhilippe Mathieu-Daudé }
19614a026ddSPhilippe Mathieu-Daudé
piix4_post_load(void * opaque,int version_id)19716971899SBernhard Beschow static int piix4_post_load(void *opaque, int version_id)
19816971899SBernhard Beschow {
1997d6f2659SBernhard Beschow PIIXState *s = opaque;
20016971899SBernhard Beschow
20116971899SBernhard Beschow if (version_id == 2) {
20216971899SBernhard Beschow s->rcr = 0;
20316971899SBernhard Beschow }
20416971899SBernhard Beschow
2050c9fd5a3SBernhard Beschow return piix_post_load(opaque, version_id);
20616971899SBernhard Beschow }
20716971899SBernhard Beschow
piix3_pre_save(void * opaque)20814a026ddSPhilippe Mathieu-Daudé static int piix3_pre_save(void *opaque)
20914a026ddSPhilippe Mathieu-Daudé {
21014a026ddSPhilippe Mathieu-Daudé int i;
2119769cfc3SBernhard Beschow PIIXState *piix3 = opaque;
21214a026ddSPhilippe Mathieu-Daudé
21314a026ddSPhilippe Mathieu-Daudé for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
21414a026ddSPhilippe Mathieu-Daudé piix3->pci_irq_levels_vmstate[i] =
21514a026ddSPhilippe Mathieu-Daudé pci_bus_get_irq_level(pci_get_bus(&piix3->dev), i);
21614a026ddSPhilippe Mathieu-Daudé }
21714a026ddSPhilippe Mathieu-Daudé
21814a026ddSPhilippe Mathieu-Daudé return 0;
21914a026ddSPhilippe Mathieu-Daudé }
22014a026ddSPhilippe Mathieu-Daudé
piix3_rcr_needed(void * opaque)22114a026ddSPhilippe Mathieu-Daudé static bool piix3_rcr_needed(void *opaque)
22214a026ddSPhilippe Mathieu-Daudé {
2239769cfc3SBernhard Beschow PIIXState *piix3 = opaque;
22414a026ddSPhilippe Mathieu-Daudé
22514a026ddSPhilippe Mathieu-Daudé return (piix3->rcr != 0);
22614a026ddSPhilippe Mathieu-Daudé }
22714a026ddSPhilippe Mathieu-Daudé
22814a026ddSPhilippe Mathieu-Daudé static const VMStateDescription vmstate_piix3_rcr = {
22914a026ddSPhilippe Mathieu-Daudé .name = "PIIX3/rcr",
23014a026ddSPhilippe Mathieu-Daudé .version_id = 1,
23114a026ddSPhilippe Mathieu-Daudé .minimum_version_id = 1,
23214a026ddSPhilippe Mathieu-Daudé .needed = piix3_rcr_needed,
233cbf19506SRichard Henderson .fields = (const VMStateField[]) {
2349769cfc3SBernhard Beschow VMSTATE_UINT8(rcr, PIIXState),
23514a026ddSPhilippe Mathieu-Daudé VMSTATE_END_OF_LIST()
23614a026ddSPhilippe Mathieu-Daudé }
23714a026ddSPhilippe Mathieu-Daudé };
23814a026ddSPhilippe Mathieu-Daudé
23914a026ddSPhilippe Mathieu-Daudé static const VMStateDescription vmstate_piix3 = {
24014a026ddSPhilippe Mathieu-Daudé .name = "PIIX3",
24114a026ddSPhilippe Mathieu-Daudé .version_id = 3,
24214a026ddSPhilippe Mathieu-Daudé .minimum_version_id = 2,
2432a62c479SBernhard Beschow .post_load = piix_post_load,
24414a026ddSPhilippe Mathieu-Daudé .pre_save = piix3_pre_save,
245cbf19506SRichard Henderson .fields = (const VMStateField[]) {
2469769cfc3SBernhard Beschow VMSTATE_PCI_DEVICE(dev, PIIXState),
2479769cfc3SBernhard Beschow VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIXState,
24814a026ddSPhilippe Mathieu-Daudé PIIX_NUM_PIRQS, 3),
24914a026ddSPhilippe Mathieu-Daudé VMSTATE_END_OF_LIST()
25014a026ddSPhilippe Mathieu-Daudé },
251cbf19506SRichard Henderson .subsections = (const VMStateDescription * const []) {
25214a026ddSPhilippe Mathieu-Daudé &vmstate_piix3_rcr,
25314a026ddSPhilippe Mathieu-Daudé NULL
25414a026ddSPhilippe Mathieu-Daudé }
25514a026ddSPhilippe Mathieu-Daudé };
25614a026ddSPhilippe Mathieu-Daudé
25716971899SBernhard Beschow static const VMStateDescription vmstate_piix4 = {
25816971899SBernhard Beschow .name = "PIIX4",
25916971899SBernhard Beschow .version_id = 3,
26016971899SBernhard Beschow .minimum_version_id = 2,
26116971899SBernhard Beschow .post_load = piix4_post_load,
262cbf19506SRichard Henderson .fields = (const VMStateField[]) {
2637d6f2659SBernhard Beschow VMSTATE_PCI_DEVICE(dev, PIIXState),
2647d6f2659SBernhard Beschow VMSTATE_UINT8_V(rcr, PIIXState, 3),
26516971899SBernhard Beschow VMSTATE_END_OF_LIST()
26616971899SBernhard Beschow }
26716971899SBernhard Beschow };
26814a026ddSPhilippe Mathieu-Daudé
rcr_write(void * opaque,hwaddr addr,uint64_t val,unsigned len)26914a026ddSPhilippe Mathieu-Daudé static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
27014a026ddSPhilippe Mathieu-Daudé {
2719769cfc3SBernhard Beschow PIIXState *d = opaque;
27214a026ddSPhilippe Mathieu-Daudé
27314a026ddSPhilippe Mathieu-Daudé if (val & 4) {
27414a026ddSPhilippe Mathieu-Daudé qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
27514a026ddSPhilippe Mathieu-Daudé return;
27614a026ddSPhilippe Mathieu-Daudé }
27714a026ddSPhilippe Mathieu-Daudé d->rcr = val & 2; /* keep System Reset type only */
27814a026ddSPhilippe Mathieu-Daudé }
27914a026ddSPhilippe Mathieu-Daudé
rcr_read(void * opaque,hwaddr addr,unsigned len)28014a026ddSPhilippe Mathieu-Daudé static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
28114a026ddSPhilippe Mathieu-Daudé {
2829769cfc3SBernhard Beschow PIIXState *d = opaque;
28314a026ddSPhilippe Mathieu-Daudé
28414a026ddSPhilippe Mathieu-Daudé return d->rcr;
28514a026ddSPhilippe Mathieu-Daudé }
28614a026ddSPhilippe Mathieu-Daudé
28714a026ddSPhilippe Mathieu-Daudé static const MemoryRegionOps rcr_ops = {
28814a026ddSPhilippe Mathieu-Daudé .read = rcr_read,
28914a026ddSPhilippe Mathieu-Daudé .write = rcr_write,
2903ee15e80SBernhard Beschow .endianness = DEVICE_LITTLE_ENDIAN,
2913ee15e80SBernhard Beschow .impl = {
2923ee15e80SBernhard Beschow .min_access_size = 1,
2933ee15e80SBernhard Beschow .max_access_size = 1,
2943ee15e80SBernhard Beschow },
29514a026ddSPhilippe Mathieu-Daudé };
29614a026ddSPhilippe Mathieu-Daudé
pci_piix_realize(PCIDevice * dev,const char * uhci_type,Error ** errp)2972922dbc2SBernhard Beschow static void pci_piix_realize(PCIDevice *dev, const char *uhci_type,
2982922dbc2SBernhard Beschow Error **errp)
29914a026ddSPhilippe Mathieu-Daudé {
3009769cfc3SBernhard Beschow PIIXState *d = PIIX_PCI_DEVICE(dev);
301e47e5a5bSBernhard Beschow PCIBus *pci_bus = pci_get_bus(dev);
302503a35e7SBernhard Beschow ISABus *isa_bus;
30356b1f50eSBernhard Beschow uint32_t irq;
30414a026ddSPhilippe Mathieu-Daudé
30557654b8eSBernhard Beschow isa_bus = isa_bus_new(DEVICE(d), pci_address_space(dev),
306503a35e7SBernhard Beschow pci_address_space_io(dev), errp);
307503a35e7SBernhard Beschow if (!isa_bus) {
30814a026ddSPhilippe Mathieu-Daudé return;
30914a026ddSPhilippe Mathieu-Daudé }
31014a026ddSPhilippe Mathieu-Daudé
31114a026ddSPhilippe Mathieu-Daudé memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d,
312f97479caSBernhard Beschow "piix-reset-control", 1);
31314a026ddSPhilippe Mathieu-Daudé memory_region_add_subregion_overlap(pci_address_space_io(dev),
31414a026ddSPhilippe Mathieu-Daudé PIIX_RCR_IOPORT, &d->rcr_mem, 1);
31514a026ddSPhilippe Mathieu-Daudé
3162d7630f5SBernhard Beschow /* PIC */
3172d7630f5SBernhard Beschow if (d->has_pic) {
3182d7630f5SBernhard Beschow qemu_irq *i8259_out_irq = qemu_allocate_irqs(piix_request_i8259_irq, d,
3192d7630f5SBernhard Beschow 1);
3202d7630f5SBernhard Beschow qemu_irq *i8259 = i8259_init(isa_bus, *i8259_out_irq);
3212d7630f5SBernhard Beschow size_t i;
3222d7630f5SBernhard Beschow
3232d7630f5SBernhard Beschow for (i = 0; i < ISA_NUM_IRQS; i++) {
3242d7630f5SBernhard Beschow d->isa_irqs_in[i] = i8259[i];
3252d7630f5SBernhard Beschow }
3262d7630f5SBernhard Beschow
3272d7630f5SBernhard Beschow g_free(i8259);
3282d7630f5SBernhard Beschow
3292d7630f5SBernhard Beschow qdev_init_gpio_out_named(DEVICE(dev), &d->cpu_intr, "intr", 1);
3302d7630f5SBernhard Beschow }
3312d7630f5SBernhard Beschow
33264127940SBernhard Beschow isa_bus_register_input_irqs(isa_bus, d->isa_irqs_in);
33364127940SBernhard Beschow
334ac433035SBernhard Beschow /* PIT */
335ac433035SBernhard Beschow if (d->has_pit) {
336ac433035SBernhard Beschow i8254_pit_init(isa_bus, 0x40, 0, NULL);
337ac433035SBernhard Beschow }
338ac433035SBernhard Beschow
3395e37bc49SPhilippe Mathieu-Daudé i8257_dma_init(OBJECT(dev), isa_bus, 0);
340f0bc6bf7SBernhard Beschow
341f0bc6bf7SBernhard Beschow /* RTC */
342f0bc6bf7SBernhard Beschow qdev_prop_set_int32(DEVICE(&d->rtc), "base_year", 2000);
343f0bc6bf7SBernhard Beschow if (!qdev_realize(DEVICE(&d->rtc), BUS(isa_bus), errp)) {
344f0bc6bf7SBernhard Beschow return;
345f0bc6bf7SBernhard Beschow }
34656b1f50eSBernhard Beschow irq = object_property_get_uint(OBJECT(&d->rtc), "irq", &error_fatal);
34756b1f50eSBernhard Beschow isa_connect_gpio_out(ISA_DEVICE(&d->rtc), 0, irq);
348e47e5a5bSBernhard Beschow
349e47e5a5bSBernhard Beschow /* IDE */
350e47e5a5bSBernhard Beschow qdev_prop_set_int32(DEVICE(&d->ide), "addr", dev->devfn + 1);
351e47e5a5bSBernhard Beschow if (!qdev_realize(DEVICE(&d->ide), BUS(pci_bus), errp)) {
352e47e5a5bSBernhard Beschow return;
353e47e5a5bSBernhard Beschow }
3546fe4464cSBernhard Beschow
3556fe4464cSBernhard Beschow /* USB */
3566fe4464cSBernhard Beschow if (d->has_usb) {
3572922dbc2SBernhard Beschow object_initialize_child(OBJECT(dev), "uhci", &d->uhci, uhci_type);
3586fe4464cSBernhard Beschow qdev_prop_set_int32(DEVICE(&d->uhci), "addr", dev->devfn + 2);
3596fe4464cSBernhard Beschow if (!qdev_realize(DEVICE(&d->uhci), BUS(pci_bus), errp)) {
3606fe4464cSBernhard Beschow return;
3616fe4464cSBernhard Beschow }
3626fe4464cSBernhard Beschow }
3630a15cf08SBernhard Beschow
3640a15cf08SBernhard Beschow /* Power Management */
3650a15cf08SBernhard Beschow if (d->has_acpi) {
3660a15cf08SBernhard Beschow object_initialize_child(OBJECT(d), "pm", &d->pm, TYPE_PIIX4_PM);
3670a15cf08SBernhard Beschow qdev_prop_set_int32(DEVICE(&d->pm), "addr", dev->devfn + 3);
3680a15cf08SBernhard Beschow qdev_prop_set_uint32(DEVICE(&d->pm), "smb_io_base", d->smb_io_base);
3690a15cf08SBernhard Beschow qdev_prop_set_bit(DEVICE(&d->pm), "smm-enabled", d->smm_enabled);
3700a15cf08SBernhard Beschow if (!qdev_realize(DEVICE(&d->pm), BUS(pci_bus), errp)) {
3710a15cf08SBernhard Beschow return;
3720a15cf08SBernhard Beschow }
3730a15cf08SBernhard Beschow qdev_connect_gpio_out(DEVICE(&d->pm), 0, d->isa_irqs_in[9]);
3740a15cf08SBernhard Beschow }
375a203cc53SBernhard Beschow
376a203cc53SBernhard Beschow pci_bus_irqs(pci_bus, piix_set_pci_irq, d, PIIX_NUM_PIRQS);
37712cecd45SBernhard Beschow pci_bus_set_route_irq_fn(pci_bus, piix_route_intx_pin_to_irq);
37814a026ddSPhilippe Mathieu-Daudé }
37914a026ddSPhilippe Mathieu-Daudé
build_pci_isa_aml(AcpiDevAmlIf * adev,Aml * scope)38092ea7fb3SIgor Mammedov static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
38192ea7fb3SIgor Mammedov {
38247a373faSIgor Mammedov Aml *field;
3834fd75ce0SIgor Mammedov Aml *sb_scope = aml_scope("\\_SB");
38492ea7fb3SIgor Mammedov BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0");
38592ea7fb3SIgor Mammedov
38692ea7fb3SIgor Mammedov /* PIIX PCI to ISA irq remapping */
38792ea7fb3SIgor Mammedov aml_append(scope, aml_operation_region("P40C", AML_PCI_CONFIG,
38892ea7fb3SIgor Mammedov aml_int(0x60), 0x04));
38947a373faSIgor Mammedov /* Fields declarion has to happen *after* operation region */
3904fd75ce0SIgor Mammedov field = aml_field("PCI0.S08.P40C", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
39147a373faSIgor Mammedov aml_append(field, aml_named_field("PRQ0", 8));
39247a373faSIgor Mammedov aml_append(field, aml_named_field("PRQ1", 8));
39347a373faSIgor Mammedov aml_append(field, aml_named_field("PRQ2", 8));
39447a373faSIgor Mammedov aml_append(field, aml_named_field("PRQ3", 8));
3954fd75ce0SIgor Mammedov aml_append(sb_scope, field);
3964fd75ce0SIgor Mammedov aml_append(scope, sb_scope);
39747a373faSIgor Mammedov
3989c6c0aeaSBernhard Beschow qbus_build_aml(bus, scope);
39992ea7fb3SIgor Mammedov }
40092ea7fb3SIgor Mammedov
pci_piix_init(Object * obj)4017d6f2659SBernhard Beschow static void pci_piix_init(Object *obj)
402f0bc6bf7SBernhard Beschow {
4039769cfc3SBernhard Beschow PIIXState *d = PIIX_PCI_DEVICE(obj);
404f0bc6bf7SBernhard Beschow
40540f70623SBernhard Beschow qdev_init_gpio_out_named(DEVICE(obj), d->isa_irqs_in, "isa-irqs",
40640f70623SBernhard Beschow ISA_NUM_IRQS);
407001cb25fSBernhard Beschow
408f0bc6bf7SBernhard Beschow object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC);
409f0bc6bf7SBernhard Beschow }
410f0bc6bf7SBernhard Beschow
4117f68219cSRichard Henderson static const Property pci_piix_props[] = {
4129769cfc3SBernhard Beschow DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0),
4139769cfc3SBernhard Beschow DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true),
4142d7630f5SBernhard Beschow DEFINE_PROP_BOOL("has-pic", PIIXState, has_pic, true),
415ac433035SBernhard Beschow DEFINE_PROP_BOOL("has-pit", PIIXState, has_pit, true),
4169769cfc3SBernhard Beschow DEFINE_PROP_BOOL("has-usb", PIIXState, has_usb, true),
4179769cfc3SBernhard Beschow DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false),
4186fe4464cSBernhard Beschow };
4196fe4464cSBernhard Beschow
pci_piix_class_init(ObjectClass * klass,const void * data)42012d1a768SPhilippe Mathieu-Daudé static void pci_piix_class_init(ObjectClass *klass, const void *data)
42114a026ddSPhilippe Mathieu-Daudé {
42214a026ddSPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass);
42314a026ddSPhilippe Mathieu-Daudé PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
42492ea7fb3SIgor Mammedov AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
42514a026ddSPhilippe Mathieu-Daudé
4260c9fd5a3SBernhard Beschow k->config_write = piix_write_config;
427e3d08143SPeter Maydell device_class_set_legacy_reset(dc, piix_reset);
42814a026ddSPhilippe Mathieu-Daudé dc->desc = "ISA bridge";
42914a026ddSPhilippe Mathieu-Daudé dc->hotpluggable = false;
43014a026ddSPhilippe Mathieu-Daudé k->vendor_id = PCI_VENDOR_ID_INTEL;
43114a026ddSPhilippe Mathieu-Daudé k->class_id = PCI_CLASS_BRIDGE_ISA;
43214a026ddSPhilippe Mathieu-Daudé /*
4337d6f2659SBernhard Beschow * Reason: part of PIIX southbridge, needs to be wired up by e.g.
43414a026ddSPhilippe Mathieu-Daudé * pc_piix.c's pc_init1()
43514a026ddSPhilippe Mathieu-Daudé */
43614a026ddSPhilippe Mathieu-Daudé dc->user_creatable = false;
4372922dbc2SBernhard Beschow device_class_set_props(dc, pci_piix_props);
43892ea7fb3SIgor Mammedov adevc->build_dev_aml = build_pci_isa_aml;
43914a026ddSPhilippe Mathieu-Daudé }
44014a026ddSPhilippe Mathieu-Daudé
4419769cfc3SBernhard Beschow static const TypeInfo piix_pci_type_info = {
4429769cfc3SBernhard Beschow .name = TYPE_PIIX_PCI_DEVICE,
44314a026ddSPhilippe Mathieu-Daudé .parent = TYPE_PCI_DEVICE,
4449769cfc3SBernhard Beschow .instance_size = sizeof(PIIXState),
4457d6f2659SBernhard Beschow .instance_init = pci_piix_init,
44614a026ddSPhilippe Mathieu-Daudé .abstract = true,
4477d6f2659SBernhard Beschow .class_init = pci_piix_class_init,
448*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
44914a026ddSPhilippe Mathieu-Daudé { INTERFACE_CONVENTIONAL_PCI_DEVICE },
45092ea7fb3SIgor Mammedov { TYPE_ACPI_DEV_AML_IF },
45114a026ddSPhilippe Mathieu-Daudé { },
45214a026ddSPhilippe Mathieu-Daudé },
45314a026ddSPhilippe Mathieu-Daudé };
45414a026ddSPhilippe Mathieu-Daudé
piix3_realize(PCIDevice * dev,Error ** errp)455fe3055d2SBernhard Beschow static void piix3_realize(PCIDevice *dev, Error **errp)
456fe3055d2SBernhard Beschow {
4572922dbc2SBernhard Beschow pci_piix_realize(dev, TYPE_PIIX3_USB_UHCI, errp);
45805c049f1SBernhard Beschow }
459fe3055d2SBernhard Beschow
piix3_init(Object * obj)4607d6f2659SBernhard Beschow static void piix3_init(Object *obj)
4617d6f2659SBernhard Beschow {
4627d6f2659SBernhard Beschow PIIXState *d = PIIX_PCI_DEVICE(obj);
4637d6f2659SBernhard Beschow
4647d6f2659SBernhard Beschow object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE);
4657d6f2659SBernhard Beschow }
4667d6f2659SBernhard Beschow
piix3_class_init(ObjectClass * klass,const void * data)46712d1a768SPhilippe Mathieu-Daudé static void piix3_class_init(ObjectClass *klass, const void *data)
46814a026ddSPhilippe Mathieu-Daudé {
4697d6f2659SBernhard Beschow DeviceClass *dc = DEVICE_CLASS(klass);
47014a026ddSPhilippe Mathieu-Daudé PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
47114a026ddSPhilippe Mathieu-Daudé
472fe3055d2SBernhard Beschow k->realize = piix3_realize;
4737d6f2659SBernhard Beschow /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
4747d6f2659SBernhard Beschow k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
4757d6f2659SBernhard Beschow dc->vmsd = &vmstate_piix3;
47614a026ddSPhilippe Mathieu-Daudé }
47714a026ddSPhilippe Mathieu-Daudé
47814a026ddSPhilippe Mathieu-Daudé static const TypeInfo piix3_info = {
47914a026ddSPhilippe Mathieu-Daudé .name = TYPE_PIIX3_DEVICE,
4809769cfc3SBernhard Beschow .parent = TYPE_PIIX_PCI_DEVICE,
4817d6f2659SBernhard Beschow .instance_init = piix3_init,
48214a026ddSPhilippe Mathieu-Daudé .class_init = piix3_class_init,
48314a026ddSPhilippe Mathieu-Daudé };
48414a026ddSPhilippe Mathieu-Daudé
piix4_realize(PCIDevice * dev,Error ** errp)48516971899SBernhard Beschow static void piix4_realize(PCIDevice *dev, Error **errp)
48616971899SBernhard Beschow {
4872922dbc2SBernhard Beschow pci_piix_realize(dev, TYPE_PIIX4_USB_UHCI, errp);
48816971899SBernhard Beschow }
48916971899SBernhard Beschow
piix4_init(Object * obj)49016971899SBernhard Beschow static void piix4_init(Object *obj)
49116971899SBernhard Beschow {
4927d6f2659SBernhard Beschow PIIXState *s = PIIX_PCI_DEVICE(obj);
49316971899SBernhard Beschow
49416971899SBernhard Beschow object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE);
49516971899SBernhard Beschow }
49616971899SBernhard Beschow
piix4_class_init(ObjectClass * klass,const void * data)49712d1a768SPhilippe Mathieu-Daudé static void piix4_class_init(ObjectClass *klass, const void *data)
49816971899SBernhard Beschow {
49916971899SBernhard Beschow DeviceClass *dc = DEVICE_CLASS(klass);
50016971899SBernhard Beschow PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
50116971899SBernhard Beschow
50216971899SBernhard Beschow k->realize = piix4_realize;
50316971899SBernhard Beschow k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
50416971899SBernhard Beschow dc->vmsd = &vmstate_piix4;
50516971899SBernhard Beschow }
50616971899SBernhard Beschow
50716971899SBernhard Beschow static const TypeInfo piix4_info = {
50816971899SBernhard Beschow .name = TYPE_PIIX4_PCI_DEVICE,
5097d6f2659SBernhard Beschow .parent = TYPE_PIIX_PCI_DEVICE,
51016971899SBernhard Beschow .instance_init = piix4_init,
51116971899SBernhard Beschow .class_init = piix4_class_init,
51216971899SBernhard Beschow };
51316971899SBernhard Beschow
piix3_register_types(void)51414a026ddSPhilippe Mathieu-Daudé static void piix3_register_types(void)
51514a026ddSPhilippe Mathieu-Daudé {
5169769cfc3SBernhard Beschow type_register_static(&piix_pci_type_info);
51714a026ddSPhilippe Mathieu-Daudé type_register_static(&piix3_info);
51816971899SBernhard Beschow type_register_static(&piix4_info);
51914a026ddSPhilippe Mathieu-Daudé }
52014a026ddSPhilippe Mathieu-Daudé
52114a026ddSPhilippe Mathieu-Daudé type_init(piix3_register_types)
522