aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k/debug.c
diff options
context:
space:
mode:
authorMarty Faltesek <mfaltesek@google.com>2016-10-10 12:00:04 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2016-10-13 07:06:20 -0400
commitf67b107d4ceddcf7aa65b706aaaf50d68edb52a6 (patch)
tree8fe67cfc8010ede1cfdd870735a9a0f58618b899 /drivers/net/wireless/ath/ath10k/debug.c
parentcf4747d7535a936105f0abe8d8109d3fe339162b (diff)
ath10k: cache calibration data when the core is stopped
Commit 0b8e3c4ca29f ("ath10k: move cal data len to hw_params") broke retrieving the calibration data from cal_data debugfs file. The length of file was always zero. The reason is: static ssize_t ath10k_debug_cal_data_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; void *buf = file->private_data; This is obviously bogus, private_data cannot contain both struct ath10k and the buffer. Fix it by caching calibration data to ar->debug.cal_data. This also allows it to be accessed when the device is not active (interface is down). The cal_data buffer is fixed size because during the first firmware probe we don't yet know what will be the lenght of the calibration data. It was simplest just to use a fixed length. There's a WARN_ON() in ath10k_debug_cal_data_fetch() if the buffer is too small. Tested with qca988x and firmware 10.2.4.70.56. Reported-by: Nikolay Martynov <mar.kolya@gmail.com> Fixes: 0b8e3c4ca29f ("ath10k: move cal data len to hw_params") Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Marty Faltesek <mfaltesek@google.com> [kvalo@qca.qualcomm.com: improve commit log and minor other changes] Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/debug.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c75
1 files changed, 39 insertions, 36 deletions
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 832da6ed9f13..82a4c67f3672 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -30,6 +30,8 @@
30/* ms */ 30/* ms */
31#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 31#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
32 32
33#define ATH10K_DEBUG_CAL_DATA_LEN 12064
34
33#define ATH10K_FW_CRASH_DUMP_VERSION 1 35#define ATH10K_FW_CRASH_DUMP_VERSION 1
34 36
35/** 37/**
@@ -1451,56 +1453,51 @@ static const struct file_operations fops_fw_dbglog = {
1451 .llseek = default_llseek, 1453 .llseek = default_llseek,
1452}; 1454};
1453 1455
1454static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) 1456static int ath10k_debug_cal_data_fetch(struct ath10k *ar)
1455{ 1457{
1456 struct ath10k *ar = inode->i_private;
1457 void *buf;
1458 u32 hi_addr; 1458 u32 hi_addr;
1459 __le32 addr; 1459 __le32 addr;
1460 int ret; 1460 int ret;
1461 1461
1462 mutex_lock(&ar->conf_mutex); 1462 lockdep_assert_held(&ar->conf_mutex);
1463
1464 if (ar->state != ATH10K_STATE_ON &&
1465 ar->state != ATH10K_STATE_UTF) {
1466 ret = -ENETDOWN;
1467 goto err;
1468 }
1469 1463
1470 buf = vmalloc(ar->hw_params.cal_data_len); 1464 if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN))
1471 if (!buf) { 1465 return -EINVAL;
1472 ret = -ENOMEM;
1473 goto err;
1474 }
1475 1466
1476 hi_addr = host_interest_item_address(HI_ITEM(hi_board_data)); 1467 hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
1477 1468
1478 ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr)); 1469 ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
1479 if (ret) { 1470 if (ret) {
1480 ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret); 1471 ath10k_warn(ar, "failed to read hi_board_data address: %d\n",
1481 goto err_vfree; 1472 ret);
1473 return ret;
1482 } 1474 }
1483 1475
1484 ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf, 1476 ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data,
1485 ar->hw_params.cal_data_len); 1477 ar->hw_params.cal_data_len);
1486 if (ret) { 1478 if (ret) {
1487 ath10k_warn(ar, "failed to read calibration data: %d\n", ret); 1479 ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
1488 goto err_vfree; 1480 return ret;
1489 } 1481 }
1490 1482
1491 file->private_data = buf; 1483 return 0;
1484}
1492 1485
1493 mutex_unlock(&ar->conf_mutex); 1486static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
1487{
1488 struct ath10k *ar = inode->i_private;
1494 1489
1495 return 0; 1490 mutex_lock(&ar->conf_mutex);
1496 1491
1497err_vfree: 1492 if (ar->state == ATH10K_STATE_ON ||
1498 vfree(buf); 1493 ar->state == ATH10K_STATE_UTF) {
1494 ath10k_debug_cal_data_fetch(ar);
1495 }
1499 1496
1500err: 1497 file->private_data = ar;
1501 mutex_unlock(&ar->conf_mutex); 1498 mutex_unlock(&ar->conf_mutex);
1502 1499
1503 return ret; 1500 return 0;
1504} 1501}
1505 1502
1506static ssize_t ath10k_debug_cal_data_read(struct file *file, 1503static ssize_t ath10k_debug_cal_data_read(struct file *file,
@@ -1508,18 +1505,16 @@ static ssize_t ath10k_debug_cal_data_read(struct file *file,
1508 size_t count, loff_t *ppos) 1505 size_t count, loff_t *ppos)
1509{ 1506{
1510 struct ath10k *ar = file->private_data; 1507 struct ath10k *ar = file->private_data;
1511 void *buf = file->private_data;
1512 1508
1513 return simple_read_from_buffer(user_buf, count, ppos, 1509 mutex_lock(&ar->conf_mutex);
1514 buf, ar->hw_params.cal_data_len);
1515}
1516 1510
1517static int ath10k_debug_cal_data_release(struct inode *inode, 1511 count = simple_read_from_buffer(user_buf, count, ppos,
1518 struct file *file) 1512 ar->debug.cal_data,
1519{ 1513 ar->hw_params.cal_data_len);
1520 vfree(file->private_data);
1521 1514
1522 return 0; 1515 mutex_unlock(&ar->conf_mutex);
1516
1517 return count;
1523} 1518}
1524 1519
1525static ssize_t ath10k_write_ani_enable(struct file *file, 1520static ssize_t ath10k_write_ani_enable(struct file *file,
@@ -1580,7 +1575,6 @@ static const struct file_operations fops_ani_enable = {
1580static const struct file_operations fops_cal_data = { 1575static const struct file_operations fops_cal_data = {
1581 .open = ath10k_debug_cal_data_open, 1576 .open = ath10k_debug_cal_data_open,
1582 .read = ath10k_debug_cal_data_read, 1577 .read = ath10k_debug_cal_data_read,
1583 .release = ath10k_debug_cal_data_release,
1584 .owner = THIS_MODULE, 1578 .owner = THIS_MODULE,
1585 .llseek = default_llseek, 1579 .llseek = default_llseek,
1586}; 1580};
@@ -1932,6 +1926,8 @@ void ath10k_debug_stop(struct ath10k *ar)
1932{ 1926{
1933 lockdep_assert_held(&ar->conf_mutex); 1927 lockdep_assert_held(&ar->conf_mutex);
1934 1928
1929 ath10k_debug_cal_data_fetch(ar);
1930
1935 /* Must not use _sync to avoid deadlock, we do that in 1931 /* Must not use _sync to avoid deadlock, we do that in
1936 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid 1932 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
1937 * warning from del_timer(). */ 1933 * warning from del_timer(). */
@@ -2344,6 +2340,10 @@ int ath10k_debug_create(struct ath10k *ar)
2344 if (!ar->debug.fw_crash_data) 2340 if (!ar->debug.fw_crash_data)
2345 return -ENOMEM; 2341 return -ENOMEM;
2346 2342
2343 ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
2344 if (!ar->debug.cal_data)
2345 return -ENOMEM;
2346
2347 INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); 2347 INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
2348 INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); 2348 INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
2349 INIT_LIST_HEAD(&ar->debug.fw_stats.peers); 2349 INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
@@ -2357,6 +2357,9 @@ void ath10k_debug_destroy(struct ath10k *ar)
2357 vfree(ar->debug.fw_crash_data); 2357 vfree(ar->debug.fw_crash_data);
2358 ar->debug.fw_crash_data = NULL; 2358 ar->debug.fw_crash_data = NULL;
2359 2359
2360 vfree(ar->debug.cal_data);
2361 ar->debug.cal_data = NULL;
2362
2360 ath10k_debug_fw_stats_reset(ar); 2363 ath10k_debug_fw_stats_reset(ar);
2361 2364
2362 kfree(ar->debug.tpc_stats); 2365 kfree(ar->debug.tpc_stats);