HelenOS sources

root/kernel/genarch/src/drivers/gicv2/gicv2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gicv2_init
  2. gicv2_inum_get_total
  3. gicv2_inum_get
  4. gicv2_end
  5. gicv2_enable
  6. gicv2_disable

/*
 * Copyright (c) 2016 Petr Pavlu
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup genarch
 * @{
 */
/** @file
 * @brief ARM Generic Interrupt Controller, Architecture version 2.0.
 *
 * This IRQ controller is present on the QEMU virt platform for ARM.
 */

#include <arch/asm.h>
#include <genarch/drivers/gicv2/gicv2.h>
#include <assert.h>

/** Initialize GICv2 interrupt controller.
 *
 * @param irqc Instance structure.
 * @param distr Distributor registers.
 * @param cpui CPU interface registers.
 */
void gicv2_init(gicv2_t *irqc, gicv2_distr_regs_t *distr,
    gicv2_cpui_regs_t *cpui)
{
        irqc->distr = distr;
        irqc->cpui = cpui;

        /* Get maximum number of interrupts. */
        uint32_t typer = pio_read_32(&distr->typer);
        irqc->inum_total = (((typer & GICV2D_TYPER_IT_LINES_NUMBER_MASK) >>
            GICV2D_TYPER_IT_LINES_NUMBER_SHIFT) + 1) * 32;

        /* Disable all interrupts. */
        for (unsigned i = 0; i < irqc->inum_total / 32; i++)
                pio_write_32(&distr->icenabler[i], 0xffffffff);

        /* Enable interrupts for all priority levels. */
        pio_write_32(&cpui->pmr, 0xff);

        /* Enable signaling of interrupts. */
        pio_write_32(&cpui->ctlr, GICV2C_CTLR_ENABLE_FLAG);
        pio_write_32(&distr->ctlr, GICV2D_CTLR_ENABLE_FLAG);
}

/** Obtain total number of interrupts that the controller supports. */
unsigned gicv2_inum_get_total(gicv2_t *irqc)
{
        return irqc->inum_total;
}

/** Obtain number of pending interrupt. */
void gicv2_inum_get(gicv2_t *irqc, unsigned *inum, unsigned *cpuid)
{
        uint32_t iar = pio_read_32(&irqc->cpui->iar);

        *inum = (iar & GICV2C_IAR_INTERRUPT_ID_MASK) >>
            GICV2C_IAR_INTERRUPT_ID_SHIFT;
        *cpuid = (iar & GICV2C_IAR_CPUID_MASK) >> GICV2C_IAR_CPUID_SHIFT;
}

/** Signal end of interrupt to the controller. */
void gicv2_end(gicv2_t *irqc, unsigned inum, unsigned cpuid)
{
        assert((inum & ~((unsigned) GICV2C_IAR_INTERRUPT_ID_MASK >>
            GICV2C_IAR_INTERRUPT_ID_SHIFT)) == 0);
        assert((cpuid & ~((unsigned) GICV2C_IAR_CPUID_MASK >>
            GICV2C_IAR_CPUID_SHIFT)) == 0);

        uint32_t eoir = (inum << GICV2C_IAR_INTERRUPT_ID_SHIFT) |
            (cpuid << GICV2C_IAR_CPUID_SHIFT);
        pio_write_32(&irqc->cpui->eoir, eoir);
}

/** Enable specific interrupt. */
void gicv2_enable(gicv2_t *irqc, unsigned inum)
{
        assert(inum < irqc->inum_total);

        pio_write_32(&irqc->distr->isenabler[inum / 32], 1 << (inum % 32));
}

/** Disable specific interrupt. */
void gicv2_disable(gicv2_t *irqc, unsigned inum)
{
        assert(inum < irqc->inum_total);

        pio_write_32(&irqc->distr->icenabler[inum / 32], 1 << (inum % 32));
}

/** @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub