Skip to content

Commit

Permalink
ath10k-ct: CCA, eeprom, other changes.
Browse files Browse the repository at this point in the history
* Support enabling CCA in latest wave-1 CT firmware.
* Append custom eeprom config from board.bin with latest wave-1 CT firmware.
  This can help users that need custom board.bin in conjunction with OTP.
* Add debugfs files to dump some raw power-table and other eeprom data.
  This is somewhat un-needed since at least recent kernels can already dump the
  entire eeprom.

Signed-off-by: Ben Greear <greearb@candelatech.com>
  • Loading branch information
greearb committed Apr 3, 2019
1 parent a696e60 commit 75e2705
Show file tree
Hide file tree
Showing 25 changed files with 2,021 additions and 66 deletions.
34 changes: 34 additions & 0 deletions ath10k-4.13/core.c
Expand Up @@ -1586,6 +1586,24 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar)
}

success:
/* Store configAddr overloads to apply after firmware boots. OTP will likely
* overwrite them and so they would otherwise be lost.
*/
if (ar->dev_id == QCA988X_2_0_DEVICE_ID) {
int addrs = 24;
int i;
u32 *e32 = (u32*)(ar->normal_mode_fw.board_data);
int offset = (ar->hw_params.cal_data_len - (addrs * 4)) / 4; /* Start of configAddr */
/*ath10k_dbg(ar, ATH10K_DBG_BOOT, "Check saving eeprom configAddr from board-data\n");*/
for (i = 0; i<addrs; i++) {
ar->eeprom_configAddrs[i] = e32[offset + i];
if (ar->eeprom_configAddrs[i]) {
ath10k_dbg(ar, ATH10K_DBG_BOOT, "saving eeprom configAddr[%i]: 0x%08x\n",
i, ar->eeprom_configAddrs[i]);
}
}
}

ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d, specified-file-name: %s\n",
ar->bd_api, ar->fwcfg.bname[0] ? ar->fwcfg.bname : "NA");
return 0;
Expand Down Expand Up @@ -2758,6 +2776,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
/* Don't worry about failures..not much we can do, and not worth failing init even
* if this fails.
*/

for (band = 0; band < 2; band++) {
u32 val;
for (i = 0; i<MIN_CCA_PWR_COUNT; i++) {
Expand Down Expand Up @@ -2854,6 +2873,21 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (ar->eeprom_overrides.rc_txbf_probe)
ath10k_wmi_pdev_set_fwtest(ar, 20,
ar->eeprom_overrides.rc_txbf_probe);

for (i = 0; i<ARRAY_SIZE(ar->eeprom_configAddrs); i += 2) {
if (ar->eeprom_configAddrs[i]) {
ath10k_dbg(ar, ATH10K_DBG_BOOT, "Applying eeprom configAddr[%i]: 0x%08x 0x%08x\n",
i, ar->eeprom_configAddrs[i], ar->eeprom_configAddrs[i+1]);

ath10k_wmi_pdev_set_special(ar, SET_SPECIAL_ID_EEPROM_CFG_ADDR_A,
ar->eeprom_configAddrs[i]);
ath10k_wmi_pdev_set_special(ar, SET_SPECIAL_ID_EEPROM_CFG_ADDR_V,
ar->eeprom_configAddrs[i+1]);
}
else {
break;
}
}
}

return 0;
Expand Down
14 changes: 14 additions & 0 deletions ath10k-4.13/core.h
Expand Up @@ -182,6 +182,10 @@ struct ath10k_wmi {
u32 num_mem_chunks;
u32 rx_decap_mode;
struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];

int gen_buf_len; /* so far */
u8 gen_buffer[2048]; /* Not clear what is true max size */
struct wmi_generic_buffer_event last_generic_event;
};

