Skip to content

Commit

Permalink
iwlwifi: dbg_ini: implement monitor allocation flow
Browse files Browse the repository at this point in the history
Allow allocating fragmented buffers for several allocation IDs.

Signed-off-by: Shahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
  • Loading branch information
Shahar S Matityahu authored and Luca Coelho committed Oct 25, 2019
1 parent cf29c5b commit 14124b2
Showing 1 changed file with 248 additions and 1 deletion.
249 changes: 248 additions & 1 deletion drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,34 @@ void iwl_dbg_tlv_del_timers(struct iwl_trans *trans)
}
IWL_EXPORT_SYMBOL(iwl_dbg_tlv_del_timers);

static void iwl_dbg_tlv_fragments_free(struct iwl_trans *trans,
enum iwl_fw_ini_allocation_id alloc_id)
{
struct iwl_fw_mon *fw_mon;
int i;

if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID ||
alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
return;

fw_mon = &trans->dbg.fw_mon_ini[alloc_id];

for (i = 0; i < fw_mon->num_frags; i++) {
struct iwl_dram_data *frag = &fw_mon->frags[i];

dma_free_coherent(trans->dev, frag->size, frag->block,
frag->physical);

frag->physical = 0;
frag->block = NULL;
frag->size = 0;
}

kfree(fw_mon->frags);
fw_mon->frags = NULL;
fw_mon->num_frags = 0;
}

void iwl_dbg_tlv_free(struct iwl_trans *trans)
{
struct iwl_dbg_tlv_node *tlv_node, *tlv_node_tmp;
Expand Down Expand Up @@ -357,6 +385,9 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans)
kfree(tlv_node);
}
}

for (i = 0; i < ARRAY_SIZE(trans->dbg.fw_mon_ini); i++)
iwl_dbg_tlv_fragments_free(trans, i);
}

static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
Expand Down Expand Up @@ -418,6 +449,187 @@ void iwl_dbg_tlv_init(struct iwl_trans *trans)
}
}

static int iwl_dbg_tlv_alloc_fragment(struct iwl_fw_runtime *fwrt,
struct iwl_dram_data *frag, u32 pages)
{
void *block = NULL;
dma_addr_t physical;

if (!frag || frag->size || !pages)
return -EIO;

while (pages) {
block = dma_alloc_coherent(fwrt->dev, pages * PAGE_SIZE,
&physical,
GFP_KERNEL | __GFP_NOWARN);
if (block)
break;

IWL_WARN(fwrt, "WRT: Failed to allocate fragment size %lu\n",
pages * PAGE_SIZE);

pages = DIV_ROUND_UP(pages, 2);
}

if (!block)
return -ENOMEM;

frag->physical = physical;
frag->block = block;
frag->size = pages * PAGE_SIZE;

return pages;
}

static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_allocation_id alloc_id)
{
struct iwl_fw_mon *fw_mon;
struct iwl_fw_ini_allocation_tlv *fw_mon_cfg;
u32 num_frags, remain_pages, frag_pages;
int i;

if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID ||
alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
return -EIO;

fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id];
fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];

if (fw_mon->num_frags ||
fw_mon_cfg->buf_location !=
cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH))
return 0;

num_frags = le32_to_cpu(fw_mon_cfg->max_frags_num);
if (!fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP)) {
if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
return -EIO;
num_frags = 1;
}

remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size),
PAGE_SIZE);
num_frags = min_t(u32, num_frags, BUF_ALLOC_MAX_NUM_FRAGS);
num_frags = min_t(u32, num_frags, remain_pages);
frag_pages = DIV_ROUND_UP(remain_pages, num_frags);

fw_mon->frags = kcalloc(num_frags, sizeof(*fw_mon->frags), GFP_KERNEL);
if (!fw_mon->frags)
return -ENOMEM;

for (i = 0; i < num_frags; i++) {
int pages = min_t(u32, frag_pages, remain_pages);

IWL_DEBUG_FW(fwrt,
"WRT: Allocating DRAM buffer (alloc_id=%u, fragment=%u, size=0x%lx)\n",
alloc_id, i, pages * PAGE_SIZE);

pages = iwl_dbg_tlv_alloc_fragment(fwrt, &fw_mon->frags[i],
pages);
if (pages < 0) {
u32 alloc_size = le32_to_cpu(fw_mon_cfg->req_size) -
(remain_pages * PAGE_SIZE);

if (alloc_size < le32_to_cpu(fw_mon_cfg->min_size)) {
iwl_dbg_tlv_fragments_free(fwrt->trans,
alloc_id);
return pages;
}
break;
}

remain_pages -= pages;
fw_mon->num_frags++;
}

