Skip to content

Commit

Permalink
pci: Add PCI VGA helpers
Browse files Browse the repository at this point in the history
Allow devices to register VGA memory regions for handling PCI spec
defined VGA I/O port and MMIO areas.  PCI will attach these to the
bus address spaces and enable them according to the device command
register value.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
awilliam authored and mstsirkin committed Mar 26, 2013
1 parent a38b2c4 commit e01fd68
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
61 changes: 61 additions & 0 deletions hw/pci/pci.c
Expand Up @@ -875,6 +875,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
continue;
memory_region_del_subregion(r->address_space, r->memory);
}

pci_unregister_vga(pci_dev);
}

static int pci_unregister_device(DeviceState *dev)
Expand Down Expand Up @@ -937,6 +939,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
: pci_dev->bus->address_space_mem;
}

static void pci_update_vga(PCIDevice *pci_dev)
{
uint16_t cmd;

if (!pci_dev->has_vga) {
return;
}

cmd = pci_get_word(pci_dev->config + PCI_COMMAND);

memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_MEM],
cmd & PCI_COMMAND_MEMORY);
memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO],
cmd & PCI_COMMAND_IO);
memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI],
cmd & PCI_COMMAND_IO);
}

void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
MemoryRegion *io_lo, MemoryRegion *io_hi)
{
assert(!pci_dev->has_vga);

assert(memory_region_size(mem) == QEMU_PCI_VGA_MEM_SIZE);
pci_dev->vga_regions[QEMU_PCI_VGA_MEM] = mem;
memory_region_add_subregion_overlap(pci_dev->bus->address_space_mem,
QEMU_PCI_VGA_MEM_BASE, mem, 1);

assert(memory_region_size(io_lo) == QEMU_PCI_VGA_IO_LO_SIZE);
pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO] = io_lo;
memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
QEMU_PCI_VGA_IO_LO_BASE, io_lo, 1);

assert(memory_region_size(io_hi) == QEMU_PCI_VGA_IO_HI_SIZE);
pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI] = io_hi;
memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
QEMU_PCI_VGA_IO_HI_BASE, io_hi, 1);
pci_dev->has_vga = true;

pci_update_vga(pci_dev);
}

void pci_unregister_vga(PCIDevice *pci_dev)
{
if (!pci_dev->has_vga) {
return;
}

memory_region_del_subregion(pci_dev->bus->address_space_mem,
pci_dev->vga_regions[QEMU_PCI_VGA_MEM]);
memory_region_del_subregion(pci_dev->bus->address_space_io,
pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO]);
memory_region_del_subregion(pci_dev->bus->address_space_io,
pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI]);
pci_dev->has_vga = false;
}

pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
{
return pci_dev->io_regions[region_num].addr;
Expand Down Expand Up @@ -1036,6 +1095,8 @@ static void pci_update_mappings(PCIDevice *d)
r->addr, r->memory, 1);
}
}

pci_update_vga(d);
}

static inline int pci_irq_disabled(PCIDevice *d)
Expand Down
21 changes: 21 additions & 0 deletions hw/pci/pci.h
Expand Up @@ -108,6 +108,20 @@ typedef struct PCIIORegion {
#define PCI_ROM_SLOT 6
#define PCI_NUM_REGIONS 7

enum {
QEMU_PCI_VGA_MEM,
QEMU_PCI_VGA_IO_LO,
QEMU_PCI_VGA_IO_HI,
QEMU_PCI_VGA_NUM_REGIONS,
};

#define QEMU_PCI_VGA_MEM_BASE 0xa0000
#define QEMU_PCI_VGA_MEM_SIZE 0x20000
#define QEMU_PCI_VGA_IO_LO_BASE 0x3b0
#define QEMU_PCI_VGA_IO_LO_SIZE 0xc
#define QEMU_PCI_VGA_IO_HI_BASE 0x3c0
#define QEMU_PCI_VGA_IO_HI_SIZE 0x20

#include "hw/pci/pci_regs.h"

/* PCI HEADER_TYPE */
Expand Down Expand Up @@ -234,6 +248,10 @@ struct PCIDevice {
/* IRQ objects for the INTA-INTD pins. */
qemu_irq *irq;

/* Legacy PCI VGA regions */
MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
bool has_vga;

/* Current IRQ levels. Used internally by the generic PCI code. */
uint8_t irq_state;

Expand Down Expand Up @@ -287,6 +305,9 @@ struct PCIDevice {

void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory);
void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
MemoryRegion *io_lo, MemoryRegion *io_hi);
void pci_unregister_vga(PCIDevice *pci_dev);
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);

int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
Expand Down

0 comments on commit e01fd68

Please sign in to comment.