1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * QEMU Loongson 7A1000 msi interrupt controller.
5 * Copyright (C) 2021 Loongson Technology Corporation Limited
8 #include "qemu/osdep.h"
11 #include "hw/intc/loongarch_pch_msi.h"
12 #include "hw/intc/loongarch_pch_pic.h"
13 #include "hw/pci/msi.h"
14 #include "hw/misc/unimp.h"
15 #include "migration/vmstate.h"
18 static uint64_t loongarch_msi_mem_read(void *opaque
, hwaddr addr
, unsigned size
)
23 static void loongarch_msi_mem_write(void *opaque
, hwaddr addr
,
24 uint64_t val
, unsigned size
)
26 LoongArchPCHMSI
*s
= (LoongArchPCHMSI
*)opaque
;
30 * vector number is irq number from upper extioi intc
31 * need subtract irq base to get msi vector offset
33 irq_num
= (val
& 0xff) - s
->irq_base
;
34 trace_loongarch_msi_set_irq(irq_num
);
35 assert(irq_num
< s
->irq_num
);
36 qemu_set_irq(s
->pch_msi_irq
[irq_num
], 1);
39 static const MemoryRegionOps loongarch_pch_msi_ops
= {
40 .read
= loongarch_msi_mem_read
,
41 .write
= loongarch_msi_mem_write
,
42 .endianness
= DEVICE_LITTLE_ENDIAN
,
45 static void pch_msi_irq_handler(void *opaque
, int irq
, int level
)
47 LoongArchPCHMSI
*s
= LOONGARCH_PCH_MSI(opaque
);
49 qemu_set_irq(s
->pch_msi_irq
[irq
], level
);
52 static void loongarch_pch_msi_realize(DeviceState
*dev
, Error
**errp
)
54 LoongArchPCHMSI
*s
= LOONGARCH_PCH_MSI(dev
);
56 if (!s
->irq_num
|| s
->irq_num
> PCH_MSI_IRQ_NUM
) {
57 error_setg(errp
, "Invalid 'msi_irq_num'");
61 s
->pch_msi_irq
= g_new(qemu_irq
, s
->irq_num
);
63 qdev_init_gpio_out(dev
, s
->pch_msi_irq
, s
->irq_num
);
64 qdev_init_gpio_in(dev
, pch_msi_irq_handler
, s
->irq_num
);
67 static void loongarch_pch_msi_unrealize(DeviceState
*dev
)
69 LoongArchPCHMSI
*s
= LOONGARCH_PCH_MSI(dev
);
71 g_free(s
->pch_msi_irq
);
74 static void loongarch_pch_msi_init(Object
*obj
)
76 LoongArchPCHMSI
*s
= LOONGARCH_PCH_MSI(obj
);
77 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
79 memory_region_init_io(&s
->msi_mmio
, obj
, &loongarch_pch_msi_ops
,
80 s
, TYPE_LOONGARCH_PCH_MSI
, 0x8);
81 sysbus_init_mmio(sbd
, &s
->msi_mmio
);
86 static Property loongarch_msi_properties
[] = {
87 DEFINE_PROP_UINT32("msi_irq_base", LoongArchPCHMSI
, irq_base
, 0),
88 DEFINE_PROP_UINT32("msi_irq_num", LoongArchPCHMSI
, irq_num
, 0),
89 DEFINE_PROP_END_OF_LIST(),
92 static void loongarch_pch_msi_class_init(ObjectClass
*klass
, void *data
)
94 DeviceClass
*dc
= DEVICE_CLASS(klass
);
96 dc
->realize
= loongarch_pch_msi_realize
;
97 dc
->unrealize
= loongarch_pch_msi_unrealize
;
98 device_class_set_props(dc
, loongarch_msi_properties
);
101 static const TypeInfo loongarch_pch_msi_info
= {
102 .name
= TYPE_LOONGARCH_PCH_MSI
,
103 .parent
= TYPE_SYS_BUS_DEVICE
,
104 .instance_size
= sizeof(LoongArchPCHMSI
),
105 .instance_init
= loongarch_pch_msi_init
,
106 .class_init
= loongarch_pch_msi_class_init
,
109 static void loongarch_pch_msi_register_types(void)
111 type_register_static(&loongarch_pch_msi_info
);
114 type_init(loongarch_pch_msi_register_types
)