struct ath10k_fw_stats_peer {
Expand Down Expand Up @@ -590,6 +594,14 @@ struct ath10k_debug {
u64 tx_noack_bytes;
u64 tx_discard_bytes;
u64 tx_bytes; /* counter, total sent to firmware */

int ratepwr_tbl_len;
struct qc988xxEepromRateTbl ratepwr_tbl;
struct completion ratepwr_tbl_complete;

int powerctl_tbl_len;
struct qca9880_power_ctrl powerctl_tbl;
struct completion powerctl_tbl_complete;
};

enum ath10k_state {
Expand Down Expand Up @@ -1209,6 +1221,8 @@ struct ath10k {
#endif
u32 wmi_get_temp_count;

u32 eeprom_configAddrs[24]; /* Store sticky eeprom register settings to re-apply after OTP */

struct {
/* protected by conf_mutex */
struct ath10k_fw_components utf_mode_fw;
Expand Down
183 changes: 173 additions & 10 deletions ath10k-4.13/debug.c
Expand Up @@ -524,6 +524,30 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
spin_unlock_bh(&ar->data_lock);
}

void ath10k_debug_fw_ratepwr_table_process(struct ath10k *ar, struct sk_buff *skb)
{
size_t sz = skb->len;
if (sz != sizeof(struct qc988xxEepromRateTbl)) {
ath10k_info(ar, "Invalid ratepwr table results length, expected: %d got: %d\n",
(int)(sizeof(struct qc988xxEepromRateTbl)), (int)sz);
sz = min(sz, sizeof(struct qc988xxEepromRateTbl));
}
memcpy(ar->debug.ratepwr_tbl.data, skb->data, sz);
complete(&ar->debug.ratepwr_tbl_complete);
}

void ath10k_debug_fw_powerctl_table_process(struct ath10k *ar, struct sk_buff *skb)
{
size_t sz = skb->len;
if (sz != sizeof(struct qca9880_power_ctrl)) {
ath10k_info(ar, "Invalid powerctl table results length, expected: %d got: %d\n",
(int)(sizeof(struct qca9880_power_ctrl)), (int)sz);
sz = min(sz, sizeof(struct qca9880_power_ctrl));
}
memcpy(ar->debug.powerctl_tbl.data, skb->data, sz);
complete(&ar->debug.powerctl_tbl_complete);
}

void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_fw_stats stats = {};
Expand Down Expand Up @@ -2375,6 +2399,129 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file,
return ret;
}

static ssize_t ath10k_read_ratepwr(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
int size = 8000;
u8 *buf = kzalloc(size, GFP_KERNEL);
int retval = 0, len = 0;
int mx = sizeof(ar->debug.ratepwr_tbl.data) / 4;
int i;

if (buf == NULL)
return -ENOMEM;

/* TODO: Locking? */

if (ar->state == ATH10K_STATE_ON) {
unsigned long time_left;
int ret;

reinit_completion(&ar->debug.ratepwr_tbl_complete);

ret = ath10k_wmi_request_ratepwr_tbl(ar);
if (ret) {
ath10k_warn(ar, "could not request ratepwr table: ret %d\n",
ret);
time_left = 1;
}
else {
time_left = wait_for_completion_timeout(&ar->debug.ratepwr_tbl_complete, 1*HZ);
}

/* ath10k_warn(ar, "Requested ratepwr (type 0x%x ret %d specifier %d jiffies: %lu time-left: %lu)\n",
type, ret, specifier, jiffies, time_left);*/

if (time_left == 0)
ath10k_warn(ar, "Timeout requesting ratepwr table.\n");
}

len += scnprintf(buf + len, size - len, "RatePower table, length: %d\n",
ar->debug.ratepwr_tbl_len);
for (i = 0; i<mx; i++) {
len += scnprintf(buf + len, size - len, "%08x ", ar->debug.ratepwr_tbl.data[i]);
if (((i + 1) % 8) == 0)
buf[len - 1] = '\n';
}
buf[len - 1] = '\n';

retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);

return retval;
}

static const struct file_operations fops_ratepwr_table = {
.read = ath10k_read_ratepwr,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};

static ssize_t ath10k_read_powerctl(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
int size = 8000;
u8 *buf = kzalloc(size, GFP_KERNEL);
int retval = 0, len = 0;
int mx = sizeof(ar->debug.powerctl_tbl.data) / 4;
int i;

if (buf == NULL)
return -ENOMEM;

/* TODO: Locking? */

if (ar->state == ATH10K_STATE_ON) {
unsigned long time_left;
int ret;

reinit_completion(&ar->debug.powerctl_tbl_complete);

ret = ath10k_wmi_request_powerctl_tbl(ar);
if (ret) {
ath10k_warn(ar, "could not request powerctl table: ret %d\n",
ret);
time_left = 1;
}
else {
time_left = wait_for_completion_timeout(&ar->debug.powerctl_tbl_complete, 1*HZ);
}

/* ath10k_warn(ar, "Requested powerctl (type 0x%x ret %d specifier %d jiffies: %lu time-left: %lu)\n",
type, ret, specifier, jiffies, time_left);*/

if (time_left == 0)
ath10k_warn(ar, "Timeout requesting powerctl table.\n");
}

len += scnprintf(buf + len, size - len, "PowerCtl table, length: %d\n",
ar->debug.powerctl_tbl_len);
for (i = 0; i<mx; i++) {
len += scnprintf(buf + len, size - len, "%08x ", ar->debug.powerctl_tbl.data[i]);
if (((i + 1) % 8) == 0)
buf[len - 1] = '\n';
}
buf[len - 1] = '\n';

retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);

return retval;
}

