* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
+#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "hw/isa/i8259_internal.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "monitor/monitor.h"
+
+static int irq_level[16];
+static uint64_t irq_count[16];
void pic_reset_common(PICCommonState *s)
{
/* Note: ELCR is not reset */
}
-static void pic_dispatch_pre_save(void *opaque)
+static int pic_dispatch_pre_save(void *opaque)
{
PICCommonState *s = opaque;
PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
if (info->pre_save) {
info->pre_save(s);
}
+
+ return 0;
}
static int pic_dispatch_post_load(void *opaque, int version_id)
return 0;
}
-static int pic_init_common(ISADevice *dev)
+static void pic_common_realize(DeviceState *dev, Error **errp)
{
- PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
- PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+ PICCommonState *s = PIC_COMMON(dev);
+ ISADevice *isa = ISA_DEVICE(dev);
- info->init(s);
-
- isa_register_ioport(NULL, &s->base_io, s->iobase);
+ isa_register_ioport(isa, &s->base_io, s->iobase);
if (s->elcr_addr != -1) {
- isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+ isa_register_ioport(isa, &s->elcr_io, s->elcr_addr);
}
- qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
-
- return 0;
+ qdev_set_legacy_instance_id(dev, s->iobase, 1);
}
ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
{
- ISADevice *dev;
+ DeviceState *dev;
+ ISADevice *isadev;
+
+ isadev = isa_create(bus, name);
+ dev = DEVICE(isadev);
+ qdev_prop_set_uint32(dev, "iobase", master ? 0x20 : 0xa0);
+ qdev_prop_set_uint32(dev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+ qdev_prop_set_uint8(dev, "elcr_mask", master ? 0xf8 : 0xde);
+ qdev_prop_set_bit(dev, "master", master);
+ qdev_init_nofail(dev);
+
+ return isadev;
+}
+
+void pic_stat_update_irq(int irq, int level)
+{
+ if (level != irq_level[irq]) {
+ irq_level[irq] = level;
+ if (level == 1) {
+ irq_count[irq]++;
+ }
+ }
+}
- dev = isa_create(bus, name);
- qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
- qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
- qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
- qdev_prop_set_bit(&dev->qdev, "master", master);
- qdev_init_nofail(&dev->qdev);
+bool pic_get_statistics(InterruptStatsProvider *obj,
+ uint64_t **irq_counts, unsigned int *nb_irqs)
+{
+ PICCommonState *s = PIC_COMMON(obj);
+
+ if (s->master) {
+ *irq_counts = irq_count;
+ *nb_irqs = ARRAY_SIZE(irq_count);
+ } else {
+ *irq_counts = NULL;
+ *nb_irqs = 0;
+ }
+
+ return true;
+}
- return dev;
+void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
+{
+ PICCommonState *s = PIC_COMMON(obj);
+
+ pic_dispatch_pre_save(s);
+ monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
+ "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
+ s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
+ s->irq_base, s->read_reg_select, s->elcr,
+ s->special_fully_nested_mode);
}
static const VMStateDescription vmstate_pic_common = {
.name = "i8259",
.version_id = 1,
.minimum_version_id = 1,
- .minimum_version_id_old = 1,
.pre_save = pic_dispatch_pre_save,
.post_load = pic_dispatch_post_load,
.fields = (VMStateField[]) {
};
static Property pic_properties_common[] = {
- DEFINE_PROP_HEX32("iobase", PICCommonState, iobase, -1),
- DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr, -1),
- DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask, -1),
+ DEFINE_PROP_UINT32("iobase", PICCommonState, iobase, -1),
+ DEFINE_PROP_UINT32("elcr_addr", PICCommonState, elcr_addr, -1),
+ DEFINE_PROP_UINT8("elcr_mask", PICCommonState, elcr_mask, -1),
DEFINE_PROP_BIT("master", PICCommonState, master, 0, false),
DEFINE_PROP_END_OF_LIST(),
};
static void pic_common_class_init(ObjectClass *klass, void *data)
{
- ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
+ InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
dc->vmsd = &vmstate_pic_common;
- dc->no_user = 1;
dc->props = pic_properties_common;
- ic->init = pic_init_common;
+ dc->realize = pic_common_realize;
+ /*
+ * Reason: unlike ordinary ISA devices, the PICs need additional
+ * wiring: its IRQ input lines are set up by board code, and the
+ * wiring of the slave to the master is hard-coded in device model
+ * code.
+ */
+ dc->user_creatable = false;
+ ic->get_statistics = pic_get_statistics;
+ ic->print_info = pic_print_info;
}
static const TypeInfo pic_common_type = {
.class_size = sizeof(PICCommonClass),
.class_init = pic_common_class_init,
.abstract = true,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_INTERRUPT_STATS_PROVIDER },
+ { }
+ },
};
-static void register_types(void)
+static void pic_common_register_types(void)
{
type_register_static(&pic_common_type);
}
-type_init(register_types);
+type_init(pic_common_register_types)