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 |