static const struct file_operations fops_powerctl_table = {
.read = ath10k_read_powerctl,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};


/* TODO: Would be nice to always support ethtool stats, would need to
* move the stats storage out of ath10k_debug, or always have ath10k_debug
* struct available..
Expand Down Expand Up @@ -2829,39 +2976,38 @@ static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
{
int i;
size_t buf_len;
static const char table_str[][5] = { "CDD",
static const char table_str[][5] = { " CDD",
"STBC",
"TXBF" };
static const char pream_str[][6] = { "CCK",
"OFDM",
"HT20",
"HT40",
static const char pream_str[][6] = { " CCK",
" OFDM",
" HT20",
" HT40",
"VHT20",
"VHT40",
"VHT80",
"HTCUP" };

buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
*len += scnprintf(buf + *len, buf_len - *len,
"********************************\n");
"*****************************************************\n");
*len += scnprintf(buf + *len, buf_len - *len,
"******************* %s POWER TABLE ****************\n",
table_str[j]);
*len += scnprintf(buf + *len, buf_len - *len,
"********************************\n");
"*****************************************************\n");
*len += scnprintf(buf + *len, buf_len - *len,
"No. Preamble Rate_code tpc_value1 tpc_value2 tpc_value3\n");

for (i = 0; i < tpc_stats->rate_max; i++) {
*len += scnprintf(buf + *len, buf_len - *len,
"%8d %s 0x%2x %s\n", i,
"%3d %s 0x%2x %s\n", i,
pream_str[tpc_stats->tpc_table[j].pream_idx[i]],
tpc_stats->tpc_table[j].rate_code[i],
tpc_stats->tpc_table[j].tpc_value[i]);
}

*len += scnprintf(buf + *len, buf_len - *len,
"***********************************\n");
*len += scnprintf(buf + *len, buf_len - *len, "\n\n");
}

static void ath10k_tpc_stats_fill(struct ath10k *ar,
Expand Down Expand Up @@ -3422,6 +3568,14 @@ static ssize_t ath10k_write_ct_special(struct file *file,
/* Not stored in driver, will not be restored upon FW crash/restart */
ath10k_warn(ar, "Setting ct-andmask for peer: %d to 0x%x.\n", val >> 16, val & 0x16);
}
else if (id == SET_SPECIAL_ID_EEPROM_CFG_ADDR_A) {
/* Not stored in driver, will not be restored upon FW crash/restart */
ath10k_warn(ar, "Adding EEPROM configAddr address setting 0x08%x.\n", val);
}
else if (id == SET_SPECIAL_ID_EEPROM_CFG_ADDR_V) {
/* Not stored in driver, will not be restored upon FW crash/restart */
ath10k_warn(ar, "Adding EEPROM configAddr value setting 0x08%x.\n", val);
}
/* Below here are local driver hacks, and not necessarily passed directly to firmware. */
else if (id == 0x1001) {
/* Set station failed-transmit kickout threshold. */
Expand Down Expand Up @@ -3524,6 +3678,7 @@ static ssize_t ath10k_read_ct_special(struct file *file,
"id: 0x11 allow tx-hang logic to try cold resets instead of just warm resets.\n"
"id: 0x12 disable special CCA setting for IBSS queues.\n"
"id: 0x13 set 5-bit antenna-mask for peer, format: (peer-id << 16) | ant_mask\n"
"id: 0x14 Add a 32-bit sticky register / value override to the eeprom."
"\nBelow here should work with most firmware, including non-CT firmware.\n"
"id: 0x1001 set sta-kickout threshold due to tx-failures (0 means disable. Default is 20 * 16.)\n"
"id: 0x1002 set su-sounding-timer-ms (0 means use defaults next FW reload. Default is 100, max is 500)\n"
Expand Down Expand Up @@ -3841,6 +3996,8 @@ int ath10k_debug_register(struct ath10k *ar)

init_completion(&ar->debug.tpc_complete);
init_completion(&ar->debug.fw_stats_complete);
init_completion(&ar->debug.ratepwr_tbl_complete);
init_completion(&ar->debug.powerctl_tbl_complete);

debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar,
&fops_fw_stats);
Expand Down Expand Up @@ -3923,6 +4080,12 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar,
&fops_quiet_period);

debugfs_create_file("powerctl_table", 0600, ar->debug.debugfs_phy, ar,
&fops_powerctl_table);

debugfs_create_file("ratepwr_table", 0600, ar->debug.debugfs_phy, ar,
&fops_ratepwr_table);

debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar,
&fops_tpc_stats);

Expand Down

0 comments on commit 75e2705

Please sign in to comment.