Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup DevIRQGIC
0007  *
0008  * @brief This source file contains the implementation of the generic GICv2
0009  *   support.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2013, 2021 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #include <dev/irq/arm-gic.h>
0038 #include <dev/irq/arm-gic-arch.h>
0039 
0040 #include <bsp/irq-generic.h>
0041 #include <bsp/start.h>
0042 #include <rtems/score/assert.h>
0043 #include <rtems/score/processormaskimpl.h>
0044 
0045 /*
0046  * The GIC architecture reserves interrupt ID numbers 1020 to 1023 for special
0047  * purposes.
0048  */
0049 #if BSP_INTERRUPT_VECTOR_COUNT >= 1020
0050 #error "BSP_INTERRUPT_VECTOR_COUNT is too large"
0051 #endif
0052 
0053 #define GIC_CPUIF ((volatile gic_cpuif *) BSP_ARM_GIC_CPUIF_BASE)
0054 
0055 #define PRIORITY_DEFAULT 127
0056 
0057 /*
0058  * The following variants
0059  *
0060  * - GICv1 with Security Extensions,
0061  * - GICv2 without Security Extensions, and
0062  * - GICv2 with Security Extensions and in Secure processor mode
0063  *
0064  * have the ability to assign group 0 or 1 to individual interrupts.  Group
0065  * 0 interrupts can be configured to raise an FIQ exception.  This enables
0066  * the use of NMIs with respect to RTEMS.
0067  *
0068  * Use arm_gic_irq_set_group() to change the group of an interrupt (default
0069  * group is 1, if BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0 is defined).  To use FIQ
0070  * interrupts, you have to install an FIQ exception handler and enable FIQs in
0071  * the Current Program Status Register (CPSR).
0072  */
0073 #ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
0074 #define DIST_ICDDCR (GIC_DIST_ICDDCR_ENABLE_GRP_1 | GIC_DIST_ICDDCR_ENABLE)
0075 #define CPUIF_ICCICR \
0076   (GIC_CPUIF_ICCICR_CBPR | GIC_CPUIF_ICCICR_FIQ_EN \
0077     | GIC_CPUIF_ICCICR_ACK_CTL | GIC_CPUIF_ICCICR_ENABLE_GRP_1 \
0078     | GIC_CPUIF_ICCICR_ENABLE)
0079 #else
0080 #define DIST_ICDDCR GIC_DIST_ICDDCR_ENABLE
0081 #define CPUIF_ICCICR GIC_CPUIF_ICCICR_ENABLE
0082 #endif
0083 
0084 void bsp_interrupt_dispatch(void)
0085 {
0086   volatile gic_cpuif *cpuif = GIC_CPUIF;
0087 
0088   while (true) {
0089     uint32_t icciar = cpuif->icciar;
0090     rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar);
0091     uint32_t status;
0092 
0093     if (!bsp_interrupt_is_valid_vector(vector)) {
0094       break;
0095     }
0096 
0097     status = arm_interrupt_enable_interrupts();
0098     bsp_interrupt_handler_dispatch_unchecked(vector);
0099     arm_interrupt_restore_interrupts(status);
0100 
0101     cpuif->icceoir = icciar;
0102   }
0103 }
0104 
0105 rtems_status_code bsp_interrupt_is_pending(
0106   rtems_vector_number vector,
0107   bool               *pending
0108 )
0109 {
0110   volatile gic_dist *dist = ARM_GIC_DIST;
0111 
0112   *pending = gic_id_is_pending(dist, vector);
0113   return RTEMS_SUCCESSFUL;
0114 }
0115 
0116 rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
0117 {
0118   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0119 
0120   if (vector <= ARM_GIC_IRQ_SGI_LAST) {
0121     arm_gic_trigger_sgi(vector, 1U << _SMP_Get_current_processor());
0122   } else {
0123     volatile gic_dist *dist = ARM_GIC_DIST;
0124 
0125     gic_id_set_pending(dist, vector);
0126   }
0127 
0128   return RTEMS_SUCCESSFUL;
0129 }
0130 
0131 #if defined(RTEMS_SMP)
0132 rtems_status_code bsp_interrupt_raise_on(
0133   rtems_vector_number vector,
0134   uint32_t            cpu_index
0135 )
0136 {
0137   if (vector > ARM_GIC_IRQ_SGI_LAST) {
0138     return RTEMS_UNSATISFIED;
0139   }
0140 
0141   arm_gic_trigger_sgi(vector, 1U << cpu_index);
0142   return RTEMS_SUCCESSFUL;
0143 }
0144 #endif
0145 
0146 rtems_status_code bsp_interrupt_clear(rtems_vector_number vector)
0147 {
0148   volatile gic_dist *dist = ARM_GIC_DIST;
0149 
0150   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0151 
0152   if (vector <= ARM_GIC_IRQ_SGI_LAST) {
0153     return RTEMS_UNSATISFIED;
0154   }
0155 
0156   gic_id_clear_pending(dist, vector);
0157   return RTEMS_SUCCESSFUL;
0158 }
0159 
0160 rtems_status_code bsp_interrupt_vector_is_enabled(
0161   rtems_vector_number vector,
0162   bool               *enabled
0163 )
0164 {
0165   volatile gic_dist *dist = ARM_GIC_DIST;
0166 
0167   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0168   bsp_interrupt_assert(enabled != NULL);
0169 
0170   *enabled = gic_id_is_enabled(dist, vector);
0171   return RTEMS_SUCCESSFUL;
0172 }
0173 
0174 rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
0175 {
0176   volatile gic_dist *dist = ARM_GIC_DIST;
0177 
0178   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0179 
0180   gic_id_enable(dist, vector);
0181   return RTEMS_SUCCESSFUL;
0182 }
0183 
0184 rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
0185 {
0186   volatile gic_dist *dist = ARM_GIC_DIST;
0187 
0188   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0189 
0190   gic_id_disable(dist, vector);
0191   return RTEMS_SUCCESSFUL;
0192 }
0193 
0194 static inline uint32_t get_id_count(volatile gic_dist *dist)
0195 {
0196   uint32_t id_count = GIC_DIST_ICDICTR_IT_LINES_NUMBER_GET(dist->icdictr);
0197 
0198   id_count = 32 * (id_count + 1);
0199   id_count = id_count <= 1020 ? id_count : 1020;
0200 
0201   return id_count;
0202 }
0203 
0204 static inline void init_distributor(volatile gic_dist *dist)
0205 {
0206   uint32_t id_count = get_id_count(dist);
0207   uint32_t id;
0208 
0209   for (id = 0; id < id_count; id += 32) {
0210 #ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
0211     dist->icdigr[id / 32] = 0xffffffff;
0212 #endif
0213     dist->icdicer[id / 32] = 0xffffffff;
0214   }
0215 
0216   for (id = 0; id < id_count; ++id) {
0217     gic_id_set_priority(dist, id, PRIORITY_DEFAULT);
0218   }
0219 
0220   for (id = 32; id < id_count; ++id) {
0221     gic_id_set_targets(dist, id, 0x01);
0222   }
0223 }
0224 
0225 static inline void init_sgi_ppi(volatile gic_dist *dist)
0226 {
0227   uint32_t id;
0228 
0229 #ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
0230   dist->icdigr[0] = 0xffffffff;
0231 #endif
0232 
0233   /* Initialize priority of SGIs and PPIs */
0234   for (id = 0; id <= ARM_GIC_IRQ_PPI_LAST; ++id) {
0235     gic_id_set_priority(dist, id, PRIORITY_DEFAULT);
0236   }
0237 }
0238 
0239 void bsp_interrupt_facility_initialize(void)
0240 {
0241   volatile gic_cpuif *cpuif = GIC_CPUIF;
0242   volatile gic_dist *dist = ARM_GIC_DIST;
0243 
0244   arm_interrupt_facility_set_exception_handler();
0245 
0246 #ifdef BSP_ARM_GIC_MULTI_PROCESSOR_SECONDARY
0247   while ((dist->icddcr & GIC_DIST_ICDDCR_ENABLE) == 0) {
0248     /* Wait */
0249   }
0250 
0251   init_sgi_ppi(dist);
0252 #else
0253   init_distributor(dist);
0254 #endif
0255 
0256   cpuif->iccpmr = GIC_CPUIF_ICCPMR_PRIORITY(0xff);
0257   cpuif->iccbpr = GIC_CPUIF_ICCBPR_BINARY_POINT(0x0);
0258   cpuif->iccicr = CPUIF_ICCICR;
0259 
0260   dist->icddcr = GIC_DIST_ICDDCR_ENABLE_GRP_1 | GIC_DIST_ICDDCR_ENABLE;
0261 }
0262 
0263 #ifdef RTEMS_SMP
0264 BSP_START_TEXT_SECTION void arm_gic_irq_initialize_secondary_cpu(void)
0265 {
0266   volatile gic_cpuif *cpuif = GIC_CPUIF;
0267   volatile gic_dist *dist = ARM_GIC_DIST;
0268 
0269   init_sgi_ppi(dist);
0270 
0271   cpuif->iccpmr = GIC_CPUIF_ICCPMR_PRIORITY(0xff);
0272   cpuif->iccbpr = GIC_CPUIF_ICCBPR_BINARY_POINT(0x0);
0273   cpuif->iccicr = CPUIF_ICCICR;
0274 }
0275 #endif
0276 
0277 rtems_status_code bsp_interrupt_set_priority(
0278   rtems_vector_number vector,
0279   uint32_t priority
0280 )
0281 {
0282   volatile gic_dist *dist = ARM_GIC_DIST;
0283   uint8_t gic_priority = (uint8_t) priority;
0284 
0285   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0286 
0287   if (gic_priority != priority) {
0288     return RTEMS_INVALID_PRIORITY;
0289   }
0290 
0291   gic_id_set_priority(dist, vector, gic_priority);
0292   return RTEMS_SUCCESSFUL;
0293 }
0294 
0295 rtems_status_code bsp_interrupt_get_priority(
0296   rtems_vector_number vector,
0297   uint32_t *priority
0298 )
0299 {
0300   volatile gic_dist *dist = ARM_GIC_DIST;
0301 
0302   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0303   bsp_interrupt_assert(priority != NULL);
0304 
0305   *priority = gic_id_get_priority(dist, vector);
0306   return RTEMS_SUCCESSFUL;
0307 }
0308 
0309 #ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
0310 rtems_status_code arm_gic_irq_set_group(
0311   rtems_vector_number vector,
0312   gic_group group
0313 )
0314 {
0315   rtems_status_code sc = RTEMS_SUCCESSFUL;
0316 
0317   if (bsp_interrupt_is_valid_vector(vector)) {
0318     volatile gic_dist *dist = ARM_GIC_DIST;
0319 
0320     gic_id_set_group(dist, vector, group);
0321   } else {
0322     sc = RTEMS_INVALID_ID;
0323   }
0324 
0325   return sc;
0326 }
0327 
0328 rtems_status_code arm_gic_irq_get_group(
0329   rtems_vector_number vector,
0330   gic_group *group
0331 )
0332 {
0333   rtems_status_code sc = RTEMS_SUCCESSFUL;
0334 
0335   if (bsp_interrupt_is_valid_vector(vector)) {
0336     volatile gic_dist *dist = ARM_GIC_DIST;
0337 
0338     *group = gic_id_get_group(dist, vector);
0339   } else {
0340     sc = RTEMS_INVALID_ID;
0341   }
0342 
0343   return sc;
0344 }
0345 #endif
0346 
0347 #if defined(BSP_IRQ_HAVE_GET_SET_AFFINITY)
0348 rtems_status_code bsp_interrupt_set_affinity(
0349   rtems_vector_number vector,
0350   const Processor_mask *affinity
0351 )
0352 {
0353   volatile gic_dist *dist = ARM_GIC_DIST;
0354   uint8_t targets = (uint8_t) _Processor_mask_To_uint32_t(affinity, 0);
0355   rtems_interrupt_attributes attr;
0356   rtems_status_code sc;
0357 
0358   attr.can_set_affinity = false;
0359   sc = bsp_interrupt_get_attributes( vector, &attr );
0360   _Assert_Unused_variable_equals( sc, RTEMS_SUCCESSFUL );
0361 
0362   if ( !attr.can_set_affinity ) {
0363     return RTEMS_UNSATISFIED;
0364   }
0365 
0366   gic_id_set_targets(dist, vector, targets);
0367   return RTEMS_SUCCESSFUL;
0368 }
0369 
0370 rtems_status_code bsp_interrupt_get_affinity(
0371   rtems_vector_number vector,
0372   Processor_mask *affinity
0373 )
0374 {
0375   volatile gic_dist *dist = ARM_GIC_DIST;
0376   uint8_t targets;
0377   rtems_interrupt_attributes attr;
0378   rtems_status_code sc;
0379 
0380   attr.can_get_affinity = false;
0381   sc = bsp_interrupt_get_attributes( vector, &attr );
0382   _Assert_Unused_variable_equals( sc, RTEMS_SUCCESSFUL );
0383 
0384   targets = gic_id_get_targets(dist, vector);
0385 
0386   if ( !attr.can_get_affinity ) {
0387     return RTEMS_UNSATISFIED;
0388   }
0389 
0390   _Processor_mask_From_uint32_t(affinity, targets, 0);
0391   return RTEMS_SUCCESSFUL;
0392 }
0393 #endif
0394 
0395 void arm_gic_trigger_sgi(rtems_vector_number vector, uint32_t targets)
0396 {
0397   volatile gic_dist *dist = ARM_GIC_DIST;
0398 
0399   dist->icdsgir = GIC_DIST_ICDSGIR_TARGET_LIST_FILTER(0)
0400     | GIC_DIST_ICDSGIR_CPU_TARGET_LIST(targets)
0401 #ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
0402     | GIC_DIST_ICDSGIR_NSATT
0403 #endif
0404     | GIC_DIST_ICDSGIR_SGIINTID(vector);
0405 }
0406 
0407 #ifdef RTEMS_SMP
0408 uint32_t arm_gic_irq_processor_count(void)
0409 {
0410   volatile gic_dist *dist = ARM_GIC_DIST;
0411 
0412   return GIC_DIST_ICDICTR_CPU_NUMBER_GET(dist->icdictr) + 1;
0413 }
0414 #endif