summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/qoriq/irq/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/qoriq/irq/irq.c')
-rw-r--r--bsps/powerpc/qoriq/irq/irq.c340
1 files changed, 308 insertions, 32 deletions
diff --git a/bsps/powerpc/qoriq/irq/irq.c b/bsps/powerpc/qoriq/irq/irq.c
index a510b8e996..96fbe4e020 100644
--- a/bsps/powerpc/qoriq/irq/irq.c
+++ b/bsps/powerpc/qoriq/irq/irq.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
@@ -7,14 +9,32 @@
*/
/*
- * Copyright (c) 2010, 2017 embedded brains GmbH. All rights reserved.
+ * Copyright (C) 2010, 2017 embedded brains GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include <sys/param.h>
+#include <sys/bitset.h>
#include <rtems.h>
@@ -23,11 +43,11 @@
#include <asm/epapr_hcalls.h>
#include <bsp.h>
-#include <bsp/irq.h>
#include <bsp/irq-generic.h>
#include <bsp/vectors.h>
#include <bsp/utility.h>
#include <bsp/qoriq.h>
+#include <rtems/score/processormaskimpl.h>
#ifdef RTEMS_SMP
#include <rtems/score/smpimpl.h>
@@ -160,7 +180,7 @@ void bsp_interrupt_dispatch(uintptr_t exception_number)
* This works only if the "has-external-proxy" property is present in the
* "epapr,hv-pic" device tree node.
*/
- vector = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_EPR);
+ PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_EPR, vector);
if (vector != SPURIOUS) {
uint32_t msr;
@@ -274,7 +294,7 @@ static volatile qoriq_pic_src_cfg *get_src_cfg(rtems_vector_number vector)
}
}
-static bool is_ipi(rtems_vector_number vector)
+static bool pic_is_ipi(rtems_vector_number vector)
{
return (vector - QORIQ_IRQ_IPI_BASE) < 4;
}
@@ -288,6 +308,10 @@ rtems_status_code qoriq_pic_set_priority(
rtems_status_code sc = RTEMS_SUCCESSFUL;
uint32_t old_vpr = 0;
+ if (QORIQ_IRQ_IS_MSI(vector)) {
+ return RTEMS_UNSATISFIED;
+ }
+
if (bsp_interrupt_is_valid_vector(vector)) {
volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(vector);
@@ -314,6 +338,62 @@ rtems_status_code qoriq_pic_set_priority(
return sc;
}
+rtems_status_code qoriq_pic_set_sense_and_polarity(
+ rtems_vector_number vector,
+ qoriq_eirq_sense_and_polarity new_sense_and_polarity,
+ qoriq_eirq_sense_and_polarity *old_sense_and_polarity
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint32_t old_vpr = 0;
+ volatile qoriq_pic_src_cfg *src_cfg;
+ rtems_interrupt_lock_context lock_context;
+ uint32_t new_p_s = 0;
+
+ if (!QORIQ_IRQ_IS_EXT(vector)) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ if (new_sense_and_polarity == QORIQ_EIRQ_TRIGGER_EDGE_RISING ||
+ new_sense_and_polarity == QORIQ_EIRQ_TRIGGER_LEVEL_HIGH) {
+ new_p_s |= VPR_P;
+ }
+
+ if (new_sense_and_polarity == QORIQ_EIRQ_TRIGGER_LEVEL_HIGH ||
+ new_sense_and_polarity == QORIQ_EIRQ_TRIGGER_LEVEL_LOW) {
+ new_p_s |= VPR_S;
+ }
+
+ src_cfg = get_src_cfg(vector);
+
+ rtems_interrupt_lock_acquire(&lock, &lock_context);
+ old_vpr = src_cfg->vpr;
+ src_cfg->vpr = (old_vpr & ~(VPR_P | VPR_S)) | new_p_s;
+ rtems_interrupt_lock_release(&lock, &lock_context);
+
+ if (old_sense_and_polarity != NULL) {
+ if ((old_vpr & VPR_P) == 0) {
+ if ((old_vpr & VPR_S) == 0) {
+ *old_sense_and_polarity =
+ QORIQ_EIRQ_TRIGGER_EDGE_FALLING;
+ } else {
+ *old_sense_and_polarity =
+ QORIQ_EIRQ_TRIGGER_LEVEL_LOW;
+ }
+ } else {
+ if ((old_vpr & VPR_S) == 0) {
+ *old_sense_and_polarity =
+ QORIQ_EIRQ_TRIGGER_EDGE_RISING;
+ } else {
+ *old_sense_and_polarity =
+ QORIQ_EIRQ_TRIGGER_LEVEL_HIGH;
+ }
+ }
+ }
+
+ return sc;
+}
+
rtems_status_code bsp_interrupt_set_affinity(
rtems_vector_number vector,
const Processor_mask *affinity
@@ -321,7 +401,11 @@ rtems_status_code bsp_interrupt_set_affinity(
{
volatile qoriq_pic_src_cfg *src_cfg;
- if (is_ipi(vector)) {
+ if (pic_is_ipi(vector)) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ if (QORIQ_IRQ_IS_MSI(vector)) {
return RTEMS_UNSATISFIED;
}
@@ -337,7 +421,11 @@ rtems_status_code bsp_interrupt_get_affinity(
{
volatile qoriq_pic_src_cfg *src_cfg;
- if (is_ipi(vector)) {
+ if (pic_is_ipi(vector)) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ if (QORIQ_IRQ_IS_MSI(vector)) {
return RTEMS_UNSATISFIED;
}
@@ -346,17 +434,25 @@ rtems_status_code bsp_interrupt_get_affinity(
return RTEMS_SUCCESSFUL;
}
-static void pic_vector_enable(rtems_vector_number vector, uint32_t msk)
+static rtems_status_code pic_vector_set_mask(
+ rtems_vector_number vector,
+ uint32_t msk
+)
{
volatile qoriq_pic_src_cfg *src_cfg;
rtems_interrupt_lock_context lock_context;
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+ if (QORIQ_IRQ_IS_MSI(vector)) {
+ return RTEMS_UNSATISFIED;
+ }
+
src_cfg = get_src_cfg(vector);
rtems_interrupt_lock_acquire(&lock, &lock_context);
src_cfg->vpr = (src_cfg->vpr & ~VPR_MSK) | msk;
rtems_interrupt_lock_release(&lock, &lock_context);
+ return RTEMS_SUCCESSFUL;
}
rtems_status_code bsp_interrupt_get_attributes(
@@ -364,17 +460,25 @@ rtems_status_code bsp_interrupt_get_attributes(
rtems_interrupt_attributes *attributes
)
{
- bool vector_is_ipi = is_ipi(vector);
+ bool is_ipi = pic_is_ipi(vector);
+ bool is_msi = QORIQ_IRQ_IS_MSI(vector);
+
attributes->is_maskable = true;
- attributes->can_enable = true;
- attributes->maybe_enable = true;
- attributes->can_disable = true;
- attributes->maybe_disable = true;
+ attributes->can_enable = !is_msi;
+ attributes->maybe_enable = !is_msi;
+ attributes->can_disable = !is_msi;
+ attributes->maybe_disable = !is_msi;
attributes->cleared_by_acknowledge = true;
- attributes->can_get_affinity = !vector_is_ipi;
- attributes->can_set_affinity = !vector_is_ipi;
- attributes->can_raise = vector_is_ipi;
- attributes->can_raise_on = vector_is_ipi;
+ attributes->can_get_affinity = !(is_ipi || is_msi);
+ attributes->can_set_affinity = !(is_ipi || is_msi);
+ attributes->can_raise = is_ipi;
+ attributes->can_raise_on = is_ipi;
+
+ if (is_msi) {
+ attributes->can_be_triggered_by_message = true;
+ attributes->trigger_signal = RTEMS_INTERRUPT_NO_SIGNAL;
+ }
+
return RTEMS_SUCCESSFUL;
}
@@ -388,6 +492,11 @@ rtems_status_code bsp_interrupt_is_pending(
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
bsp_interrupt_assert(pending != NULL);
+ if (QORIQ_IRQ_IS_MSI(vector)) {
+ *pending = false;
+ return RTEMS_SUCCESSFUL;
+ }
+
src_cfg = get_src_cfg(vector);
*pending = (src_cfg->vpr & VPR_A) != 0;
return RTEMS_SUCCESSFUL;
@@ -403,7 +512,7 @@ rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
{
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
- if (is_ipi(vector)) {
+ if (pic_is_ipi(vector)) {
raise_on(vector, rtems_scheduler_get_processor());
return RTEMS_SUCCESSFUL;
}
@@ -419,7 +528,7 @@ rtems_status_code bsp_interrupt_raise_on(
{
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
- if (is_ipi(vector)) {
+ if (pic_is_ipi(vector)) {
raise_on(vector, cpu_index);
return RTEMS_SUCCESSFUL;
}
@@ -444,6 +553,10 @@ rtems_status_code bsp_interrupt_vector_is_enabled(
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
bsp_interrupt_assert(enabled != NULL);
+ if (QORIQ_IRQ_IS_MSI(vector)) {
+ vector = QORIQ_IRQ_MSI_0 + QORIQ_IRQ_MSI_INDEX(vector) / 32;
+ }
+
src_cfg = get_src_cfg(vector);
*enabled = (src_cfg->vpr & VPR_MSK) == 0;
return RTEMS_SUCCESSFUL;
@@ -451,14 +564,12 @@ rtems_status_code bsp_interrupt_vector_is_enabled(
rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
{
- pic_vector_enable(vector, 0);
- return RTEMS_SUCCESSFUL;
+ return pic_vector_set_mask(vector, 0);
}
rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
{
- pic_vector_enable(vector, VPR_MSK);
- return RTEMS_SUCCESSFUL;
+ return pic_vector_set_mask(vector, VPR_MSK);
}
void bsp_interrupt_dispatch(uintptr_t exception_number)
@@ -479,11 +590,6 @@ void bsp_interrupt_dispatch(uintptr_t exception_number)
}
}
-static bool pic_is_ipi(rtems_vector_number vector)
-{
- return QORIQ_IRQ_IPI_0 <= vector && vector <= QORIQ_IRQ_IPI_3;
-}
-
static void pic_reset(void)
{
qoriq.pic.gcr = GCR_RST;
@@ -515,7 +621,7 @@ void bsp_interrupt_facility_initialize(void)
pic_reset();
- for (i = 0; i < BSP_INTERRUPT_VECTOR_COUNT; ++i) {
+ for (i = 0; i < QORIQ_INTERRUPT_SOURCE_COUNT; ++i) {
volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(i);
src_cfg->vpr = VPR_MSK | VPR_P
@@ -531,16 +637,186 @@ void bsp_interrupt_facility_initialize(void)
qoriq.pic.svr = SPURIOUS;
qoriq.pic.gcr = GCR_M;
+ /* Clear shared message signaled interrupts */
+ for (i = 0; i < RTEMS_ARRAY_SIZE(qoriq.pic.msir); ++i) {
+ (void) qoriq.pic.msir[i].reg;
+ }
+
pic_global_timer_init();
}
qoriq.pic.ctpr = 0;
- for (i = 0; i < BSP_INTERRUPT_VECTOR_COUNT; ++i) {
+ for (i = 0; i < QORIQ_INTERRUPT_SOURCE_COUNT; ++i) {
qoriq.pic.iack;
qoriq.pic.eoi = 0;
qoriq.pic.whoami;
}
}
+typedef __BITSET_DEFINE(pic_msi_bitset, QORIQ_IRQ_MSI_COUNT) pic_msi_bitset;
+
+static pic_msi_bitset pic_msi_available =
+ __BITSET_T_INITIALIZER(__BITSET_FSET(__bitset_words(QORIQ_IRQ_MSI_COUNT)));
+
+
+static uint32_t pic_msi_bitset_to_uint32_t(
+ const pic_msi_bitset *bitset,
+ uint32_t index
+)
+{
+ long bits = bitset->__bits[index / _BITSET_BITS];
+
+ return (uint32_t) (bits >> (32 * ((index % _BITSET_BITS) / 32)));
+}
+
+static void pic_msi_dispatch(void *arg)
+{
+ uintptr_t reg = (uintptr_t) arg;
+ uint32_t msir = qoriq.pic.msir[reg].reg;
+
+ while (msir != 0) {
+ uint32_t index = 31 - __builtin_clz(msir);
+ const rtems_interrupt_entry *entry;
+
+ msir &= ~(UINT32_C(1) << index);
+ entry = bsp_interrupt_entry_load_first(
+ QORIQ_IRQ_MSI_VECTOR(32 * reg + index)
+ );
+
+ if (entry != NULL) {
+ bsp_interrupt_dispatch_entries(entry);
+ }
+ }
+}
+
+static rtems_status_code pic_msi_allocate(rtems_vector_number *vector)
+{
+ pic_msi_bitset *available = &pic_msi_available;
+ long found = __BIT_FFS(QORIQ_IRQ_MSI_COUNT, available);
+ rtems_vector_number index;
+ uint32_t subset;
+
+ if (found == 0) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ index = (rtems_vector_number) found - 1;
+ subset = pic_msi_bitset_to_uint32_t(available, index);
+
+ if (subset == 0xffffffff) {
+ uintptr_t reg = index / 32;
+ rtems_status_code sc;
+
+ sc = rtems_interrupt_handler_install(
+ QORIQ_IRQ_MSI_0 + reg,
+ "MSI",
+ RTEMS_INTERRUPT_UNIQUE,
+ pic_msi_dispatch,
+ (void *) reg
+ );
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+ }
+
+ __BIT_CLR(QORIQ_IRQ_MSI_COUNT, index, available);
+ *vector = QORIQ_IRQ_MSI_VECTOR(index);
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code pic_msi_free(rtems_vector_number vector)
+{
+ pic_msi_bitset *available = &pic_msi_available;
+ rtems_vector_number index = QORIQ_IRQ_MSI_INDEX(vector);
+ uint32_t subset;
+
+ if (__BIT_ISSET(QORIQ_IRQ_MSI_COUNT, index, available)) {
+ return RTEMS_NOT_DEFINED;
+ }
+
+ __BIT_SET(QORIQ_IRQ_MSI_COUNT, index, available);
+ subset = pic_msi_bitset_to_uint32_t(available, index);
+
+ if (subset == 0xffffffff) {
+ uintptr_t reg = index / 32;
+
+ return rtems_interrupt_handler_remove(
+ QORIQ_IRQ_MSI_0 + reg,
+ pic_msi_dispatch,
+ (void *) reg
+ );
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code qoriq_pic_msi_allocate(rtems_vector_number *vector)
+{
+ rtems_status_code sc;
+
+ if (!bsp_interrupt_is_initialized()) {
+ return RTEMS_INCORRECT_STATE;
+ }
+
+ if (vector == NULL) {
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ if (rtems_interrupt_is_in_progress()) {
+ return RTEMS_CALLED_FROM_ISR;
+ }
+
+ bsp_interrupt_lock();
+ sc = pic_msi_allocate(vector);
+ bsp_interrupt_unlock();
+ return sc;
+}
+
+rtems_status_code qoriq_pic_msi_free(rtems_vector_number vector)
+{
+ rtems_status_code sc;
+
+ if (!bsp_interrupt_is_initialized()) {
+ return RTEMS_INCORRECT_STATE;
+ }
+
+ if (!QORIQ_IRQ_IS_MSI(vector) ) {
+ return RTEMS_INVALID_ID;
+ }
+
+ if (rtems_interrupt_is_in_progress()) {
+ return RTEMS_CALLED_FROM_ISR;
+ }
+
+ bsp_interrupt_lock();
+ sc = pic_msi_free(vector);
+ bsp_interrupt_unlock();
+ return sc;
+}
+
+rtems_status_code qoriq_pic_msi_map(
+ rtems_vector_number vector,
+ uint64_t *addr,
+ uint32_t *data
+)
+{
+ if (addr == NULL) {
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ if (data == NULL) {
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ if (!QORIQ_IRQ_IS_MSI(vector) ) {
+ return RTEMS_INVALID_ID;
+ }
+
+ *addr = (uint64_t)(uintptr_t) &qoriq.pic.msiir;
+ *data = QORIQ_IRQ_MSI_INDEX(vector) << 24;
+ return RTEMS_SUCCESSFUL;
+}
+
#endif /* QORIQ_IS_HYPERVISOR_GUEST */