/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: import/chips/p9/procedures/ppe/iota/iota_uih.c $ */ /* */ /* OpenPOWER HCODE Project */ /* */ /* COPYRIGHT 2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ #include "iota.h" #include "iota_uih.h" #include "iota_panic_codes.h" uint32_t g_current_prty_level = IOTA_NUM_EXT_IRQ_PRIORITIES - 1; uint8_t g_eimr_stack[IOTA_NUM_EXT_IRQ_PRIORITIES]; int g_eimr_stack_ctr = -1; uint64_t g_eimr_override_stack[IOTA_NUM_EXT_IRQ_PRIORITIES]; uint64_t g_eimr_override = 0x0000000000000000; uint64_t g_ext_irq_vector = 0; // Unified IRQ priority and masking handler. // - Locates the highest priority IRQ task vector that has at least one of its // interrupts in the current external PK interrupt vector. uint32_t iota_uih(void) { uint32_t iPrtyLvl = 0, bFound = 0; //uint64_t ext_irq_vector; // 1. Identify the priority level of the interrupt. g_ext_irq_vector = in64(CME_LCL_EISTR); if(g_ext_irq_vector == 0) { iota_dead(IOTA_UIH_PHANTOM_INTERRUPT); } do { if(ext_irq_vectors_cme[iPrtyLvl][IDX_PRTY_VEC] & g_ext_irq_vector) { bFound = 1; break; } } while(++iPrtyLvl < (IOTA_NUM_EXT_IRQ_PRIORITIES - 1)); //No need to check DISABLED. // Only manipulate EIMR masks for task level prty levels. // Let shared non-task IRQs (iPrtyLvl=0) be processed by // the PK kernel in usual fashion. if(bFound) { // 2. Save current mask (assume current prty level). // Note, reading EIMR is NOT safe because overrides may already have // happened to the EIMR. And we always want to restore // the EIMR to a known value when we exit our thread. if(++g_eimr_stack_ctr < IOTA_NUM_EXT_IRQ_PRIORITIES) { // Make a note of present prty level and // then update tracker to new prty level. g_eimr_stack[g_eimr_stack_ctr] = g_current_prty_level; g_current_prty_level = iPrtyLvl; // Update prty level tracker. g_eimr_override_stack[g_eimr_stack_ctr] = g_eimr_override; } else { iota_dead(IOTA_UIH_STACK_OVERFLOW); } // 3. Write the new mask for this priority level. out64(CME_LCL_EIMR, ext_irq_vectors_cme[iPrtyLvl][IDX_MASK_VEC] | g_eimr_override); } else { // Disabled IRQ fired iota_dead(IOTA_UIH_DISABLED_FIRED); } // Return the priority level return iPrtyLvl; } void iota_uih_restore() { if (g_eimr_stack_ctr >= 0) { out64(CME_LCL_EIMR, ext_irq_vectors_cme[g_eimr_stack[g_eimr_stack_ctr]][IDX_MASK_VEC]); out64(CME_LCL_EIMR_CLR, g_eimr_override_stack[g_eimr_stack_ctr]); out64(CME_LCL_EIMR_OR, g_eimr_override); // Restore the prty level tracker to the task that was interrupted, if any. g_current_prty_level = g_eimr_stack[g_eimr_stack_ctr]; g_eimr_stack_ctr--; } else { iota_dead(IOTA_UIH_STACK_UNDERFLOW); } }