Files
openairinterface5g/openair1/PHY/NR_REFSIG/refsig.c
T

221 lines
7.7 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* 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
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* 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.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "nr_refsig.h"
#include "openair1/PHY/LTE_TRANSPORT/transport_proto.h" // for lte_gold_generic()
#define REFRESH_RATE (1000 * 100)
typedef struct {
int key;
int length;
int usage;
} gold_cache_t;
typedef struct {
uint32_t *table;
uint32_t tblSz;
int calls;
int iterate;
} gold_cache_table_t;
static const int roundedHeaderSz = (((sizeof(gold_cache_t) + 63) / 64) * 64) / sizeof(uint32_t);
static const int grain = 64 / sizeof(uint32_t);
// Allocate, also reorder to have the most frequent first, so the cache search is optimized
static void refresh_table(gold_cache_table_t *t, int sizeIncrease)
{
uint32_t *old = t->table;
uint oldSz = t->tblSz;
if (t->tblSz == 0)
t->tblSz = PAGE_SIZE / sizeof(*t->table);
if (sizeIncrease)
t->tblSz += max(sizeIncrease, PAGE_SIZE / sizeof(*t->table));
int ret = posix_memalign((void **)&t->table, 64, t->tblSz * sizeof(*t->table));
AssertFatal(ret == 0, "No more memory");
LOG_D(PHY,
"re-organize gold sequence table to %lu pages of memory calls since last reorder: %d, search rate: %f\n",
t->tblSz * sizeof(*t->table) / PAGE_SIZE,
t->calls,
t->calls ? t->iterate / (float)t->calls : 0.0);
int maxUsage;
uint32_t *currentTmp = t->table;
do {
maxUsage = 0;
gold_cache_t *entryToCopy = NULL;
for (uint32_t *searchmax = old; searchmax < old + oldSz; searchmax += roundedHeaderSz) {
gold_cache_t *tbl = (gold_cache_t *)searchmax;
if (!tbl->length)
break;
if (tbl->usage > maxUsage) {
maxUsage = tbl->usage;
entryToCopy = tbl;
}
searchmax += tbl->length;
}
if (maxUsage) {
memcpy(currentTmp, entryToCopy, (roundedHeaderSz + entryToCopy->length) * sizeof(*t->table));
currentTmp += roundedHeaderSz + entryToCopy->length;
entryToCopy->usage = 0;
}
} while (maxUsage);
const uint usedSz = currentTmp - t->table;
memset(t->table + usedSz, 0, (t->tblSz - usedSz) * sizeof(*t->table));
free(old);
t->calls = 0;
t->iterate = 0;
return;
}
static pthread_key_t gold_table_key;
static pthread_once_t gold_key_once = PTHREAD_ONCE_INIT;
static void delete_table(void *ptr)
{
gold_cache_table_t *table = (gold_cache_table_t *)ptr;
if (table->table)
free(table->table);
free(ptr);
}
static void make_table_key()
{
(void)pthread_key_create(&gold_table_key, delete_table);
}
uint32_t *gold_cache(uint32_t key, int length)
{
(void)pthread_once(&gold_key_once, make_table_key);
gold_cache_table_t *tableCache;
if ((tableCache = pthread_getspecific(gold_table_key)) == NULL) {
tableCache = calloc(1, sizeof(gold_cache_table_t));
(void)pthread_setspecific(gold_table_key, tableCache);
}
// align for AVX512
length = ((length + grain - 1) / grain) * grain;
tableCache->calls++;
// periodic refresh
if (tableCache->calls > REFRESH_RATE)
refresh_table(tableCache, 0);
uint32_t *ptr = tableCache->table;
// check if already cached
for (; ptr < tableCache->table + tableCache->tblSz; ptr += roundedHeaderSz) {
gold_cache_t *tbl = (gold_cache_t *)ptr;
tableCache->iterate++;
if (tbl->length >= length && tbl->key == key) {
tbl->usage++;
return ptr + roundedHeaderSz;
}
if (tbl->key == key) {
// We use a longer sequence, same key
// let's delete the shorter and force reorganize
tbl->usage = 0;
tableCache->calls += REFRESH_RATE;
}
if (!tbl->length)
break;
ptr += tbl->length;
}
// not enough space in the table
if (!ptr || ptr > tableCache->table + tableCache->tblSz - (2 * roundedHeaderSz + length))
refresh_table(tableCache, 2 * roundedHeaderSz + length);
// We will add a new entry
uint32_t *firstFree;
int size = 0;
for (firstFree = tableCache->table; firstFree < tableCache->table + tableCache->tblSz; firstFree += roundedHeaderSz) {
gold_cache_t *tbl = (gold_cache_t *)firstFree;
if (!tbl->length)
break;
firstFree += tbl->length;
size++;
}
if (!tableCache->calls)
LOG_D(PHY, "Number of entries (after reorganization) in gold cache: %d\n", size);
gold_cache_t *new = (gold_cache_t *)firstFree;
*new = (gold_cache_t){.key = key, .length = length, .usage = 1};
unsigned int x1 = 0, x2 = key;
uint32_t *sequence = firstFree + roundedHeaderSz;
*sequence++ = lte_gold_generic(&x1, &x2, 1);
for (int n = 1; n < length; n++)
*sequence++ = lte_gold_generic(&x1, &x2, 0);
LOG_D(PHY, "created a gold sequence, start %d; len %d\n", key, length);
return firstFree + roundedHeaderSz;
}
uint32_t *nr_gold_pbch(int Lmax, int Nid, int n_hf, int l)
{
int i_ssb = l & (Lmax - 1);
int i_ssb2 = i_ssb + (n_hf << 2);
uint32_t x2 = (1 << 11) * (i_ssb2 + 1) * ((Nid >> 2) + 1) + (1 << 6) * (i_ssb2 + 1) + (Nid & 3);
return gold_cache(x2, NR_PBCH_DMRS_LENGTH_DWORD);
}
uint32_t *nr_gold_pdcch(int N_RB_DL, int symbols_per_slot, unsigned short nid, int ns, int l)
{
int pdcch_dmrs_init_length = (((N_RB_DL << 1) * 3) >> 5) + 1;
uint64_t x2tmp0 = (((uint64_t)symbols_per_slot * ns + l + 1) * ((nid << 1) + 1));
x2tmp0 <<= 17;
x2tmp0 += (nid << 1);
uint32_t x2 = x2tmp0 % (1U << 31); // cinit
LOG_D(PHY, "PDCCH DMRS slot %d, symb %d, Nid %d, x2 %x\n", ns, l, nid, x2);
return gold_cache(x2, pdcch_dmrs_init_length);
}
uint32_t *nr_gold_pdsch(int N_RB_DL, int symbols_per_slot, int nid, int nscid, int slot, int symbol)
{
int pdsch_dmrs_init_length = ((N_RB_DL * 24) >> 5) + 1;
uint64_t x2tmp0 = (((uint64_t)symbols_per_slot * slot + symbol + 1) * (((uint64_t)nid << 1) + 1)) << 17;
uint32_t x2 = (x2tmp0 + (nid << 1) + nscid) % (1U << 31); // cinit
LOG_D(PHY, "UE DMRS slot %d, symb %d, nscid %d, x2 %x\n", slot, symbol, nscid, x2);
return gold_cache(x2, pdsch_dmrs_init_length);
}
uint32_t *nr_gold_pusch(int N_RB_UL, int symbols_per_slot, int Nid, int nscid, int slot, int symbol)
{
return nr_gold_pdsch(N_RB_UL, symbols_per_slot, Nid, nscid, slot, symbol);
}
uint32_t *nr_gold_csi_rs(int N_RB_DL, int symbols_per_slot, int slot, int symb, uint32_t Nid)
{
int csi_dmrs_init_length = ((N_RB_DL << 4) >> 5) + 1;
uint64_t temp_x2 = (1ULL << 10) * ((uint64_t)symbols_per_slot * slot + symb + 1) * ((Nid << 1) + 1) + Nid;
uint32_t x2 = temp_x2 % (1U << 31);
return gold_cache(x2, csi_dmrs_init_length);
}
uint32_t *nr_gold_prs(int Nid, int slotNum, int symNum)
{
LOG_D(PHY, "Initialised NR-PRS sequence for PCI %d\n", Nid);
// initial x2 for prs as ts138.211
uint32_t pow22 = 1 << 22;
uint32_t pow10 = 1 << 10;
uint32_t c_init1 = pow22 * ceil(Nid / 1024);
uint32_t c_init2 = pow10 * (slotNum + symNum + 1) * (2 * (Nid % 1024) + 1);
uint32_t c_init3 = Nid % 1024;
uint32_t x2 = c_init1 + c_init2 + c_init3;
return gold_cache(x2, NR_MAX_PRS_INIT_LENGTH_DWORD);
}