Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RtemsIntrReqClear
0007  */
0008 
0009 /*
0010  * Copyright (C) 2021 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 /*
0035  * This file is part of the RTEMS quality process and was automatically
0036  * generated.  If you find something that needs to be fixed or
0037  * worded better please post a report or patch to an RTEMS mailing list
0038  * or raise a bug report:
0039  *
0040  * https://www.rtems.org/bugs.html
0041  *
0042  * For information on updating and regenerating please refer to the How-To
0043  * section in the Software Requirements Engineering chapter of the
0044  * RTEMS Software Engineering manual.  The manual is provided as a part of
0045  * a release.  For development sources please refer to the online
0046  * documentation at:
0047  *
0048  * https://docs.rtems.org
0049  */
0050 
0051 #ifdef HAVE_CONFIG_H
0052 #include "config.h"
0053 #endif
0054 
0055 #include <string.h>
0056 #include <bsp/irq-generic.h>
0057 #include <rtems/irq-extension.h>
0058 
0059 #include "tx-support.h"
0060 
0061 #include <rtems/test.h>
0062 
0063 /**
0064  * @defgroup RtemsIntrReqClear spec:/rtems/intr/req/clear
0065  *
0066  * @ingroup TestsuitesValidationIntr
0067  *
0068  * @{
0069  */
0070 
0071 typedef enum {
0072   RtemsIntrReqClear_Pre_Vector_Valid,
0073   RtemsIntrReqClear_Pre_Vector_Invalid,
0074   RtemsIntrReqClear_Pre_Vector_NA
0075 } RtemsIntrReqClear_Pre_Vector;
0076 
0077 typedef enum {
0078   RtemsIntrReqClear_Pre_CanClear_Yes,
0079   RtemsIntrReqClear_Pre_CanClear_No,
0080   RtemsIntrReqClear_Pre_CanClear_NA
0081 } RtemsIntrReqClear_Pre_CanClear;
0082 
0083 typedef enum {
0084   RtemsIntrReqClear_Post_Status_Ok,
0085   RtemsIntrReqClear_Post_Status_InvId,
0086   RtemsIntrReqClear_Post_Status_Unsat,
0087   RtemsIntrReqClear_Post_Status_NA
0088 } RtemsIntrReqClear_Post_Status;
0089 
0090 typedef enum {
0091   RtemsIntrReqClear_Post_Cleared_Yes,
0092   RtemsIntrReqClear_Post_Cleared_No,
0093   RtemsIntrReqClear_Post_Cleared_NA
0094 } RtemsIntrReqClear_Post_Cleared;
0095 
0096 typedef struct {
0097   uint8_t Skip : 1;
0098   uint8_t Pre_Vector_NA : 1;
0099   uint8_t Pre_CanClear_NA : 1;
0100   uint8_t Post_Status : 2;
0101   uint8_t Post_Cleared : 2;
0102 } RtemsIntrReqClear_Entry;
0103 
0104 /**
0105  * @brief Test context for spec:/rtems/intr/req/clear test case.
0106  */
0107 typedef struct {
0108   /**
0109    * @brief This member contains the count of serviced interrupts.
0110    */
0111   volatile uint32_t interrupt_count;
0112 
0113   /**
0114    * @brief If this member is true, then the interrupt shall be cleared.
0115    */
0116   bool do_clear;
0117 
0118   /**
0119    * @brief This member contains the current vector number.
0120    */
0121   rtems_vector_number vector;
0122 
0123   /**
0124    * @brief If this member is true, then the ``vector`` parameter shall be
0125    *   valid.
0126    */
0127   bool valid_vector;
0128 
0129   /**
0130    * @brief This member contains the return value of the
0131    *   rtems_interrupt_clear() call.
0132    */
0133   rtems_status_code status;
0134 
0135   struct {
0136     /**
0137      * @brief This member defines the pre-condition indices for the next
0138      *   action.
0139      */
0140     size_t pci[ 2 ];
0141 
0142     /**
0143      * @brief This member defines the pre-condition states for the next action.
0144      */
0145     size_t pcs[ 2 ];
0146 
0147     /**
0148      * @brief If this member is true, then the test action loop is executed.
0149      */
0150     bool in_action_loop;
0151 
0152     /**
0153      * @brief This member contains the next transition map index.
0154      */
0155     size_t index;
0156 
0157     /**
0158      * @brief This member contains the current transition map entry.
0159      */
0160     RtemsIntrReqClear_Entry entry;
0161 
0162     /**
0163      * @brief If this member is true, then the current transition variant
0164      *   should be skipped.
0165      */
0166     bool skip;
0167   } Map;
0168 } RtemsIntrReqClear_Context;
0169 
0170 static RtemsIntrReqClear_Context
0171   RtemsIntrReqClear_Instance;
0172 
0173 static const char * const RtemsIntrReqClear_PreDesc_Vector[] = {
0174   "Valid",
0175   "Invalid",
0176   "NA"
0177 };
0178 
0179 static const char * const RtemsIntrReqClear_PreDesc_CanClear[] = {
0180   "Yes",
0181   "No",
0182   "NA"
0183 };
0184 
0185 static const char * const * const RtemsIntrReqClear_PreDesc[] = {
0186   RtemsIntrReqClear_PreDesc_Vector,
0187   RtemsIntrReqClear_PreDesc_CanClear,
0188   NULL
0189 };
0190 
0191 typedef RtemsIntrReqClear_Context Context;
0192 
0193 static bool IsEnabled( const Context *ctx )
0194 {
0195   rtems_status_code sc;
0196   bool              enabled;
0197 
0198   enabled = false;
0199   sc = rtems_interrupt_vector_is_enabled( ctx->vector, &enabled );
0200   T_rsc_success( sc );
0201 
0202   return enabled;
0203 }
0204 
0205 static bool IsPending( const Context *ctx )
0206 {
0207   rtems_status_code sc;
0208   bool              pending;
0209 
0210   pending = false;
0211   sc = rtems_interrupt_is_pending( ctx->vector, &pending );
0212   T_rsc_success( sc );
0213 
0214   return pending;
0215 }
0216 
0217 static void Disable( const Context *ctx )
0218 {
0219   rtems_status_code sc;
0220 
0221   sc = rtems_interrupt_vector_disable( ctx->vector );
0222   T_rsc_success( sc );
0223 }
0224 
0225 static void Raise( const Context *ctx )
0226 {
0227   rtems_status_code sc;
0228 
0229   sc = rtems_interrupt_raise( ctx->vector );
0230   T_rsc_success( sc );
0231 }
0232 
0233 static void Clear( const Context *ctx )
0234 {
0235   rtems_status_code sc;
0236 
0237   sc = rtems_interrupt_clear( ctx->vector );
0238   T_rsc_success( sc );
0239 }
0240 
0241 static void EntryRoutine( void *arg )
0242 {
0243   Context *ctx;
0244   uint32_t count;
0245 
0246   (void) arg;
0247   ctx = T_fixture_context();
0248 
0249   count = ctx->interrupt_count;
0250   ctx->interrupt_count = count + 1;
0251 
0252   if ( ctx->do_clear ) {
0253     rtems_status_code sc;
0254 
0255     sc = rtems_interrupt_clear( ctx->vector );
0256     T_rsc_success( sc );
0257   }
0258 
0259   if ( count > 2 ) {
0260     /* Some interrupts are probably cased by a peripheral */
0261     Disable( ctx );
0262   }
0263 }
0264 
0265 static void CheckUnsatisfied( const Context *ctx )
0266 {
0267   rtems_status_code sc;
0268   bool              pending_before;
0269   bool              pending_after;
0270 
0271   pending_before = true;
0272   sc = rtems_interrupt_is_pending( ctx->vector, &pending_before );
0273   T_rsc_success( sc );
0274 
0275   sc = rtems_interrupt_clear( ctx->vector );
0276   T_rsc( sc, RTEMS_UNSATISFIED );
0277 
0278   pending_after = !pending_before;
0279   sc = rtems_interrupt_is_pending( ctx->vector, &pending_after );
0280   T_rsc_success( sc );
0281 
0282   T_eq( pending_before, pending_after );
0283 }
0284 
0285 static void CheckClear(
0286   Context                          *ctx,
0287   const rtems_interrupt_attributes *attr,
0288   bool                              has_installed_entries
0289 )
0290 {
0291   rtems_status_code sc;
0292 
0293   if ( !attr->can_clear ) {
0294     CheckUnsatisfied( ctx );
0295   } else if ( has_installed_entries ) {
0296     /* We cannot test this vector, since it is used by a device driver */
0297   } else if ( !attr->is_maskable ) {
0298     /* We can only safely test maskable interrupts */
0299   } else if ( IsPending( ctx ) ) {
0300     /*
0301      * If there is already an interrupt pending, then it is probably cleard
0302      * by a peripheral which we cannot control.
0303      */
0304   } else if ( attr->can_disable ) {
0305     rtems_interrupt_entry entry;
0306     rtems_interrupt_level level;
0307 
0308     ctx->interrupt_count = 0;
0309     ctx->do_clear = !attr->cleared_by_acknowledge;
0310     rtems_interrupt_entry_initialize( &entry, EntryRoutine, ctx, "Info" );
0311     sc = rtems_interrupt_entry_install(
0312       ctx->vector,
0313       RTEMS_INTERRUPT_UNIQUE,
0314       &entry
0315     );
0316     T_rsc_success( sc );
0317 
0318     Clear( ctx );
0319 
0320     if ( !IsPending( ctx) && ( attr->can_enable || IsEnabled( ctx ) ) ) {
0321       T_false( IsPending( ctx ) );
0322       Clear( ctx );
0323       T_false( IsPending( ctx ) );
0324 
0325       if ( attr->can_disable ) {
0326         Disable( ctx );
0327         Raise( ctx );
0328         T_true( IsPending( ctx ) );
0329         Clear( ctx );
0330         T_false( IsPending( ctx ) );
0331 
0332         sc = rtems_interrupt_vector_enable( ctx->vector );
0333         T_rsc_success( sc );
0334       }
0335 
0336       T_false( IsPending( ctx ) );
0337       Clear( ctx );
0338       T_false( IsPending( ctx ) );
0339 
0340       rtems_interrupt_local_disable( level );
0341       Raise( ctx );
0342       T_true( IsPending( ctx ) );
0343       Clear( ctx );
0344       T_false( IsPending( ctx ) );
0345       rtems_interrupt_local_enable( level );
0346 
0347       T_false( IsPending( ctx ) );
0348       Clear( ctx );
0349       T_false( IsPending( ctx ) );
0350     }
0351 
0352     sc = rtems_interrupt_entry_remove( ctx->vector, &entry );
0353     T_rsc_success( sc );
0354   }
0355 }
0356 
0357 static void RtemsIntrReqClear_Pre_Vector_Prepare(
0358   RtemsIntrReqClear_Context   *ctx,
0359   RtemsIntrReqClear_Pre_Vector state
0360 )
0361 {
0362   switch ( state ) {
0363     case RtemsIntrReqClear_Pre_Vector_Valid: {
0364       /*
0365        * While the ``vector`` parameter is associated with an interrupt vector.
0366        */
0367       ctx->valid_vector = true;
0368       break;
0369     }
0370 
0371     case RtemsIntrReqClear_Pre_Vector_Invalid: {
0372       /*
0373        * While the ``vector`` parameter is not associated with an interrupt
0374        * vector.
0375        */
0376       ctx->valid_vector = false;
0377       break;
0378     }
0379 
0380     case RtemsIntrReqClear_Pre_Vector_NA:
0381       break;
0382   }
0383 }
0384 
0385 static void RtemsIntrReqClear_Pre_CanClear_Prepare(
0386   RtemsIntrReqClear_Context     *ctx,
0387   RtemsIntrReqClear_Pre_CanClear state
0388 )
0389 {
0390   switch ( state ) {
0391     case RtemsIntrReqClear_Pre_CanClear_Yes: {
0392       /*
0393        * While the interrupt vector associated with the ``vector`` parameter
0394        * can be cleard.
0395        */
0396       /*
0397        * This pre-condition depends on the attributes of an interrupt vector,
0398        * see CheckClear().
0399        */
0400       break;
0401     }
0402 
0403     case RtemsIntrReqClear_Pre_CanClear_No: {
0404       /*
0405        * While the interrupt vector associated with the ``vector`` parameter
0406        * cannot be cleard.
0407        */
0408       /*
0409        * This pre-condition depends on the attributes of an interrupt vector,
0410        * see CheckClear().
0411        */
0412       break;
0413     }
0414 
0415     case RtemsIntrReqClear_Pre_CanClear_NA:
0416       break;
0417   }
0418 }
0419 
0420 static void RtemsIntrReqClear_Post_Status_Check(
0421   RtemsIntrReqClear_Context    *ctx,
0422   RtemsIntrReqClear_Post_Status state
0423 )
0424 {
0425   switch ( state ) {
0426     case RtemsIntrReqClear_Post_Status_Ok: {
0427       /*
0428        * The return status of rtems_interrupt_clear() shall be
0429        * RTEMS_SUCCESSFUL.
0430        */
0431       /* Validation is done by CheckClear() for each interrupt vector */
0432       break;
0433     }
0434 
0435     case RtemsIntrReqClear_Post_Status_InvId: {
0436       /*
0437        * The return status of rtems_interrupt_clear() shall be
0438        * RTEMS_INVALID_ID.
0439        */
0440       T_rsc( ctx->status, RTEMS_INVALID_ID );
0441       break;
0442     }
0443 
0444     case RtemsIntrReqClear_Post_Status_Unsat: {
0445       /*
0446        * The return status of rtems_interrupt_clear() shall be
0447        * RTEMS_UNSATISFIED.
0448        */
0449       /* Validation is done by CheckClear() for each interrupt vector */
0450       break;
0451     }
0452 
0453     case RtemsIntrReqClear_Post_Status_NA:
0454       break;
0455   }
0456 }
0457 
0458 static void RtemsIntrReqClear_Post_Cleared_Check(
0459   RtemsIntrReqClear_Context     *ctx,
0460   RtemsIntrReqClear_Post_Cleared state
0461 )
0462 {
0463   switch ( state ) {
0464     case RtemsIntrReqClear_Post_Cleared_Yes: {
0465       /*
0466        * The pending state of the interrupt associated with the interrupt
0467        * vector specified by ``vector`` shall be cleared for the processor
0468        * executing the rtems_interrupt_clear() call at some time point during
0469        * the call.
0470        */
0471       /* Validation is done by CheckClear() for each interrupt vector */
0472       break;
0473     }
0474 
0475     case RtemsIntrReqClear_Post_Cleared_No: {
0476       /*
0477        * The pending state of the interrupt associated with the interrupt
0478        * vector specified by ``vector`` shall not be cleared by the
0479        * rtems_interrupt_clear() call.
0480        */
0481       /* Validation is done by CheckClear() for each interrupt vector */
0482       break;
0483     }
0484 
0485     case RtemsIntrReqClear_Post_Cleared_NA:
0486       break;
0487   }
0488 }
0489 
0490 static void RtemsIntrReqClear_Action( RtemsIntrReqClear_Context *ctx )
0491 {
0492   if ( ctx->valid_vector ) {
0493     for (
0494       ctx->vector = 0;
0495       ctx->vector < BSP_INTERRUPT_VECTOR_COUNT;
0496       ++ctx->vector
0497     ) {
0498       rtems_status_code          sc;
0499       rtems_interrupt_attributes attr;
0500       bool                       has_installed_entries;
0501 
0502       memset( &attr, 0, sizeof( attr ) );
0503       sc = rtems_interrupt_get_attributes( ctx->vector, &attr );
0504 
0505       if ( sc == RTEMS_INVALID_ID ) {
0506         continue;
0507       }
0508 
0509       T_rsc_success( sc );
0510 
0511       has_installed_entries = HasInterruptVectorEntriesInstalled( ctx->vector );
0512       CheckClear( ctx, &attr, has_installed_entries );
0513     }
0514   } else {
0515     ctx->vector = BSP_INTERRUPT_VECTOR_COUNT;
0516     ctx->status = rtems_interrupt_clear( ctx->vector );
0517   }
0518 }
0519 
0520 static const RtemsIntrReqClear_Entry
0521 RtemsIntrReqClear_Entries[] = {
0522   { 0, 0, 1, RtemsIntrReqClear_Post_Status_InvId,
0523     RtemsIntrReqClear_Post_Cleared_NA },
0524   { 0, 0, 0, RtemsIntrReqClear_Post_Status_Ok,
0525     RtemsIntrReqClear_Post_Cleared_Yes },
0526   { 0, 0, 0, RtemsIntrReqClear_Post_Status_Unsat,
0527     RtemsIntrReqClear_Post_Cleared_No }
0528 };
0529 
0530 static const uint8_t
0531 RtemsIntrReqClear_Map[] = {
0532   1, 2, 0, 0
0533 };
0534 
0535 static size_t RtemsIntrReqClear_Scope( void *arg, char *buf, size_t n )
0536 {
0537   RtemsIntrReqClear_Context *ctx;
0538 
0539   ctx = arg;
0540 
0541   if ( ctx->Map.in_action_loop ) {
0542     return T_get_scope( RtemsIntrReqClear_PreDesc, buf, n, ctx->Map.pcs );
0543   }
0544 
0545   return 0;
0546 }
0547 
0548 static T_fixture RtemsIntrReqClear_Fixture = {
0549   .setup = NULL,
0550   .stop = NULL,
0551   .teardown = NULL,
0552   .scope = RtemsIntrReqClear_Scope,
0553   .initial_context = &RtemsIntrReqClear_Instance
0554 };
0555 
0556 static inline RtemsIntrReqClear_Entry RtemsIntrReqClear_PopEntry(
0557   RtemsIntrReqClear_Context *ctx
0558 )
0559 {
0560   size_t index;
0561 
0562   index = ctx->Map.index;
0563   ctx->Map.index = index + 1;
0564   return RtemsIntrReqClear_Entries[
0565     RtemsIntrReqClear_Map[ index ]
0566   ];
0567 }
0568 
0569 static void RtemsIntrReqClear_SetPreConditionStates(
0570   RtemsIntrReqClear_Context *ctx
0571 )
0572 {
0573   ctx->Map.pcs[ 0 ] = ctx->Map.pci[ 0 ];
0574 
0575   if ( ctx->Map.entry.Pre_CanClear_NA ) {
0576     ctx->Map.pcs[ 1 ] = RtemsIntrReqClear_Pre_CanClear_NA;
0577   } else {
0578     ctx->Map.pcs[ 1 ] = ctx->Map.pci[ 1 ];
0579   }
0580 }
0581 
0582 static void RtemsIntrReqClear_TestVariant( RtemsIntrReqClear_Context *ctx )
0583 {
0584   RtemsIntrReqClear_Pre_Vector_Prepare( ctx, ctx->Map.pcs[ 0 ] );
0585   RtemsIntrReqClear_Pre_CanClear_Prepare( ctx, ctx->Map.pcs[ 1 ] );
0586   RtemsIntrReqClear_Action( ctx );
0587   RtemsIntrReqClear_Post_Status_Check( ctx, ctx->Map.entry.Post_Status );
0588   RtemsIntrReqClear_Post_Cleared_Check( ctx, ctx->Map.entry.Post_Cleared );
0589 }
0590 
0591 /**
0592  * @fn void T_case_body_RtemsIntrReqClear( void )
0593  */
0594 T_TEST_CASE_FIXTURE( RtemsIntrReqClear, &RtemsIntrReqClear_Fixture )
0595 {
0596   RtemsIntrReqClear_Context *ctx;
0597 
0598   ctx = T_fixture_context();
0599   ctx->Map.in_action_loop = true;
0600   ctx->Map.index = 0;
0601 
0602   for (
0603     ctx->Map.pci[ 0 ] = RtemsIntrReqClear_Pre_Vector_Valid;
0604     ctx->Map.pci[ 0 ] < RtemsIntrReqClear_Pre_Vector_NA;
0605     ++ctx->Map.pci[ 0 ]
0606   ) {
0607     for (
0608       ctx->Map.pci[ 1 ] = RtemsIntrReqClear_Pre_CanClear_Yes;
0609       ctx->Map.pci[ 1 ] < RtemsIntrReqClear_Pre_CanClear_NA;
0610       ++ctx->Map.pci[ 1 ]
0611     ) {
0612       ctx->Map.entry = RtemsIntrReqClear_PopEntry( ctx );
0613       RtemsIntrReqClear_SetPreConditionStates( ctx );
0614       RtemsIntrReqClear_TestVariant( ctx );
0615     }
0616   }
0617 }
0618 
0619 /** @} */