qemu/hw/intc/slavio_intctl.c
<<
>>
Prefs
   1/*
   2 * QEMU Sparc SLAVIO interrupt controller emulation
   3 *
   4 * Copyright (c) 2003-2005 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "migration/vmstate.h"
  27#include "monitor/monitor.h"
  28#include "qemu/module.h"
  29#include "hw/sysbus.h"
  30#include "hw/intc/intc.h"
  31#include "hw/irq.h"
  32#include "trace.h"
  33#include "qom/object.h"
  34
  35//#define DEBUG_IRQ_COUNT
  36
  37/*
  38 * Registers of interrupt controller in sun4m.
  39 *
  40 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
  41 * produced as NCR89C105. See
  42 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
  43 *
  44 * There is a system master controller and one for each cpu.
  45 *
  46 */
  47
  48#define MAX_CPUS 16
  49#define MAX_PILS 16
  50
  51struct SLAVIO_INTCTLState;
  52
  53typedef struct SLAVIO_CPUINTCTLState {
  54    MemoryRegion iomem;
  55    struct SLAVIO_INTCTLState *master;
  56    uint32_t intreg_pending;
  57    uint32_t cpu;
  58    uint32_t irl_out;
  59} SLAVIO_CPUINTCTLState;
  60
  61#define TYPE_SLAVIO_INTCTL "slavio_intctl"
  62OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_INTCTLState, SLAVIO_INTCTL)
  63
  64struct SLAVIO_INTCTLState {
  65    SysBusDevice parent_obj;
  66
  67    MemoryRegion iomem;
  68#ifdef DEBUG_IRQ_COUNT
  69    uint64_t irq_count[32];
  70#endif
  71    qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
  72    SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
  73    uint32_t intregm_pending;
  74    uint32_t intregm_disabled;
  75    uint32_t target_cpu;
  76};
  77
  78#define INTCTL_MAXADDR 0xf
  79#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
  80#define INTCTLM_SIZE 0x14
  81#define MASTER_IRQ_MASK ~0x0fa2007f
  82#define MASTER_DISABLE 0x80000000
  83#define CPU_SOFTIRQ_MASK 0xfffe0000
  84#define CPU_IRQ_INT15_IN (1 << 15)
  85#define CPU_IRQ_TIMER_IN (1 << 14)
  86
  87static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
  88
  89// per-cpu interrupt controller
  90static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
  91                                        unsigned size)
  92{
  93    SLAVIO_CPUINTCTLState *s = opaque;
  94    uint32_t saddr, ret;
  95
  96    saddr = addr >> 2;
  97    switch (saddr) {
  98    case 0:
  99        ret = s->intreg_pending;
 100        break;
 101    default:
 102        ret = 0;
 103        break;
 104    }
 105    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
 106
 107    return ret;
 108}
 109
 110static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
 111                                     uint64_t val, unsigned size)
 112{
 113    SLAVIO_CPUINTCTLState *s = opaque;
 114    uint32_t saddr;
 115
 116    saddr = addr >> 2;
 117    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
 118    switch (saddr) {
 119    case 1: // clear pending softints
 120        val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
 121        s->intreg_pending &= ~val;
 122        slavio_check_interrupts(s->master, 1);
 123        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
 124        break;
 125    case 2: // set softint
 126        val &= CPU_SOFTIRQ_MASK;
 127        s->intreg_pending |= val;
 128        slavio_check_interrupts(s->master, 1);
 129        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
 130        break;
 131    default:
 132        break;
 133    }
 134}
 135
 136static const MemoryRegionOps slavio_intctl_mem_ops = {
 137    .read = slavio_intctl_mem_readl,
 138    .write = slavio_intctl_mem_writel,
 139    .endianness = DEVICE_NATIVE_ENDIAN,
 140    .valid = {
 141        .min_access_size = 4,
 142        .max_access_size = 4,
 143    },
 144};
 145
 146// master system interrupt controller
 147static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
 148                                         unsigned size)
 149{
 150    SLAVIO_INTCTLState *s = opaque;
 151    uint32_t saddr, ret;
 152
 153    saddr = addr >> 2;
 154    switch (saddr) {
 155    case 0:
 156        ret = s->intregm_pending & ~MASTER_DISABLE;
 157        break;
 158    case 1:
 159        ret = s->intregm_disabled & MASTER_IRQ_MASK;
 160        break;
 161    case 4:
 162        ret = s->target_cpu;
 163        break;
 164    default:
 165        ret = 0;
 166        break;
 167    }
 168    trace_slavio_intctlm_mem_readl(addr, ret);
 169
 170    return ret;
 171}
 172
 173static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
 174                                      uint64_t val, unsigned size)
 175{
 176    SLAVIO_INTCTLState *s = opaque;
 177    uint32_t saddr;
 178
 179    saddr = addr >> 2;
 180    trace_slavio_intctlm_mem_writel(addr, val);
 181    switch (saddr) {
 182    case 2: // clear (enable)
 183        // Force clear unused bits
 184        val &= MASTER_IRQ_MASK;
 185        s->intregm_disabled &= ~val;
 186        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
 187        slavio_check_interrupts(s, 1);
 188        break;
 189    case 3: // set (disable; doesn't affect pending)
 190        // Force clear unused bits
 191        val &= MASTER_IRQ_MASK;
 192        s->intregm_disabled |= val;
 193        slavio_check_interrupts(s, 1);
 194        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
 195        break;
 196    case 4:
 197        s->target_cpu = val & (MAX_CPUS - 1);
 198        slavio_check_interrupts(s, 1);
 199        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
 200        break;
 201    default:
 202        break;
 203    }
 204}
 205
 206static const MemoryRegionOps slavio_intctlm_mem_ops = {
 207    .read = slavio_intctlm_mem_readl,
 208    .write = slavio_intctlm_mem_writel,
 209    .endianness = DEVICE_NATIVE_ENDIAN,
 210    .valid = {
 211        .min_access_size = 4,
 212        .max_access_size = 4,
 213    },
 214};
 215
 216static const uint32_t intbit_to_level[] = {
 217    2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
 218    6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
 219};
 220
 221static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
 222{
 223    uint32_t pending = s->intregm_pending, pil_pending;
 224    unsigned int i, j;
 225
 226    pending &= ~s->intregm_disabled;
 227
 228    trace_slavio_check_interrupts(pending, s->intregm_disabled);
 229    for (i = 0; i < MAX_CPUS; i++) {
 230        pil_pending = 0;
 231
 232        /* If we are the current interrupt target, get hard interrupts */
 233        if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
 234            (i == s->target_cpu)) {
 235            for (j = 0; j < 32; j++) {
 236                if ((pending & (1 << j)) && intbit_to_level[j]) {
 237                    pil_pending |= 1 << intbit_to_level[j];
 238                }
 239            }
 240        }
 241
 242        /* Calculate current pending hard interrupts for display */
 243        s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
 244            CPU_IRQ_TIMER_IN;
 245        if (i == s->target_cpu) {
 246            for (j = 0; j < 32; j++) {
 247                if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
 248                    s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
 249                }
 250            }
 251        }
 252
 253        /* Level 15 and CPU timer interrupts are only masked when
 254           the MASTER_DISABLE bit is set */
 255        if (!(s->intregm_disabled & MASTER_DISABLE)) {
 256            pil_pending |= s->slaves[i].intreg_pending &
 257                (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
 258        }
 259
 260        /* Add soft interrupts */
 261        pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
 262
 263        if (set_irqs) {
 264            /* Since there is not really an interrupt 0 (and pil_pending
 265             * and irl_out bit zero are thus always zero) there is no need
 266             * to do anything with cpu_irqs[i][0] and it is OK not to do
 267             * the j=0 iteration of this loop.
 268             */
 269            for (j = MAX_PILS-1; j > 0; j--) {
 270                if (pil_pending & (1 << j)) {
 271                    if (!(s->slaves[i].irl_out & (1 << j))) {
 272                        qemu_irq_raise(s->cpu_irqs[i][j]);
 273                    }
 274                } else {
 275                    if (s->slaves[i].irl_out & (1 << j)) {
 276                        qemu_irq_lower(s->cpu_irqs[i][j]);
 277                    }
 278                }
 279            }
 280        }
 281        s->slaves[i].irl_out = pil_pending;
 282    }
 283}
 284
 285/*
 286 * "irq" here is the bit number in the system interrupt register to
 287 * separate serial and keyboard interrupts sharing a level.
 288 */
 289static void slavio_set_irq(void *opaque, int irq, int level)
 290{
 291    SLAVIO_INTCTLState *s = opaque;
 292    uint32_t mask = 1 << irq;
 293    uint32_t pil = intbit_to_level[irq];
 294    unsigned int i;
 295
 296    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
 297    if (pil > 0) {
 298        if (level) {
 299#ifdef DEBUG_IRQ_COUNT
 300            s->irq_count[pil]++;
 301#endif
 302            s->intregm_pending |= mask;
 303            if (pil == 15) {
 304                for (i = 0; i < MAX_CPUS; i++) {
 305                    s->slaves[i].intreg_pending |= 1 << pil;
 306                }
 307            }
 308        } else {
 309            s->intregm_pending &= ~mask;
 310            if (pil == 15) {
 311                for (i = 0; i < MAX_CPUS; i++) {
 312                    s->slaves[i].intreg_pending &= ~(1 << pil);
 313                }
 314            }
 315        }
 316        slavio_check_interrupts(s, 1);
 317    }
 318}
 319
 320static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
 321{
 322    SLAVIO_INTCTLState *s = opaque;
 323
 324    trace_slavio_set_timer_irq_cpu(cpu, level);
 325
 326    if (level) {
 327        s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
 328    } else {
 329        s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
 330    }
 331
 332    slavio_check_interrupts(s, 1);
 333}
 334
 335static void slavio_set_irq_all(void *opaque, int irq, int level)
 336{
 337    if (irq < 32) {
 338        slavio_set_irq(opaque, irq, level);
 339    } else {
 340        slavio_set_timer_irq_cpu(opaque, irq - 32, level);
 341    }
 342}
 343
 344static int vmstate_intctl_post_load(void *opaque, int version_id)
 345{
 346    SLAVIO_INTCTLState *s = opaque;
 347
 348    slavio_check_interrupts(s, 0);
 349    return 0;
 350}
 351
 352static const VMStateDescription vmstate_intctl_cpu = {
 353    .name ="slavio_intctl_cpu",
 354    .version_id = 1,
 355    .minimum_version_id = 1,
 356    .fields = (VMStateField[]) {
 357        VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
 358        VMSTATE_END_OF_LIST()
 359    }
 360};
 361
 362static const VMStateDescription vmstate_intctl = {
 363    .name ="slavio_intctl",
 364    .version_id = 1,
 365    .minimum_version_id = 1,
 366    .post_load = vmstate_intctl_post_load,
 367    .fields = (VMStateField[]) {
 368        VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
 369                             vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
 370        VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
 371        VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
 372        VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
 373        VMSTATE_END_OF_LIST()
 374    }
 375};
 376
 377static void slavio_intctl_reset(DeviceState *d)
 378{
 379    SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
 380    int i;
 381
 382    for (i = 0; i < MAX_CPUS; i++) {
 383        s->slaves[i].intreg_pending = 0;
 384        s->slaves[i].irl_out = 0;
 385    }
 386    s->intregm_disabled = ~MASTER_IRQ_MASK;
 387    s->intregm_pending = 0;
 388    s->target_cpu = 0;
 389    slavio_check_interrupts(s, 0);
 390}
 391
 392#ifdef DEBUG_IRQ_COUNT
 393static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
 394                                         uint64_t **irq_counts,
 395                                         unsigned int *nb_irqs)
 396{
 397    SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
 398    *irq_counts = s->irq_count;
 399    *nb_irqs = ARRAY_SIZE(s->irq_count);
 400    return true;
 401}
 402#endif
 403
 404static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon)
 405{
 406    SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
 407    int i;
 408
 409    for (i = 0; i < MAX_CPUS; i++) {
 410        monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
 411                       s->slaves[i].intreg_pending);
 412    }
 413    monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
 414                   s->intregm_pending, s->intregm_disabled);
 415}
 416
 417static void slavio_intctl_init(Object *obj)
 418{
 419    DeviceState *dev = DEVICE(obj);
 420    SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
 421    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 422    unsigned int i, j;
 423    char slave_name[45];
 424
 425    qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
 426    memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
 427                          "master-interrupt-controller", INTCTLM_SIZE);
 428    sysbus_init_mmio(sbd, &s->iomem);
 429
 430    for (i = 0; i < MAX_CPUS; i++) {
 431        snprintf(slave_name, sizeof(slave_name),
 432                 "slave-interrupt-controller-%i", i);
 433        for (j = 0; j < MAX_PILS; j++) {
 434            sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
 435        }
 436        memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
 437                              &slavio_intctl_mem_ops,
 438                              &s->slaves[i], slave_name, INTCTL_SIZE);
 439        sysbus_init_mmio(sbd, &s->slaves[i].iomem);
 440        s->slaves[i].cpu = i;
 441        s->slaves[i].master = s;
 442    }
 443}
 444
 445static void slavio_intctl_class_init(ObjectClass *klass, void *data)
 446{
 447    DeviceClass *dc = DEVICE_CLASS(klass);
 448    InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
 449
 450    dc->reset = slavio_intctl_reset;
 451    dc->vmsd = &vmstate_intctl;
 452#ifdef DEBUG_IRQ_COUNT
 453    ic->get_statistics = slavio_intctl_get_statistics;
 454#endif
 455    ic->print_info = slavio_intctl_print_info;
 456}
 457
 458static const TypeInfo slavio_intctl_info = {
 459    .name          = TYPE_SLAVIO_INTCTL,
 460    .parent        = TYPE_SYS_BUS_DEVICE,
 461    .instance_size = sizeof(SLAVIO_INTCTLState),
 462    .instance_init = slavio_intctl_init,
 463    .class_init    = slavio_intctl_class_init,
 464    .interfaces = (InterfaceInfo[]) {
 465        { TYPE_INTERRUPT_STATS_PROVIDER },
 466        { }
 467    },
 468};
 469
 470static void slavio_intctl_register_types(void)
 471{
 472    type_register_static(&slavio_intctl_info);
 473}
 474
 475type_init(slavio_intctl_register_types)
 476