From 23f8ca6d303f55ebe9afd79670b89f73e4e0daad Mon Sep 17 00:00:00 2001 From: tyhsu <tyhsu@cs.nctu.edu.tw> Date: Fri, 11 May 2018 18:04:24 +0800 Subject: [PATCH] threading_push --- openair1/PHY/defs.h | 61 ++- openair1/SCHED/phy_procedures_lte_eNb.c | 391 +++------------ targets/RT/USER/lte-enb.c | 624 +++++++++++++++++++++++- 3 files changed, 739 insertions(+), 337 deletions(-) diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 2b47ded8fb..4b5442ffb4 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -29,6 +29,18 @@ \note \warning */ + +/*! \file PHY/defs.h + \brief Based on OAI structure definitions and add structure def. for multi-threads of PHY DL + \author Terng-Yin Hsu, Shao-Ying Yeh (fdragon) + \date 2018 + \version 0.1, based on 67df8e0e + \company NCTU + \email: tyhsu@cs.nctu.edu.tw, fdragon.cs96g@g2.nctu.edu.tw + \note + \warning +*/ + #ifndef __PHY_DEFS__H__ #define __PHY_DEFS__H__ @@ -457,6 +469,36 @@ typedef struct { UE_rxtx_proc_t proc_rxtx[RX_NB_TH]; } UE_proc_t; +// ----------------Part of TX procedure---------------- +typedef struct{ + pthread_t pthread_m2p; + pthread_cond_t cond_tx; + pthread_mutex_t mutex_tx; + pthread_attr_t attr_m2p; + //=====// +}mac2phy; + +typedef struct{ + pthread_t pthread_cch; + pthread_cond_t cond_tx; + pthread_mutex_t mutex_tx; + pthread_attr_t attr_cch; + //=====// + relaying_type_t r_type; + int do_pdcch_flag; + PHY_VARS_RN *rn; +}control_channel; + +typedef struct{ + pthread_t pthread_tx; + pthread_cond_t cond_tx; + pthread_mutex_t mutex_tx; + pthread_attr_t attr_sch; + //=====// + int id; +}multi_share_channel; +// [end] ----------------Part of TX procedure---------------- + /// Top-level PHY Data Structure for eNB typedef struct PHY_VARS_eNB_s { /// Module ID indicator for this instance @@ -682,6 +724,23 @@ typedef struct PHY_VARS_eNB_s { openair0_device ifdevice; /// Pointer for ifdevice buffer struct if_buffer_t ifbuffer; + + //---------------- [start] Part of TX procedure---------------- + // Thread + mac2phy thread_m2p; + control_channel thread_cch; + multi_share_channel thread_g[2]; + //Thread 0 for even, + //Thread 1 for odd + + //DONE + volatile uint8_t complete_m2p; + volatile uint8_t complete_dci; + volatile uint8_t complete_cch; + volatile uint8_t complete_sch_SR; + volatile uint8_t complete_pdsch[2]; + + //---------------- [end] Part of TX procedure---------------- } PHY_VARS_eNB; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 08e424061c..0a617b2463 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -29,6 +29,17 @@ * \note * \warning */ + +/*! \file phy_procedures_lte_eNB.c + * \brief Design the function of "phy_procedures_eNB_TX" as PHY-DL master threads + * \author Terng-Yin Hsu, Shao-Ying Yeh (fdragon) + * \date 2018 + * \version 0.1, based on 67df8e0e + * \company NCTU + * \email: tyhsu@cs.nctu.edu.tw, fdragon.cs96g@g2.nctu.edu.tw + * \note + * \warning + */ #include "PHY/defs.h" #include "PHY/extern.h" @@ -75,6 +86,19 @@ #define PUCCH 1 +//DLSH thread +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <semaphore.h> +#include <sys/sysinfo.h> +#include <sys/signal.h> +#include <assert.h> +#include <sched.h> +#include <pthread.h> + void exit_fun(const char* s); extern int exit_openair; @@ -1169,25 +1193,25 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,LTE_eNB_DLSCH_t *d void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, - relaying_type_t r_type, + relaying_type_t r_type, PHY_VARS_RN *rn, int do_meas, int do_pdcch_flag) { UNUSED(rn); - int frame=proc->frame_tx; + //int frame=proc->frame_tx; int subframe=proc->subframe_tx; // uint16_t input_buffer_length; - uint32_t i,j,aa; - uint8_t harq_pid; - DCI_PDU *DCI_pdu; - DCI_PDU DCI_pdu_tmp; - int8_t UE_id=0; - uint8_t num_pdcch_symbols=0; - uint8_t ul_subframe; - uint32_t ul_frame; + //uint32_t i,j,aa; + //uint8_t harq_pid; + //DCI_PDU *DCI_pdu; + //DCI_PDU DCI_pdu_tmp; + //int8_t UE_id=0; + //uint8_t num_pdcch_symbols=0; + //uint8_t ul_subframe; + //uint32_t ul_frame; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - DCI_ALLOC_t *dci_alloc=(DCI_ALLOC_t *)NULL; + //DCI_ALLOC_t *dci_alloc=(DCI_ALLOC_t *)NULL; int offset = eNB->CC_id;//proc == &eNB->proc.proc_rxtx[0] ? 0 : 1; @@ -1205,328 +1229,27 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, T(T_ENB_PHY_DL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); - for (i=0; i<NUMBER_OF_UE_MAX; i++) { - // If we've dropped the UE, go back to PRACH mode for this UE - if ((frame==0)&&(subframe==0)) { - if (eNB->UE_stats[i].crnti > 0) { - LOG_I(PHY,"UE %d : rnti %x\n",i,eNB->UE_stats[i].crnti); - } - } - if (eNB->UE_stats[i].ulsch_consecutive_errors == ULSCH_max_consecutive_errors) { - LOG_W(PHY,"[eNB %d, CC %d] frame %d, subframe %d, UE %d: ULSCH consecutive error count reached %u, triggering UL Failure\n", - eNB->Mod_id,eNB->CC_id,frame,subframe, i, eNB->UE_stats[i].ulsch_consecutive_errors); - eNB->UE_stats[i].ulsch_consecutive_errors=0; - mac_xface->UL_failure_indication(eNB->Mod_id, - eNB->CC_id, - frame, - eNB->UE_stats[i].crnti, - subframe); - - } - - - } - - - // Get scheduling info for next subframe - // This is called only for the CC_id = 0 and triggers scheduling for all CC_id's - if (eNB->mac_enabled==1) { - if (eNB->CC_id == 0) { - mac_xface->eNB_dlsch_ulsch_scheduler(eNB->Mod_id,0,frame,subframe);//,1); - } - } - - // clear the transmit data array for the current subframe - if (eNB->abstraction_flag==0) { - for (aa=0; aa<fp->nb_antenna_ports_eNB; aa++) { - memset(&eNB->common_vars.txdataF[0][aa][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)], - 0,fp->ofdm_symbol_size*(fp->symbols_per_tti)*sizeof(int32_t)); - } - } - - if (is_pmch_subframe(frame,subframe,fp)) { - pmch_procedures(eNB,proc,rn,r_type); - } - else { - // this is not a pmch subframe, so generate PSS/SSS/PBCH - common_signal_procedures(eNB,proc); - } - -#if defined(SMBV) - - // PBCH takes one allocation - if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { - if (subframe==0) - smbv_alloc_cnt++; - } - -#endif - - if (eNB->mac_enabled==1) { - // Parse DCI received from MAC - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); - DCI_pdu = mac_xface->get_dci_sdu(eNB->Mod_id, - eNB->CC_id, - frame, - subframe); - } - else { - DCI_pdu = &DCI_pdu_tmp; -#ifdef EMOS_CHANNEL - fill_dci_emos(DCI_pdu,eNB); -#else - fill_dci(DCI_pdu,eNB,proc); - // clear previous allocation information for all UEs - for (i=0; i<NUMBER_OF_UE_MAX; i++) { - if (eNB->dlsch[i][0]){ - for (j=0; j<8; j++) - eNB->dlsch[i][0]->harq_processes[j]->round = 0; - } - } - -#endif - } - - // clear existing ulsch dci allocations before applying info from MAC (this is table - ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); - ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); - - if ((subframe_select(fp,ul_subframe)==SF_UL) || - (fp->frame_type == FDD)) { - harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); - - // clear DCI allocation maps for new subframe - for (i=0; i<NUMBER_OF_UE_MAX; i++) - if (eNB->ulsch[i]) { - eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc=0; - eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc=0; - } - } - - // clear previous allocation information for all UEs - for (i=0; i<NUMBER_OF_UE_MAX; i++) { - if (eNB->dlsch[i][0]) - eNB->dlsch[i][0]->subframe_tx[subframe] = 0; - } - - /* save old HARQ information needed for PHICH generation */ - for (i=0; i<NUMBER_OF_UE_MAX; i++) { - if (eNB->ulsch[i]) { - /* Store first_rb and n_DMRS for correct PHICH generation below. - * For PHICH generation we need "old" values of last scheduling - * for this HARQ process. 'generate_eNB_dlsch_params' below will - * overwrite first_rb and n_DMRS and 'generate_phich_top', done - * after 'generate_eNB_dlsch_params', would use the "new" values - * instead of the "old" ones. - * - * This has been tested for FDD only, may be wrong for TDD. - * - * TODO: maybe we should restructure the code to be sure it - * is done correctly. The main concern is if the code - * changes and first_rb and n_DMRS are modified before - * we reach here, then the PHICH processing will be wrong, - * using wrong first_rb and n_DMRS values to compute - * ngroup_PHICH and nseq_PHICH. - * - * TODO: check if that works with TDD. - */ - if ((subframe_select(fp,ul_subframe)==SF_UL) || - (fp->frame_type == FDD)) { - harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); - eNB->ulsch[i]->harq_processes[harq_pid]->previous_first_rb = - eNB->ulsch[i]->harq_processes[harq_pid]->first_rb; - eNB->ulsch[i]->harq_processes[harq_pid]->previous_n_DMRS = - eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS; - } - } - } - - - // loop over all DCIs for this subframe to generate DLSCH allocations - for (i=0; i<DCI_pdu->Num_dci; i++) { - LOG_D(PHY,"[eNB] Subframe %d: DCI %d/%d : rnti %x, CCEind %d\n",subframe,i,DCI_pdu->Num_dci,DCI_pdu->dci_alloc[i].rnti,DCI_pdu->dci_alloc[i].firstCCE); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].rnti); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].format); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].firstCCE); - dci_alloc = &DCI_pdu->dci_alloc[i]; - - if ((dci_alloc->rnti<= P_RNTI) && - (dci_alloc->ra_flag!=1)) { - if (eNB->mac_enabled==1) - UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); - else - UE_id = i; - } - else UE_id=0; - - generate_eNB_dlsch_params(eNB,proc,dci_alloc,UE_id); - - } - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); - - // Apply physicalConfigDedicated if needed - // This is for UEs that have received this IE, which changes these DL and UL configuration, we apply after a delay for the eNodeB UL parameters - phy_config_dedicated_eNB_step2(eNB); - - // Now loop again over the DCIs for UL configuration - for (i=0; i<DCI_pdu->Num_dci; i++) { - dci_alloc = &DCI_pdu->dci_alloc[i]; - - if (dci_alloc->format == format0) { // this is a ULSCH allocation - if (eNB->mac_enabled==1) - UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); - else - UE_id = i; - - if (UE_id<0) { // should not happen, log an error and exit, this is a fatal error - LOG_E(PHY,"[eNB %"PRIu8"] Frame %d: Unknown UE_id for rnti %"PRIx16"\n",eNB->Mod_id,frame,dci_alloc->rnti); - mac_xface->macphy_exit("FATAL\n"); - } - generate_eNB_ulsch_params(eNB,proc,dci_alloc,UE_id); - } - } - - - - - - // if we have DCI to generate do it now - if (DCI_pdu->Num_dci>0) { - - - } else { // for emulation!! - eNB->num_ue_spec_dci[(subframe)&1]=0; - eNB->num_common_dci[(subframe)&1]=0; - } - - - if (eNB->abstraction_flag == 0) { - if (do_pdcch_flag) { - if (DCI_pdu->Num_dci > 0) { - LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (Num_dci=%d)\n",eNB->Mod_id,frame, subframe, - DCI_pdu->Num_dci); - } - - num_pdcch_symbols = generate_dci_top(DCI_pdu->Num_dci, - DCI_pdu->dci_alloc, - 0, - AMP, - fp, - eNB->common_vars.txdataF[0], - subframe); - } - else { - num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; - LOG_D(PHY,"num_pdcch_symbols %"PRIu8" (Num_dci %d)\n",num_pdcch_symbols, - DCI_pdu->Num_dci); - } - } - -#ifdef PHY_ABSTRACTION // FIXME this ifdef seems suspicious - else { - LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_to_emul\n",eNB->Mod_id,frame, subframe); - num_pdcch_symbols = generate_dci_top_emul(eNB,DCI_pdu->Num_dci,DCI_pdu->dci_alloc,subframe); - } - -#endif - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->num_pdcch_symbols); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,0); - -#if defined(SMBV) - // Sets up PDCCH and DCI table - if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4) && (DCI_pdu->Num_dci>0)) { - LOG_D(PHY,"[SMBV] Frame %3d, SF %d PDCCH, number of DCIs %d\n",frame,subframe,DCI_pdu->Num_dci); - dump_dci(fp,&DCI_pdu->dci_alloc[0]); - smbv_configure_pdcch(smbv_fname,(smbv_frame_cnt*10) + (subframe),num_pdcch_symbols,DCI_pdu->Num_dci); - } -#endif - - // Check for SI activity - - if ((eNB->dlsch_SI) && (eNB->dlsch_SI->active == 1)) { - - pdsch_procedures(eNB,proc,eNB->dlsch_SI,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,0,num_pdcch_symbols); - -#if defined(SMBV) - - // Configures the data source of allocation (allocation is configured by DCI) - if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { - LOG_D(PHY,"[SMBV] Frame %3d, Configuring SI payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); - smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), DLSCH_pdu, input_buffer_length); - } - -#endif - } - - // Check for RA activity - if ((eNB->dlsch_ra) && (eNB->dlsch_ra->active == 1)) { - -#if defined(SMBV) - - // Configures the data source of allocation (allocation is configured by DCI) - if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { - LOG_D(PHY,"[SMBV] Frame %3d, Configuring RA payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); - smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), dlsch_input_buffer, input_buffer_length); - } - -#endif - - - LOG_D(PHY,"[eNB %"PRIu8"][RAPROC] Frame %d, subframe %d: Calling generate_dlsch (RA),Msg3 frame %"PRIu32", Msg3 subframe %"PRIu8"\n", - eNB->Mod_id, - frame, subframe, - eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, - eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); - - pdsch_procedures(eNB,proc,eNB->dlsch_ra,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,1,num_pdcch_symbols); - - - eNB->dlsch_ra->active = 0; - } - - // Now scan UE specific DLSCH - for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) - { - if ((eNB->dlsch[(uint8_t)UE_id][0])&& - (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& - (eNB->dlsch[(uint8_t)UE_id][0]->active == 1)) { - - pdsch_procedures(eNB,proc,eNB->dlsch[(uint8_t)UE_id][0],eNB->dlsch[(uint8_t)UE_id][1],&eNB->UE_stats[(uint32_t)UE_id],0,num_pdcch_symbols); - - - } - - else if ((eNB->dlsch[(uint8_t)UE_id][0])&& - (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& - (eNB->dlsch[(uint8_t)UE_id][0]->active == 0)) { - - // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) - eNB->dlsch[(uint8_t)UE_id][0]->subframe_tx[subframe]=0; - } - } - - - - // if we have PHICH to generate - - if (is_phich_subframe(fp,subframe)) - { - generate_phich_top(eNB, - proc, - AMP, - 0); - } - - /* - if (frame>=10 && subframe>=9) { - write_output("/tmp/txsigF0.m","txsF0", &eNB->common_vars.txdataF[0][0][0],120*eNB->frame_parms.ofdm_symbol_size,1,1); - write_output("/tmp/txsigF1.m","txsF1", &eNB->common_vars.txdataF[0][0][0],120*eNB->frame_parms.ofdm_symbol_size,1,1); - abort(); - } - */ + eNB->complete_m2p = 0; + eNB->complete_dci = 0; + eNB->complete_sch_SR = 0; + pthread_cond_signal(&eNB->thread_m2p.cond_tx); + while(eNB->complete_m2p!=1); + + eNB->thread_cch.r_type = r_type; + eNB->thread_cch.do_pdcch_flag = do_pdcch_flag; + eNB->thread_cch.rn = rn; + eNB->complete_cch = 0; + pthread_cond_signal(&eNB->thread_cch.cond_tx); + while(eNB->complete_dci!=1); + + eNB->complete_pdsch[0]=0; + eNB->complete_pdsch[1]=0; + pthread_cond_signal(&eNB->thread_g[0].cond_tx); + pthread_cond_signal(&eNB->thread_g[1].cond_tx); + + while(!eNB->complete_pdsch[0]||!eNB->complete_pdsch[1]); + while(eNB->complete_cch!=1); + while(eNB->complete_sch_SR!=1); #ifdef EMOS phy_procedures_emos_eNB_TX(subframe, eNB); diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 2a1be10680..2911f9fc69 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -29,6 +29,18 @@ * \note * \warning */ + +/*! \file lte-enb.c + * \brief Based on top-level threads for eNodeB and include multi-threads of PHY DL + * \author Terng-Yin Hsu, Shao-Ying Yeh (fdragon) + * \date 2018 + * \version 0.1, based on 67df8e0e + * \company NCTU + * \email: tyhsu@cs.nctu.edu.tw, fdragon.cs96g@g2.nctu.edu.tw + * \note + * \warning + */ + #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> @@ -45,6 +57,12 @@ #include <sys/sysinfo.h> #include "rt_wrapper.h" +// DLSH thread +#include <semaphore.h> +#include <assert.h> +#include <pthread.h> +//===== + #include "time_utils.h" #undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all @@ -1748,6 +1766,539 @@ static void* eNB_thread_single( void* param ) { extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *); +extern void pdsch_procedures(PHY_VARS_eNB *,eNB_rxtx_proc_t *,LTE_eNB_DLSCH_t *, LTE_eNB_DLSCH_t *,LTE_eNB_UE_stats *,int ,int ); +extern void pmch_procedures(PHY_VARS_eNB *,eNB_rxtx_proc_t *,PHY_VARS_RN *,relaying_type_t ); +extern void common_signal_procedures (PHY_VARS_eNB *,eNB_rxtx_proc_t *); +extern void generate_eNB_dlsch_params(PHY_VARS_eNB *,eNB_rxtx_proc_t *,DCI_ALLOC_t *,const int ); +extern void generate_eNB_ulsch_params(PHY_VARS_eNB *,eNB_rxtx_proc_t *,DCI_ALLOC_t *,const int ); + +//----------------Part of TX procedure---------------- +static void *mac2phy_proc(void *ptr){ + PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][0]; + eNB_rxtx_proc_t *proc; + + int frame; + int subframe; + uint32_t i,j,aa; + uint8_t harq_pid; + DCI_PDU *DCI_pdu; + DCI_PDU DCI_pdu_tmp; + int8_t UE_id=0; + uint8_t num_pdcch_symbols=0; + uint8_t ul_subframe; + uint32_t ul_frame; + LTE_DL_FRAME_PARMS *fp; + DCI_ALLOC_t *dci_alloc=(DCI_ALLOC_t *)NULL; + + static int mac2phy_proc_status = 0; + + /**********************************************************************/ + cpu_set_t cpuset; + //the CPU we whant to use + int cpu = 1; + int s; + CPU_ZERO(&cpuset); //clears the cpuset + CPU_SET( cpu , &cpuset); //set CPU 0~7 on cpuset + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) + { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + printf("[SCHED][eNB] MAC to PHY thread started on CPU %d TID %ld\n",sched_getcpu(),gettid()); + /**********************************************************************/ + + while(!oai_exit){ + // wait signal + while(pthread_cond_wait(&eNB->thread_m2p.cond_tx, &eNB->thread_m2p.mutex_tx)!=0); + + // start mac2phy + proc = &eNB->proc.proc_rxtx[0]; + fp=&eNB->frame_parms; + frame = proc->frame_tx; + subframe = proc->subframe_tx; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + // If we've dropped the UE, go back to PRACH mode for this UE + if ((frame==0)&&(subframe==0)) { + if (eNB->UE_stats[i].crnti > 0) { + LOG_I(PHY,"UE %d : rnti %x\n",i,eNB->UE_stats[i].crnti); + } + } + if (eNB->UE_stats[i].ulsch_consecutive_errors == ULSCH_max_consecutive_errors) { + LOG_W(PHY,"[eNB %d, CC %d] frame %d, subframe %d, UE %d: ULSCH consecutive error count reached %u, triggering UL Failure\n", + eNB->Mod_id,eNB->CC_id,frame,subframe, i, eNB->UE_stats[i].ulsch_consecutive_errors); + eNB->UE_stats[i].ulsch_consecutive_errors=0; + mac_xface->UL_failure_indication(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->UE_stats[i].crnti, + subframe); + + } + + + } + + // Get scheduling info for next subframe + // This is called only for the CC_id = 0 and triggers scheduling for all CC_id's + if (eNB->mac_enabled==1) { + if (eNB->CC_id == 0) { + mac_xface->eNB_dlsch_ulsch_scheduler(eNB->Mod_id,0,frame,subframe);//,1); + } + } + + // clear the transmit data array for the current subframe + if (eNB->abstraction_flag==0) { + for (aa=0; aa<fp->nb_antenna_ports_eNB; aa++) { + memset(&eNB->common_vars.txdataF[0][aa][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)], + 0,fp->ofdm_symbol_size*(fp->symbols_per_tti)*sizeof(int32_t)); + } + } + + eNB->complete_m2p = 1; /////////////////////////////////////// + + if (eNB->mac_enabled==1) { + // Parse DCI received from MAC + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); + DCI_pdu = mac_xface->get_dci_sdu(eNB->Mod_id, + eNB->CC_id, + frame, + subframe); + } + else { + DCI_pdu = &DCI_pdu_tmp; +#ifdef EMOS_CHANNEL + fill_dci_emos(DCI_pdu,eNB); +#else + fill_dci(DCI_pdu,eNB,proc); + // clear previous allocation information for all UEs + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]){ + for (j=0; j<8; j++) + eNB->dlsch[i][0]->harq_processes[j]->round = 0; + } + } + +#endif + } + + // clear existing ulsch dci allocations before applying info from MAC (this is table + ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); + ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); + + if ((subframe_select(fp,ul_subframe)==SF_UL) || + (fp->frame_type == FDD)) { + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + + // clear DCI allocation maps for new subframe + for (i=0; i<NUMBER_OF_UE_MAX; i++) + if (eNB->ulsch[i]) { + eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc=0; + eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc=0; + } + } + + // clear previous allocation information for all UEs + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]) + eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + } + + /* save old HARQ information needed for PHICH generation */ + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->ulsch[i]) { + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + if ((subframe_select(fp,ul_subframe)==SF_UL) || + (fp->frame_type == FDD)) { + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + eNB->ulsch[i]->harq_processes[harq_pid]->previous_first_rb = + eNB->ulsch[i]->harq_processes[harq_pid]->first_rb; + eNB->ulsch[i]->harq_processes[harq_pid]->previous_n_DMRS = + eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS; + } + } + } + + /*/////////////////////////////////////////////// + + num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; + LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols, + DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); + + #if defined(SMBV) + // Sets up PDCCH and DCI table + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4) && ((DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci)>0)) { + LOG_D(PHY,"[SMBV] Frame %3d, SF %d PDCCH, number of DCIs %d\n",frame,subframe,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci); + dump_dci(fp,&DCI_pdu->dci_alloc[0]); + smbv_configure_pdcch(smbv_fname,(smbv_frame_cnt*10) + (subframe),num_pdcch_symbols,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci); + } + #endif + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->num_pdcch_symbols); + ///////////////////////////////////////////////*/ + + // loop over all DCIs for this subframe to generate DLSCH allocations + for (i=0; i<DCI_pdu->Num_dci; i++) { + LOG_D(PHY,"[eNB] Subframe %d: DCI %d/%d : rnti %x, CCEind %d\n",subframe,i,DCI_pdu->Num_dci,DCI_pdu->dci_alloc[i].rnti,DCI_pdu->dci_alloc[i].firstCCE); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].rnti); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].format); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].firstCCE); + dci_alloc = &DCI_pdu->dci_alloc[i]; + + if ((dci_alloc->rnti<= P_RNTI) && + (dci_alloc->ra_flag!=1)) { + if (eNB->mac_enabled==1) + UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); + else + UE_id = i; + } + else UE_id=0; + + generate_eNB_dlsch_params(eNB,proc,dci_alloc,UE_id); + + } + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); + + // Apply physicalConfigDedicated if needed + // This is for UEs that have received this IE, which changes these DL and UL configuration, we apply after a delay for the eNodeB UL parameters + phy_config_dedicated_eNB_step2(eNB); + + // Now loop again over the DCIs for UL configuration + for (i=0; i<DCI_pdu->Num_dci; i++) { + dci_alloc = &DCI_pdu->dci_alloc[i]; + + if (dci_alloc->format == format0) { // this is a ULSCH allocation + if (eNB->mac_enabled==1) + UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); + else + UE_id = i; + + if (UE_id<0) { // should not happen, log an error and exit, this is a fatal error + LOG_E(PHY,"[eNB %"PRIu8"] Frame %d: Unknown UE_id for rnti %"PRIx16"\n",eNB->Mod_id,frame,dci_alloc->rnti); + mac_xface->macphy_exit("FATAL\n"); + } + generate_eNB_ulsch_params(eNB,proc,dci_alloc,UE_id); + } + } + + // if we have DCI to generate do it now + if (DCI_pdu->Num_dci>0) { + + } else { // for emulation!! + eNB->num_ue_spec_dci[(subframe)&1]=0; + eNB->num_common_dci[(subframe)&1]=0; + } + + eNB->complete_dci = 1; /////////////////////////////////////// + + num_pdcch_symbols = get_num_pdcch_symbols(DCI_pdu->Num_dci,DCI_pdu->dci_alloc,fp,subframe); + + // Check for SI activity + if ((eNB->dlsch_SI) && (eNB->dlsch_SI->active == 1)) { + pdsch_procedures(eNB,proc,eNB->dlsch_SI,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,0,num_pdcch_symbols); + +#if defined(SMBV) + // Configures the data source of allocation (allocation is configured by DCI) + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, Configuring SI payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); + smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), DLSCH_pdu, input_buffer_length); + } +#endif + } + + // Check for RA activity + if ((eNB->dlsch_ra) && (eNB->dlsch_ra->active == 1)) { + +#if defined(SMBV) + // Configures the data source of allocation (allocation is configured by DCI) + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, Configuring RA payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); + smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), dlsch_input_buffer, input_buffer_length); + } +#endif + LOG_D(PHY,"[eNB %"PRIu8"][RAPROC] Frame %d, subframe %d: Calling generate_dlsch (RA),Msg3 frame %"PRIu32", Msg3 subframe %"PRIu8"\n", + eNB->Mod_id, + frame, subframe, + eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, + eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); + + pdsch_procedures(eNB,proc,eNB->dlsch_ra,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,1,num_pdcch_symbols); + + eNB->dlsch_ra->active = 0; + } + + eNB->complete_sch_SR = 1; /////////////////////////////////////// + } + + printf( "Exiting eNB thread mac2phy\n"); + return &mac2phy_proc_status; +} + +static void *cch_proc(void *ptr){ + control_channel *cch = (control_channel*)ptr; + + PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][0]; + eNB_rxtx_proc_t *proc; + relaying_type_t r_type; + PHY_VARS_RN *rn; + + int frame; + int subframe; + // uint32_t i,j; + DCI_PDU *DCI_pdu; + DCI_PDU DCI_pdu_tmp; + uint8_t num_pdcch_symbols=0; + LTE_DL_FRAME_PARMS *fp; + + static int control_channel_status = 0; + int do_pdcch_flag; + + /**********************************************************************/ + cpu_set_t cpuset; + //the CPU we whant to use + int cpu = 2; + int s; + CPU_ZERO(&cpuset); //clears the cpuset + CPU_SET( cpu , &cpuset); //set CPU 0~7 on cpuset + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) + { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + printf("[SCHED][eNB] Control_channel thread started on CPU %d TID %ld\n",sched_getcpu(),gettid()); + /**********************************************************************/ + + while(!oai_exit) + { + // wait signal + while(pthread_cond_wait(&eNB->thread_cch.cond_tx, &eNB->thread_cch.mutex_tx)!=0); + + // start cch + proc = &eNB->proc.proc_rxtx[0]; + fp=&eNB->frame_parms; + frame = proc->frame_tx; + subframe = proc->subframe_tx; + r_type = cch->r_type; + do_pdcch_flag = cch->do_pdcch_flag; + rn = cch->rn; + UNUSED(rn); + + if (is_pmch_subframe(frame,subframe,fp)) { + pmch_procedures(eNB,proc,rn,r_type); + } + else { + // this is not a pmch subframe, so generate PSS/SSS/PBCH + common_signal_procedures(eNB,proc); + } + +#if defined(SMBV) + + // PBCH takes one allocation + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + if (subframe==0) + smbv_alloc_cnt++; + } + +#endif + + if (eNB->mac_enabled==1) { + // Parse DCI received from MAC + DCI_pdu = mac_xface->get_dci_sdu(eNB->Mod_id, + eNB->CC_id, + frame, + subframe); + } + else { + DCI_pdu = &DCI_pdu_tmp; +#ifdef EMOS_CHANNEL + fill_dci_emos(DCI_pdu,eNB); +#else + fill_dci(DCI_pdu,eNB,proc); +#endif + } + + if (eNB->abstraction_flag == 0) { + if (do_pdcch_flag) { + if (DCI_pdu->Num_dci > 0) { + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (Num_dci=%d)\n",eNB->Mod_id,frame, subframe, + DCI_pdu->Num_dci); + } + + num_pdcch_symbols = generate_dci_top(DCI_pdu->Num_dci, + DCI_pdu->dci_alloc, + 0, + AMP, + fp, + eNB->common_vars.txdataF[0], + subframe); + } + else { + num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; + LOG_D(PHY,"num_pdcch_symbols %"PRIu8" (Num_dci %d)\n",num_pdcch_symbols, + DCI_pdu->Num_dci); + } + } + +#ifdef PHY_ABSTRACTION // FIXME this ifdef seems suspicious + else { + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_to_emul\n",eNB->Mod_id,frame, subframe); + num_pdcch_symbols = generate_dci_top_emul(eNB,DCI_pdu->Num_dci,DCI_pdu->dci_alloc,subframe); + } + +#endif + +#if defined(SMBV) + // Sets up PDCCH and DCI table + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4) && (DCI_pdu->Num_dci>0)) { + LOG_D(PHY,"[SMBV] Frame %3d, SF %d PDCCH, number of DCIs %d\n",frame,subframe,DCI_pdu->Num_dci); + dump_dci(fp,&DCI_pdu->dci_alloc[0]); + smbv_configure_pdcch(smbv_fname,(smbv_frame_cnt*10) + (subframe),num_pdcch_symbols,DCI_pdu->Num_dci); + } +#endif + + + // if we have PHICH to generate + + if (is_phich_subframe(fp,subframe)) + { + generate_phich_top(eNB, + proc, + AMP, + 0); + } + + eNB->complete_cch = 1; + + } + + printf( "Exiting eNB thread control_channel\n"); + return &control_channel_status; +} + +static void *multi_sch_proc(void *ptr){ + multi_share_channel *sch =(multi_share_channel*) ptr; + + PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][0]; + eNB_rxtx_proc_t *proc; + + int frame; + int subframe; + DCI_PDU *DCI_pdu; + DCI_PDU DCI_pdu_tmp; + int UE_id=0; + int num_pdcch_symbols=0; + LTE_DL_FRAME_PARMS *fp; + + static int multi_sch_proc_status = 0; + + /**********************************************************************/ + cpu_set_t cpuset; + //the CPU we whant to use + int cpu = 3+UE_id; + int s; + CPU_ZERO(&cpuset); //clears the cpuset + CPU_SET( cpu , &cpuset); //set CPU 0~7 on cpuset + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) + { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + printf("[SCHED][eNB] PDSCH thread %d started on CPU %d TID %ld\n",UE_id,sched_getcpu(),gettid()); + /**********************************************************************/ + + while(!oai_exit){ + // wait signal + while(pthread_cond_wait(&eNB->thread_g[sch->id].cond_tx,&eNB->thread_g[sch->id].mutex_tx)!=0); + + // start sch + proc=&eNB->proc.proc_rxtx[0]; + frame = proc->frame_tx; + subframe = proc->subframe_tx; + fp=&eNB->frame_parms; + + if (eNB->mac_enabled==1) { + // Parse DCI received from MAC + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); + DCI_pdu = mac_xface->get_dci_sdu(eNB->Mod_id, + eNB->CC_id, + frame, + subframe); + } + else { + DCI_pdu = &DCI_pdu_tmp; +#ifdef EMOS_CHANNEL + fill_dci_emos(DCI_pdu,eNB); +#else + fill_dci(DCI_pdu,eNB,proc); +#endif + } + + num_pdcch_symbols = get_num_pdcch_symbols(DCI_pdu->Num_dci,DCI_pdu->dci_alloc,fp,subframe); + + // Now scan UE specific DLSCH + for (UE_id=sch->id; UE_id<NUMBER_OF_UE_MAX; UE_id+=2) + { + if ((eNB->dlsch[(uint8_t)UE_id][0])&& + (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& + (eNB->dlsch[(uint8_t)UE_id][0]->active == 1)) { + + pdsch_procedures(eNB,proc,eNB->dlsch[(uint8_t)UE_id][0],eNB->dlsch[(uint8_t)UE_id][1],&eNB->UE_stats[(uint32_t)UE_id],0,num_pdcch_symbols); + + } + + else if ((eNB->dlsch[(uint8_t)UE_id][0])&& + (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& + (eNB->dlsch[(uint8_t)UE_id][0]->active == 0)) { + + // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) + eNB->dlsch[(uint8_t)UE_id][0]->subframe_tx[subframe]=0; + } + } + + eNB->complete_pdsch[sch->id]=1; + } + + printf( "Exiting eNB thread multi_sch_proc %d\n",sch->id); + multi_sch_proc_status=0; + return &multi_sch_proc_status; +} +// =================================================== void init_eNB_proc(int inst) { @@ -1793,6 +2344,18 @@ void init_eNB_proc(int inst) { pthread_cond_init( &proc->cond_FH, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); pthread_cond_init( &proc->cond_synch,NULL); + + //----------------Part of TX procedure---------------- + pthread_mutex_init( &eNB->thread_m2p.mutex_tx, NULL); + pthread_mutex_init( &(eNB->thread_cch.mutex_tx), NULL); + pthread_mutex_init( &eNB->thread_g[0].mutex_tx, NULL); + pthread_mutex_init( &eNB->thread_g[1].mutex_tx, NULL); + + pthread_cond_init( &eNB->thread_m2p.cond_tx, NULL); + pthread_cond_init( &(eNB->thread_cch.cond_tx), NULL); + pthread_cond_init( &eNB->thread_g[0].cond_tx, NULL); + pthread_cond_init( &eNB->thread_g[1].cond_tx, NULL); + //==================================================== pthread_attr_init( &proc->attr_FH); pthread_attr_init( &proc->attr_prach); @@ -1804,6 +2367,14 @@ void init_eNB_proc(int inst) { pthread_attr_init( &proc->attr_te); pthread_attr_init( &proc_rxtx[0].attr_rxtx); pthread_attr_init( &proc_rxtx[1].attr_rxtx); + + //----------------Part of TX procedure---------------- + pthread_attr_init( &eNB->thread_m2p.attr_m2p); + pthread_attr_init( &eNB->thread_cch.attr_cch); + pthread_attr_init( &eNB->thread_g[0].attr_sch); + pthread_attr_init( &eNB->thread_g[1].attr_sch); + //==================================================== + #ifndef DEADLINE_SCHEDULER attr0 = &proc_rxtx[0].attr_rxtx; attr1 = &proc_rxtx[1].attr_rxtx; @@ -1836,8 +2407,16 @@ void init_eNB_proc(int inst) { pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, eNB_thread_asynch_rxtx, &eNB->proc ); + + //----------------Part of TX procedure---------------- + pthread_create(&(eNB->thread_m2p.pthread_m2p),&eNB->thread_m2p.attr_m2p,mac2phy_proc,NULL); + pthread_create(&(eNB->thread_cch.pthread_cch),&eNB->thread_cch.attr_cch,cch_proc,&eNB->thread_cch); + pthread_create(&(eNB->thread_g[0].pthread_tx),&eNB->thread_g[0].attr_sch,multi_sch_proc,&eNB->thread_g[0]); + pthread_create(&(eNB->thread_g[1].pthread_tx),&eNB->thread_g[1].attr_sch,multi_sch_proc,&eNB->thread_g[1]); + //==================================================== + - char name[16]; + char name[32]; if (eNB->single_thread_flag == 0) { snprintf( name, sizeof(name), "RXTX0 %d", i ); pthread_setname_np( proc_rxtx[0].pthread_rxtx, name ); @@ -1850,6 +2429,17 @@ void init_eNB_proc(int inst) { snprintf( name, sizeof(name), " %d", i ); pthread_setname_np( proc->pthread_single, name ); } + + //----------------Part of TX procedure---------------- + snprintf( name, sizeof(name), "MAC to PHY thread"); + pthread_setname_np(eNB->thread_m2p.pthread_m2p, name ); + snprintf( name, sizeof(name), "Control_channel thread"); + pthread_setname_np(eNB->thread_cch.pthread_cch, name ); + snprintf( name, sizeof(name), "PDSCH thread 0"); + pthread_setname_np(eNB->thread_g[0].pthread_tx, name ); + snprintf( name, sizeof(name), "PDSCH thread 1"); + pthread_setname_np(eNB->thread_g[1].pthread_tx, name ); + //==================================================== } //for multiple CCs: setup master and slaves @@ -1905,6 +2495,13 @@ void kill_eNB_proc(int inst) { pthread_cond_signal( &proc->cond_prach ); pthread_cond_signal( &proc->cond_FH ); pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); + + //----------------Part of TX procedure---------------- + pthread_cond_signal(&eNB->thread_m2p.cond_tx); + pthread_cond_signal(&eNB->thread_cch.cond_tx); + pthread_cond_signal(&eNB->thread_g[0].cond_tx); + pthread_cond_signal(&eNB->thread_g[1].cond_tx); + //==================================================== pthread_join( proc->pthread_FH, (void**)&status ); pthread_mutex_destroy( &proc->mutex_FH ); @@ -1920,6 +2517,24 @@ void kill_eNB_proc(int inst) { pthread_mutex_destroy( &proc_rxtx[i].mutex_rxtx ); pthread_cond_destroy( &proc_rxtx[i].cond_rxtx ); } + + //----------------Part of TX procedure---------------- + pthread_join(eNB->thread_m2p.pthread_m2p,(void**)&status); + pthread_mutex_destroy(&eNB->thread_m2p.mutex_tx); + pthread_cond_destroy(&eNB->thread_m2p.cond_tx); + + pthread_join(eNB->thread_cch.pthread_cch,(void**)&status); + pthread_mutex_destroy(&eNB->thread_cch.mutex_tx); + pthread_cond_destroy(&eNB->thread_cch.cond_tx); + + pthread_join(eNB->thread_g[0].pthread_tx,(void**)&status); + pthread_mutex_destroy( &(eNB->thread_g[0].mutex_tx) ); + pthread_cond_destroy( &(eNB->thread_g[0].cond_tx) ); + + pthread_join(eNB->thread_g[1].pthread_tx,(void**)&status); + pthread_mutex_destroy( &(eNB->thread_g[1].mutex_tx) ); + pthread_cond_destroy( &(eNB->thread_g[1].cond_tx) ); + //==================================================== } } @@ -2075,6 +2690,11 @@ void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst eNB->ts_offset = 0; eNB->in_synch = 0; eNB->is_slave = (wait_for_sync>0) ? 1 : 0; + + //----------------Part of TX procedure---------------- + eNB->thread_g[0].id = 0; + eNB->thread_g[1].id = 1; + //==================================================== #ifndef OCP_FRAMEWORK -- 2.26.2