/* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define FARF_ERROR 1 #include "HAP_farf.h" #include "platform_libs.h" #include "AEEatomic.h" #include "AEEstd.h" #include "AEEStdErr.h" #include #include #include "verify.h" extern struct platform_lib* (*pl_list[])(void); static uint32 atomic_IfNotThenAdd(uint32* volatile puDest, uint32 uCompare, int nAdd); int pl_lib_init(struct platform_lib* (*plf)(void)) { int nErr = AEE_SUCCESS; struct platform_lib* pl = plf(); if(1 == atomic_Add(&pl->uRefs, 1)) { if(pl->init) { FARF(HIGH, "calling init for %s",pl->name); nErr = pl->init(); FARF(HIGH, "init for %s returned %x",pl->name, nErr); } pl->nErr = nErr; } if(pl->nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: %s init failed", nErr, pl->name); } return pl->nErr; } void pl_lib_deinit(struct platform_lib* (*plf)(void)) { struct platform_lib* pl = plf(); if(1 == atomic_IfNotThenAdd(&pl->uRefs, 0, -1)) { if(pl->deinit && pl->nErr == 0) { pl->deinit(); } } return; } static int pl_init_lst(struct platform_lib* (*lst[])(void)) { int nErr = AEE_SUCCESS; int ii; for(ii = 0; lst[ii] != 0; ++ii) { nErr = pl_lib_init(lst[ii]); if(nErr != 0) { break; } } if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: plinit failed\n", nErr); } return nErr; } int pl_init(void) { int nErr = pl_init_lst(pl_list); return nErr; } static void pl_deinit_lst(struct platform_lib* (*lst[])(void)) { int size, ii; for(size = 0; lst[size] != 0; ++size) {;} for(ii = size - 1; ii >= 0; --ii) { pl_lib_deinit(lst[ii]); } return; } void pl_deinit(void) { pl_deinit_lst(pl_list); return; } static uint32 atomic_IfNotThenAdd(uint32* volatile puDest, uint32 uCompare, int nAdd) { uint32 uPrev; uint32 uCurr; do { //check puDest uCurr = *puDest; uPrev = uCurr; //see if we need to update it if(uCurr != uCompare) { //update it uPrev = atomic_CompareAndExchange(puDest, uCurr + nAdd, uCurr); } //verify that the value was the same during the update as when we decided to update } while(uCurr != uPrev); return uPrev; }