#include "hw.h"
#include "pci.h"
+#include "msi.h"
#include "qemu-timer.h"
#include "audiodev.h"
#include "intel-hda.h"
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
- if (dev->cad > 15)
+ if (dev->cad >= 15) {
return -1;
+ }
bus->next_cad = dev->cad + 1;
return info->init(dev);
}
IntelHDAStream st[8];
/* state */
- int mmio_addr;
+ MemoryRegion mmio;
uint32_t rirb_count;
int64_t wall_base_ns;
/* properties */
uint32_t debug;
+ uint32_t msi;
};
struct IntelHDAReg {
return addr;
}
-static void stl_phys_le(target_phys_addr_t addr, uint32_t value)
-{
- uint32_t value_le = cpu_to_le32(value);
- cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le));
-}
-
-static uint32_t ldl_phys_le(target_phys_addr_t addr)
-{
- uint32_t value_le;
- cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le));
- return le32_to_cpu(value_le);
-}
-
static void intel_hda_update_int_sts(IntelHDAState *d)
{
uint32_t sts = 0;
static void intel_hda_update_irq(IntelHDAState *d)
{
+ int msi = d->msi && msi_enabled(&d->pci);
int level;
intel_hda_update_int_sts(d);
} else {
level = 0;
}
- dprint(d, 2, "%s: level %d\n", __FUNCTION__, level);
- qemu_set_irq(d->pci.irq[0], level);
+ dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
+ level, msi ? "msi" : "intx");
+ if (msi) {
+ if (level) {
+ msi_notify(&d->pci, 0);
+ }
+ } else {
+ qemu_set_irq(d->pci.irq[0], level);
+ }
}
static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
rp = (d->corb_rp + 1) & 0xff;
addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
- verb = ldl_phys_le(addr + 4*rp);
+ verb = ldl_le_phys(addr + 4*rp);
d->corb_rp = rp;
dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
ex = (solicited ? 0 : (1 << 4)) | dev->cad;
wp = (d->rirb_wp + 1) & 0xff;
addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
- stl_phys_le(addr + 8*wp, response);
- stl_phys_le(addr + 8*wp + 4, ex);
+ stl_le_phys(addr + 8*wp, response);
+ stl_le_phys(addr + 8*wp + 4, ex);
d->rirb_wp = wp;
dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
}
if (d->dp_lbase & 0x01) {
addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
- stl_phys_le(addr + 8*s, st->lpib);
+ stl_le_phys(addr + 8*s, st->lpib);
}
dprint(d, 3, "dma: --\n");
addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
st->bentries = st->lvi +1;
- qemu_free(st->bpl);
- st->bpl = qemu_malloc(sizeof(bpl) * st->bentries);
+ g_free(st->bpl);
+ st->bpl = g_malloc(sizeof(bpl) * st->bentries);
for (i = 0; i < st->bentries; i++, addr += 16) {
cpu_physical_memory_read(addr, buf, 16);
st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf);
}
}
+static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_update_irq(d);
+}
+
static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
{
intel_hda_update_irq(d);
[ ICH6_REG_WAKEEN ] = {
.name = "WAKEEN",
.size = 2,
- .wmask = 0x3fff,
+ .wmask = 0x7fff,
.offset = offsetof(IntelHDAState, wake_en),
+ .whandler = intel_hda_set_wake_en,
},
[ ICH6_REG_STATESTS ] = {
.name = "STATESTS",
.size = 2,
- .wmask = 0x3fff,
- .wclear = 0x3fff,
+ .wmask = 0x7fff,
+ .wclear = 0x7fff,
.offset = offsetof(IntelHDAState, state_sts),
.whandler = intel_hda_set_state_sts,
},
return intel_hda_reg_read(d, reg, 0xffffffff);
}
-static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
- intel_hda_mmio_readb,
- intel_hda_mmio_readw,
- intel_hda_mmio_readl,
-};
-
-static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
- intel_hda_mmio_writeb,
- intel_hda_mmio_writew,
- intel_hda_mmio_writel,
+static const MemoryRegionOps intel_hda_mmio_ops = {
+ .old_mmio = {
+ .read = {
+ intel_hda_mmio_readb,
+ intel_hda_mmio_readw,
+ intel_hda_mmio_readl,
+ },
+ .write = {
+ intel_hda_mmio_writeb,
+ intel_hda_mmio_writew,
+ intel_hda_mmio_writel,
+ },
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
-static void intel_hda_map(PCIDevice *pci, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
- cpu_register_physical_memory(addr, 0x4000, d->mmio_addr);
-}
-
/* --------------------------------------------------------------------- */
static void intel_hda_reset(DeviceState *dev)
HDACodecDevice *cdev;
intel_hda_regs_reset(d);
- d->wall_base_ns = qemu_get_clock(vm_clock);
+ d->wall_base_ns = qemu_get_clock_ns(vm_clock);
/* reset codecs */
QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
d->name = d->pci.qdev.info->name;
- pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(conf, 0x2668);
- pci_config_set_revision(conf, 1);
- pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO);
pci_config_set_interrupt_pin(conf, 1);
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
conf[0x40] = 0x01;
- d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
- intel_hda_mmio_write, d);
- pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
- intel_hda_map);
+ memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
+ "intel-hda", 0x4000);
+ pci_register_bar(&d->pci, 0, 0, &d->mmio);
+ if (d->msi) {
+ msi_init(&d->pci, 0x50, 1, true, false);
+ }
hda_codec_bus_init(&d->pci.qdev, &d->codecs,
intel_hda_response, intel_hda_xfer);
{
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
- cpu_unregister_io_memory(d->mmio_addr);
+ msi_uninit(&d->pci);
+ memory_region_destroy(&d->mmio);
return 0;
}
+static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
+ uint32_t val, int len)
+{
+ IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+ pci_default_write_config(pci, addr, val, len);
+ if (d->msi) {
+ msi_write_config(pci, addr, val, len);
+ }
+}
+
static int intel_hda_post_load(void *opaque, int version)
{
IntelHDAState* d = opaque;
.qdev.reset = intel_hda_reset,
.init = intel_hda_init,
.exit = intel_hda_exit,
+ .config_write = intel_hda_write_config,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = 0x2668,
+ .revision = 1,
+ .class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+ DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
DEFINE_PROP_END_OF_LIST(),
}
};