diff options
author | Marty Faltesek <mfaltesek@google.com> | 2016-10-10 12:00:04 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2016-10-13 07:06:20 -0400 |
commit | f67b107d4ceddcf7aa65b706aaaf50d68edb52a6 (patch) | |
tree | 8fe67cfc8010ede1cfdd870735a9a0f58618b899 /drivers/net/wireless/ath/ath10k/debug.c | |
parent | cf4747d7535a936105f0abe8d8109d3fe339162b (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.c | 75 |
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 | ||
1454 | static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) | 1456 | static 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); | 1486 | static 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 | ||
1497 | err_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 | ||
1500 | err: | 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 | ||
1506 | static ssize_t ath10k_debug_cal_data_read(struct file *file, | 1503 | static 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 | ||
1517 | static 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 | ||
1525 | static ssize_t ath10k_write_ani_enable(struct file *file, | 1520 | static ssize_t ath10k_write_ani_enable(struct file *file, |
@@ -1580,7 +1575,6 @@ static const struct file_operations fops_ani_enable = { | |||
1580 | static const struct file_operations fops_cal_data = { | 1575 | static 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); |