qemu

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

grlib_irqmp.c (9285B)


      1 /*
      2  * QEMU GRLIB IRQMP Emulator
      3  *
      4  * (Multiprocessor and extended interrupt not supported)
      5  *
      6  * Copyright (c) 2010-2019 AdaCore
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a copy
      9  * of this software and associated documentation files (the "Software"), to deal
     10  * in the Software without restriction, including without limitation the rights
     11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12  * copies of the Software, and to permit persons to whom the Software is
     13  * furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included in
     16  * all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     24  * THE SOFTWARE.
     25  */
     26 
     27 #include "qemu/osdep.h"
     28 #include "hw/irq.h"
     29 #include "hw/sysbus.h"
     30 
     31 #include "hw/qdev-properties.h"
     32 #include "hw/sparc/grlib.h"
     33 
     34 #include "trace.h"
     35 #include "qapi/error.h"
     36 #include "qemu/module.h"
     37 #include "qom/object.h"
     38 
     39 #define IRQMP_MAX_CPU 16
     40 #define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
     41 
     42 /* Memory mapped register offsets */
     43 #define LEVEL_OFFSET     0x00
     44 #define PENDING_OFFSET   0x04
     45 #define FORCE0_OFFSET    0x08
     46 #define CLEAR_OFFSET     0x0C
     47 #define MP_STATUS_OFFSET 0x10
     48 #define BROADCAST_OFFSET 0x14
     49 #define MASK_OFFSET      0x40
     50 #define FORCE_OFFSET     0x80
     51 #define EXTENDED_OFFSET  0xC0
     52 
     53 #define MAX_PILS 16
     54 
     55 OBJECT_DECLARE_SIMPLE_TYPE(IRQMP, GRLIB_IRQMP)
     56 
     57 typedef struct IRQMPState IRQMPState;
     58 
     59 struct IRQMP {
     60     SysBusDevice parent_obj;
     61 
     62     MemoryRegion iomem;
     63 
     64     IRQMPState *state;
     65     qemu_irq irq;
     66 };
     67 
     68 struct IRQMPState {
     69     uint32_t level;
     70     uint32_t pending;
     71     uint32_t clear;
     72     uint32_t broadcast;
     73 
     74     uint32_t mask[IRQMP_MAX_CPU];
     75     uint32_t force[IRQMP_MAX_CPU];
     76     uint32_t extended[IRQMP_MAX_CPU];
     77 
     78     IRQMP    *parent;
     79 };
     80 
     81 static void grlib_irqmp_check_irqs(IRQMPState *state)
     82 {
     83     uint32_t      pend   = 0;
     84     uint32_t      level0 = 0;
     85     uint32_t      level1 = 0;
     86 
     87     assert(state != NULL);
     88     assert(state->parent != NULL);
     89 
     90     /* IRQ for CPU 0 (no SMP support) */
     91     pend = (state->pending | state->force[0])
     92         & state->mask[0];
     93 
     94     level0 = pend & ~state->level;
     95     level1 = pend &  state->level;
     96 
     97     trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
     98                                  state->mask[0], level1, level0);
     99 
    100     /* Trigger level1 interrupt first and level0 if there is no level1 */
    101     qemu_set_irq(state->parent->irq, level1 ?: level0);
    102 }
    103 
    104 static void grlib_irqmp_ack_mask(IRQMPState *state, uint32_t mask)
    105 {
    106     /* Clear registers */
    107     state->pending  &= ~mask;
    108     state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
    109 
    110     grlib_irqmp_check_irqs(state);
    111 }
    112 
    113 void grlib_irqmp_ack(DeviceState *dev, int intno)
    114 {
    115     IRQMP        *irqmp = GRLIB_IRQMP(dev);
    116     IRQMPState   *state;
    117     uint32_t      mask;
    118 
    119     state = irqmp->state;
    120     assert(state != NULL);
    121 
    122     intno &= 15;
    123     mask = 1 << intno;
    124 
    125     trace_grlib_irqmp_ack(intno);
    126 
    127     grlib_irqmp_ack_mask(state, mask);
    128 }
    129 
    130 static void grlib_irqmp_set_irq(void *opaque, int irq, int level)
    131 {
    132     IRQMP      *irqmp = GRLIB_IRQMP(opaque);
    133     IRQMPState *s;
    134     int         i = 0;
    135 
    136     s = irqmp->state;
    137     assert(s         != NULL);
    138     assert(s->parent != NULL);
    139 
    140 
    141     if (level) {
    142         trace_grlib_irqmp_set_irq(irq);
    143 
    144         if (s->broadcast & 1 << irq) {
    145             /* Broadcasted IRQ */
    146             for (i = 0; i < IRQMP_MAX_CPU; i++) {
    147                 s->force[i] |= 1 << irq;
    148             }
    149         } else {
    150             s->pending |= 1 << irq;
    151         }
    152         grlib_irqmp_check_irqs(s);
    153 
    154     }
    155 }
    156 
    157 static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr,
    158                                  unsigned size)
    159 {
    160     IRQMP      *irqmp = opaque;
    161     IRQMPState *state;
    162 
    163     assert(irqmp != NULL);
    164     state = irqmp->state;
    165     assert(state != NULL);
    166 
    167     addr &= 0xff;
    168 
    169     /* global registers */
    170     switch (addr) {
    171     case LEVEL_OFFSET:
    172         return state->level;
    173 
    174     case PENDING_OFFSET:
    175         return state->pending;
    176 
    177     case FORCE0_OFFSET:
    178         /* This register is an "alias" for the force register of CPU 0 */
    179         return state->force[0];
    180 
    181     case CLEAR_OFFSET:
    182     case MP_STATUS_OFFSET:
    183         /* Always read as 0 */
    184         return 0;
    185 
    186     case BROADCAST_OFFSET:
    187         return state->broadcast;
    188 
    189     default:
    190         break;
    191     }
    192 
    193     /* mask registers */
    194     if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
    195         int cpu = (addr - MASK_OFFSET) / 4;
    196         assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
    197 
    198         return state->mask[cpu];
    199     }
    200 
    201     /* force registers */
    202     if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
    203         int cpu = (addr - FORCE_OFFSET) / 4;
    204         assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
    205 
    206         return state->force[cpu];
    207     }
    208 
    209     /* extended (not supported) */
    210     if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
    211         int cpu = (addr - EXTENDED_OFFSET) / 4;
    212         assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
    213 
    214         return state->extended[cpu];
    215     }
    216 
    217     trace_grlib_irqmp_readl_unknown(addr);
    218     return 0;
    219 }
    220 
    221 static void grlib_irqmp_write(void *opaque, hwaddr addr,
    222                               uint64_t value, unsigned size)
    223 {
    224     IRQMP      *irqmp = opaque;
    225     IRQMPState *state;
    226 
    227     assert(irqmp != NULL);
    228     state = irqmp->state;
    229     assert(state != NULL);
    230 
    231     addr &= 0xff;
    232 
    233     /* global registers */
    234     switch (addr) {
    235     case LEVEL_OFFSET:
    236         value &= 0xFFFF << 1; /* clean up the value */
    237         state->level = value;
    238         return;
    239 
    240     case PENDING_OFFSET:
    241         /* Read Only */
    242         return;
    243 
    244     case FORCE0_OFFSET:
    245         /* This register is an "alias" for the force register of CPU 0 */
    246 
    247         value &= 0xFFFE; /* clean up the value */
    248         state->force[0] = value;
    249         grlib_irqmp_check_irqs(irqmp->state);
    250         return;
    251 
    252     case CLEAR_OFFSET:
    253         value &= ~1; /* clean up the value */
    254         grlib_irqmp_ack_mask(state, value);
    255         return;
    256 
    257     case MP_STATUS_OFFSET:
    258         /* Read Only (no SMP support) */
    259         return;
    260 
    261     case BROADCAST_OFFSET:
    262         value &= 0xFFFE; /* clean up the value */
    263         state->broadcast = value;
    264         return;
    265 
    266     default:
    267         break;
    268     }
    269 
    270     /* mask registers */
    271     if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
    272         int cpu = (addr - MASK_OFFSET) / 4;
    273         assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
    274 
    275         value &= ~1; /* clean up the value */
    276         state->mask[cpu] = value;
    277         grlib_irqmp_check_irqs(irqmp->state);
    278         return;
    279     }
    280 
    281     /* force registers */
    282     if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
    283         int cpu = (addr - FORCE_OFFSET) / 4;
    284         assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
    285 
    286         uint32_t force = value & 0xFFFE;
    287         uint32_t clear = (value >> 16) & 0xFFFE;
    288         uint32_t old   = state->force[cpu];
    289 
    290         state->force[cpu] = (old | force) & ~clear;
    291         grlib_irqmp_check_irqs(irqmp->state);
    292         return;
    293     }
    294 
    295     /* extended (not supported) */
    296     if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
    297         int cpu = (addr - EXTENDED_OFFSET) / 4;
    298         assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
    299 
    300         value &= 0xF; /* clean up the value */
    301         state->extended[cpu] = value;
    302         return;
    303     }
    304 
    305     trace_grlib_irqmp_writel_unknown(addr, value);
    306 }
    307 
    308 static const MemoryRegionOps grlib_irqmp_ops = {
    309     .read = grlib_irqmp_read,
    310     .write = grlib_irqmp_write,
    311     .endianness = DEVICE_NATIVE_ENDIAN,
    312     .valid = {
    313         .min_access_size = 4,
    314         .max_access_size = 4,
    315     },
    316 };
    317 
    318 static void grlib_irqmp_reset(DeviceState *d)
    319 {
    320     IRQMP *irqmp = GRLIB_IRQMP(d);
    321     assert(irqmp->state != NULL);
    322 
    323     memset(irqmp->state, 0, sizeof *irqmp->state);
    324     irqmp->state->parent = irqmp;
    325 }
    326 
    327 static void grlib_irqmp_init(Object *obj)
    328 {
    329     IRQMP *irqmp = GRLIB_IRQMP(obj);
    330     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
    331 
    332     qdev_init_gpio_in(DEVICE(obj), grlib_irqmp_set_irq, MAX_PILS);
    333     qdev_init_gpio_out_named(DEVICE(obj), &irqmp->irq, "grlib-irq", 1);
    334     memory_region_init_io(&irqmp->iomem, obj, &grlib_irqmp_ops, irqmp,
    335                           "irqmp", IRQMP_REG_SIZE);
    336 
    337     irqmp->state = g_malloc0(sizeof *irqmp->state);
    338 
    339     sysbus_init_mmio(dev, &irqmp->iomem);
    340 }
    341 
    342 static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
    343 {
    344     DeviceClass *dc = DEVICE_CLASS(klass);
    345 
    346     dc->reset = grlib_irqmp_reset;
    347 }
    348 
    349 static const TypeInfo grlib_irqmp_info = {
    350     .name          = TYPE_GRLIB_IRQMP,
    351     .parent        = TYPE_SYS_BUS_DEVICE,
    352     .instance_size = sizeof(IRQMP),
    353     .instance_init = grlib_irqmp_init,
    354     .class_init    = grlib_irqmp_class_init,
    355 };
    356 
    357 static void grlib_irqmp_register_types(void)
    358 {
    359     type_register_static(&grlib_irqmp_info);
    360 }
    361 
    362 type_init(grlib_irqmp_register_types)