X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/dff7424dc09635c33b42193fbb40c90fc9a971f4..7acd80e82d9332dfdaedc60c91eb3ec5195738bb:/hw/audio/intel-hda.c diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index d41f82cec4..23a2cf6484 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -17,14 +17,17 @@ * along with this program; if not, see . */ +#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 */ @@ -49,31 +52,33 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size, 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) @@ -83,7 +88,7 @@ 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; } @@ -93,14 +98,14 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) 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); } @@ -186,7 +191,8 @@ struct IntelHDAState { /* properties */ uint32_t debug; - uint32_t msi; + OnOffAuto msi; + bool old_msi_addr; }; #define TYPE_INTEL_HDA_GENERIC "intel-hda-generic" @@ -213,10 +219,7 @@ static void intel_hda_reset(DeviceState *dev); 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) @@ -245,7 +248,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) /* update global status */ if (sts & d->int_ctl) { - sts |= (1 << 31); + sts |= (1U << 31); } d->int_sts = sts; @@ -253,16 +256,16 @@ 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); - if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) { + if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) { level = 1; } 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) { @@ -282,7 +285,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) 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; @@ -290,7 +293,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) 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); @@ -304,22 +307,22 @@ static void intel_hda_corb_run(IntelHDAState *d) 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; } @@ -328,21 +331,21 @@ static void intel_hda_corb_run(IntelHDAState *d) 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)); @@ -350,7 +353,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res } 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; } @@ -362,17 +365,17 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res 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; @@ -384,7 +387,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res 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; @@ -404,16 +407,10 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, 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; @@ -491,7 +488,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn 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); @@ -574,7 +571,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3 if (st->ctl & 0x01) { /* reset */ dprint(d, 1, "st #%d: reset\n", reg->stream); - st->ctl = 0; + st->ctl = SD_STS_FIFO_READY << 24; } if ((st->ctl & 0x02) != (old & 0x02)) { uint32_t stnr = (st->ctl >> 20) & 0x0f; @@ -829,6 +826,7 @@ static const struct IntelHDAReg regtab[] = { .wclear = 0x1c000000, \ .offset = offsetof(IntelHDAState, st[_i].ctl), \ .whandler = intel_hda_set_st_ctl, \ + .reset = SD_STS_FIFO_READY << 24 \ }, \ [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \ .stream = _i, \ @@ -1039,66 +1037,29 @@ static void intel_hda_regs_reset(IntelHDAState *d) /* --------------------------------------------------------------------- */ -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, }; @@ -1117,17 +1078,19 @@ static void intel_hda_reset(DeviceState *dev) /* 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)); @@ -1136,17 +1099,30 @@ static int intel_hda_init(PCIDevice *pci) /* 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, 0x50, 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) @@ -1154,7 +1130,6 @@ 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) @@ -1162,7 +1137,7 @@ 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]); @@ -1175,7 +1150,7 @@ static int intel_hda_post_load(void *opaque, int version) static const VMStateDescription vmstate_intel_hda_stream = { .name = "intel-hda-stream", .version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(ctl, IntelHDAStream), VMSTATE_UINT32(lpib, IntelHDAStream), VMSTATE_UINT32(cbl, IntelHDAStream), @@ -1191,7 +1166,7 @@ static const VMStateDescription vmstate_intel_hda = { .name = "intel-hda", .version_id = 1, .post_load = intel_hda_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(pci, IntelHDAState), /* registers */ @@ -1234,7 +1209,8 @@ static const VMStateDescription vmstate_intel_hda = { 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(), }; @@ -1243,7 +1219,7 @@ static void intel_hda_class_init(ObjectClass *klass, void *data) 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; @@ -1280,6 +1256,10 @@ static const TypeInfo intel_hda_info = { .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 = { @@ -1297,8 +1277,8 @@ static const TypeInfo intel_hda_info_ich9 = { 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;