* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
#include "qemu/timer.h"
-#include "hw/audio/audio.h"
+#include "qemu/bitops.h"
+#include "hw/audio/soundhw.h"
#include "intel-hda.h"
#include "intel-hda-defs.h"
#include "sysemu/dma.h"
+#include "qapi/error.h"
/* --------------------------------------------------------------------- */
/* hda bus */
bus->xfer = xfer;
}
-static int hda_codec_dev_init(DeviceState *qdev)
+static void hda_codec_dev_realize(DeviceState *qdev, Error **errp)
{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
- HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ HDACodecBus *bus = HDA_BUS(qdev->parent_bus);
+ HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
if (dev->cad >= 15) {
- return -1;
+ error_setg(errp, "HDA audio codec address is full");
+ return;
}
bus->next_cad = dev->cad + 1;
- return cdc->init(dev);
+ if (cdc->init(dev) != 0) {
+ error_setg(errp, "HDA audio init failed");
+ }
}
-static int hda_codec_dev_exit(DeviceState *qdev)
+static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp)
{
- HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
if (cdc->exit) {
cdc->exit(dev);
}
- return 0;
}
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
- cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ cdev = HDA_CODEC_DEVICE(qdev);
if (cdev->cad == cad) {
return cdev;
}
void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
bus->response(dev, solicited, response);
}
bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
uint8_t *buf, uint32_t len)
{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
return bus->xfer(dev, stnr, output, buf, len);
}
/* properties */
uint32_t debug;
- uint32_t msi;
+ OnOffAuto msi;
bool old_msi_addr;
};
static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase)
{
- hwaddr addr;
-
- addr = ((uint64_t)ubase << 32) | lbase;
- return addr;
+ return ((uint64_t)ubase << 32) | lbase;
}
static void intel_hda_update_int_sts(IntelHDAState *d)
static void intel_hda_update_irq(IntelHDAState *d)
{
- int msi = d->msi && msi_enabled(&d->pci);
+ bool msi = msi_enabled(&d->pci);
int level;
intel_hda_update_int_sts(d);
} else {
level = 0;
}
- dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
+ dprint(d, 2, "%s: level %d [%s]\n", __func__,
level, msi ? "msi" : "intx");
if (msi) {
if (level) {
cad = (verb >> 28) & 0x0f;
if (verb & (1 << 27)) {
/* indirect node addressing, not specified in HDA 1.0 */
- dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
+ dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __func__);
return -1;
}
nid = (verb >> 20) & 0x7f;
codec = hda_codec_find(&d->codecs, cad);
if (codec == NULL) {
- dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
+ dprint(d, 1, "%s: addressed non-existing codec\n", __func__);
return -1;
}
cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
uint32_t rp, verb;
if (d->ics & ICH6_IRS_BUSY) {
- dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
+ dprint(d, 2, "%s: [icw] verb 0x%08x\n", __func__, d->icw);
intel_hda_send_command(d, d->icw);
return;
}
for (;;) {
if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
- dprint(d, 2, "%s: !run\n", __FUNCTION__);
+ dprint(d, 2, "%s: !run\n", __func__);
return;
}
if ((d->corb_rp & 0xff) == d->corb_wp) {
- dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
+ dprint(d, 2, "%s: corb ring empty\n", __func__);
return;
}
if (d->rirb_count == d->rirb_cnt) {
- dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
+ dprint(d, 2, "%s: rirb count reached\n", __func__);
return;
}
verb = ldl_le_pci_dma(&d->pci, addr + 4*rp);
d->corb_rp = rp;
- dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
+ dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __func__, rp, verb);
intel_hda_send_command(d, verb);
}
}
static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
hwaddr addr;
uint32_t wp, ex;
if (d->ics & ICH6_IRS_BUSY) {
dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
- __FUNCTION__, response, dev->cad);
+ __func__, response, dev->cad);
d->irr = response;
d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
}
if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
- dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
+ dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __func__);
return;
}
d->rirb_wp = wp;
dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
- __FUNCTION__, wp, response, ex);
+ __func__, wp, response, ex);
d->rirb_count++;
if (d->rirb_count == d->rirb_cnt) {
- dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
+ dprint(d, 2, "%s: rirb count reached (%d)\n", __func__, d->rirb_count);
if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
d->rirb_sts |= ICH6_RBSTS_IRQ;
intel_hda_update_irq(d);
}
} else if ((d->corb_rp & 0xff) == d->corb_wp) {
- dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
+ dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __func__,
d->rirb_count, d->rirb_cnt);
if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
d->rirb_sts |= ICH6_RBSTS_IRQ;
static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
uint8_t *buf, uint32_t len)
{
- HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
hwaddr addr;
uint32_t s, copy, left;
if (st->bpl == NULL) {
return false;
}
- if (st->ctl & (1 << 26)) {
- /*
- * Wait with the next DMA xfer until the guest
- * has acked the buffer completion interrupt
- */
- return false;
- }
left = len;
- while (left > 0) {
+ s = st->bentries;
+ while (left > 0 && s-- > 0) {
copy = left;
if (copy > st->bsize - st->lpib)
copy = st->bsize - st->lpib;
DeviceState *qdev = kid->child;
HDACodecDeviceClass *cdc;
- cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ cdev = HDA_CODEC_DEVICE(qdev);
cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
if (cdc->stream) {
cdc->stream(cdev, stream, running, output);
/* --------------------------------------------------------------------- */
-static void intel_hda_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- intel_hda_reg_write(d, reg, val, 0xff);
-}
-
-static void intel_hda_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- intel_hda_reg_write(d, reg, val, 0xffff);
-}
-
-static void intel_hda_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
+static void intel_hda_mmio_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
{
IntelHDAState *d = opaque;
const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
- intel_hda_reg_write(d, reg, val, 0xffffffff);
+ intel_hda_reg_write(d, reg, val, MAKE_64BIT_MASK(0, size * 8));
}
-static uint32_t intel_hda_mmio_readb(void *opaque, hwaddr addr)
+static uint64_t intel_hda_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
IntelHDAState *d = opaque;
const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
- return intel_hda_reg_read(d, reg, 0xff);
-}
-
-static uint32_t intel_hda_mmio_readw(void *opaque, hwaddr addr)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- return intel_hda_reg_read(d, reg, 0xffff);
-}
-
-static uint32_t intel_hda_mmio_readl(void *opaque, hwaddr addr)
-{
- IntelHDAState *d = opaque;
- const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
- return intel_hda_reg_read(d, reg, 0xffffffff);
+ return intel_hda_reg_read(d, reg, MAKE_64BIT_MASK(0, size * 8));
}
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,
- },
+ .read = intel_hda_mmio_read,
+ .write = intel_hda_mmio_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
},
.endianness = DEVICE_NATIVE_ENDIAN,
};
/* reset codecs */
QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
DeviceState *qdev = kid->child;
- cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ cdev = HDA_CODEC_DEVICE(qdev);
device_reset(DEVICE(cdev));
d->state_sts |= (1 << cdev->cad);
}
intel_hda_update_irq(d);
}
-static int intel_hda_init(PCIDevice *pci)
+static void intel_hda_realize(PCIDevice *pci, Error **errp)
{
IntelHDAState *d = INTEL_HDA(pci);
uint8_t *conf = d->pci.config;
+ Error *err = NULL;
+ int ret;
d->name = object_get_typename(OBJECT(d));
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
conf[0x40] = 0x01;
+ if (d->msi != ON_OFF_AUTO_OFF) {
+ ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60,
+ 1, true, false, &err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && d->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return;
+ }
+ assert(!err || d->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(err);
+ }
+
memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
"intel-hda", 0x4000);
pci_register_bar(&d->pci, 0, 0, &d->mmio);
- if (d->msi) {
- msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false);
- }
hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
intel_hda_response, intel_hda_xfer);
-
- return 0;
}
static void intel_hda_exit(PCIDevice *pci)
IntelHDAState *d = INTEL_HDA(pci);
msi_uninit(&d->pci);
- memory_region_destroy(&d->mmio);
}
static int intel_hda_post_load(void *opaque, int version)
IntelHDAState* d = opaque;
int i;
- dprint(d, 1, "%s\n", __FUNCTION__);
+ dprint(d, 1, "%s\n", __func__);
for (i = 0; i < ARRAY_SIZE(d->st); i++) {
if (d->st[i].ctl & 0x02) {
intel_hda_parse_bdl(d, &d->st[i]);
static Property intel_hda_properties[] = {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
- DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+ DEFINE_PROP_ON_OFF_AUTO("msi", IntelHDAState, msi, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
DEFINE_PROP_END_OF_LIST(),
};
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = intel_hda_init;
+ k->realize = intel_hda_realize;
k->exit = intel_hda_exit;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
.instance_size = sizeof(IntelHDAState),
.class_init = intel_hda_class_init,
.abstract = true,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
};
static const TypeInfo intel_hda_info_ich6 = {
static void hda_codec_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
- k->init = hda_codec_dev_init;
- k->exit = hda_codec_dev_exit;
+ k->realize = hda_codec_dev_realize;
+ k->unrealize = hda_codec_dev_unrealize;
set_bit(DEVICE_CATEGORY_SOUND, k->categories);
k->bus_type = TYPE_HDA_BUS;
k->props = hda_props;