diff options
Diffstat (limited to 'bsps/powerpc/qoriq/irq/irq.c')
-rw-r--r-- | bsps/powerpc/qoriq/irq/irq.c | 315 |
1 files changed, 286 insertions, 29 deletions
diff --git a/bsps/powerpc/qoriq/irq/irq.c b/bsps/powerpc/qoriq/irq/irq.c index 2858ff7581..96fbe4e020 100644 --- a/bsps/powerpc/qoriq/irq/irq.c +++ b/bsps/powerpc/qoriq/irq/irq.c @@ -9,7 +9,7 @@ */ /* - * 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 @@ -34,6 +34,7 @@ */ #include <sys/param.h> +#include <sys/bitset.h> #include <rtems.h> @@ -42,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> @@ -179,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; @@ -293,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; } @@ -307,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); @@ -333,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 @@ -340,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; } @@ -356,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; } @@ -365,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( @@ -383,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; } @@ -407,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; @@ -422,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; } @@ -438,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; } @@ -463,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; @@ -470,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) @@ -498,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; @@ -534,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 @@ -550,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 */ |