Commit ca2c72be18dd8104fa9108ecefcd562e85672360
1 parent
5e3cb534
qemu: pci hotplug GPE support (Marcelo Tosatti)
Enable the corresponding bit on the PCIST region and trigger the SCI and handle the _EJ0 notifications. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6608 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
95 additions
and
0 deletions
hw/acpi.c
@@ -563,13 +563,21 @@ void qemu_system_powerdown(void) | @@ -563,13 +563,21 @@ void qemu_system_powerdown(void) | ||
563 | #endif | 563 | #endif |
564 | 564 | ||
565 | #define GPE_BASE 0xafe0 | 565 | #define GPE_BASE 0xafe0 |
566 | +#define PCI_BASE 0xae00 | ||
567 | +#define PCI_EJ_BASE 0xae08 | ||
566 | 568 | ||
567 | struct gpe_regs { | 569 | struct gpe_regs { |
568 | uint16_t sts; /* status */ | 570 | uint16_t sts; /* status */ |
569 | uint16_t en; /* enabled */ | 571 | uint16_t en; /* enabled */ |
570 | }; | 572 | }; |
571 | 573 | ||
574 | +struct pci_status { | ||
575 | + uint32_t up; | ||
576 | + uint32_t down; | ||
577 | +}; | ||
578 | + | ||
572 | static struct gpe_regs gpe; | 579 | static struct gpe_regs gpe; |
580 | +static struct pci_status pci0_status; | ||
573 | 581 | ||
574 | static uint32_t gpe_readb(void *opaque, uint32_t addr) | 582 | static uint32_t gpe_readb(void *opaque, uint32_t addr) |
575 | { | 583 | { |
@@ -623,9 +631,95 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) | @@ -623,9 +631,95 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) | ||
623 | #endif | 631 | #endif |
624 | } | 632 | } |
625 | 633 | ||
634 | +static uint32_t pcihotplug_read(void *opaque, uint32_t addr) | ||
635 | +{ | ||
636 | + uint32_t val = 0; | ||
637 | + struct pci_status *g = opaque; | ||
638 | + switch (addr) { | ||
639 | + case PCI_BASE: | ||
640 | + val = g->up; | ||
641 | + break; | ||
642 | + case PCI_BASE + 4: | ||
643 | + val = g->down; | ||
644 | + break; | ||
645 | + default: | ||
646 | + break; | ||
647 | + } | ||
648 | + | ||
649 | +#if defined(DEBUG) | ||
650 | + printf("pcihotplug read %lx == %lx\n", addr, val); | ||
651 | +#endif | ||
652 | + return val; | ||
653 | +} | ||
654 | + | ||
655 | +static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val) | ||
656 | +{ | ||
657 | + struct pci_status *g = opaque; | ||
658 | + switch (addr) { | ||
659 | + case PCI_BASE: | ||
660 | + g->up = val; | ||
661 | + break; | ||
662 | + case PCI_BASE + 4: | ||
663 | + g->down = val; | ||
664 | + break; | ||
665 | + } | ||
666 | + | ||
667 | +#if defined(DEBUG) | ||
668 | + printf("pcihotplug write %lx <== %d\n", addr, val); | ||
669 | +#endif | ||
670 | +} | ||
671 | + | ||
672 | +static uint32_t pciej_read(void *opaque, uint32_t addr) | ||
673 | +{ | ||
674 | +#if defined(DEBUG) | ||
675 | + printf("pciej read %lx == %lx\n", addr, val); | ||
676 | +#endif | ||
677 | + return 0; | ||
678 | +} | ||
679 | + | ||
680 | +static void pciej_write(void *opaque, uint32_t addr, uint32_t val) | ||
681 | +{ | ||
682 | + int slot = ffs(val) - 1; | ||
683 | + | ||
684 | +#if defined(DEBUG) | ||
685 | + printf("pciej write %lx <== %d\n", addr, val); | ||
686 | +#endif | ||
687 | +} | ||
688 | + | ||
626 | void qemu_system_hot_add_init(void) | 689 | void qemu_system_hot_add_init(void) |
627 | { | 690 | { |
628 | register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe); | 691 | register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe); |
629 | register_ioport_read(GPE_BASE, 4, 1, gpe_readb, &gpe); | 692 | register_ioport_read(GPE_BASE, 4, 1, gpe_readb, &gpe); |
630 | 693 | ||
694 | + register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status); | ||
695 | + register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, &pci0_status); | ||
696 | + | ||
697 | + register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, NULL); | ||
698 | + register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, NULL); | ||
699 | +} | ||
700 | + | ||
701 | +static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot) | ||
702 | +{ | ||
703 | + g->sts |= 2; | ||
704 | + g->en |= 2; | ||
705 | + p->up |= (1 << slot); | ||
706 | +} | ||
707 | + | ||
708 | +static void disable_device(struct pci_status *p, struct gpe_regs *g, int slot) | ||
709 | +{ | ||
710 | + g->sts |= 2; | ||
711 | + g->en |= 2; | ||
712 | + p->down |= (1 << slot); | ||
713 | +} | ||
714 | + | ||
715 | +void qemu_system_device_hot_add(int bus, int slot, int state) | ||
716 | +{ | ||
717 | + qemu_set_irq(pm_state->irq, 1); | ||
718 | + pci0_status.up = 0; | ||
719 | + pci0_status.down = 0; | ||
720 | + if (state) | ||
721 | + enable_device(&pci0_status, &gpe, slot); | ||
722 | + else | ||
723 | + disable_device(&pci0_status, &gpe, slot); | ||
724 | + qemu_set_irq(pm_state->irq, 0); | ||
631 | } | 725 | } |
sysemu.h
@@ -168,6 +168,7 @@ extern int drive_init(struct drive_opt *arg, int snapshot, void *machine); | @@ -168,6 +168,7 @@ extern int drive_init(struct drive_opt *arg, int snapshot, void *machine); | ||
168 | 168 | ||
169 | /* acpi */ | 169 | /* acpi */ |
170 | void qemu_system_hot_add_init(void); | 170 | void qemu_system_hot_add_init(void); |
171 | +void qemu_system_device_hot_add(int pcibus, int slot, int state); | ||
171 | 172 | ||
172 | /* serial ports */ | 173 | /* serial ports */ |
173 | 174 |