blob: 0d415b7d32e94554195100fc3c304df60a0ab4ef [file] [log] [blame]
/*
* Copyright (c) 2018-2020 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.
*/
#include "ipa_table.h"
#include "ipa_nat_utils.h"
#include <errno.h>
#define IPA_BASE_TABLE_PERCENTAGE .8
#define IPA_EXPANSION_TABLE_PERCENTAGE .2
#define IPA_BASE_TABLE_PCNT_4SRAM 1.00
#define IPA_EXPANSION_TABLE_PCNT_4SRAM 0.43
/*
* The table number of entries is limited by Entry ID structure
* above. The base table max entries is limited by index into table
* bits number.
*
* The table max ents number is: (base table max ents / base table percentage)
*
* IPA_TABLE_MAX_ENTRIES = 2^(index into table) / IPA_BASE_TABLE_PERCENTAGE
*/
static int InsertHead(
ipa_table* table,
void* rec_ptr, /* empty record in table */
uint16_t rec_index, /* index of record above */
void* user_data,
struct ipa_ioc_nat_dma_cmd* cmd );
static int InsertTail(
ipa_table* table,
void* rec_ptr, /* occupied record at index below */
uint16_t* rec_index_ptr, /* pointer to index of record above */
void* user_data,
struct ipa_ioc_nat_dma_cmd* cmd );
static uint16_t MakeEntryHdl(
ipa_table* tbl,
uint16_t tbl_entry );
static int FindExpnTblFreeEntry(
ipa_table* table,
void** free_entry,
uint16_t* entry_index );
static int Get2PowerTightUpperBound(
uint16_t num);
static int GetEvenTightUpperBound(
uint16_t num);
void ipa_table_init(
ipa_table* table,
const char* table_name,
enum ipa3_nat_mem_in nmi,
int entry_size,
void* meta,
int meta_entry_size,
ipa_table_entry_interface* entry_interface )
{
IPADBG("In\n");
memset(table, 0, sizeof(ipa_table));
strlcpy(table->name, table_name, IPA_RESOURCE_NAME_MAX);
table->nmi = nmi;
table->entry_size = entry_size;
table->meta = meta;
table->meta_entry_size = meta_entry_size;
table->entry_interface = entry_interface;
IPADBG("Table %s with entry size %d has been initialized\n",
table->name, table->entry_size);
IPADBG("Out\n");
}
int ipa_table_calculate_entries_num(
ipa_table* table,
uint16_t number_of_entries,
enum ipa3_nat_mem_in nmi)
{
uint16_t table_entries, expn_table_entries;
float btp, etp;
int result = 0;
IPADBG("In\n");
if (number_of_entries > IPA_TABLE_MAX_ENTRIES)
{
IPAERR("Required number of %s entries %d exceeds the maximum %d\n",
table->name, number_of_entries, IPA_TABLE_MAX_ENTRIES);
result = -EINVAL;
goto bail;
}
if ( nmi == IPA_NAT_MEM_IN_SRAM )
{
btp = IPA_BASE_TABLE_PCNT_4SRAM;
etp = IPA_EXPANSION_TABLE_PCNT_4SRAM;
}
else
{
btp = IPA_BASE_TABLE_PERCENTAGE;
etp = IPA_EXPANSION_TABLE_PERCENTAGE;
}
table_entries = Get2PowerTightUpperBound(number_of_entries * btp);
expn_table_entries = GetEvenTightUpperBound(number_of_entries * etp);
table->tot_tbl_ents = table_entries + expn_table_entries;
if ( table->tot_tbl_ents > IPA_TABLE_MAX_ENTRIES )
{
IPAERR("Required number of %s entries %u "
"(user provided %u) exceeds the maximum %u\n",
table->name,
table->tot_tbl_ents,
number_of_entries,
IPA_TABLE_MAX_ENTRIES);
result = -EINVAL;
goto bail;
}
table->table_entries = table_entries;
table->expn_table_entries = expn_table_entries;
IPADBG("Num of %s entries:%u expn entries:%u total entries:%u\n",
table->name,
table->table_entries,
table->expn_table_entries,
table->tot_tbl_ents);
bail:
IPADBG("Out\n");
return result;
}
int ipa_table_calculate_size(ipa_table* table)
{
int size = table->entry_size * (table->table_entries + table->expn_table_entries);
IPADBG("In\n");
IPADBG("%s size: %d\n", table->name, size);
IPADBG("Out\n");
return size;
}
uint8_t* ipa_table_calculate_addresses(
ipa_table* table,
uint8_t* base_addr)
{
uint8_t* result = NULL;
IPADBG("In\n");
table->table_addr = base_addr;
table->expn_table_addr =
table->table_addr + table->entry_size * table->table_entries;
IPADBG("Table %s addresses: table_addr %pK expn_table_addr %pK\n",
table->name, table->table_addr, table->expn_table_addr);
result = table->expn_table_addr + table->entry_size * table->expn_table_entries;
IPADBG("Out\n");
return result;
}
void ipa_table_reset(
ipa_table* table)
{
uint32_t i,tot;
IPADBG("In\n");
IPADBG("memset %s table to 0, %pK\n", table->name, table->table_addr);
tot = table->entry_size * table->table_entries;
for (i = 0; i < tot; i++)
table->table_addr[i] = '\0';
IPADBG("memset %s expn table to 0, %pK\n", table->name, table->expn_table_addr);
tot = table->entry_size * table->expn_table_entries;
for (i = 0; i < tot; i++)
table->expn_table_addr[i] = '\0';
IPADBG("Out\n");
}
int ipa_table_add_entry(
ipa_table* table,
void* user_data,
uint16_t* rec_index_ptr,
uint32_t* rule_hdl,
struct ipa_ioc_nat_dma_cmd* cmd )
{
void* rec_ptr;
int ret = 0, occupied;
IPADBG("In\n");
rec_ptr = GOTO_REC(table, *rec_index_ptr);
/*
* Check whether there is any collision
*/
occupied = table->entry_interface->entry_is_valid(rec_ptr);
if ( ! occupied )
{
IPADBG("Collision free (in %s) ... found open slot\n", table->name);
ret = InsertHead(table, rec_ptr, *rec_index_ptr, user_data, cmd);
}
else
{
IPADBG("Collision (in %s) ... will probe for open slot\n", table->name);
ret = InsertTail(table, rec_ptr, rec_index_ptr, user_data, cmd);
}
if (ret)
goto bail;
IPADBG("New Entry Index %u in %s\n", *rec_index_ptr, table->name);
if ( rule_hdl ) {
*rule_hdl = MakeEntryHdl(table, *rec_index_ptr);
IPADBG("rule_hdl value(%u)\n", *rule_hdl);
}
bail:
IPADBG("Out\n");
return ret;
}
void ipa_table_create_delete_command(
ipa_table* table,
struct ipa_ioc_nat_dma_cmd* cmd,
ipa_table_iterator* iterator)
{
IPADBG("In\n");
IPADBG("Delete rule at index(0x%04X) in %s\n",
iterator->curr_index,
table->name);
if ( ! VALID_INDEX(iterator->prev_index) )
{
/*
* The following two assigns (ie. the defaults), will cause
* the enabled bit in the record to be set to 0.
*/
uint16_t data = 0;
dma_help_type ht = HELP_UPDATE_HEAD;
if ( VALID_INDEX(iterator->next_index) )
{
/*
* NOTE WELL HERE:
*
* This record is the first in a chain/list of
* records. Delete means something different in this
* context.
*
* The code below will cause the change of the protocol
* field in the rule record to 0xFF. It does not set the
* enable bit in the record to 0. This is done in special
* cases when the record being deleted is the first in a
* list of records.
*
* What does this mean? It means that the record is
* functionally deleted, but not really deleted. Why?
* Because the IPA will no longer use it because of the
* bad protocol (ie. functionally deleted), but these
* higher level APIs still see it as "enabled."
*
* This all means that deleted really means two things: 1)
* Not enabled, and 2) Not a valid record. APIs that walk
* the table...looking for enabled records (ie. the
* enabled bit)....now have to be a bit smarter to see the
* bad protocol as well.
*/
data = table->entry_interface->
entry_get_delete_head_dma_command_data(
iterator->curr_entry, iterator->next_entry);
ht = HELP_DELETE_HEAD;
}
ipa_table_add_dma_cmd(table,
ht,
iterator->curr_entry,
iterator->curr_index,
data,
cmd);
}
else
{
ipa_table_add_dma_cmd(table,
HELP_UPDATE_ENTRY,
iterator->prev_entry,
iterator->prev_index,
iterator->next_index,
cmd);
}
IPADBG("Out\n");
}
void ipa_table_delete_entry(
ipa_table* table,
ipa_table_iterator* iterator,
uint8_t is_prev_empty)
{
IPADBG("In\n");
if ( VALID_INDEX(iterator->next_index) )
{
/*
* Update the next entry's prev_index field with current
* entry's prev_index
*/
table->entry_interface->entry_set_prev_index(
iterator->next_entry,
iterator->next_index,
iterator->prev_index,
table->meta,
table->table_entries);
}
else if (is_prev_empty)
{
if (iterator->prev_entry == NULL)
{
IPAERR("failed to delete of an empty head %d while delete the next entry %d in %s",
iterator->prev_index, iterator->curr_index, table->name);
}
else
{
/*
* Delete an empty head rule after the whole tail was deleted
*/
IPADBG("deleting the dead node %d for %s\n",
iterator->prev_index, table->name);
memset(iterator->prev_entry, 0, table->entry_size);
--table->cur_tbl_cnt;
}
}
ipa_table_erase_entry(table, iterator->curr_index);
IPADBG("Out\n");
}
void ipa_table_erase_entry(
ipa_table* table,
uint16_t index)
{
void* entry = GOTO_REC(table, index);
IPADBG("In\n");
IPADBG("table(%p) index(%u)\n", table, index);
memset(entry, 0, table->entry_size);
if ( index < table->table_entries )
{
--table->cur_tbl_cnt;
}
else
{
--table->cur_expn_tbl_cnt;
}
IPADBG("Out\n");
}
/**
* ipa_table_get_entry() - returns a table entry according to the received entry handle
* @table: [in] the table
* @entry_handle: [in] entry handle
* @entry: [out] the retrieved entry
* @entry_index: [out] absolute index of the retrieved entry
*
* Parse the entry handle to retrieve the entry and its index
*
* Returns: 0 on success, negative on failure
*/
int ipa_table_get_entry(
ipa_table* table,
uint32_t entry_handle,
void** entry,
uint16_t* entry_index )
{
enum ipa3_nat_mem_in nmi;
uint8_t is_expn_tbl;
uint16_t rec_index;
int ret = 0;
IPADBG("In\n");
IPADBG("table(%p) entry_handle(%u) entry(%p) entry_index(%p)\n",
table, entry_handle, entry, entry_index);
/*
* Retrieve the memory and table type as well as the index
*/
BREAK_RULE_HDL(table, entry_handle, nmi, is_expn_tbl, rec_index);
if ( is_expn_tbl )
{
IPADBG("Retrieving entry from expansion table\n");
}
else
{
IPADBG("Retrieving entry from base (non-expansion) table\n");
}
if ( rec_index >= table->tot_tbl_ents )
{
IPAERR("The entry handle's record index (%u) exceeds table size (%u)\n",
rec_index, table->tot_tbl_ents);
ret = -EINVAL;
goto bail;
}
*entry = GOTO_REC(table, rec_index);
if ( entry_index )
{
*entry_index = rec_index;
}
bail:
IPADBG("Out\n");
return ret;
}
void* ipa_table_get_entry_by_index(
ipa_table* table,
uint16_t rec_index )
{
void* result = NULL;
IPADBG("In\n");
IPADBG("table(%p) rec_index(%u)\n",
table,
rec_index);
if ( ! rec_index || rec_index >= table->tot_tbl_ents )
{
IPAERR("Invalid record index (%u): It's "
"either zero or exceeds table size (%u)\n",
rec_index, table->tot_tbl_ents);
goto bail;
}
result = GOTO_REC(table, rec_index);
bail:
IPADBG("Out\n");
return result;
}
void ipa_table_dma_cmd_helper_init(
ipa_table_dma_cmd_helper* dma_cmd_helper,
uint8_t table_indx,
ipa_table_dma_type table_type,
ipa_table_dma_type expn_table_type,
uint32_t offset)
{
IPADBG("In\n");
dma_cmd_helper->offset = offset;
dma_cmd_helper->table_indx = table_indx;
dma_cmd_helper->table_type = table_type;
dma_cmd_helper->expn_table_type = expn_table_type;
IPADBG("Out\n");
}
void ipa_table_dma_cmd_generate(
ipa_table_dma_cmd_helper* dma_cmd_helper,
uint8_t is_expn,
uint32_t entry_offset,
uint16_t data,
struct ipa_ioc_nat_dma_cmd* cmd)
{
struct ipa_ioc_nat_dma_one* dma = &cmd->dma[cmd->entries];
IPADBG("In\n");
IPADBG("is_expn(0x%02X) entry_offset(0x%08X) data(0x%04X)\n",
is_expn, entry_offset, data);
dma->table_index = dma_cmd_helper->table_indx;
/*
* DMA parameter base_addr is the table type (see the IPA
* architecture document)
*/
dma->base_addr =
(is_expn) ?
dma_cmd_helper->expn_table_type :
dma_cmd_helper->table_type;
dma->offset = dma_cmd_helper->offset + entry_offset;
dma->data = data;
IPADBG("dma_entry[%u](table_index(0x%02X) "
"base_addr(0x%02X) data(0x%04X) offset(0x%08X))\n",
cmd->entries,
dma->table_index,
dma->base_addr,
dma->data,
dma->offset);
cmd->entries++;
IPADBG("Out\n");
}
int ipa_table_iterator_init(
ipa_table_iterator* iterator,
ipa_table* table,
void* curr_entry,
uint16_t curr_index)
{
int occupied;
int ret = 0;
IPADBG("In\n");
memset(iterator, 0, sizeof(ipa_table_iterator));
occupied = table->entry_interface->entry_is_valid(curr_entry);
if ( ! occupied )
{
IPAERR("Invalid (not enabled) rule %u in %s\n", curr_index, table->name);
ret = -EINVAL;
goto bail;
}
iterator->curr_entry = curr_entry;
iterator->curr_index = curr_index;
iterator->prev_index = table->entry_interface->entry_get_prev_index(
curr_entry,
curr_index,
table->meta,
table->table_entries);
iterator->next_index = table->entry_interface->entry_get_next_index(
curr_entry);
if ( VALID_INDEX(iterator->prev_index) )
{
iterator->prev_entry = ipa_table_get_entry_by_index(
table,
iterator->prev_index);
if ( iterator->prev_entry == NULL )
{
IPAERR("Failed to retrieve the entry at index 0x%04X for %s\n",
iterator->prev_index, table->name);
ret = -EPERM;
goto bail;
}
}
if ( VALID_INDEX(iterator->next_index) )
{
iterator->next_entry = ipa_table_get_entry_by_index(
table,
iterator->next_index);
if ( iterator->next_entry == NULL )
{
IPAERR("Failed to retrieve the entry at index 0x%04X for %s\n",
iterator->next_index, table->name);
ret = -EPERM;
goto bail;
}
}
IPADBG("[index/entry] for "
"prev:[0x%04X/%p] "
"curr:[0x%04X/%p] "
"next:[0x%04X/%p] "
"\"%s\"\n",
iterator->prev_index,
iterator->prev_entry,
iterator->curr_index,
iterator->curr_entry,
iterator->next_index,
iterator->next_entry,
table->name);
bail:
IPADBG("Out\n");
return ret;
}
int ipa_table_iterator_next(
ipa_table_iterator* iterator,
ipa_table* table)
{
int ret = 0;
IPADBG("In\n");
iterator->prev_entry = iterator->curr_entry;
iterator->prev_index = iterator->curr_index;
iterator->curr_entry = iterator->next_entry;
iterator->curr_index = iterator->next_index;
iterator->next_index = table->entry_interface->entry_get_next_index(
iterator->curr_entry);
if ( ! VALID_INDEX(iterator->next_index) )
{
iterator->next_entry = NULL;
}
else
{
iterator->next_entry = ipa_table_get_entry_by_index(
table, iterator->next_index);
if (iterator->next_entry == NULL)
{
IPAERR("Failed to retrieve the entry at index %d for %s\n",
iterator->next_index, table->name);
ret = -EPERM;
goto bail;
}
}
IPADBG("Iterator moved to: prev_index=%d curr_index=%d next_index=%d\n",
iterator->prev_index, iterator->curr_index, iterator->next_index);
IPADBG(" prev_entry=%pK curr_entry=%pK next_entry=%pK\n",
iterator->prev_entry, iterator->curr_entry, iterator->next_entry);
bail:
IPADBG("Out\n");
return ret;
}
int ipa_table_iterator_end(
ipa_table_iterator* iterator,
ipa_table* table_ptr,
uint16_t rec_index, /* a table slot relative to hash */
void* rec_ptr ) /* occupant record at index above */
{
bool found_end = false;
int ret;
IPADBG("In\n");
if ( ! iterator || ! table_ptr || ! rec_ptr )
{
IPAERR("Bad arg: iterator(%p) and/or table_ptr (%p) and/or rec_ptr(%p)\n",
iterator, table_ptr, rec_ptr);
ret = -1;
goto bail;
}
memset(iterator, 0, sizeof(ipa_table_iterator));
iterator->prev_index = rec_index;
iterator->prev_entry = rec_ptr;
while ( 1 )
{
uint16_t next_index =
table_ptr->entry_interface->entry_get_next_index(iterator->prev_entry);
if ( ! VALID_INDEX(next_index) )
{
found_end = true;
break;
}
if ( next_index == iterator->prev_index )
{
IPAERR("next_index(%u) and prev_index(%u) shouldn't be equal in %s\n",
next_index,
iterator->prev_index,
table_ptr->name);
break;
}
iterator->prev_index = next_index;
iterator->prev_entry = GOTO_REC(table_ptr, next_index);
}
if ( found_end )
{
IPADBG("Iterator found end of list record\n");
ret = 0;
}
else
{
IPAERR("Iterator can't find end of list record\n");
ret = -1;
}
bail:
IPADBG("Out\n");
return ret;
}
int ipa_table_iterator_is_head_with_tail(
ipa_table_iterator* iterator)
{
int ret = 0;
IPADBG("In\n");
ret = VALID_INDEX(iterator->next_index) && ! VALID_INDEX(iterator->prev_index);
IPADBG("Out\n");
return ret;
}
static int InsertHead(
ipa_table* table,
void* rec_ptr, /* empty record in table */
uint16_t rec_index, /* index of record above */
void* user_data,
struct ipa_ioc_nat_dma_cmd* cmd )
{
uint16_t enable_data = 0;
int ret = 0;
IPADBG("In\n");
ret = table->entry_interface->entry_head_insert(
rec_ptr,
user_data,
&enable_data);
if (ret)
{
IPAERR("unable to insert a new entry to the head in %s\n", table->name);
goto bail;
}
ipa_table_add_dma_cmd(
table,
HELP_UPDATE_HEAD,
rec_ptr,
rec_index,
enable_data,
cmd);
++table->cur_tbl_cnt;
bail:
IPADBG("Out\n");
return ret;
}
static int InsertTail(
ipa_table* table,
void* rec_ptr, /* occupied record at index below */
uint16_t* rec_index_ptr, /* pointer to index of record above */
void* user_data,
struct ipa_ioc_nat_dma_cmd* cmd )
{
bool is_index_tbl = (table->meta) ? true : false;
ipa_table_iterator iterator;
uint16_t enable_data = 0;
int ret = 0;
IPADBG("In\n");
/*
* The most important side effect of the following is to set the
* iterator's prev_index and prev_entry...which will be the last
* valid entry on the end of the list.
*/
ret = ipa_table_iterator_end(&iterator, table, *rec_index_ptr, rec_ptr);
if ( ret )
{
IPAERR("Failed to reach the end of list following rec_index(%u) in %s\n",
*rec_index_ptr, table->name);
goto bail;
}
/*
* The most important side effect of the following is to set the
* iterator's curr_index and curr_entry with the next available
* expansion table open slot.
*/
ret = FindExpnTblFreeEntry(table, &iterator.curr_entry, &iterator.curr_index);
if ( ret )
{
IPAERR("FindExpnTblFreeEntry of %s failed\n", table->name);
goto bail;
}
/*
* Copy data into curr_entry (ie. open slot).
*/
if ( is_index_tbl )
{
ret = table->entry_interface->entry_tail_insert(
iterator.curr_entry,
user_data);
}
else
{
/*
* We need enable bit when not index table, hence...
*/
ret = table->entry_interface->entry_head_insert(
iterator.curr_entry,
user_data,
&enable_data);
}
if (ret)
{
IPAERR("Unable to insert a new entry to the tail in %s\n", table->name);
goto bail;
}
/*
* Update curr_entry's prev_index field with iterator.prev_index
*/
table->entry_interface->entry_set_prev_index(
iterator.curr_entry, /* set by FindExpnTblFreeEntry above */
iterator.curr_index, /* set by FindExpnTblFreeEntry above */
iterator.prev_index, /* set by ipa_table_iterator_end above */
table->meta,
table->table_entries);
if ( ! is_index_tbl )
{
/*
* Generate dma command to have the IPA update the
* curr_entry's enable field when not the index table...
*/
ipa_table_add_dma_cmd(
table,
HELP_UPDATE_HEAD,
iterator.curr_entry,
iterator.curr_index,
enable_data,
cmd);
}
/*
* Generate a dma command to have the IPA update the prev_entry's
* next_index with iterator.curr_index.
*/
ipa_table_add_dma_cmd(
table,
HELP_UPDATE_ENTRY,
iterator.prev_entry,
iterator.prev_index,
iterator.curr_index,
cmd);
++table->cur_expn_tbl_cnt;
*rec_index_ptr = iterator.curr_index;
bail:
IPADBG("Out\n");
return ret;
}
/**
* MakeEntryHdl() - makes an entry handle
* @tbl_hdl: [in] tbl - the table
* @tbl_entry: [in] tbl_entry - table entry
*
* Calculate the entry handle which will be returned to client
*
* Returns: >0 table entry handle
*/
static uint16_t MakeEntryHdl(
ipa_table* tbl,
uint16_t tbl_entry )
{
uint16_t entry_hdl = 0;
IPADBG("In\n");
if (tbl_entry >= tbl->table_entries)
{
/*
* Update the index into table
*/
entry_hdl = tbl_entry - tbl->table_entries;
entry_hdl = (entry_hdl << IPA_TABLE_TYPE_BITS);
/*
* Update the expansion table type bit
*/
entry_hdl = (entry_hdl | IPA_TABLE_TYPE_MASK);
}
else
{
entry_hdl = tbl_entry;
entry_hdl = (entry_hdl << IPA_TABLE_TYPE_BITS);
}
/*
* Set memory type bit.
*/
entry_hdl = entry_hdl | (tbl->nmi << IPA_TABLE_TYPE_MEM_SHIFT);
IPADBG("In: tbl_entry(%u) Out: entry_hdl(%u)\n", tbl_entry, entry_hdl);
IPADBG("Out\n");
return entry_hdl;
}
static int mt_slot(
ipa_table* table_ptr,
uint32_t rule_hdl,
void* record_ptr,
uint16_t record_index,
void* meta_record_ptr,
uint16_t meta_record_index,
void* arb_data_ptr )
{
IPADBG("%s: Empty expansion slot: (%u) in table of size: (%u)\n",
table_ptr->name,
record_index,
table_ptr->tot_tbl_ents);
return record_index;
}
/*
* returns expn table entry absolute index
*/
static int FindExpnTblFreeEntry(
ipa_table* table,
void** free_entry,
uint16_t* entry_index )
{
int ret;
IPADBG("In\n");
if ( ! table || ! free_entry || ! entry_index )
{
IPAERR("Bad arg: table(%p) and/or "
"free_entry(%p) and/or entry_index(%p)\n",
table, free_entry, entry_index);
ret = -1;
goto bail;
}
*entry_index = 0;
*free_entry = NULL;
/*
* The following will start walk at expansion slots
* (ie. just after table->table_entries)...
*/
ret = ipa_table_walk(table, table->table_entries, WHEN_SLOT_EMPTY, mt_slot, 0);
if ( ret > 0 )
{
*entry_index = (uint16_t) ret;
*free_entry = GOTO_REC(table, *entry_index);
IPADBG("%s: entry_index val (%u) free_entry val (%p)\n",
table->name,
*entry_index,
*free_entry);
ret = 0;
}
else
{
if ( ret < 0 )
{
IPAERR("%s: While searching table for emtpy slot\n",
table->name);
}
else
{
IPADBG("%s: No empty slots (ie. expansion table full): "
"BASE (avail/used): (%u/%u) EXPN (avail/used): (%u/%u)\n",
table->name,
table->table_entries,
table->cur_tbl_cnt,
table->expn_table_entries,
table->cur_expn_tbl_cnt);
}
ret = -1;
}
bail:
IPADBG("Out\n");
return ret;
}
/**
* Get2PowerTightUpperBound() - Returns the tight upper bound which is a power of 2
* @num: [in] given number
*
* Returns the tight upper bound for a given number which is power of 2
*
* Returns: the tight upper bound which is power of 2
*/
static int Get2PowerTightUpperBound(uint16_t num)
{
uint16_t tmp = num, prev = 0, curr = 2;
if (num == 0)
return 2;
while (tmp != 1)
{
prev = curr;
curr <<= 1;
tmp >>= 1;
}
return (num == prev) ? prev : curr;
}
/**
* GetEvenTightUpperBound() - Returns the tight upper bound which is an even number
* @num: [in] given number
*
* Returns the tight upper bound for a given number which is an even number
*
* Returns: the tight upper bound which is an even number
*/
static int GetEvenTightUpperBound(uint16_t num)
{
if (num == 0)
return 2;
return (num % 2) ? num + 1 : num;
}
int ipa_calc_num_sram_table_entries(
uint32_t sram_size,
uint32_t table1_ent_size,
uint32_t table2_ent_size,
uint16_t* num_entries_ptr)
{
ipa_table nat_table;
ipa_table index_table;
int size = 0;
uint16_t tot;
IPADBG("In\n");
IPADBG("sram_size(%x or %u)\n", sram_size, sram_size);
*num_entries_ptr = 0;
tot = 1;
while ( 1 )
{
IPADBG("Trying %u entries\n", tot);
ipa_table_init(&nat_table,
"tmp_sram_table1",
IPA_NAT_MEM_IN_DDR,
table1_ent_size,
NULL,
0,
NULL);
ipa_table_init(&index_table,
"tmp_sram_table1",
IPA_NAT_MEM_IN_DDR,
table2_ent_size,
NULL,
0,
NULL);
nat_table.table_entries = index_table.table_entries =
Get2PowerTightUpperBound(tot * IPA_BASE_TABLE_PCNT_4SRAM);
nat_table.expn_table_entries = index_table.expn_table_entries =
GetEvenTightUpperBound(tot * IPA_EXPANSION_TABLE_PCNT_4SRAM);
size = ipa_table_calculate_size(&nat_table);
size += ipa_table_calculate_size(&index_table);
IPADBG("%u entries consumes size(0x%x or %u)\n", tot, size, size);
if ( size > sram_size )
break;
*num_entries_ptr = tot;
++tot;
}
IPADBG("Optimal number of entries: %u\n", *num_entries_ptr);
IPADBG("Out\n");
return (*num_entries_ptr) ? 0 : -1;
}
int ipa_table_walk(
ipa_table* ipa_tbl_ptr,
uint16_t start_index,
When2Callback when2cb,
ipa_table_walk_cb walk_cb,
void* arb_data_ptr )
{
uint16_t i;
uint32_t tot;
uint8_t* rec_ptr;
void* meta_record_ptr;
uint16_t meta_record_index;
int ret = 0;
IPADBG("In\n");
if ( ! ipa_tbl_ptr ||
! VALID_WHEN2CALLBACK(when2cb) ||
! walk_cb )
{
IPAERR("Bad arg: ipa_tbl_ptr(%p) and/or "
"when2cb(%u) and/or walk_cb(%p)\n",
ipa_tbl_ptr,
when2cb,
walk_cb);
ret = -EINVAL;
goto bail;
}
tot =
ipa_tbl_ptr->table_entries +
ipa_tbl_ptr->expn_table_entries;
if ( start_index >= tot )
{
IPAERR("Bad arg: start_index(%u)\n", start_index);
ret = -EINVAL;
goto bail;
}
/*
* Go through table...
*/
for ( i = start_index, rec_ptr = GOTO_REC(ipa_tbl_ptr, start_index);
i < tot;
i++, rec_ptr += ipa_tbl_ptr->entry_size )
{
bool call_back;
if ( ipa_tbl_ptr->entry_interface->entry_is_valid(rec_ptr) )
{
call_back = (when2cb == WHEN_SLOT_FILLED) ? true : false;
}
else
{
call_back = (when2cb == WHEN_SLOT_EMPTY) ? true : false;
}
if ( call_back )
{
uint32_t rule_hdl = MakeEntryHdl(ipa_tbl_ptr, i);
meta_record_ptr = NULL;
meta_record_index = 0;
if ( i >= ipa_tbl_ptr->table_entries && ipa_tbl_ptr->meta )
{
meta_record_index = i - ipa_tbl_ptr->table_entries;
meta_record_ptr = (uint8_t*) ipa_tbl_ptr->meta +
(meta_record_index * ipa_tbl_ptr->meta_entry_size);
}
ret = walk_cb(
ipa_tbl_ptr,
rule_hdl,
rec_ptr,
i,
meta_record_ptr,
meta_record_index,
arb_data_ptr);
if ( ret != 0 )
{
if ( ret < 0 )
{
IPAERR("walk_cb returned non-zero (%d)\n", ret);
}
else
{
IPADBG("walk_cb returned non-zero (%d)\n", ret);
}
goto bail;
}
}
}
bail:
IPADBG("Out\n");
return ret;
}
int ipa_table_add_dma_cmd(
ipa_table* tbl_ptr,
dma_help_type help_type,
void* rec_ptr,
uint16_t rec_index,
uint16_t data_for_entry,
struct ipa_ioc_nat_dma_cmd* cmd_ptr )
{
ipa_table_dma_cmd_helper* help_ptr;
uint32_t tab_sz, entry_offset;
uint8_t is_expn;
int ret = 0;
IPADBG("In\n");
if ( ! tbl_ptr ||
! VALID_DMA_HELP_TYPE(help_type) ||
! rec_ptr ||
! cmd_ptr )
{
IPAERR("Bad arg: tbl_ptr(%p) and/or help_type(%u) "
"and/or rec_ptr(%p) and/or cmd_ptr(%p)\n",
tbl_ptr,
help_type,
rec_ptr,
cmd_ptr);
ret = -EINVAL;
goto bail;
}
tab_sz =
tbl_ptr->table_entries +
tbl_ptr->expn_table_entries;
if ( rec_index >= tab_sz )
{
IPAERR("Bad arg: rec_index(%u)\n", rec_index);
ret = -EINVAL;
goto bail;
}
is_expn = (rec_index >= tbl_ptr->table_entries);
entry_offset = (uint8_t*) rec_ptr -
((is_expn) ? tbl_ptr->expn_table_addr : tbl_ptr->table_addr);
ipa_table_dma_cmd_generate(
tbl_ptr->dma_help[help_type],
is_expn,
entry_offset,
data_for_entry,
cmd_ptr);
bail:
IPADBG("Out\n");
return ret;
}