return 0;
}

static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_allocation_id alloc_id)
{
struct iwl_fw_mon *fw_mon;
u32 remain_frags, num_commands;
int i, fw_mon_idx = 0;

if (!fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP))
return 0;

if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID ||
alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
return -EIO;

if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) !=
IWL_FW_INI_LOCATION_DRAM_PATH)
return 0;

fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];

/* the first fragment of DBGC1 is given to the FW via register
* or context info
*/
if (alloc_id == IWL_FW_INI_ALLOCATION_ID_DBGC1)
fw_mon_idx++;

remain_frags = fw_mon->num_frags - fw_mon_idx;
if (!remain_frags)
return 0;

num_commands = DIV_ROUND_UP(remain_frags, BUF_ALLOC_MAX_NUM_FRAGS);

IWL_DEBUG_FW(fwrt, "WRT: Applying DRAM destination (alloc_id=%u)\n",
alloc_id);

for (i = 0; i < num_commands; i++) {
u32 num_frags = min_t(u32, remain_frags,
BUF_ALLOC_MAX_NUM_FRAGS);
struct iwl_buf_alloc_cmd data = {
.alloc_id = cpu_to_le32(alloc_id),
.num_frags = cpu_to_le32(num_frags),
.buf_location =
cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH),
};
struct iwl_host_cmd hcmd = {
.id = WIDE_ID(DEBUG_GROUP, BUFFER_ALLOCATION),
.data[0] = &data,
.len[0] = sizeof(data),
};
int ret, j;

for (j = 0; j < num_frags; j++) {
struct iwl_buf_alloc_frag *frag = &data.frags[j];
struct iwl_dram_data *fw_mon_frag =
&fw_mon->frags[fw_mon_idx++];

frag->addr = cpu_to_le64(fw_mon_frag->physical);
frag->size = cpu_to_le32(fw_mon_frag->size);
}
ret = iwl_trans_send_cmd(fwrt->trans, &hcmd);
if (ret)
return ret;

remain_frags -= num_frags;
}

return 0;
}

static void iwl_dbg_tlv_apply_buffers(struct iwl_fw_runtime *fwrt)
{
int ret, i;

for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) {
ret = iwl_dbg_tlv_apply_buffer(fwrt, i);
if (ret)
IWL_WARN(fwrt,
"WRT: Failed to apply DRAM buffer for allocation id %d, ret=%d\n",
i, ret);
}
}

static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt,
struct list_head *hcmd_list)
{
Expand Down Expand Up @@ -670,6 +882,36 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt,
return 0;
}

static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt)
{
enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest;
int ret, i;

iwl_dbg_tlv_gen_active_trigs(fwrt, IWL_FW_DBG_DOMAIN);

*ini_dest = IWL_FW_INI_LOCATION_INVALID;
for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) {
struct iwl_fw_ini_allocation_tlv *fw_mon_cfg =
&fwrt->trans->dbg.fw_mon_cfg[i];
u32 dest = le32_to_cpu(fw_mon_cfg->buf_location);

if (dest == IWL_FW_INI_LOCATION_INVALID)
continue;

if (*ini_dest == IWL_FW_INI_LOCATION_INVALID)
*ini_dest = dest;

if (dest != *ini_dest)
continue;

ret = iwl_dbg_tlv_alloc_fragments(fwrt, i);
if (ret)
IWL_WARN(fwrt,
"WRT: Failed to allocate DRAM buffer for allocation id %d, ret=%d\n",
i, ret);
}
}

void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_time_point tp_id,
union iwl_dbg_tlv_tp_data *tp_data)
Expand All @@ -686,7 +928,12 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,

switch (tp_id) {
case IWL_FW_INI_TIME_POINT_EARLY:
iwl_dbg_tlv_gen_active_trigs(fwrt, IWL_FW_DBG_DOMAIN);
iwl_dbg_tlv_init_cfg(fwrt);
iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL);
break;
case IWL_FW_INI_TIME_POINT_AFTER_ALIVE:
iwl_dbg_tlv_apply_buffers(fwrt);
iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL);
break;
default:
Expand Down

0 comments on commit 14124b2

Please sign in to comment.