Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsSPARCLEON3
0007  *
0008  * @brief This source file contains the implementation of the interrupt
0009  *   controller support.
0010  */
0011 
0012 /*
0013  *  Copyright (C) 2021 embedded brains GmbH & Co. KG
0014  *
0015  *  COPYRIGHT (c) 2011
0016  *  Aeroflex Gaisler
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  *
0039  */
0040 
0041 #include <bsp/irq-generic.h>
0042 #include <bsp/irqimpl.h>
0043 #include <rtems/score/processormaskimpl.h>
0044 
0045 #if !defined(LEON3_IRQAMP_EXTENDED_INTERRUPT)
0046 /* GRLIB extended IRQ controller IRQ number */
0047 uint32_t LEON3_IrqCtrl_EIrq;
0048 #endif
0049 
0050 rtems_interrupt_lock LEON3_IrqCtrl_Lock =
0051   RTEMS_INTERRUPT_LOCK_INITIALIZER("LEON3 IrqCtrl");
0052 
0053 /* Initialize Extended Interrupt controller */
0054 void leon3_ext_irq_init(irqamp *regs)
0055 {
0056   grlib_store_32(&regs->pimask[LEON3_Cpu_Index], 0);
0057   grlib_store_32(&regs->piforce[LEON3_Cpu_Index], 0);
0058   grlib_store_32(&regs->iclear, 0xffffffff);
0059 #if !defined(LEON3_IRQAMP_EXTENDED_INTERRUPT)
0060   LEON3_IrqCtrl_EIrq = IRQAMP_MPSTAT_EIRQ_GET(grlib_load_32(&regs->mpstat));
0061 #endif
0062 }
0063 
0064 bool bsp_interrupt_is_valid_vector(rtems_vector_number vector)
0065 {
0066   if (vector == 0) {
0067     return false;
0068   }
0069 
0070 #if defined(LEON3_IRQAMP_EXTENDED_INTERRUPT)
0071   return vector <= BSP_INTERRUPT_VECTOR_MAX_EXT;
0072 #else
0073   if (LEON3_IrqCtrl_EIrq > 0) {
0074     return vector <= BSP_INTERRUPT_VECTOR_MAX_EXT;
0075   }
0076 
0077   return vector <= BSP_INTERRUPT_VECTOR_MAX_STD;
0078 #endif
0079 }
0080 
0081 #if defined(RTEMS_SMP)
0082 Processor_mask leon3_interrupt_affinities[BSP_INTERRUPT_VECTOR_MAX_STD + 1];
0083 #endif
0084 
0085 void bsp_interrupt_facility_initialize(void)
0086 {
0087 #if defined(RTEMS_SMP)
0088   Processor_mask affinity;
0089   size_t i;
0090 
0091   _Processor_mask_From_index(&affinity, rtems_scheduler_get_processor());
0092 
0093   for (i = 0; i < RTEMS_ARRAY_SIZE(leon3_interrupt_affinities); ++i) {
0094     leon3_interrupt_affinities[i] = affinity;
0095   }
0096 #endif
0097 
0098   leon3_ext_irq_init(LEON3_IrqCtrl_Regs);
0099 }
0100 
0101 rtems_status_code bsp_interrupt_get_attributes(
0102   rtems_vector_number         vector,
0103   rtems_interrupt_attributes *attributes
0104 )
0105 {
0106   bool is_standard_interrupt;
0107 
0108   is_standard_interrupt = (vector <= BSP_INTERRUPT_VECTOR_MAX_STD);
0109   attributes->is_maskable = (vector != 15);
0110   attributes->can_enable = true;
0111   attributes->maybe_enable = true;
0112   attributes->can_disable = true;
0113   attributes->maybe_disable = true;
0114   attributes->can_raise = true;
0115   attributes->can_raise_on = is_standard_interrupt;
0116   attributes->can_clear = true;
0117   attributes->cleared_by_acknowledge = true;
0118   attributes->can_get_affinity = is_standard_interrupt;
0119   attributes->can_set_affinity = is_standard_interrupt;
0120   return RTEMS_SUCCESSFUL;
0121 }
0122 
0123 rtems_status_code bsp_interrupt_is_pending(
0124   rtems_vector_number vector,
0125   bool               *pending
0126 )
0127 {
0128   rtems_interrupt_level level;
0129   uint32_t bit;
0130   irqamp *regs;
0131 
0132   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0133   bsp_interrupt_assert(pending != NULL);
0134   bit = 1U << vector;
0135   regs = LEON3_IrqCtrl_Regs;
0136 
0137   rtems_interrupt_local_disable(level);
0138   *pending = (grlib_load_32(&regs->ipend) & bit) != 0 ||
0139     (grlib_load_32(&regs->piforce[rtems_scheduler_get_processor()]) & bit) != 0;
0140   rtems_interrupt_local_enable(level);
0141   return RTEMS_SUCCESSFUL;
0142 }
0143 
0144 rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
0145 {
0146   uint32_t bit;
0147   irqamp *regs;
0148 
0149   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0150   bit = 1U << vector;
0151   regs = LEON3_IrqCtrl_Regs;
0152 
0153   if ( vector <= BSP_INTERRUPT_VECTOR_MAX_STD ) {
0154     uint32_t cpu_count;
0155     uint32_t cpu_index;
0156 
0157     cpu_count = rtems_scheduler_get_processor_maximum();
0158 
0159     for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
0160       grlib_store_32(&regs->piforce[cpu_index], bit);
0161     }
0162   } else {
0163     rtems_interrupt_lock_context lock_context;
0164     uint32_t ipend;
0165 
0166     /*
0167      * This is a very dangerous operation and should only be used for test
0168      * software.  We may accidentally clear the pending state set by
0169      * peripherals with this read-modify-write operation.
0170      */
0171     LEON3_IRQCTRL_ACQUIRE(&lock_context);
0172     ipend = grlib_load_32(&regs->ipend);
0173     ipend |= bit;
0174     grlib_store_32(&regs->ipend, ipend);
0175     LEON3_IRQCTRL_RELEASE(&lock_context);
0176   }
0177 
0178   return RTEMS_SUCCESSFUL;
0179 }
0180 
0181 #if defined(RTEMS_SMP)
0182 rtems_status_code bsp_interrupt_raise_on(
0183   rtems_vector_number vector,
0184   uint32_t            cpu_index
0185 )
0186 {
0187   irqamp *regs;
0188 
0189   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0190   bsp_interrupt_assert(cpu_index < rtems_scheduler_get_processor_maximum());
0191 
0192   if ( vector > BSP_INTERRUPT_VECTOR_MAX_STD ) {
0193     return RTEMS_UNSATISFIED;
0194   }
0195 
0196   regs = LEON3_IrqCtrl_Regs;
0197   grlib_store_32(&regs->piforce[cpu_index], 1U << vector);
0198   return RTEMS_SUCCESSFUL;
0199 }
0200 #endif
0201 
0202 rtems_status_code bsp_interrupt_clear(rtems_vector_number vector)
0203 {
0204   uint32_t bit;
0205   irqamp *regs;
0206 
0207   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0208   bit = 1U << vector;
0209   regs = LEON3_IrqCtrl_Regs;
0210 
0211   grlib_store_32(&regs->iclear, bit);
0212 
0213   if (vector <= BSP_INTERRUPT_VECTOR_MAX_STD) {
0214     grlib_store_32(&regs->piforce[rtems_scheduler_get_processor()], bit << 16);
0215   }
0216 
0217   return RTEMS_SUCCESSFUL;
0218 }
0219 
0220 rtems_status_code bsp_interrupt_vector_is_enabled(
0221   rtems_vector_number vector,
0222   bool               *enabled
0223 )
0224 {
0225   uint32_t bit;
0226   irqamp *regs;
0227   uint32_t pimask;
0228 
0229   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0230 
0231   bit = 1U << vector;
0232   regs = LEON3_IrqCtrl_Regs;
0233   pimask = grlib_load_32(&regs->pimask[_LEON3_Get_current_processor()]);
0234   *enabled = (pimask & bit) != 0;
0235   return RTEMS_SUCCESSFUL;
0236 }
0237 
0238 #if defined(RTEMS_SMP)
0239 static void leon3_interrupt_vector_enable(rtems_vector_number vector)
0240 {
0241   uint32_t cpu_index;
0242   uint32_t cpu_count;
0243   Processor_mask affinity;
0244   uint32_t bit;
0245   uint32_t unmasked;
0246   uint32_t brdcst;
0247   irqamp *regs;
0248 
0249   if (vector <= BSP_INTERRUPT_VECTOR_MAX_STD) {
0250     affinity = leon3_interrupt_affinities[vector];
0251   } else {
0252     affinity = leon3_interrupt_affinities[LEON3_IrqCtrl_EIrq];
0253   }
0254 
0255   cpu_count = rtems_scheduler_get_processor_maximum();
0256   bit = 1U << vector;
0257   regs = LEON3_IrqCtrl_Regs;
0258   unmasked = 0;
0259 
0260   for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
0261     uint32_t pimask;
0262 
0263     pimask = grlib_load_32(&regs->pimask[cpu_index]);
0264 
0265     if (_Processor_mask_Is_set(&affinity, cpu_index)) {
0266       ++unmasked;
0267       pimask |= bit;
0268     } else {
0269       pimask &= ~bit;
0270     }
0271 
0272     grlib_store_32(&regs->pimask[cpu_index], pimask);
0273   }
0274 
0275   brdcst = grlib_load_32(&regs->brdcst);
0276 
0277   if (unmasked > 1) {
0278     brdcst |= bit;
0279   } else {
0280     brdcst &= ~bit;
0281   }
0282 
0283   grlib_store_32(&regs->brdcst, brdcst);
0284 }
0285 #endif
0286 
0287 rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
0288 {
0289   rtems_interrupt_lock_context lock_context;
0290 #if !defined(RTEMS_SMP)
0291   uint32_t bit;
0292   irqamp *regs;
0293   uint32_t pimask;
0294   uint32_t cpu_index;
0295 #endif
0296 
0297   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0298 #if !defined(RTEMS_SMP)
0299   bit = 1U << vector;
0300   regs = LEON3_IrqCtrl_Regs;
0301 #endif
0302 
0303   LEON3_IRQCTRL_ACQUIRE(&lock_context);
0304 #if defined(RTEMS_SMP)
0305   leon3_interrupt_vector_enable(vector);
0306 #else
0307   cpu_index = _LEON3_Get_current_processor();
0308   pimask = grlib_load_32(&regs->pimask[cpu_index]);
0309   pimask |= bit;
0310   grlib_store_32(&regs->pimask[cpu_index], pimask);
0311 #endif
0312   LEON3_IRQCTRL_RELEASE(&lock_context);
0313   return RTEMS_SUCCESSFUL;
0314 }
0315 
0316 rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
0317 {
0318   rtems_interrupt_lock_context lock_context;
0319   uint32_t bit;
0320   irqamp *regs;
0321   uint32_t pimask;
0322   uint32_t cpu_index;
0323 #if defined(RTEMS_SMP)
0324   uint32_t cpu_count;
0325   uint32_t brdcst;
0326 #endif
0327 
0328   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0329   bit = 1U << vector;
0330   regs = LEON3_IrqCtrl_Regs;
0331 
0332   LEON3_IRQCTRL_ACQUIRE(&lock_context);
0333 
0334 #if defined(RTEMS_SMP)
0335   cpu_count = rtems_scheduler_get_processor_maximum();
0336 
0337   for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
0338     pimask = grlib_load_32(&regs->pimask[cpu_index]);
0339     pimask &= ~bit;
0340     grlib_store_32(&regs->pimask[cpu_index], pimask);
0341   }
0342 
0343   brdcst = grlib_load_32(&regs->brdcst);
0344   brdcst &= ~bit;
0345   grlib_store_32(&regs->brdcst, brdcst);
0346 #else
0347   cpu_index = _LEON3_Get_current_processor();
0348   pimask = grlib_load_32(&regs->pimask[cpu_index]);
0349   pimask &= ~bit;
0350   grlib_store_32(&regs->pimask[cpu_index], pimask);
0351 #endif
0352 
0353   LEON3_IRQCTRL_RELEASE(&lock_context);
0354   return RTEMS_SUCCESSFUL;
0355 }
0356 
0357 rtems_status_code bsp_interrupt_set_priority(
0358   rtems_vector_number vector,
0359   uint32_t priority
0360 )
0361 {
0362   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0363   return RTEMS_UNSATISFIED;
0364 }
0365 
0366 rtems_status_code bsp_interrupt_get_priority(
0367   rtems_vector_number vector,
0368   uint32_t *priority
0369 )
0370 {
0371   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0372   bsp_interrupt_assert(priority != NULL);
0373   return RTEMS_UNSATISFIED;
0374 }
0375 
0376 #if defined(RTEMS_SMP)
0377 rtems_status_code bsp_interrupt_set_affinity(
0378   rtems_vector_number vector,
0379   const Processor_mask *affinity
0380 )
0381 {
0382   rtems_interrupt_lock_context lock_context;
0383   uint32_t cpu_count;
0384   uint32_t cpu_index;
0385   uint32_t bit;
0386   irqamp *regs;
0387 
0388   if (vector >= RTEMS_ARRAY_SIZE(leon3_interrupt_affinities)) {
0389     return RTEMS_UNSATISFIED;
0390   }
0391 
0392   cpu_count = rtems_scheduler_get_processor_maximum();
0393   bit = 1U << vector;
0394   regs = LEON3_IrqCtrl_Regs;
0395 
0396   LEON3_IRQCTRL_ACQUIRE(&lock_context);
0397   leon3_interrupt_affinities[vector] = *affinity;
0398 
0399   /*
0400    * If the interrupt is enabled on at least one processor, then re-enable it
0401    * using the new affinity.
0402    */
0403   for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
0404     if ((grlib_load_32(&regs->pimask[cpu_index]) & bit) != 0) {
0405       leon3_interrupt_vector_enable(vector);
0406       break;
0407     }
0408   }
0409 
0410   LEON3_IRQCTRL_RELEASE(&lock_context);
0411   return RTEMS_SUCCESSFUL;
0412 }
0413 
0414 rtems_status_code bsp_interrupt_get_affinity(
0415   rtems_vector_number vector,
0416   Processor_mask *affinity
0417 )
0418 {
0419   if (vector >= RTEMS_ARRAY_SIZE(leon3_interrupt_affinities)) {
0420     return RTEMS_UNSATISFIED;
0421   }
0422 
0423   *affinity = leon3_interrupt_affinities[vector];
0424   return RTEMS_SUCCESSFUL;
0425 }
0426 #endif