From 4c765449c7ac81a666f678c6e404ad4de4dd6630 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 24 Jun 2013 07:23:16 +0200 Subject: [PATCH 16/21] serial: add pci variant RH-Author: Gerd Hoffmann Message-id: <1372058597-15860-2-git-send-email-kraxel@redhat.com> Patchwork-id: 52175 O-Subject: [RHEL-6.5 qemu-kvm PATCH v2 1/2] serial: add pci variant Bugzilla: 872015 RH-Acked-by: Laszlo Ersek RH-Acked-by: Michal Novotny RH-Acked-by: Hans de Goede So we get a hot-pluggable 16550 uart. bugzilla: #872015 - A Windows VM can only see 2 of 4 assigned COM ports upstream: 419ad67208a37367932a5bf88d3860f85e06282c rhel6: * put the bits directly into serial.c instead of serial-pci.c * adapt to pre-memory-api and pre-qom qemu. Signed-off-by: Gerd Hoffmann --- hw/pci.h | 3 ++ hw/pci_ids.h | 1 + hw/serial.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) Signed-off-by: Miroslav Rezanina --- hw/pci.h | 3 ++ hw/pci_ids.h | 1 + hw/serial.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 0 deletions(-) diff --git a/hw/pci.h b/hw/pci.h index 6002492..7d06f40 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -78,6 +78,9 @@ extern target_phys_addr_t pci_mem_base; #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 +#define PCI_VENDOR_ID_REDHAT 0x1b36 +#define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 + typedef uint64_t pcibus_t; #define FMT_PCIBUS PRIx64 diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 62dc9c0..2eb976a 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -35,6 +35,7 @@ #define PCI_CLASS_BRIDGE_PCI 0x0604 #define PCI_CLASS_BRIDGE_OTHER 0x0680 +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 #define PCI_CLASS_COMMUNICATION_OTHER 0x0780 #define PCI_CLASS_PROCESSOR_CO 0x0b40 diff --git a/hw/serial.c b/hw/serial.c index 940bc01..9bdc4d3 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -25,6 +25,8 @@ #include "hw.h" #include "qemu-char.h" #include "isa.h" +#include "pci.h" +#include "pci_ids.h" #include "pc.h" #include "qemu-timer.h" #include "sysemu.h" @@ -736,6 +738,12 @@ static void serial_init_core(SerialState *s) serial_event, s); } +static void serial_exit_core(SerialState *s) +{ + qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); + qemu_unregister_reset(serial_reset, s); +} + /* Change the main reference oscillator frequency. */ void serial_set_frequency(SerialState *s, uint32_t frequency) { @@ -916,9 +924,88 @@ static ISADeviceInfo serial_isa_info = { }, }; +typedef struct PCISerialState { + PCIDevice dev; + pcibus_t addr; + SerialState state; +} PCISerialState; + +static void serial_pci_map(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, pci_dev); + SerialState *s = &pci->state; + + if (pci->addr) { + isa_unassign_ioport(pci->addr, 8); + pci->addr = 0; + } + register_ioport_write(addr, 8, 1, serial_ioport_write, s); + register_ioport_read(addr, 8, 1, serial_ioport_read, s); + pci->addr = addr; +} + +static int serial_pci_init(PCIDevice *dev) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); + SerialState *s = &pci->state; + + s->baudbase = 115200; + serial_init_core(s); + + pci_config_set_vendor_id(pci->dev.config, PCI_VENDOR_ID_REDHAT); + pci_config_set_device_id(pci->dev.config, PCI_DEVICE_ID_REDHAT_SERIAL); + pci_config_set_class(pci->dev.config, PCI_CLASS_COMMUNICATION_SERIAL); + pci->dev.config[PCI_REVISION_ID] = 0x01; + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + s->irq = pci->dev.irq[0]; + + pci_register_bar(&pci->dev, 0, 8, PCI_BASE_ADDRESS_SPACE_IO, serial_pci_map); + return 0; +} + +static int serial_pci_exit(PCIDevice *dev) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); + SerialState *s = &pci->state; + + if (pci->addr) { + isa_unassign_ioport(pci->addr, 8); + pci->addr = 0; + } + serial_exit_core(s); + return 0; +} + +static const VMStateDescription vmstate_pci_serial = { + .name = "pci-serial", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCISerialState), + VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static Property serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static PCIDeviceInfo serial_pci_info = { + .qdev.name = "pci-serial", + .qdev.size = sizeof(PCISerialState), + .qdev.vmsd = &vmstate_pci_serial, + .init = serial_pci_init, + .exit = serial_pci_exit, + .qdev.props = serial_pci_properties, +}; + static void serial_register_devices(void) { isa_qdev_register(&serial_isa_info); + pci_qdev_register(&serial_pci_info); } device_init(serial_register_devices) -- 1.7.1