qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

loongarch_ipi.c (7316B)


      1 /* SPDX-License-Identifier: GPL-2.0-or-later */
      2 /*
      3  * LoongArch ipi interrupt support
      4  *
      5  * Copyright (C) 2021 Loongson Technology Corporation Limited
      6  */
      7 
      8 #include "qemu/osdep.h"
      9 #include "hw/sysbus.h"
     10 #include "hw/intc/loongarch_ipi.h"
     11 #include "hw/irq.h"
     12 #include "qapi/error.h"
     13 #include "qemu/log.h"
     14 #include "exec/address-spaces.h"
     15 #include "hw/loongarch/virt.h"
     16 #include "migration/vmstate.h"
     17 #include "target/loongarch/internals.h"
     18 #include "trace.h"
     19 
     20 static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
     21 {
     22     IPICore *s = opaque;
     23     uint64_t ret = 0;
     24     int index = 0;
     25 
     26     addr &= 0xff;
     27     switch (addr) {
     28     case CORE_STATUS_OFF:
     29         ret = s->status;
     30         break;
     31     case CORE_EN_OFF:
     32         ret = s->en;
     33         break;
     34     case CORE_SET_OFF:
     35         ret = 0;
     36         break;
     37     case CORE_CLEAR_OFF:
     38         ret = 0;
     39         break;
     40     case CORE_BUF_20 ... CORE_BUF_38 + 4:
     41         index = (addr - CORE_BUF_20) >> 2;
     42         ret = s->buf[index];
     43         break;
     44     default:
     45         qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
     46         break;
     47     }
     48 
     49     trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
     50     return ret;
     51 }
     52 
     53 static void send_ipi_data(CPULoongArchState *env, target_ulong val, target_ulong addr)
     54 {
     55     int i, mask = 0, data = 0;
     56 
     57     /*
     58      * bit 27-30 is mask for byte writing,
     59      * if the mask is 0, we need not to do anything.
     60      */
     61     if ((val >> 27) & 0xf) {
     62         data = address_space_ldl(&env->address_space_iocsr, addr,
     63                                  MEMTXATTRS_UNSPECIFIED, NULL);
     64         for (i = 0; i < 4; i++) {
     65             /* get mask for byte writing */
     66             if (val & (0x1 << (27 + i))) {
     67                 mask |= 0xff << (i * 8);
     68             }
     69         }
     70     }
     71 
     72     data &= mask;
     73     data |= (val >> 32) & ~mask;
     74     address_space_stl(&env->address_space_iocsr, addr,
     75                       data, MEMTXATTRS_UNSPECIFIED, NULL);
     76 }
     77 
     78 static void ipi_send(uint64_t val)
     79 {
     80     int cpuid, data;
     81     CPULoongArchState *env;
     82     CPUState *cs;
     83     LoongArchCPU *cpu;
     84 
     85     cpuid = (val >> 16) & 0x3ff;
     86     /* IPI status vector */
     87     data = 1 << (val & 0x1f);
     88     cs = qemu_get_cpu(cpuid);
     89     cpu = LOONGARCH_CPU(cs);
     90     env = &cpu->env;
     91     address_space_stl(&env->address_space_iocsr, 0x1008,
     92                       data, MEMTXATTRS_UNSPECIFIED, NULL);
     93 
     94 }
     95 
     96 static void mail_send(uint64_t val)
     97 {
     98     int cpuid;
     99     hwaddr addr;
    100     CPULoongArchState *env;
    101     CPUState *cs;
    102     LoongArchCPU *cpu;
    103 
    104     cpuid = (val >> 16) & 0x3ff;
    105     addr = 0x1020 + (val & 0x1c);
    106     cs = qemu_get_cpu(cpuid);
    107     cpu = LOONGARCH_CPU(cs);
    108     env = &cpu->env;
    109     send_ipi_data(env, val, addr);
    110 }
    111 
    112 static void any_send(uint64_t val)
    113 {
    114     int cpuid;
    115     hwaddr addr;
    116     CPULoongArchState *env;
    117 
    118     cpuid = (val >> 16) & 0x3ff;
    119     addr = val & 0xffff;
    120     CPUState *cs = qemu_get_cpu(cpuid);
    121     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
    122     env = &cpu->env;
    123     send_ipi_data(env, val, addr);
    124 }
    125 
    126 static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
    127                                  unsigned size)
    128 {
    129     IPICore *s = opaque;
    130     int index = 0;
    131 
    132     addr &= 0xff;
    133     trace_loongarch_ipi_write(size, (uint64_t)addr, val);
    134     switch (addr) {
    135     case CORE_STATUS_OFF:
    136         qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
    137         break;
    138     case CORE_EN_OFF:
    139         s->en = val;
    140         break;
    141     case CORE_SET_OFF:
    142         s->status |= val;
    143         if (s->status != 0 && (s->status & s->en) != 0) {
    144             qemu_irq_raise(s->irq);
    145         }
    146         break;
    147     case CORE_CLEAR_OFF:
    148         s->status &= ~val;
    149         if (s->status == 0 && s->en != 0) {
    150             qemu_irq_lower(s->irq);
    151         }
    152         break;
    153     case CORE_BUF_20 ... CORE_BUF_38 + 4:
    154         index = (addr - CORE_BUF_20) >> 2;
    155         s->buf[index] = val;
    156         break;
    157     case IOCSR_IPI_SEND:
    158         ipi_send(val);
    159         break;
    160     default:
    161         qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
    162         break;
    163     }
    164 }
    165 
    166 static const MemoryRegionOps loongarch_ipi_ops = {
    167     .read = loongarch_ipi_readl,
    168     .write = loongarch_ipi_writel,
    169     .impl.min_access_size = 4,
    170     .impl.max_access_size = 4,
    171     .valid.min_access_size = 4,
    172     .valid.max_access_size = 8,
    173     .endianness = DEVICE_LITTLE_ENDIAN,
    174 };
    175 
    176 /* mail send and any send only support writeq */
    177 static void loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
    178                                  unsigned size)
    179 {
    180     addr &= 0xfff;
    181     switch (addr) {
    182     case MAIL_SEND_OFFSET:
    183         mail_send(val);
    184         break;
    185     case ANY_SEND_OFFSET:
    186         any_send(val);
    187         break;
    188     default:
    189        break;
    190     }
    191 }
    192 
    193 static const MemoryRegionOps loongarch_ipi64_ops = {
    194     .write = loongarch_ipi_writeq,
    195     .impl.min_access_size = 8,
    196     .impl.max_access_size = 8,
    197     .valid.min_access_size = 8,
    198     .valid.max_access_size = 8,
    199     .endianness = DEVICE_LITTLE_ENDIAN,
    200 };
    201 
    202 static void loongarch_ipi_init(Object *obj)
    203 {
    204     int cpu;
    205     LoongArchMachineState *lams;
    206     LoongArchIPI *s = LOONGARCH_IPI(obj);
    207     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    208     Object *machine = qdev_get_machine();
    209     ObjectClass *mc = object_get_class(machine);
    210     /* 'lams' should be initialized */
    211     if (!strcmp(MACHINE_CLASS(mc)->name, "none")) {
    212         return;
    213     }
    214     lams = LOONGARCH_MACHINE(machine);
    215     for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
    216         memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops,
    217                             &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x48);
    218         sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]);
    219 
    220         memory_region_init_io(&s->ipi64_iocsr_mem[cpu], obj, &loongarch_ipi64_ops,
    221                               &lams->ipi_core[cpu], "loongarch_ipi64_iocsr", 0x118);
    222         sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem[cpu]);
    223         qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1);
    224     }
    225 }
    226 
    227 static const VMStateDescription vmstate_ipi_core = {
    228     .name = "ipi-single",
    229     .version_id = 0,
    230     .minimum_version_id = 0,
    231     .fields = (VMStateField[]) {
    232         VMSTATE_UINT32(status, IPICore),
    233         VMSTATE_UINT32(en, IPICore),
    234         VMSTATE_UINT32(set, IPICore),
    235         VMSTATE_UINT32(clear, IPICore),
    236         VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2),
    237         VMSTATE_END_OF_LIST()
    238     }
    239 };
    240 
    241 static const VMStateDescription vmstate_loongarch_ipi = {
    242     .name = TYPE_LOONGARCH_IPI,
    243     .version_id = 0,
    244     .minimum_version_id = 0,
    245     .fields = (VMStateField[]) {
    246         VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState,
    247                              MAX_IPI_CORE_NUM, 0,
    248                              vmstate_ipi_core, IPICore),
    249         VMSTATE_END_OF_LIST()
    250     }
    251 };
    252 
    253 static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
    254 {
    255     DeviceClass *dc = DEVICE_CLASS(klass);
    256 
    257     dc->vmsd = &vmstate_loongarch_ipi;
    258 }
    259 
    260 static const TypeInfo loongarch_ipi_info = {
    261     .name          = TYPE_LOONGARCH_IPI,
    262     .parent        = TYPE_SYS_BUS_DEVICE,
    263     .instance_size = sizeof(LoongArchIPI),
    264     .instance_init = loongarch_ipi_init,
    265     .class_init    = loongarch_ipi_class_init,
    266 };
    267 
    268 static void loongarch_ipi_register_types(void)
    269 {
    270     type_register_static(&loongarch_ipi_info);
    271 }
    272 
    273 type_init(loongarch_ipi_register_types)