ath.git patches for v6.10

ath12k
 
 * debugfs support
 
 * dfs_simulate_radar debugfs file
 
 * disable Wireless Extensions
 
 * suspend and hibernation support
 
 * ACPI support
 
 * refactoring in preparation of multi-link support
 
 ath11k
 
 * support hibernation (required changes in qrtr and MHI subsystems)
 
 * ieee80211-freq-limit Device Tree property support
 
 ath10k
 
 * firmware-name Device Tree property support
 -----BEGIN PGP SIGNATURE-----
 
 iQFLBAABCgA1FiEEiBjanGPFTz4PRfLobhckVSbrbZsFAmYztxUXHHF1aWNfa3Zh
 bG9AcXVpY2luYy5jb20ACgkQbhckVSbrbZs0NQf/dYF+Pjy3eh9vabwZ05rUZwLF
 P/k7Q8o631Gl0LTkmGw6SseUFswAOH1uwaKpWQvjhzHE8Fy4ziMeQ+aruqtbfZ3i
 Q1BYsnCbQHZ+1HX0EJmB9KDz8+/G1JxOlwiux7EsujOuFixjomm08VEJ4QXGVSnj
 NnCg0zx/0njDqT/3KjJuoL4stAk0HDvIayiVGsQOwcQQJelLGudqTNmRPnKQkR5w
 yRUX+NaFlVHgbbhsnEyW3XeqKVFwgy64BtNRIVpJ0lF51aazT80DagNmw5CawznC
 uak1nFktAtX/AID3lWRjek3smIdlnUz39JojKW7iO60/wfZXXFbR8Xl2XEpp9g==
 =fF10
 -----END PGP SIGNATURE-----

Merge tag 'ath-next-20240502' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath

ath.git patches for v6.10

ath12k

* debugfs support

* dfs_simulate_radar debugfs file

* disable Wireless Extensions

* suspend and hibernation support

* ACPI support

* refactoring in preparation of multi-link support

ath11k

* support hibernation (required changes in qrtr and MHI subsystems)

* ieee80211-freq-limit Device Tree property support

ath10k

* firmware-name Device Tree property support
This commit is contained in:
Kalle Valo 2024-05-03 13:30:19 +03:00
commit f1c26960b6
64 changed files with 2656 additions and 676 deletions

View File

@ -73,6 +73,12 @@ properties:
- sky85703-11
- sky85803
firmware-name:
maxItems: 1
description:
If present, a board or platform specific string used to lookup firmware
files for the device.
wifi-firmware:
type: object
additionalProperties: false

View File

@ -59,6 +59,8 @@ properties:
minItems: 1
maxItems: 2
ieee80211-freq-limit: true
wifi-firmware:
type: object
description: |
@ -88,6 +90,7 @@ required:
additionalProperties: false
allOf:
- $ref: ieee80211.yaml#
- if:
properties:
compatible:

View File

@ -80,6 +80,7 @@ enum dev_st_transition {
DEV_ST_TRANSITION_FP,
DEV_ST_TRANSITION_SYS_ERR,
DEV_ST_TRANSITION_DISABLE,
DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE,
DEV_ST_TRANSITION_MAX,
};
@ -90,7 +91,8 @@ enum dev_st_transition {
dev_st_trans(MISSION_MODE, "MISSION MODE") \
dev_st_trans(FP, "FLASH PROGRAMMER") \
dev_st_trans(SYS_ERR, "SYS ERROR") \
dev_st_trans_end(DISABLE, "DISABLE")
dev_st_trans(DISABLE, "DISABLE") \
dev_st_trans_end(DISABLE_DESTROY_DEVICE, "DISABLE (DESTROY DEVICE)")
extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX];
#define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \

View File

@ -468,7 +468,8 @@ error_mission_mode:
}
/* Handle shutdown transitions */
static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
bool destroy_device)
{
enum mhi_pm_state cur_state;
struct mhi_event *mhi_event;
@ -530,8 +531,16 @@ skip_mhi_reset:
dev_dbg(dev, "Waiting for all pending threads to complete\n");
wake_up_all(&mhi_cntrl->state_event);
dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
/*
* Only destroy the 'struct device' for channels if indicated by the
* 'destroy_device' flag. Because, during system suspend or hibernation
* state, there is no need to destroy the 'struct device' as the endpoint
* device would still be physically attached to the machine.
*/
if (destroy_device) {
dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
}
mutex_lock(&mhi_cntrl->pm_mutex);
@ -821,7 +830,10 @@ void mhi_pm_st_worker(struct work_struct *work)
mhi_pm_sys_error_transition(mhi_cntrl);
break;
case DEV_ST_TRANSITION_DISABLE:
mhi_pm_disable_transition(mhi_cntrl);
mhi_pm_disable_transition(mhi_cntrl, false);
break;
case DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE:
mhi_pm_disable_transition(mhi_cntrl, true);
break;
default:
break;
@ -1175,7 +1187,8 @@ error_exit:
}
EXPORT_SYMBOL_GPL(mhi_async_power_up);
void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
static void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
bool destroy_device)
{
enum mhi_pm_state cur_state, transition_state;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
@ -1211,15 +1224,32 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
write_unlock_irq(&mhi_cntrl->pm_lock);
mutex_unlock(&mhi_cntrl->pm_mutex);
mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
if (destroy_device)
mhi_queue_state_transition(mhi_cntrl,
DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE);
else
mhi_queue_state_transition(mhi_cntrl,
DEV_ST_TRANSITION_DISABLE);
/* Wait for shutdown to complete */
flush_work(&mhi_cntrl->st_worker);
disable_irq(mhi_cntrl->irq[0]);
}
void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
{
__mhi_power_down(mhi_cntrl, graceful, true);
}
EXPORT_SYMBOL_GPL(mhi_power_down);
void mhi_power_down_keep_dev(struct mhi_controller *mhi_cntrl,
bool graceful)
{
__mhi_power_down(mhi_cntrl, graceful, false);
}
EXPORT_SYMBOL_GPL(mhi_power_down_keep_dev);
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
{
int ret = mhi_async_power_up(mhi_cntrl);

View File

@ -1594,6 +1594,20 @@ static int ar5523_probe(struct usb_interface *intf,
struct ar5523 *ar;
int error = -ENOMEM;
static const u8 bulk_ep_addr[] = {
AR5523_CMD_TX_PIPE | USB_DIR_OUT,
AR5523_DATA_TX_PIPE | USB_DIR_OUT,
AR5523_CMD_RX_PIPE | USB_DIR_IN,
AR5523_DATA_RX_PIPE | USB_DIR_IN,
0};
if (!usb_check_bulk_endpoints(intf, bulk_ep_addr)) {
dev_err(&dev->dev,
"Could not find all expected endpoints\n");
error = -ENODEV;
goto out;
}
/*
* Load firmware if the device requires it. This will return
* -ENXIO on success and we'll get called back afer the usb

View File

@ -171,8 +171,10 @@ struct ath_common {
unsigned int clockrate;
spinlock_t cc_lock;
struct ath_cycle_counters cc_ani;
struct ath_cycle_counters cc_survey;
struct_group(cc,
struct ath_cycle_counters cc_ani;
struct ath_cycle_counters cc_survey;
);
struct ath_regulatory regulatory;
struct ath_regulatory reg_world_copy;

View File

@ -75,7 +75,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 2116,
.fw = {
.dir = QCA988X_HW_2_0_FW_DIR,
.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
.board_size = QCA988X_BOARD_DATA_SZ,
.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
},
@ -116,7 +115,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 2116,
.fw = {
.dir = QCA988X_HW_2_0_FW_DIR,
.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
.board_size = QCA988X_BOARD_DATA_SZ,
.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
},
@ -158,7 +156,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 2116,
.fw = {
.dir = QCA9887_HW_1_0_FW_DIR,
.board = QCA9887_HW_1_0_BOARD_DATA_FILE,
.board_size = QCA9887_BOARD_DATA_SZ,
.board_ext_size = QCA9887_BOARD_EXT_DATA_SZ,
},
@ -199,7 +196,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 0,
.fw = {
.dir = QCA6174_HW_3_0_FW_DIR,
.board = QCA6174_HW_3_0_BOARD_DATA_FILE,
.board_size = QCA6174_BOARD_DATA_SZ,
.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
},
@ -236,7 +232,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 8124,
.fw = {
.dir = QCA6174_HW_2_1_FW_DIR,
.board = QCA6174_HW_2_1_BOARD_DATA_FILE,
.board_size = QCA6174_BOARD_DATA_SZ,
.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
},
@ -277,7 +272,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 8124,
.fw = {
.dir = QCA6174_HW_2_1_FW_DIR,
.board = QCA6174_HW_2_1_BOARD_DATA_FILE,
.board_size = QCA6174_BOARD_DATA_SZ,
.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
},
@ -318,7 +312,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 8124,
.fw = {
.dir = QCA6174_HW_3_0_FW_DIR,
.board = QCA6174_HW_3_0_BOARD_DATA_FILE,
.board_size = QCA6174_BOARD_DATA_SZ,
.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
},
@ -360,7 +353,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.fw = {
/* uses same binaries as hw3.0 */
.dir = QCA6174_HW_3_0_FW_DIR,
.board = QCA6174_HW_3_0_BOARD_DATA_FILE,
.board_size = QCA6174_BOARD_DATA_SZ,
.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
},
@ -409,7 +401,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 12064,
.fw = {
.dir = QCA99X0_HW_2_0_FW_DIR,
.board = QCA99X0_HW_2_0_BOARD_DATA_FILE,
.board_size = QCA99X0_BOARD_DATA_SZ,
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
},
@ -457,8 +448,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 12064,
.fw = {
.dir = QCA9984_HW_1_0_FW_DIR,
.board = QCA9984_HW_1_0_BOARD_DATA_FILE,
.eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE,
.board_size = QCA99X0_BOARD_DATA_SZ,
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
.ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ,
@ -510,7 +499,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 12064,
.fw = {
.dir = QCA9888_HW_2_0_FW_DIR,
.board = QCA9888_HW_2_0_BOARD_DATA_FILE,
.board_size = QCA99X0_BOARD_DATA_SZ,
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
},
@ -556,7 +544,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 8124,
.fw = {
.dir = QCA9377_HW_1_0_FW_DIR,
.board = QCA9377_HW_1_0_BOARD_DATA_FILE,
.board_size = QCA9377_BOARD_DATA_SZ,
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
},
@ -597,7 +584,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 8124,
.fw = {
.dir = QCA9377_HW_1_0_FW_DIR,
.board = QCA9377_HW_1_0_BOARD_DATA_FILE,
.board_size = QCA9377_BOARD_DATA_SZ,
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
},
@ -640,7 +626,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 8124,
.fw = {
.dir = QCA9377_HW_1_0_FW_DIR,
.board = QCA9377_HW_1_0_BOARD_DATA_FILE,
.board_size = QCA9377_BOARD_DATA_SZ,
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
},
@ -680,7 +665,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.cal_data_len = 12064,
.fw = {
.dir = QCA4019_HW_1_0_FW_DIR,
.board = QCA4019_HW_1_0_BOARD_DATA_FILE,
.board_size = QCA4019_BOARD_DATA_SZ,
.board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,
},
@ -720,6 +704,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.max_spatial_stream = 4,
.fw = {
.dir = WCN3990_HW_1_0_FW_DIR,
.board_size = WCN3990_BOARD_DATA_SZ,
.board_ext_size = WCN3990_BOARD_EXT_DATA_SZ,
},
.sw_decrypt_mcast_mgmt = true,
.rx_desc_ops = &wcn3990_rx_desc_ops,
@ -942,11 +928,20 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
if (dir == NULL)
dir = ".";
if (ar->board_name) {
snprintf(filename, sizeof(filename), "%s/%s/%s",
dir, ar->board_name, file);
ret = firmware_request_nowarn(&fw, filename, ar->dev);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",
filename, ret);
if (!ret)
return fw;
}
snprintf(filename, sizeof(filename), "%s/%s", dir, file);
ret = firmware_request_nowarn(&fw, filename, ar->dev);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",
filename, ret);
if (ret)
return ERR_PTR(ret);
@ -1288,11 +1283,6 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
char boardname[100];
if (bd_ie_type == ATH10K_BD_IE_BOARD) {
if (!ar->hw_params.fw.board) {
ath10k_err(ar, "failed to find board file fw entry\n");
return -EINVAL;
}
scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin",
ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
@ -1302,7 +1292,7 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
if (IS_ERR(ar->normal_mode_fw.board)) {
fw = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.board);
ATH10K_BOARD_DATA_FILE);
ar->normal_mode_fw.board = fw;
}
@ -1312,13 +1302,8 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data;
ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size;
} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {
if (!ar->hw_params.fw.eboard) {
ath10k_err(ar, "failed to find eboard file fw entry\n");
return -EINVAL;
}
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
ar->hw_params.fw.eboard);
ATH10K_EBOARD_DATA_FILE);
ar->normal_mode_fw.ext_board = fw;
if (IS_ERR(ar->normal_mode_fw.ext_board))
return PTR_ERR(ar->normal_mode_fw.ext_board);

View File

@ -1081,6 +1081,8 @@ struct ath10k {
*/
const struct ath10k_fw_components *running_fw;
const char *board_name;
const struct firmware *pre_cal_file;
const struct firmware *cal_file;

View File

@ -439,7 +439,7 @@ ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,
}
out:
mutex_unlock(&ar->conf_mutex);
return count;
return ret ?: count;
}
static const struct file_operations fops_peer_debug_trigger = {

View File

@ -39,14 +39,12 @@ enum ath10k_bus {
#define QCA988X_HW_2_0_VERSION 0x4100016c
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0"
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
/* QCA9887 1.0 definitions */
#define QCA9887_HW_1_0_VERSION 0x4100016d
#define QCA9887_HW_1_0_CHIP_ID_REV 0
#define QCA9887_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9887/hw1.0"
#define QCA9887_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA9887_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA6174 target BMI version signatures */
@ -85,11 +83,9 @@ enum qca9377_chip_id_rev {
};
#define QCA6174_HW_2_1_FW_DIR ATH10K_FW_DIR "/QCA6174/hw2.1"
#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin"
#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234
#define QCA6174_HW_3_0_FW_DIR ATH10K_FW_DIR "/QCA6174/hw3.0"
#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin"
#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234
/* QCA99X0 1.0 definitions (unsupported) */
@ -99,7 +95,6 @@ enum qca9377_chip_id_rev {
#define QCA99X0_HW_2_0_DEV_VERSION 0x01000000
#define QCA99X0_HW_2_0_CHIP_ID_REV 0x1
#define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0"
#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
/* QCA9984 1.0 defines */
@ -107,8 +102,6 @@ enum qca9377_chip_id_rev {
#define QCA9984_HW_DEV_TYPE 0xa
#define QCA9984_HW_1_0_CHIP_ID_REV 0x0
#define QCA9984_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9984/hw1.0"
#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA9984_HW_1_0_EBOARD_DATA_FILE "eboard.bin"
#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA9888 2.0 defines */
@ -116,18 +109,15 @@ enum qca9377_chip_id_rev {
#define QCA9888_HW_DEV_TYPE 0xc
#define QCA9888_HW_2_0_CHIP_ID_REV 0x0
#define QCA9888_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA9888/hw2.0"
#define QCA9888_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA9888_HW_2_0_PATCH_LOAD_ADDR 0x1234
/* QCA9377 1.0 definitions */
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA4019 1.0 definitions */
#define QCA4019_HW_1_0_DEV_VERSION 0x01000000
#define QCA4019_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA4019/hw1.0"
#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* WCN3990 1.0 definitions */
@ -159,7 +149,9 @@ enum qca9377_chip_id_rev {
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
#define ATH10K_BOARD_MAGIC "QCA-ATH10K-BOARD"
#define ATH10K_BOARD_DATA_FILE "board.bin"
#define ATH10K_BOARD_API2_FILE "board-2.bin"
#define ATH10K_EBOARD_DATA_FILE "eboard.bin"
#define REG_DUMP_COUNT_QCA988X 60
@ -553,9 +545,7 @@ struct ath10k_hw_params {
struct ath10k_hw_params_fw {
const char *dir;
const char *board;
size_t board_size;
const char *eboard;
size_t ext_board_size;
size_t board_ext_size;
} fw;

View File

@ -3826,28 +3826,28 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA9887 1.0 firmware files */
MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" QCA9887_HW_1_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA6174 2.1 firmware files */
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA6174 3.1 firmware files */
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API6_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA9377 1.0 firmware files */
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE);
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE);

View File

@ -1338,6 +1338,9 @@ static void ath10k_snoc_quirks_init(struct ath10k *ar)
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct device *dev = &ar_snoc->dev->dev;
/* ignore errors, keep NULL if there is no property */
of_property_read_string(dev->of_node, "firmware-name", &ar->board_name);
if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
}

View File

@ -491,4 +491,7 @@ struct host_interest {
#define QCA4019_BOARD_DATA_SZ 12064
#define QCA4019_BOARD_EXT_DATA_SZ 0
#define WCN3990_BOARD_DATA_SZ 26328
#define WCN3990_BOARD_EXT_DATA_SZ 0
#endif /* __TARGADDRS_H__ */

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@ -413,7 +413,7 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab)
return ret;
}
static void ath11k_ahb_power_down(struct ath11k_base *ab)
static void ath11k_ahb_power_down(struct ath11k_base *ab, bool is_suspend)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
@ -1261,7 +1261,7 @@ static void ath11k_ahb_remove(struct platform_device *pdev)
struct ath11k_base *ab = platform_get_drvdata(pdev);
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath11k_ahb_power_down(ab);
ath11k_ahb_power_down(ab, false);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;

View File

@ -906,12 +906,6 @@ int ath11k_core_suspend(struct ath11k_base *ab)
return ret;
}
ret = ath11k_wow_enable(ab);
if (ret) {
ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret);
return ret;
}
ret = ath11k_dp_rx_pktlog_stop(ab, false);
if (ret) {
ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
@ -922,20 +916,49 @@ int ath11k_core_suspend(struct ath11k_base *ab)
ath11k_ce_stop_shadow_timers(ab);
ath11k_dp_stop_shadow_timers(ab);
ath11k_hif_irq_disable(ab);
ath11k_hif_ce_irq_disable(ab);
ret = ath11k_hif_suspend(ab);
if (ret) {
ath11k_warn(ab, "failed to suspend hif: %d\n", ret);
return ret;
}
/* PM framework skips suspend_late/resume_early callbacks
* if other devices report errors in their suspend callbacks.
* However ath11k_core_resume() would still be called because
* here we return success thus kernel put us on dpm_suspended_list.
* Since we won't go through a power down/up cycle, there is
* no chance to call complete(&ab->restart_completed) in
* ath11k_core_restart(), making ath11k_core_resume() timeout.
* So call it here to avoid this issue. This also works in case
* no error happens thus suspend_late/resume_early get called,
* because it will be reinitialized in ath11k_core_resume_early().
*/
complete(&ab->restart_completed);
return 0;
}
EXPORT_SYMBOL(ath11k_core_suspend);
int ath11k_core_resume(struct ath11k_base *ab)
int ath11k_core_suspend_late(struct ath11k_base *ab)
{
struct ath11k_pdev *pdev;
struct ath11k *ar;
if (!ab->hw_params.supports_suspend)
return -EOPNOTSUPP;
/* so far single_pdev_only chips have supports_suspend as true
* and only the first pdev is valid.
*/
pdev = ath11k_core_get_single_pdev(ab);
ar = pdev->ar;
if (!ar || ar->state != ATH11K_STATE_OFF)
return 0;
ath11k_hif_irq_disable(ab);
ath11k_hif_ce_irq_disable(ab);
ath11k_hif_power_down(ab, true);
return 0;
}
EXPORT_SYMBOL(ath11k_core_suspend_late);
int ath11k_core_resume_early(struct ath11k_base *ab)
{
int ret;
struct ath11k_pdev *pdev;
@ -944,7 +967,7 @@ int ath11k_core_resume(struct ath11k_base *ab)
if (!ab->hw_params.supports_suspend)
return -EOPNOTSUPP;
/* so far signle_pdev_only chips have supports_suspend as true
/* so far single_pdev_only chips have supports_suspend as true
* and only the first pdev is valid.
*/
pdev = ath11k_core_get_single_pdev(ab);
@ -952,29 +975,46 @@ int ath11k_core_resume(struct ath11k_base *ab)
if (!ar || ar->state != ATH11K_STATE_OFF)
return 0;
ret = ath11k_hif_resume(ab);
if (ret) {
ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret);
return ret;
}
reinit_completion(&ab->restart_completed);
ret = ath11k_hif_power_up(ab);
if (ret)
ath11k_warn(ab, "failed to power up hif during resume: %d\n", ret);
ath11k_hif_ce_irq_enable(ab);
ath11k_hif_irq_enable(ab);
return ret;
}
EXPORT_SYMBOL(ath11k_core_resume_early);
int ath11k_core_resume(struct ath11k_base *ab)
{
int ret;
struct ath11k_pdev *pdev;
struct ath11k *ar;
long time_left;
if (!ab->hw_params.supports_suspend)
return -EOPNOTSUPP;
/* so far single_pdev_only chips have supports_suspend as true
* and only the first pdev is valid.
*/
pdev = ath11k_core_get_single_pdev(ab);
ar = pdev->ar;
if (!ar || ar->state != ATH11K_STATE_OFF)
return 0;
time_left = wait_for_completion_timeout(&ab->restart_completed,
ATH11K_RESET_TIMEOUT_HZ);
if (time_left == 0) {
ath11k_warn(ab, "timeout while waiting for restart complete");
return -ETIMEDOUT;
}
ret = ath11k_dp_rx_pktlog_start(ab);
if (ret) {
if (ret)
ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",
ret);
return ret;
}
ret = ath11k_wow_wakeup(ab);
if (ret) {
ath11k_warn(ab, "failed to wakeup wow during resume: %d\n", ret);
return ret;
}
return 0;
return ret;
}
EXPORT_SYMBOL(ath11k_core_resume);
@ -2072,6 +2112,8 @@ static void ath11k_core_restart(struct work_struct *work)
if (!ab->is_reset)
ath11k_core_post_reconfigure_recovery(ab);
complete(&ab->restart_completed);
}
static void ath11k_core_reset(struct work_struct *work)
@ -2141,7 +2183,7 @@ static void ath11k_core_reset(struct work_struct *work)
ath11k_hif_irq_disable(ab);
ath11k_hif_ce_irq_disable(ab);
ath11k_hif_power_down(ab);
ath11k_hif_power_down(ab, false);
ath11k_hif_power_up(ab);
ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n");
@ -2214,7 +2256,7 @@ void ath11k_core_deinit(struct ath11k_base *ab)
mutex_unlock(&ab->core_lock);
ath11k_hif_power_down(ab);
ath11k_hif_power_down(ab, false);
ath11k_mac_destroy(ab);
ath11k_core_soc_destroy(ab);
ath11k_fw_destroy(ab);
@ -2267,6 +2309,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
init_completion(&ab->htc_suspend);
init_completion(&ab->wow.wakeup_completed);
init_completion(&ab->restart_completed);
ab->dev = dev;
ab->hif.bus = bus;

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_CORE_H
@ -1033,6 +1033,8 @@ struct ath11k_base {
DECLARE_BITMAP(fw_features, ATH11K_FW_FEATURE_COUNT);
} fw;
struct completion restart_completed;
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 data_pos;
@ -1232,8 +1234,10 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
int ath11k_core_check_dt(struct ath11k_base *ath11k);
int ath11k_core_check_smbios(struct ath11k_base *ab);
void ath11k_core_halt(struct ath11k *ar);
int ath11k_core_resume_early(struct ath11k_base *ab);
int ath11k_core_resume(struct ath11k_base *ab);
int ath11k_core_suspend(struct ath11k_base *ab);
int ath11k_core_suspend_late(struct ath11k_base *ab);
void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab);
bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab);

View File

@ -664,7 +664,7 @@ struct hal_srng_config {
};
/**
* enum hal_rx_buf_return_buf_manager
* enum hal_rx_buf_return_buf_manager - manager for returned rx buffers
*
* @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list
* @HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST: Descriptor returned to WBM idle

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _HIF_H_
@ -18,7 +18,7 @@ struct ath11k_hif_ops {
int (*start)(struct ath11k_base *ab);
void (*stop)(struct ath11k_base *ab);
int (*power_up)(struct ath11k_base *ab);
void (*power_down)(struct ath11k_base *ab);
void (*power_down)(struct ath11k_base *ab, bool is_suspend);
int (*suspend)(struct ath11k_base *ab);
int (*resume)(struct ath11k_base *ab);
int (*map_service_to_pipe)(struct ath11k_base *ab, u16 service_id,
@ -67,12 +67,18 @@ static inline void ath11k_hif_irq_disable(struct ath11k_base *ab)
static inline int ath11k_hif_power_up(struct ath11k_base *ab)
{
if (!ab->hif.ops->power_up)
return -EOPNOTSUPP;
return ab->hif.ops->power_up(ab);
}
static inline void ath11k_hif_power_down(struct ath11k_base *ab)
static inline void ath11k_hif_power_down(struct ath11k_base *ab, bool is_suspend)
{
ab->hif.ops->power_down(ab);
if (!ab->hif.ops->power_down)
return;
ab->hif.ops->power_down(ab, is_suspend);
}
static inline int ath11k_hif_suspend(struct ath11k_base *ab)

View File

@ -10126,6 +10126,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
if (ret)
goto err;
wiphy_read_of_freq_limits(ar->hw->wiphy);
ath11k_mac_setup_ht_vht_cap(ar, cap, &ht_cap);
ath11k_mac_setup_he_cap(ar, cap);

View File

@ -453,9 +453,17 @@ int ath11k_mhi_start(struct ath11k_pci *ab_pci)
return 0;
}
void ath11k_mhi_stop(struct ath11k_pci *ab_pci)
void ath11k_mhi_stop(struct ath11k_pci *ab_pci, bool is_suspend)
{
mhi_power_down(ab_pci->mhi_ctrl, true);
/* During suspend we need to use mhi_power_down_keep_dev()
* workaround, otherwise ath11k_core_resume() will timeout
* during resume.
*/
if (is_suspend)
mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true);
else
mhi_power_down(ab_pci->mhi_ctrl, true);
mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);
}

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_MHI_H
#define _ATH11K_MHI_H
@ -18,7 +18,7 @@
#define MHICTRL_RESET_MASK 0x2
int ath11k_mhi_start(struct ath11k_pci *ar_pci);
void ath11k_mhi_stop(struct ath11k_pci *ar_pci);
void ath11k_mhi_stop(struct ath11k_pci *ar_pci, bool is_suspend);
int ath11k_mhi_register(struct ath11k_pci *ar_pci);
void ath11k_mhi_unregister(struct ath11k_pci *ar_pci);
void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab);
@ -26,5 +26,4 @@ void ath11k_mhi_clear_vector(struct ath11k_base *ab);
int ath11k_mhi_suspend(struct ath11k_pci *ar_pci);
int ath11k_mhi_resume(struct ath11k_pci *ar_pci);
#endif

View File

@ -638,7 +638,7 @@ static int ath11k_pci_power_up(struct ath11k_base *ab)
return 0;
}
static void ath11k_pci_power_down(struct ath11k_base *ab)
static void ath11k_pci_power_down(struct ath11k_base *ab, bool is_suspend)
{
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
@ -649,7 +649,7 @@ static void ath11k_pci_power_down(struct ath11k_base *ab)
ath11k_pci_msi_disable(ab_pci);
ath11k_mhi_stop(ab_pci);
ath11k_mhi_stop(ab_pci, is_suspend);
clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags);
ath11k_pci_sw_reset(ab_pci->ab, false);
}
@ -970,7 +970,7 @@ static void ath11k_pci_remove(struct pci_dev *pdev)
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath11k_pci_power_down(ab);
ath11k_pci_power_down(ab, false);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
@ -998,7 +998,7 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
ath11k_pci_power_down(ab);
ath11k_pci_power_down(ab, false);
}
static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
@ -1035,9 +1035,39 @@ static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
return ret;
}
static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
ath11k_pci_pm_suspend,
ath11k_pci_pm_resume);
static __maybe_unused int ath11k_pci_pm_suspend_late(struct device *dev)
{
struct ath11k_base *ab = dev_get_drvdata(dev);
int ret;
ret = ath11k_core_suspend_late(ab);
if (ret)
ath11k_warn(ab, "failed to late suspend core: %d\n", ret);
/* Similar to ath11k_pci_pm_suspend(), we return success here
* even error happens, to allow system suspend/hibernation survive.
*/
return 0;
}
static __maybe_unused int ath11k_pci_pm_resume_early(struct device *dev)
{
struct ath11k_base *ab = dev_get_drvdata(dev);
int ret;
ret = ath11k_core_resume_early(ab);
if (ret)
ath11k_warn(ab, "failed to early resume core: %d\n", ret);
return ret;
}
static const struct dev_pm_ops __maybe_unused ath11k_pci_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend,
ath11k_pci_pm_resume)
SET_LATE_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend_late,
ath11k_pci_pm_resume_early)
};
static struct pci_driver ath11k_pci_driver = {
.name = "ath11k_pci",

View File

@ -2877,7 +2877,7 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab)
}
/* reset the firmware */
ath11k_hif_power_down(ab);
ath11k_hif_power_down(ab, false);
ath11k_hif_power_up(ab);
ath11k_dbg(ab, ATH11K_DBG_QMI, "exit wait for cold boot done\n");
return 0;

View File

@ -8651,30 +8651,27 @@ exit:
kfree(tb);
}
static int ath11k_wmi_p2p_noa_event(struct ath11k_base *ab,
struct sk_buff *skb)
static void ath11k_wmi_p2p_noa_event(struct ath11k_base *ab,
struct sk_buff *skb)
{
const void **tb;
const struct wmi_p2p_noa_event *ev;
const struct ath11k_wmi_p2p_noa_info *noa;
struct ath11k *ar;
int ret, vdev_id;
int vdev_id;
u8 noa_descriptors;
tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
if (IS_ERR(tb)) {
ret = PTR_ERR(tb);
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
return ret;
ath11k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb));
return;
}
ev = tb[WMI_TAG_P2P_NOA_EVENT];
noa = tb[WMI_TAG_P2P_NOA_INFO];
if (!ev || !noa) {
ret = -EPROTO;
if (!ev || !noa)
goto out;
}
vdev_id = ev->vdev_id;
noa_descriptors = u32_get_bits(noa->noa_attr,
@ -8683,7 +8680,6 @@ static int ath11k_wmi_p2p_noa_event(struct ath11k_base *ab,
if (noa_descriptors > WMI_P2P_MAX_NOA_DESCRIPTORS) {
ath11k_warn(ab, "invalid descriptor num %d in P2P NoA event\n",
noa_descriptors);
return -EINVAL;
goto out;
}
@ -8696,7 +8692,6 @@ static int ath11k_wmi_p2p_noa_event(struct ath11k_base *ab,
if (!ar) {
ath11k_warn(ab, "invalid vdev id %d in P2P NoA event\n",
vdev_id);
ret = -EINVAL;
goto unlock;
}
@ -8706,7 +8701,6 @@ unlock:
rcu_read_unlock();
out:
kfree(tb);
return 0;
}
static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)

View File

@ -24,6 +24,15 @@ config ATH12K_DEBUG
If unsure, say Y to make it easier to debug problems. But if
you want optimal performance choose N.
config ATH12K_DEBUGFS
bool "QTI ath12k debugfs support"
depends on ATH12K && MAC80211_DEBUGFS
help
Enable ath12k debugfs support
If unsure, say Y to make it easier to debug problems. But if
you want optimal performance choose N.
config ATH12K_TRACING
bool "ath12k tracing support"
depends on ATH12K && EVENT_TRACING

View File

@ -23,6 +23,8 @@ ath12k-y += core.o \
fw.o \
p2p.o
ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o
ath12k-$(CONFIG_ACPI) += acpi.o
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
# for tracing framework to find trace.h

View File

@ -0,0 +1,394 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
#include "acpi.h"
#include "debug.h"
static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
{
union acpi_object *obj;
acpi_handle root_handle;
int ret;
root_handle = ACPI_HANDLE(ab->dev);
if (!root_handle) {
ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid acpi handler\n");
return -EOPNOTSUPP;
}
obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
NULL);
if (!obj) {
ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_evaluate_dsm() failed\n");
return -ENOENT;
}
if (obj->type == ACPI_TYPE_INTEGER) {
ab->acpi.func_bit = obj->integer.value;
} else if (obj->type == ACPI_TYPE_BUFFER) {
switch (func) {
case ATH12K_ACPI_DSM_FUNC_TAS_CFG:
if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
memcpy(&ab->acpi.tas_cfg, obj->buffer.pointer,
obj->buffer.length);
break;
case ATH12K_ACPI_DSM_FUNC_TAS_DATA:
if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
ath12k_warn(ab, "invalid ACPI DSM TAS data size: %d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
memcpy(&ab->acpi.tas_sar_power_table, obj->buffer.pointer,
obj->buffer.length);
break;
case ATH12K_ACPI_DSM_FUNC_BIOS_SAR:
if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
ath12k_warn(ab, "invalid ACPI BIOS SAR data size: %d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
memcpy(&ab->acpi.bios_sar_data, obj->buffer.pointer,
obj->buffer.length);
break;
case ATH12K_ACPI_DSM_FUNC_GEO_OFFSET:
if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
ath12k_warn(ab, "invalid ACPI GEO OFFSET data size: %d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
memcpy(&ab->acpi.geo_offset_data, obj->buffer.pointer,
obj->buffer.length);
break;
case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
ath12k_warn(ab, "invalid ACPI DSM CCA data size: %d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
memcpy(&ab->acpi.cca_data, obj->buffer.pointer,
obj->buffer.length);
break;
case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
ath12k_warn(ab, "invalid ACPI DSM band edge data size: %d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
memcpy(&ab->acpi.band_edge_power, obj->buffer.pointer,
obj->buffer.length);
break;
}
} else {
ath12k_warn(ab, "ACPI DSM method returned an unsupported object type: %d\n",
obj->type);
ret = -EINVAL;
goto out;
}
ret = 0;
out:
ACPI_FREE(obj);
return ret;
}
static int ath12k_acpi_set_power_limit(struct ath12k_base *ab)
{
const u8 *tas_sar_power_table = ab->acpi.tas_sar_power_table;
int ret;
if (tas_sar_power_table[0] != ATH12K_ACPI_TAS_DATA_VERSION ||
tas_sar_power_table[1] != ATH12K_ACPI_TAS_DATA_ENABLE) {
ath12k_warn(ab, "latest ACPI TAS data is invalid\n");
return -EINVAL;
}
ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,
tas_sar_power_table,
ATH12K_ACPI_DSM_TAS_DATA_SIZE);
if (ret) {
ath12k_warn(ab, "failed to send ACPI TAS data table: %d\n", ret);
return ret;
}
return ret;
}
static int ath12k_acpi_set_bios_sar_power(struct ath12k_base *ab)
{
int ret;
if (ab->acpi.bios_sar_data[0] != ATH12K_ACPI_POWER_LIMIT_VERSION ||
ab->acpi.bios_sar_data[1] != ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
ath12k_warn(ab, "invalid latest ACPI BIOS SAR data\n");
return -EINVAL;
}
ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);
if (ret) {
ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);
return ret;
}
return 0;
}
static void ath12k_acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
{
int ret;
struct ath12k_base *ab = data;
if (event == ATH12K_ACPI_NOTIFY_EVENT) {
ath12k_warn(ab, "unknown acpi notify %u\n", event);
return;
}
if (!ab->acpi.acpi_tas_enable) {
ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_tas_enable is false\n");
return;
}
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);
if (ret) {
ath12k_warn(ab, "failed to update ACPI TAS data table: %d\n", ret);
return;
}
ret = ath12k_acpi_set_power_limit(ab);
if (ret) {
ath12k_warn(ab, "failed to set ACPI TAS power limit data: %d", ret);
return;
}
if (!ab->acpi.acpi_bios_sar_enable)
return;
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);
if (ret) {
ath12k_warn(ab, "failed to update BIOS SAR: %d\n", ret);
return;
}
ret = ath12k_acpi_set_bios_sar_power(ab);
if (ret) {
ath12k_warn(ab, "failed to set BIOS SAR power limit: %d\n", ret);
return;
}
}
static int ath12k_acpi_set_bios_sar_params(struct ath12k_base *ab)
{
int ret;
ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);
if (ret) {
ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);
return ret;
}
ret = ath12k_wmi_set_bios_geo_cmd(ab, ab->acpi.geo_offset_data);
if (ret) {
ath12k_warn(ab, "failed to set ACPI BIOS GEO table: %d\n", ret);
return ret;
}
return 0;
}
static int ath12k_acpi_set_tas_params(struct ath12k_base *ab)
{
int ret;
ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_CONFIG_TYPE,
ab->acpi.tas_cfg,
ATH12K_ACPI_DSM_TAS_CFG_SIZE);
if (ret) {
ath12k_warn(ab, "failed to send ACPI TAS config table parameter: %d\n",
ret);
return ret;
}
ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,
ab->acpi.tas_sar_power_table,
ATH12K_ACPI_DSM_TAS_DATA_SIZE);
if (ret) {
ath12k_warn(ab, "failed to send ACPI TAS data table parameter: %d\n",
ret);
return ret;
}
return 0;
}
int ath12k_acpi_start(struct ath12k_base *ab)
{
acpi_status status;
u8 *buf;
int ret;
if (!ab->hw_params->acpi_guid)
/* not supported with this hardware */
return 0;
ab->acpi.acpi_tas_enable = false;
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS);
if (ret) {
ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret);
return ret;
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG);
if (ret) {
ath12k_warn(ab, "failed to get ACPI TAS config table: %d\n", ret);
return ret;
}
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);
if (ret) {
ath12k_warn(ab, "failed to get ACPI TAS data table: %d\n", ret);
return ret;
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
ab->acpi.tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
ab->acpi.tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE)
ab->acpi.acpi_tas_enable = true;
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);
if (ret) {
ath12k_warn(ab, "failed to get ACPI bios sar data: %d\n", ret);
return ret;
}
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_GEO_OFFSET);
if (ret) {
ath12k_warn(ab, "failed to get ACPI geo offset data: %d\n", ret);
return ret;
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
ab->acpi.bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
ab->acpi.bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
!ab->acpi.acpi_tas_enable)
ab->acpi.acpi_bios_sar_enable = true;
}
if (ab->acpi.acpi_tas_enable) {
ret = ath12k_acpi_set_tas_params(ab);
if (ret) {
ath12k_warn(ab, "failed to send ACPI parameters: %d\n", ret);
return ret;
}
}
if (ab->acpi.acpi_bios_sar_enable) {
ret = ath12k_acpi_set_bios_sar_params(ab);
if (ret)
return ret;
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) {
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
if (ret) {
ath12k_warn(ab, "failed to get ACPI DSM CCA threshold configuration: %d\n",
ret);
return ret;
}
if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
ret = ath12k_wmi_set_bios_cmd(ab,
WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,
buf,
ATH12K_ACPI_CCA_THR_OFFSET_LEN);
if (ret) {
ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",
ret);
return ret;
}
}
}
if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi,
ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
if (ret) {
ath12k_warn(ab, "failed to get ACPI DSM band edge channel power: %d\n",
ret);
return ret;
}
if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
ret = ath12k_wmi_set_bios_cmd(ab,
WMI_BIOS_PARAM_TYPE_BANDEDGE,
ab->acpi.band_edge_power,
sizeof(ab->acpi.band_edge_power));
if (ret) {
ath12k_warn(ab,
"failed to set ACPI DSM band edge channel power: %d\n",
ret);
return ret;
}
}
}
status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
ACPI_DEVICE_NOTIFY,
ath12k_acpi_dsm_notify, ab);
if (ACPI_FAILURE(status)) {
ath12k_warn(ab, "failed to install DSM notify callback: %d\n", status);
return -EIO;
}
ab->acpi.started = true;
return 0;
}
void ath12k_acpi_stop(struct ath12k_base *ab)
{
if (!ab->acpi.started)
return;
acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
ACPI_DEVICE_NOTIFY,
ath12k_acpi_dsm_notify);
}

View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_ACPI_H
#define ATH12K_ACPI_H
#include <linux/acpi.h>
#define ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS 0
#define ATH12K_ACPI_DSM_FUNC_BIOS_SAR 4
#define ATH12K_ACPI_DSM_FUNC_GEO_OFFSET 5
#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA 6
#define ATH12K_ACPI_DSM_FUNC_TAS_CFG 8
#define ATH12K_ACPI_DSM_FUNC_TAS_DATA 9
#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE 10
#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR BIT(3)
#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET BIT(4)
#define ATH12K_ACPI_FUNC_BIT_CCA BIT(5)
#define ATH12K_ACPI_FUNC_BIT_TAS_CFG BIT(7)
#define ATH12K_ACPI_FUNC_BIT_TAS_DATA BIT(8)
#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER BIT(9)
#define ATH12K_ACPI_NOTIFY_EVENT 0x86
#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func) (((_acdata).func_bit) & (_func))
#define ATH12K_ACPI_TAS_DATA_VERSION 0x1
#define ATH12K_ACPI_TAS_DATA_ENABLE 0x1
#define ATH12K_ACPI_POWER_LIMIT_VERSION 0x1
#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG 0x1
#define ATH12K_ACPI_CCA_THR_VERSION 0x1
#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG 0x1
#define ATH12K_ACPI_BAND_EDGE_VERSION 0x1
#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG 0x1
#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET 1
#define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET 2
#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET 5
#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN 10
#define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET 12
#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN 18
#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN 22
#define ATH12K_ACPI_CCA_THR_OFFSET_LEN 36
#define ATH12K_ACPI_DSM_TAS_DATA_SIZE 69
#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE 100
#define ATH12K_ACPI_DSM_TAS_CFG_SIZE 108
#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
ATH12K_ACPI_BIOS_SAR_TABLE_LEN)
#define ATH12K_ACPI_DSM_CCA_DATA_SIZE (ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET + \
ATH12K_ACPI_CCA_THR_OFFSET_LEN)
#ifdef CONFIG_ACPI
int ath12k_acpi_start(struct ath12k_base *ab);
void ath12k_acpi_stop(struct ath12k_base *ab);
#else
static inline int ath12k_acpi_start(struct ath12k_base *ab)
{
return 0;
}
static inline void ath12k_acpi_stop(struct ath12k_base *ab)
{
}
#endif /* CONFIG_ACPI */
#endif /* ATH12K_ACPI_H */

View File

@ -15,6 +15,7 @@
#include "debug.h"
#include "hif.h"
#include "fw.h"
#include "debugfs.h"
unsigned int ath12k_debug_mask;
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
@ -43,67 +44,90 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab)
int ath12k_core_suspend(struct ath12k_base *ab)
{
int ret;
struct ath12k *ar;
int ret, i;
if (!ab->hw_params->supports_suspend)
return -EOPNOTSUPP;
/* TODO: there can frames in queues so for now add delay as a hack.
* Need to implement to handle and remove this delay.
rcu_read_lock();
for (i = 0; i < ab->num_radios; i++) {
ar = ath12k_mac_get_ar_by_pdev_id(ab, i);
if (!ar)
continue;
ret = ath12k_mac_wait_tx_complete(ar);
if (ret) {
ath12k_warn(ab, "failed to wait tx complete: %d\n", ret);
rcu_read_unlock();
return ret;
}
}
rcu_read_unlock();
/* PM framework skips suspend_late/resume_early callbacks
* if other devices report errors in their suspend callbacks.
* However ath12k_core_resume() would still be called because
* here we return success thus kernel put us on dpm_suspended_list.
* Since we won't go through a power down/up cycle, there is
* no chance to call complete(&ab->restart_completed) in
* ath12k_core_restart(), making ath12k_core_resume() timeout.
* So call it here to avoid this issue. This also works in case
* no error happens thus suspend_late/resume_early get called,
* because it will be reinitialized in ath12k_core_resume_early().
*/
msleep(500);
complete(&ab->restart_completed);
ret = ath12k_dp_rx_pktlog_stop(ab, true);
if (ret) {
ath12k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(ath12k_core_suspend);
ret = ath12k_dp_rx_pktlog_stop(ab, false);
if (ret) {
ath12k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
ret);
return ret;
}
int ath12k_core_suspend_late(struct ath12k_base *ab)
{
if (!ab->hw_params->supports_suspend)
return -EOPNOTSUPP;
ath12k_hif_irq_disable(ab);
ath12k_hif_ce_irq_disable(ab);
ret = ath12k_hif_suspend(ab);
if (ret) {
ath12k_warn(ab, "failed to suspend hif: %d\n", ret);
return ret;
}
ath12k_hif_power_down(ab, true);
return 0;
}
EXPORT_SYMBOL(ath12k_core_suspend_late);
int ath12k_core_resume(struct ath12k_base *ab)
int ath12k_core_resume_early(struct ath12k_base *ab)
{
int ret;
if (!ab->hw_params->supports_suspend)
return -EOPNOTSUPP;
ret = ath12k_hif_resume(ab);
if (ret) {
ath12k_warn(ab, "failed to resume hif during resume: %d\n", ret);
return ret;
}
reinit_completion(&ab->restart_completed);
ret = ath12k_hif_power_up(ab);
if (ret)
ath12k_warn(ab, "failed to power up hif during resume: %d\n", ret);
ath12k_hif_ce_irq_enable(ab);
ath12k_hif_irq_enable(ab);
return ret;
}
EXPORT_SYMBOL(ath12k_core_resume_early);
ret = ath12k_dp_rx_pktlog_start(ab);
if (ret) {
ath12k_warn(ab, "failed to start rx pktlog during resume: %d\n",
ret);
return ret;
int ath12k_core_resume(struct ath12k_base *ab)
{
long time_left;
if (!ab->hw_params->supports_suspend)
return -EOPNOTSUPP;
time_left = wait_for_completion_timeout(&ab->restart_completed,
ATH12K_RESET_TIMEOUT_HZ);
if (time_left == 0) {
ath12k_warn(ab, "timeout while waiting for restart complete");
return -ETIMEDOUT;
}
return 0;
}
EXPORT_SYMBOL(ath12k_core_resume);
static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
size_t name_len, bool with_variant,
@ -542,6 +566,8 @@ static void ath12k_core_stop(struct ath12k_base *ab)
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
ath12k_qmi_firmware_stop(ab);
ath12k_acpi_stop(ab);
ath12k_hif_stop(ab);
ath12k_wmi_detach(ab);
ath12k_dp_rx_pdev_reo_cleanup(ab);
@ -628,6 +654,8 @@ static int ath12k_core_soc_create(struct ath12k_base *ab)
return ret;
}
ath12k_debugfs_soc_create(ab);
ret = ath12k_hif_power_up(ab);
if (ret) {
ath12k_err(ab, "failed to power up :%d\n", ret);
@ -637,6 +665,7 @@ static int ath12k_core_soc_create(struct ath12k_base *ab)
return 0;
err_qmi_deinit:
ath12k_debugfs_soc_destroy(ab);
ath12k_qmi_deinit_service(ab);
return ret;
}
@ -645,6 +674,7 @@ static void ath12k_core_soc_destroy(struct ath12k_base *ab)
{
ath12k_dp_free(ab);
ath12k_reg_free(ab);
ath12k_debugfs_soc_destroy(ab);
ath12k_qmi_deinit_service(ab);
}
@ -779,6 +809,11 @@ static int ath12k_core_start(struct ath12k_base *ab,
goto err_reo_cleanup;
}
ret = ath12k_acpi_start(ab);
if (ret)
/* ACPI is optional so continue in case of an error */
ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi failed: %d\n", ret);
return 0;
err_reo_cleanup:
@ -874,9 +909,8 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
int ret;
mutex_lock(&ab->core_lock);
ath12k_hif_irq_disable(ab);
ath12k_dp_pdev_free(ab);
ath12k_hif_stop(ab);
ath12k_ce_cleanup_pipes(ab);
ath12k_wmi_detach(ab);
ath12k_dp_rx_pdev_reo_cleanup(ab);
mutex_unlock(&ab->core_lock);
@ -1052,9 +1086,6 @@ static void ath12k_core_restart(struct work_struct *work)
struct ath12k_base *ab = container_of(work, struct ath12k_base, restart_work);
int ret;
if (!ab->is_reset)
ath12k_core_pre_reconfigure_recovery(ab);
ret = ath12k_core_reconfigure_on_crash(ab);
if (ret) {
ath12k_err(ab, "failed to reconfigure driver on crash recovery\n");
@ -1064,8 +1095,7 @@ static void ath12k_core_restart(struct work_struct *work)
if (ab->is_reset)
complete_all(&ab->reconfigure_complete);
if (!ab->is_reset)
ath12k_core_post_reconfigure_recovery(ab);
complete(&ab->restart_completed);
}
static void ath12k_core_reset(struct work_struct *work)
@ -1131,8 +1161,10 @@ static void ath12k_core_reset(struct work_struct *work)
time_left = wait_for_completion_timeout(&ab->recovery_start,
ATH12K_RECOVER_START_TIMEOUT_HZ);
ath12k_hif_power_down(ab);
ath12k_qmi_free_resource(ab);
ath12k_hif_irq_disable(ab);
ath12k_hif_ce_irq_disable(ab);
ath12k_hif_power_down(ab, false);
ath12k_hif_power_up(ab);
ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset started\n");
@ -1175,7 +1207,7 @@ void ath12k_core_deinit(struct ath12k_base *ab)
mutex_unlock(&ab->core_lock);
ath12k_hif_power_down(ab);
ath12k_hif_power_down(ab, false);
ath12k_mac_destroy(ab);
ath12k_core_soc_destroy(ab);
ath12k_fw_unmap(ab);
@ -1223,11 +1255,12 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
init_completion(&ab->htc_suspend);
init_completion(&ab->restart_completed);
ab->dev = dev;
ab->hif.bus = bus;
ab->qmi.num_radios = U8_MAX;
ab->slo_capable = true;
ab->mlo_capable_flags = ATH12K_INTRA_DEVICE_MLO_SUPPORT;
return ab;

View File

@ -26,6 +26,7 @@
#include "reg.h"
#include "dbring.h"
#include "fw.h"
#include "acpi.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@ -46,6 +47,7 @@
#define ATH12K_SMBIOS_BDF_EXT_MAGIC "BDF_"
#define ATH12K_INVALID_HW_MAC_ID 0xFF
#define ATH12K_CONNECTION_LOSS_HZ (3 * HZ)
#define ATH12K_RX_RATE_TABLE_NUM 320
#define ATH12K_RX_RATE_TABLE_11AX_NUM 576
@ -214,6 +216,24 @@ enum ath12k_monitor_flags {
ATH12K_FLAG_MONITOR_ENABLED,
};
struct ath12k_tx_conf {
bool changed;
u16 ac;
struct ieee80211_tx_queue_params tx_queue_params;
};
struct ath12k_key_conf {
bool changed;
enum set_key_cmd cmd;
struct ieee80211_key_conf *key;
};
struct ath12k_vif_cache {
struct ath12k_tx_conf tx_conf;
struct ath12k_key_conf key_conf;
u32 bss_conf_changed;
};
struct ath12k_vif {
u32 vdev_id;
enum wmi_vdev_type vdev_type;
@ -251,11 +271,13 @@ struct ath12k_vif {
} ap;
} u;
bool is_created;
bool is_started;
bool is_up;
u32 aid;
u8 bssid[ETH_ALEN];
struct cfg80211_bitrate_mask bitrate_mask;
struct delayed_work connection_loss_work;
int num_legacy_stations;
int rtscts_prot_mode;
int txpower;
@ -267,10 +289,12 @@ struct ath12k_vif {
u8 vdev_stats_id;
u32 punct_bitmap;
bool ps;
struct ath12k_vif_cache *cache;
};
struct ath12k_vif_iter {
u32 vdev_id;
struct ath12k *ar;
struct ath12k_vif *arvif;
};
@ -453,6 +477,10 @@ struct ath12k_fw_stats {
struct list_head bcn;
};
struct ath12k_debug {
struct dentry *debugfs_pdev;
};
struct ath12k_per_peer_tx_stats {
u32 succ_bytes;
u32 retry_bytes;
@ -592,16 +620,24 @@ struct ath12k {
struct ath12k_per_peer_tx_stats cached_stats;
u32 last_ppdu_id;
u32 cached_ppdu_id;
#ifdef CONFIG_ATH12K_DEBUGFS
struct ath12k_debug debug;
#endif
bool dfs_block_radar_events;
bool monitor_conf_enabled;
bool monitor_vdev_created;
bool monitor_started;
int monitor_vdev_id;
u32 freq_low;
u32 freq_high;
};
struct ath12k_hw {
struct ieee80211_hw *hw;
bool regd_updated;
bool use_6ghz_regd;
u8 num_radio;
struct ath12k radio[] __aligned(sizeof(void *));
@ -688,6 +724,21 @@ struct ath12k_soc_dp_stats {
struct ath12k_soc_dp_tx_err_stats tx_err;
};
/**
* enum ath12k_link_capable_flags - link capable flags
*
* Single/Multi link capability information
*
* @ATH12K_INTRA_DEVICE_MLO_SUPPORT: SLO/MLO form between the radio, where all
* the links (radios) present within a device.
* @ATH12K_INTER_DEVICE_MLO_SUPPORT: SLO/MLO form between the radio, where all
* the links (radios) present across the devices.
*/
enum ath12k_link_capable_flags {
ATH12K_INTRA_DEVICE_MLO_SUPPORT = BIT(0),
ATH12K_INTER_DEVICE_MLO_SUPPORT = BIT(1),
};
/* Master structure to hold the hw data which may be used in core module */
struct ath12k_base {
enum ath12k_hw_rev hw_rev;
@ -782,6 +833,9 @@ struct ath12k_base {
/* Current DFS Regulatory */
enum ath12k_dfs_region dfs_region;
struct ath12k_soc_dp_stats soc_stats;
#ifdef CONFIG_ATH12K_DEBUGFS
struct dentry *debugfs_soc;
#endif
unsigned long dev_flags;
struct completion driver_recovery;
@ -843,10 +897,31 @@ struct ath12k_base {
const struct hal_rx_ops *hal_rx_ops;
/* slo_capable denotes if the single/multi link operation
* is supported within the same chip (SoC).
/* mlo_capable_flags denotes the single/multi link operation
* capabilities of the Device.
*
* See enum ath12k_link_capable_flags
*/
bool slo_capable;
u8 mlo_capable_flags;
struct completion restart_completed;
#ifdef CONFIG_ACPI
struct {
bool started;
u32 func_bit;
bool acpi_tas_enable;
bool acpi_bios_sar_enable;
u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE];
} acpi;
#endif /* CONFIG_ACPI */
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
@ -874,8 +949,10 @@ int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd
int ath12k_core_check_dt(struct ath12k_base *ath12k);
int ath12k_core_check_smbios(struct ath12k_base *ab);
void ath12k_core_halt(struct ath12k *ar);
int ath12k_core_resume_early(struct ath12k_base *ab);
int ath12k_core_resume(struct ath12k_base *ab);
int ath12k_core_suspend(struct ath12k_base *ab);
int ath12k_core_suspend_late(struct ath12k_base *ab);
const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
const char *filename);
@ -951,13 +1028,21 @@ static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw *hw)
return hw->priv;
}
static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah)
static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 hw_link_id)
{
return ah->radio;
if (WARN(hw_link_id >= ah->num_radio,
"bad hw link id %d, so switch to default link\n", hw_link_id))
hw_link_id = 0;
return &ah->radio[hw_link_id];
}
static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar)
{
return ar->ah->hw;
}
#define for_each_ar(ah, ar, index) \
for ((index) = 0; ((index) < (ah)->num_radio && \
((ar) = &(ah)->radio[(index)])); (index)++)
#endif /* _CORE_H_ */

View File

@ -0,0 +1,90 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
#include "debugfs.h"
static ssize_t ath12k_write_simulate_radar(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath12k *ar = file->private_data;
int ret;
mutex_lock(&ar->conf_mutex);
ret = ath12k_wmi_simulate_radar(ar);
if (ret)
goto exit;
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_simulate_radar = {
.write = ath12k_write_simulate_radar,
.open = simple_open
};
void ath12k_debugfs_soc_create(struct ath12k_base *ab)
{
bool dput_needed;
char soc_name[64] = { 0 };
struct dentry *debugfs_ath12k;
debugfs_ath12k = debugfs_lookup("ath12k", NULL);
if (debugfs_ath12k) {
/* a dentry from lookup() needs dput() after we don't use it */
dput_needed = true;
} else {
debugfs_ath12k = debugfs_create_dir("ath12k", NULL);
if (IS_ERR_OR_NULL(debugfs_ath12k))
return;
dput_needed = false;
}
scnprintf(soc_name, sizeof(soc_name), "%s-%s", ath12k_bus_str(ab->hif.bus),
dev_name(ab->dev));
ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath12k);
if (dput_needed)
dput(debugfs_ath12k);
}
void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
{
debugfs_remove_recursive(ab->debugfs_soc);
ab->debugfs_soc = NULL;
/* We are not removing ath12k directory on purpose, even if it
* would be empty. This simplifies the directory handling and it's
* a minor cosmetic issue to leave an empty ath12k directory to
* debugfs.
*/
}
void ath12k_debugfs_register(struct ath12k *ar)
{
struct ath12k_base *ab = ar->ab;
struct ieee80211_hw *hw = ar->ah->hw;
char pdev_name[5];
char buf[100] = {0};
scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
/* Create a symlink under ieee80211/phy* */
scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev);
debugfs_create_symlink("ath12k", hw->wiphy->debugfsdir, buf);
if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) {
debugfs_create_file("dfs_simulate_radar", 0200,
ar->debug.debugfs_pdev, ar,
&fops_simulate_radar);
}
}

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH12K_DEBUGFS_H_
#define _ATH12K_DEBUGFS_H_
#ifdef CONFIG_ATH12K_DEBUGFS
void ath12k_debugfs_soc_create(struct ath12k_base *ab);
void ath12k_debugfs_soc_destroy(struct ath12k_base *ab);
void ath12k_debugfs_register(struct ath12k *ar);
#else
static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab)
{
}
static inline void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
{
}
static inline void ath12k_debugfs_register(struct ath12k *ar)
{
}
#endif /* CONFIG_ATH12K_DEBUGFS */
#endif /* _ATH12K_DEBUGFS_H_ */

View File

@ -14,6 +14,11 @@
#include "peer.h"
#include "dp_mon.h"
enum ath12k_dp_desc_type {
ATH12K_DP_TX_DESC,
ATH12K_DP_RX_DESC,
};
static void ath12k_dp_htt_htc_tx_complete(struct ath12k_base *ab,
struct sk_buff *skb)
{
@ -1150,7 +1155,9 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
struct ath12k_rx_desc_info *desc_info;
struct ath12k_tx_desc_info *tx_desc_info, *tmp1;
struct ath12k_dp *dp = &ab->dp;
struct ath12k_skb_cb *skb_cb;
struct sk_buff *skb;
struct ath12k *ar;
int i, j;
u32 pool_id, tx_spt_page;
@ -1201,6 +1208,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
if (!skb)
continue;
skb_cb = ATH12K_SKB_CB(skb);
ar = skb_cb->ar;
if (atomic_dec_and_test(&ar->dp.num_tx_pending))
wake_up(&ar->dp.tx_empty_waitq);
dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
@ -1344,12 +1356,16 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab,
u32 cookie)
{
struct ath12k_rx_desc_info **desc_addr_ptr;
u16 ppt_idx, spt_idx;
u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx;
ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT);
spt_idx = u32_get_bits(cookie, ATH12k_DP_CC_COOKIE_SPT);
spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT);
if (ppt_idx > ATH12K_NUM_RX_SPT_PAGES ||
start_ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET;
end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES;
if (ppt_idx < start_ppt_idx ||
ppt_idx >= end_ppt_idx ||
spt_idx > ATH12K_MAX_SPT_ENTRIES)
return NULL;
@ -1362,13 +1378,17 @@ struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab,
u32 cookie)
{
struct ath12k_tx_desc_info **desc_addr_ptr;
u16 ppt_idx, spt_idx;
u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx;
ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT);
spt_idx = u32_get_bits(cookie, ATH12k_DP_CC_COOKIE_SPT);
spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT);
if (ppt_idx < ATH12K_NUM_RX_SPT_PAGES ||
ppt_idx > ab->dp.num_spt_pages ||
start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET;
end_ppt_idx = start_ppt_idx +
(ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES);
if (ppt_idx < start_ppt_idx ||
ppt_idx >= end_ppt_idx ||
spt_idx > ATH12K_MAX_SPT_ENTRIES)
return NULL;
@ -1397,15 +1417,16 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
return -ENOMEM;
}
ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i;
dp->spt_info->rxbaddr[i] = &rx_descs[0];
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(i, j);
rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(ppt_idx, j);
rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC;
list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list);
/* Update descriptor VA in SPT */
rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, i, j);
rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, j);
*rx_desc_addr = &rx_descs[j];
}
}
@ -1425,10 +1446,11 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
}
tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page;
dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0];
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
ppt_idx = ATH12K_NUM_RX_SPT_PAGES + tx_spt_page;
tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j);
tx_descs[j].pool_id = pool_id;
list_add_tail(&tx_descs[j].list,
@ -1445,11 +1467,41 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
return 0;
}
static int ath12k_dp_cmem_init(struct ath12k_base *ab,
struct ath12k_dp *dp,
enum ath12k_dp_desc_type type)
{
u32 cmem_base;
int i, start, end;
cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start;
switch (type) {
case ATH12K_DP_TX_DESC:
start = ATH12K_TX_SPT_PAGE_OFFSET;
end = start + ATH12K_NUM_TX_SPT_PAGES;
break;
case ATH12K_DP_RX_DESC:
start = ATH12K_RX_SPT_PAGE_OFFSET;
end = start + ATH12K_NUM_RX_SPT_PAGES;
break;
default:
ath12k_err(ab, "invalid descriptor type %d in cmem init\n", type);
return -EINVAL;
}
/* Write to PPT in CMEM */
for (i = start; i < end; i++)
ath12k_hif_write32(ab, cmem_base + ATH12K_PPT_ADDR_OFFSET(i),
dp->spt_info[i].paddr >> ATH12K_SPT_4K_ALIGN_OFFSET);
return 0;
}
static int ath12k_dp_cc_init(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
int i, ret = 0;
u32 cmem_base;
INIT_LIST_HEAD(&dp->rx_desc_free_list);
spin_lock_init(&dp->rx_desc_lock);
@ -1472,8 +1524,6 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab)
return -ENOMEM;
}
cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start;
for (i = 0; i < dp->num_spt_pages; i++) {
dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev,
ATH12K_PAGE_SIZE,
@ -1490,10 +1540,18 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab)
ret = -EINVAL;
goto free;
}
}
/* Write to PPT in CMEM */
ath12k_hif_write32(ab, cmem_base + ATH12K_PPT_ADDR_OFFSET(i),
dp->spt_info[i].paddr >> ATH12K_SPT_4K_ALIGN_OFFSET);
ret = ath12k_dp_cmem_init(ab, dp, ATH12K_DP_TX_DESC);
if (ret) {
ath12k_warn(ab, "HW CC Tx cmem init failed %d", ret);
goto free;
}
ret = ath12k_dp_cmem_init(ab, dp, ATH12K_DP_RX_DESC);
if (ret) {
ath12k_warn(ab, "HW CC Rx cmem init failed %d", ret);
goto free;
}
ret = ath12k_dp_cc_desc_init(ab);

View File

@ -223,6 +223,9 @@ struct ath12k_pdev_dp {
#define ATH12K_NUM_TX_SPT_PAGES (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES)
#define ATH12K_NUM_SPT_PAGES (ATH12K_NUM_RX_SPT_PAGES + ATH12K_NUM_TX_SPT_PAGES)
#define ATH12K_TX_SPT_PAGE_OFFSET 0
#define ATH12K_RX_SPT_PAGE_OFFSET ATH12K_NUM_TX_SPT_PAGES
/* The SPT pages are divided for RX and TX, first block for RX
* and remaining for TX
*/
@ -245,7 +248,7 @@ struct ath12k_pdev_dp {
#define ATH12K_CC_SPT_MSB 8
#define ATH12K_CC_PPT_MSB 19
#define ATH12K_CC_PPT_SHIFT 9
#define ATH12k_DP_CC_COOKIE_SPT GENMASK(8, 0)
#define ATH12K_DP_CC_COOKIE_SPT GENMASK(8, 0)
#define ATH12K_DP_CC_COOKIE_PPT GENMASK(19, 9)
#define DP_REO_QREF_NUM GENMASK(31, 16)

View File

@ -944,7 +944,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
goto err_merge_fail;
ath12k_dbg(ab, ATH12K_DBG_DATA,
"mpdu_buf %pK mpdu_buf->len %u",
"mpdu_buf %p mpdu_buf->len %u",
prev_buf, prev_buf->len);
} else {
ath12k_dbg(ab, ATH12K_DBG_DATA,
@ -958,7 +958,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
err_merge_fail:
if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) {
ath12k_dbg(ab, ATH12K_DBG_DATA,
"err_merge_fail mpdu_buf %pK", mpdu_buf);
"err_merge_fail mpdu_buf %p", mpdu_buf);
/* Free the head buffer */
dev_kfree_skb_any(mpdu_buf);
}
@ -1092,7 +1092,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
spin_unlock_bh(&ar->ab->base_lock);
ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
"rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
"rx skb %p len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
msdu,
msdu->len,
peer ? peer->addr : NULL,

View File

@ -239,26 +239,12 @@ static inline u8 ath12k_dp_rx_get_msdu_src_link(struct ath12k_base *ab,
return ab->hal_rx_ops->rx_desc_get_msdu_src_link_id(desc);
}
static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab)
static void ath12k_dp_clean_up_skb_list(struct sk_buff_head *skb_list)
{
int i, reaped = 0;
unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS);
struct sk_buff *skb;
do {
for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++)
reaped += ath12k_dp_mon_process_ring(ab, i, NULL,
DP_MON_SERVICE_BUDGET,
ATH12K_DP_RX_MONITOR_MODE);
/* nothing more to reap */
if (reaped < DP_MON_SERVICE_BUDGET)
return 0;
} while (time_before(jiffies, timeout));
ath12k_warn(ab, "dp mon ring purge timeout");
return -ETIMEDOUT;
while ((skb = __skb_dequeue(skb_list)))
dev_kfree_skb_any(skb);
}
static size_t ath12k_dp_list_cut_nodes(struct list_head *list,
@ -2459,7 +2445,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
spin_unlock_bh(&ab->base_lock);
ath12k_dbg(ab, ATH12K_DBG_DATA,
"rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
"rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
msdu,
msdu->len,
peer ? peer->addr : NULL,
@ -3742,19 +3728,20 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
struct hal_rx_wbm_rel_info err_info;
struct hal_srng *srng;
struct sk_buff *msdu;
struct sk_buff_head msdu_list;
struct sk_buff_head msdu_list, scatter_msdu_list;
struct ath12k_skb_rxcb *rxcb;
void *rx_desc;
u8 mac_id;
int num_buffs_reaped = 0;
struct ath12k_rx_desc_info *desc_info;
int ret, pdev_id;
struct hal_rx_desc *msdu_data;
__skb_queue_head_init(&msdu_list);
__skb_queue_head_init(&scatter_msdu_list);
srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id];
rx_ring = &dp->rx_refill_buf_ring;
spin_lock_bh(&srng->lock);
ath12k_hal_srng_access_begin(ab, srng);
@ -3807,17 +3794,53 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
continue;
}
msdu_data = (struct hal_rx_desc *)msdu->data;
rxcb->err_rel_src = err_info.err_rel_src;
rxcb->err_code = err_info.err_code;
rxcb->rx_desc = (struct hal_rx_desc *)msdu->data;
__skb_queue_tail(&msdu_list, msdu);
rxcb->is_first_msdu = err_info.first_msdu;
rxcb->is_last_msdu = err_info.last_msdu;
rxcb->is_continuation = err_info.continuation;
rxcb->rx_desc = msdu_data;
if (err_info.continuation) {
__skb_queue_tail(&scatter_msdu_list, msdu);
continue;
}
mac_id = ath12k_dp_rx_get_msdu_src_link(ab,
msdu_data);
if (mac_id >= MAX_RADIOS) {
dev_kfree_skb_any(msdu);
/* In any case continuation bit is set
* in the previous record, cleanup scatter_msdu_list
*/
ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
continue;
}
if (!skb_queue_empty(&scatter_msdu_list)) {
struct sk_buff *msdu;
skb_queue_walk(&scatter_msdu_list, msdu) {
rxcb = ATH12K_SKB_RXCB(msdu);
rxcb->mac_id = mac_id;
}
skb_queue_splice_tail_init(&scatter_msdu_list,
&msdu_list);
}
rxcb = ATH12K_SKB_RXCB(msdu);
rxcb->mac_id = mac_id;
__skb_queue_tail(&msdu_list, msdu);
}
/* In any case continuation bit is set in the
* last record, cleanup scatter_msdu_list
*/
ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
ath12k_hal_srng_access_end(ab, srng);
spin_unlock_bh(&srng->lock);
@ -3830,8 +3853,9 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
rcu_read_lock();
while ((msdu = __skb_dequeue(&msdu_list))) {
mac_id = ath12k_dp_rx_get_msdu_src_link(ab,
(struct hal_rx_desc *)msdu->data);
rxcb = ATH12K_SKB_RXCB(msdu);
mac_id = rxcb->mac_id;
pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id);
ar = ab->pdevs[pdev_id].ar;
@ -4264,29 +4288,3 @@ int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar)
return 0;
}
int ath12k_dp_rx_pktlog_start(struct ath12k_base *ab)
{
/* start reap timer */
mod_timer(&ab->mon_reap_timer,
jiffies + msecs_to_jiffies(ATH12K_MON_TIMER_INTERVAL));
return 0;
}
int ath12k_dp_rx_pktlog_stop(struct ath12k_base *ab, bool stop_timer)
{
int ret;
if (stop_timer)
del_timer_sync(&ab->mon_reap_timer);
/* reap all the monitor related rings */
ret = ath12k_dp_purge_mon_ring(ab);
if (ret) {
ath12k_warn(ab, "failed to purge dp mon ring: %d\n", ret);
return ret;
}
return 0;
}

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_DP_RX_H
#define ATH12K_DP_RX_H
@ -123,8 +123,6 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab,
int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar);
int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id);
int ath12k_dp_rx_pktlog_start(struct ath12k_base *ab);
int ath12k_dp_rx_pktlog_stop(struct ath12k_base *ab, bool stop_timer);
u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab,
struct hal_rx_desc *desc);
struct ath12k_peer *

View File

@ -767,7 +767,7 @@ struct hal_srng_config {
};
/**
* enum hal_rx_buf_return_buf_manager
* enum hal_rx_buf_return_buf_manager - manager for returned rx buffers
*
* @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list
* @HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST: Descriptor returned to WBM idle

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HIF_H
@ -17,7 +17,7 @@ struct ath12k_hif_ops {
int (*start)(struct ath12k_base *ab);
void (*stop)(struct ath12k_base *ab);
int (*power_up)(struct ath12k_base *ab);
void (*power_down)(struct ath12k_base *ab);
void (*power_down)(struct ath12k_base *ab, bool is_suspend);
int (*suspend)(struct ath12k_base *ab);
int (*resume)(struct ath12k_base *ab);
int (*map_service_to_pipe)(struct ath12k_base *ab, u16 service_id,
@ -133,12 +133,18 @@ static inline void ath12k_hif_write32(struct ath12k_base *ab, u32 address,
static inline int ath12k_hif_power_up(struct ath12k_base *ab)
{
if (!ab->hif.ops->power_up)
return -EOPNOTSUPP;
return ab->hif.ops->power_up(ab);
}
static inline void ath12k_hif_power_down(struct ath12k_base *ab)
static inline void ath12k_hif_power_down(struct ath12k_base *ab, bool is_suspend)
{
ab->hif.ops->power_down(ab);
if (!ab->hif.ops->power_down)
return;
ab->hif.ops->power_down(ab, is_suspend);
}
#endif /* ATH12K_HIF_H */

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/skbuff.h>
#include <linux/ctype.h>
@ -358,7 +358,7 @@ void ath12k_htc_rx_completion_handler(struct ath12k_base *ab,
goto out;
}
ath12k_dbg(ab, ATH12K_DBG_HTC, "htc rx completion ep %d skb %pK\n",
ath12k_dbg(ab, ATH12K_DBG_HTC, "htc rx completion ep %d skb %p\n",
eid, skb);
ep->ep_ops.ep_rx_complete(ab, skb);

View File

@ -15,6 +15,10 @@
#include "mhi.h"
#include "dp_rx.h"
static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
0x90, 0xd6, 0x02, 0x42,
0xac, 0x12, 0x00, 0x03);
static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
{
return pdev_idx;
@ -920,6 +924,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB,
.supports_sta_ps = false,
.acpi_guid = NULL,
},
{
.name = "wcn7850 hw2.0",
@ -964,7 +970,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.idle_ps = true,
.download_calib = false,
.supports_suspend = false,
.supports_suspend = true,
.tcl_ring_retry = false,
.reoq_lut_support = false,
.supports_shadow_regs = true,
@ -993,6 +999,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.otp_board_id_register = 0,
.supports_sta_ps = true,
.acpi_guid = &wcn7850_uuid,
},
{
.name = "qcn9274 hw2.0",
@ -1061,6 +1069,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB,
.supports_sta_ps = false,
.acpi_guid = NULL,
},
};

View File

@ -8,6 +8,7 @@
#define ATH12K_HW_H
#include <linux/mhi.h>
#include <linux/uuid.h>
#include "wmi.h"
#include "hal.h"
@ -80,6 +81,7 @@
#define TARGET_RX_PEER_METADATA_VER_V1A 2
#define TARGET_RX_PEER_METADATA_VER_V1B 3
#define ATH12K_HW_DEFAULT_QUEUE 0
#define ATH12K_HW_MAX_QUEUES 4
#define ATH12K_QUEUE_LEN 4096
@ -211,6 +213,8 @@ struct ath12k_hw_params {
u32 otp_board_id_register;
bool supports_sta_ps;
const guid_t *acpi_guid;
};
struct ath12k_hw_ops {

File diff suppressed because it is too large Load Diff

View File

@ -78,4 +78,8 @@ enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw b
enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
int ath12k_mac_rfkill_config(struct ath12k *ar);
int ath12k_mac_wait_tx_complete(struct ath12k *ar);
void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb);
void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id);
#endif

View File

@ -18,34 +18,6 @@
#define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000
static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
{
.num = 0,
.name = "LOOPBACK",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 1,
.name = "LOOPBACK",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 20,
.name = "IPCR",
@ -111,34 +83,6 @@ const struct mhi_controller_config ath12k_mhi_config_qcn9274 = {
};
static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
{
.num = 0,
.name = "LOOPBACK",
.num_elements = 32,
.event_ring = 0,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 1,
.name = "LOOPBACK",
.num_elements = 32,
.event_ring = 0,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 20,
.name = "IPCR",
@ -196,7 +140,7 @@ const struct mhi_controller_config ath12k_mhi_config_wcn7850 = {
.max_channels = 128,
.timeout_ms = 2000,
.use_bounce_buf = false,
.buf_len = 0,
.buf_len = 8192,
.num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850),
.ch_cfg = ath12k_mhi_channels_wcn7850,
.num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850),
@ -385,7 +329,6 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci)
"failed to read board id\n");
} else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) {
dualmac = true;
ab->slo_capable = false;
ath12k_dbg(ab, ATH12K_DBG_BOOT,
"dualmac fw selected for board id: %x\n", board_id);
}
@ -470,6 +413,8 @@ static char *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state)
return "POWER_ON";
case ATH12K_MHI_POWER_OFF:
return "POWER_OFF";
case ATH12K_MHI_POWER_OFF_KEEP_DEV:
return "POWER_OFF_KEEP_DEV";
case ATH12K_MHI_FORCE_POWER_OFF:
return "FORCE_POWER_OFF";
case ATH12K_MHI_SUSPEND:
@ -501,6 +446,7 @@ static void ath12k_mhi_set_state_bit(struct ath12k_pci *ab_pci,
set_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state);
break;
case ATH12K_MHI_POWER_OFF:
case ATH12K_MHI_POWER_OFF_KEEP_DEV:
case ATH12K_MHI_FORCE_POWER_OFF:
clear_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state);
clear_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state);
@ -544,6 +490,7 @@ static int ath12k_mhi_check_state_bit(struct ath12k_pci *ab_pci,
return 0;
break;
case ATH12K_MHI_POWER_OFF:
case ATH12K_MHI_POWER_OFF_KEEP_DEV:
case ATH12K_MHI_SUSPEND:
if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&
!test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state))
@ -594,12 +541,27 @@ static int ath12k_mhi_set_state(struct ath12k_pci *ab_pci,
ret = 0;
break;
case ATH12K_MHI_POWER_ON:
ret = mhi_async_power_up(ab_pci->mhi_ctrl);
/* In case of resume, QRTR's resume_early() is called
* right after ath12k' resume_early(). Since QRTR requires
* MHI mission mode state when preparing IPCR channels
* (see ee_mask of that channel), we need to use the 'sync'
* version here to make sure MHI is in that state when we
* return. Or QRTR might resume before that state comes,
* and as a result it fails.
*
* The 'sync' version works for non-resume (normal power on)
* case as well.
*/
ret = mhi_sync_power_up(ab_pci->mhi_ctrl);
break;
case ATH12K_MHI_POWER_OFF:
mhi_power_down(ab_pci->mhi_ctrl, true);
ret = 0;
break;
case ATH12K_MHI_POWER_OFF_KEEP_DEV:
mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true);
ret = 0;
break;
case ATH12K_MHI_FORCE_POWER_OFF:
mhi_power_down(ab_pci->mhi_ctrl, false);
ret = 0;
@ -653,9 +615,17 @@ out:
return ret;
}
void ath12k_mhi_stop(struct ath12k_pci *ab_pci)
void ath12k_mhi_stop(struct ath12k_pci *ab_pci, bool is_suspend)
{
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF);
/* During suspend we need to use mhi_power_down_keep_dev()
* workaround, otherwise ath12k_core_resume() will timeout
* during resume.
*/
if (is_suspend)
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF_KEEP_DEV);
else
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF);
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT);
}

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH12K_MHI_H
#define _ATH12K_MHI_H
@ -22,6 +22,7 @@ enum ath12k_mhi_state {
ATH12K_MHI_DEINIT,
ATH12K_MHI_POWER_ON,
ATH12K_MHI_POWER_OFF,
ATH12K_MHI_POWER_OFF_KEEP_DEV,
ATH12K_MHI_FORCE_POWER_OFF,
ATH12K_MHI_SUSPEND,
ATH12K_MHI_RESUME,
@ -34,7 +35,7 @@ extern const struct mhi_controller_config ath12k_mhi_config_qcn9274;
extern const struct mhi_controller_config ath12k_mhi_config_wcn7850;
int ath12k_mhi_start(struct ath12k_pci *ar_pci);
void ath12k_mhi_stop(struct ath12k_pci *ar_pci);
void ath12k_mhi_stop(struct ath12k_pci *ar_pci, bool is_suspend);
int ath12k_mhi_register(struct ath12k_pci *ar_pci);
void ath12k_mhi_unregister(struct ath12k_pci *ar_pci);
void ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab);

View File

@ -121,7 +121,7 @@ static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
struct ath12k_p2p_noa_arg *arg = data;
if (arvif->vdev_id != arg->vdev_id)
if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id)
return;
ath12k_p2p_noa_update(arvif, arg->noa);
@ -132,6 +132,7 @@ void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id,
{
struct ath12k_p2p_noa_arg arg = {
.vdev_id = vdev_id,
.ar = ar,
.noa = noa,
};

View File

@ -12,6 +12,7 @@ struct ath12k_wmi_p2p_noa_info;
struct ath12k_p2p_noa_arg {
u32 vdev_id;
struct ath12k *ar;
const struct ath12k_wmi_p2p_noa_info *noa;
};

View File

@ -872,7 +872,7 @@ static int ath12k_pci_claim(struct ath12k_pci *ab_pci, struct pci_dev *pdev)
goto release_region;
}
ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot pci_mem 0x%p\n", ab->mem);
return 0;
release_region:
@ -1271,7 +1271,7 @@ int ath12k_pci_power_up(struct ath12k_base *ab)
return 0;
}
void ath12k_pci_power_down(struct ath12k_base *ab)
void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
@ -1280,7 +1280,7 @@ void ath12k_pci_power_down(struct ath12k_base *ab)
ath12k_pci_force_wake(ab_pci->ab);
ath12k_pci_msi_disable(ab_pci);
ath12k_mhi_stop(ab_pci);
ath12k_mhi_stop(ab_pci, is_suspend);
clear_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
ath12k_pci_sw_reset(ab_pci->ab, false);
}
@ -1503,7 +1503,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath12k_pci_power_down(ab);
ath12k_pci_power_down(ab, false);
ath12k_qmi_deinit_service(ab);
goto qmi_fail;
}
@ -1531,7 +1531,7 @@ static void ath12k_pci_shutdown(struct pci_dev *pdev)
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
ath12k_pci_power_down(ab);
ath12k_pci_power_down(ab, false);
}
static __maybe_unused int ath12k_pci_pm_suspend(struct device *dev)
@ -1558,9 +1558,36 @@ static __maybe_unused int ath12k_pci_pm_resume(struct device *dev)
return ret;
}
static SIMPLE_DEV_PM_OPS(ath12k_pci_pm_ops,
ath12k_pci_pm_suspend,
ath12k_pci_pm_resume);
static __maybe_unused int ath12k_pci_pm_suspend_late(struct device *dev)
{
struct ath12k_base *ab = dev_get_drvdata(dev);
int ret;
ret = ath12k_core_suspend_late(ab);
if (ret)
ath12k_warn(ab, "failed to late suspend core: %d\n", ret);
return ret;
}
static __maybe_unused int ath12k_pci_pm_resume_early(struct device *dev)
{
struct ath12k_base *ab = dev_get_drvdata(dev);
int ret;
ret = ath12k_core_resume_early(ab);
if (ret)
ath12k_warn(ab, "failed to early resume core: %d\n", ret);
return ret;
}
static const struct dev_pm_ops __maybe_unused ath12k_pci_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ath12k_pci_pm_suspend,
ath12k_pci_pm_resume)
SET_LATE_SYSTEM_SLEEP_PM_OPS(ath12k_pci_pm_suspend_late,
ath12k_pci_pm_resume_early)
};
static struct pci_driver ath12k_pci_driver = {
.name = "ath12k_pci",

View File

@ -143,5 +143,5 @@ int ath12k_pci_hif_resume(struct ath12k_base *ab);
void ath12k_pci_stop(struct ath12k_base *ab);
int ath12k_pci_start(struct ath12k_base *ab);
int ath12k_pci_power_up(struct ath12k_base *ab);
void ath12k_pci_power_down(struct ath12k_base *ab);
void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend);
#endif /* ATH12K_PCI_H */

View File

@ -582,6 +582,24 @@ static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = {
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
board_id),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.array_type = NO_ARRAY,
.tlv_type = 0x13,
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
single_chip_mlo_support_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.array_type = NO_ARRAY,
.tlv_type = 0x13,
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
single_chip_mlo_support),
},
{
.data_type = QMI_EOTI,
.array_type = NO_ARRAY,
@ -2005,7 +2023,15 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
u8 hw_link_id = 0;
int i;
if (!(ab->mlo_capable_flags & ATH12K_INTRA_DEVICE_MLO_SUPPORT)) {
ath12k_dbg(ab, ATH12K_DBG_QMI,
"intra device MLO is disabled hence skip QMI MLO cap");
return;
}
if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) {
ab->mlo_capable_flags = 0;
ath12k_dbg(ab, ATH12K_DBG_QMI,
"skip QMI MLO cap due to invalid num_radio %d\n",
ab->qmi.num_radios);
@ -2124,9 +2150,6 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
struct qmi_txn txn;
int ret;
if (!ab->slo_capable)
goto out;
ret = qmi_txn_init(&ab->qmi.handle, &txn,
qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp);
if (ret < 0)
@ -2151,6 +2174,13 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
goto out;
}
if (resp.single_chip_mlo_support_valid) {
if (resp.single_chip_mlo_support)
ab->mlo_capable_flags |= ATH12K_INTRA_DEVICE_MLO_SUPPORT;
else
ab->mlo_capable_flags &= ~ATH12K_INTRA_DEVICE_MLO_SUPPORT;
}
if (!resp.num_phy_valid) {
ret = -ENODATA;
goto out;
@ -2158,9 +2188,11 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
ab->qmi.num_radios = resp.num_phy;
ath12k_dbg(ab, ATH12K_DBG_QMI, "phy capability resp valid %d num_phy %d valid %d board_id %d\n",
ath12k_dbg(ab, ATH12K_DBG_QMI,
"phy capability resp valid %d num_phy %d valid %d board_id %d valid %d single_chip_mlo_support %d\n",
resp.num_phy_valid, resp.num_phy,
resp.board_id_valid, resp.board_id);
resp.board_id_valid, resp.board_id,
resp.single_chip_mlo_support_valid, resp.single_chip_mlo_support);
return;
@ -2325,8 +2357,9 @@ static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab)
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
if (!ab->qmi.target_mem[i].v.addr)
continue;
dma_free_coherent(ab->dev,
ab->qmi.target_mem[i].size,
ab->qmi.target_mem[i].prev_size,
ab->qmi.target_mem[i].v.addr,
ab->qmi.target_mem[i].paddr);
ab->qmi.target_mem[i].v.addr = NULL;
@ -2352,6 +2385,20 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
case M3_DUMP_REGION_TYPE:
case PAGEABLE_MEM_REGION_TYPE:
case CALDB_MEM_REGION_TYPE:
/* Firmware reloads in recovery/resume.
* In such cases, no need to allocate memory for FW again.
*/
if (chunk->v.addr) {
if (chunk->prev_type == chunk->type &&
chunk->prev_size == chunk->size)
goto this_chunk_done;
/* cannot reuse the existing chunk */
dma_free_coherent(ab->dev, chunk->prev_size,
chunk->v.addr, chunk->paddr);
chunk->v.addr = NULL;
}
chunk->v.addr = dma_alloc_coherent(ab->dev,
chunk->size,
&chunk->paddr,
@ -2370,6 +2417,10 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
chunk->type, chunk->size);
return -ENOMEM;
}
chunk->prev_type = chunk->type;
chunk->prev_size = chunk->size;
this_chunk_done:
break;
default:
ath12k_warn(ab, "memory type %u not supported\n",
@ -2666,6 +2717,19 @@ out:
return ret;
}
static void ath12k_qmi_m3_free(struct ath12k_base *ab)
{
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
if (!m3_mem->vaddr)
return;
dma_free_coherent(ab->dev, m3_mem->size,
m3_mem->vaddr, m3_mem->paddr);
m3_mem->vaddr = NULL;
m3_mem->size = 0;
}
static int ath12k_qmi_m3_load(struct ath12k_base *ab)
{
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
@ -2675,10 +2739,6 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab)
size_t m3_len;
int ret;
if (m3_mem->vaddr)
/* m3 firmware buffer is already available in the DMA buffer */
return 0;
if (ab->fw.m3_data && ab->fw.m3_len > 0) {
/* firmware-N.bin had a m3 firmware file so use that */
m3_data = ab->fw.m3_data;
@ -2700,6 +2760,15 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab)
m3_len = fw->size;
}
/* In recovery/resume cases, M3 buffer is not freed, try to reuse that */
if (m3_mem->vaddr) {
if (m3_mem->size >= m3_len)
goto skip_m3_alloc;
/* Old buffer is too small, free and reallocate */
ath12k_qmi_m3_free(ab);
}
m3_mem->vaddr = dma_alloc_coherent(ab->dev,
m3_len, &m3_mem->paddr,
GFP_KERNEL);
@ -2710,6 +2779,7 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab)
goto out;
}
skip_m3_alloc:
memcpy(m3_mem->vaddr, m3_data, m3_len);
m3_mem->size = m3_len;
@ -2721,19 +2791,6 @@ out:
return ret;
}
static void ath12k_qmi_m3_free(struct ath12k_base *ab)
{
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
if (!m3_mem->vaddr)
return;
dma_free_coherent(ab->dev, m3_mem->size,
m3_mem->vaddr, m3_mem->paddr);
m3_mem->vaddr = NULL;
m3_mem->size = 0;
}
static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab)
{
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
@ -3178,6 +3235,9 @@ static const struct qmi_msg_handler ath12k_qmi_msg_handlers[] = {
.decoded_size = sizeof(struct qmi_wlanfw_fw_ready_ind_msg_v01),
.fn = ath12k_qmi_msg_fw_ready_cb,
},
/* end of list */
{},
};
static int ath12k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
@ -3261,7 +3321,8 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work)
case ATH12K_QMI_EVENT_FW_READY:
clear_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags);
if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {
ath12k_hal_dump_srng_stats(ab);
if (ab->is_reset)
ath12k_hal_dump_srng_stats(ab);
queue_work(ab->workqueue, &ab->restart_work);
break;
}

View File

@ -96,6 +96,8 @@ struct ath12k_qmi_event_msg {
struct target_mem_chunk {
u32 size;
u32 type;
u32 prev_size;
u32 prev_type;
dma_addr_t paddr;
union {
void __iomem *ioaddr;
@ -265,6 +267,8 @@ struct qmi_wlanfw_phy_cap_resp_msg_v01 {
u8 num_phy;
u8 board_id_valid;
u32 board_id;
u8 single_chip_mlo_support_valid;
u8 single_chip_mlo_support;
};
#define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN 54

View File

@ -49,8 +49,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath12k_wmi_init_country_arg arg;
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar = ath12k_ah_to_ar(ah);
int ret;
struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
int ret, i;
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"Regulatory Notification received for %s\n", wiphy_name(wiphy));
@ -85,10 +85,16 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
arg.cc_info.alpha2[2] = 0;
ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
if (ret)
ath12k_warn(ar->ab,
"INIT Country code set to fw failed : %d\n", ret);
/* Allow fresh updates to wiphy regd */
ah->regd_updated = false;
/* Send the reg change request to all the radios */
for_each_ar(ah, ar, i) {
ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
if (ret)
ath12k_warn(ar->ab,
"INIT Country code set to fw failed : %d\n", ret);
}
}
int ath12k_reg_update_chan_list(struct ath12k *ar)
@ -202,10 +208,32 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
{
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
struct ieee80211_regdomain *regd, *regd_copy = NULL;
struct ath12k_hw *ah = ar->ah;
int ret, regd_len, pdev_id;
struct ath12k_base *ab;
int i;
ab = ar->ab;
/* If one of the radios within ah has already updated the regd for
* the wiphy, then avoid setting regd again
*/
if (ah->regd_updated)
return 0;
/* firmware provides reg rules which are similar for 2 GHz and 5 GHz
* pdev but 6 GHz pdev has superset of all rules including rules for
* all bands, we prefer 6 GHz pdev's rules to be used for setup of
* the wiphy regd.
* If 6 GHz pdev was part of the ath12k_hw, wait for the 6 GHz pdev,
* else pick the first pdev which calls this function and use its
* regd to update global hw regd.
* The regd_updated flag set at the end will not allow any further
* updates.
*/
if (ah->use_6ghz_regd && !ar->supports_6ghz)
return 0;
pdev_id = ar->pdev_idx;
spin_lock_bh(&ab->base_lock);
@ -258,10 +286,17 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
if (ret)
goto err;
if (ar->state == ATH12K_STATE_ON) {
ret = ath12k_reg_update_chan_list(ar);
if (ret)
goto err;
ah->regd_updated = true;
/* Apply the new regd to all the radios, this is expected to be received only once
* since we check for ah->regd_updated and allow here only once.
*/
for_each_ar(ah, ar, i) {
if (ar->state == ATH12K_STATE_ON) {
ab = ar->ab;
ret = ath12k_reg_update_chan_list(ar);
if (ret)
goto err;
}
}
return 0;

View File

@ -858,20 +858,20 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr,
len = sizeof(*txrx_streams);
txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_TXRX_STREAMS,
len);
txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G;
txrx_streams->band = cpu_to_le32(WMI_TPC_CHAINMASK_CONFIG_BAND_2G);
txrx_streams->supported_tx_streams =
args->chains[NL80211_BAND_2GHZ].tx;
cpu_to_le32(args->chains[NL80211_BAND_2GHZ].tx);
txrx_streams->supported_rx_streams =
args->chains[NL80211_BAND_2GHZ].rx;
cpu_to_le32(args->chains[NL80211_BAND_2GHZ].rx);
txrx_streams++;
txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_TXRX_STREAMS,
len);
txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G;
txrx_streams->band = cpu_to_le32(WMI_TPC_CHAINMASK_CONFIG_BAND_5G);
txrx_streams->supported_tx_streams =
args->chains[NL80211_BAND_5GHZ].tx;
cpu_to_le32(args->chains[NL80211_BAND_5GHZ].tx);
txrx_streams->supported_rx_streams =
args->chains[NL80211_BAND_5GHZ].rx;
cpu_to_le32(args->chains[NL80211_BAND_5GHZ].rx);
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
"WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n",
@ -2723,6 +2723,149 @@ int ath12k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath12k *ar,
return ret;
}
int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id,
const u8 *buf, size_t buf_len)
{
struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
struct wmi_pdev_set_bios_interface_cmd *cmd;
struct wmi_tlv *tlv;
struct sk_buff *skb;
u8 *ptr;
u32 len, len_aligned;
int ret;
len_aligned = roundup(buf_len, sizeof(u32));
len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
skb = ath12k_wmi_alloc_skb(wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD,
sizeof(*cmd));
cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
cmd->param_type_id = cpu_to_le32(param_id);
cmd->length = cpu_to_le32(buf_len);
ptr = skb->data + sizeof(*cmd);
tlv = (struct wmi_tlv *)ptr;
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
ptr += TLV_HDR_SIZE;
memcpy(ptr, buf, buf_len);
ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0],
skb,
WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
if (ret) {
ath12k_warn(ab,
"failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID parameter id %d: %d\n",
param_id, ret);
dev_kfree_skb(skb);
}
return 0;
}
int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table)
{
struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
struct wmi_pdev_set_bios_sar_table_cmd *cmd;
struct wmi_tlv *tlv;
struct sk_buff *skb;
int ret;
u8 *buf_ptr;
u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
const u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET;
const u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET;
sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN,
sizeof(u32));
len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
skb = ath12k_wmi_alloc_skb(wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD,
sizeof(*cmd));
cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
buf_ptr = skb->data + sizeof(*cmd);
tlv = (struct wmi_tlv *)buf_ptr;
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
sar_table_len_aligned);
buf_ptr += TLV_HDR_SIZE;
memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
buf_ptr += sar_table_len_aligned;
tlv = (struct wmi_tlv *)buf_ptr;
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
sar_dbs_backoff_len_aligned);
buf_ptr += TLV_HDR_SIZE;
memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0],
skb,
WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
if (ret) {
ath12k_warn(ab,
"failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n",
ret);
dev_kfree_skb(skb);
}
return ret;
}
int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table)
{
struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
struct wmi_pdev_set_bios_geo_table_cmd *cmd;
struct wmi_tlv *tlv;
struct sk_buff *skb;
int ret;
u8 *buf_ptr;
u32 len, sar_geo_len_aligned;
const u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
skb = ath12k_wmi_alloc_skb(wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD,
sizeof(*cmd));
cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
buf_ptr = skb->data + sizeof(*cmd);
tlv = (struct wmi_tlv *)buf_ptr;
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
buf_ptr += TLV_HDR_SIZE;
memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0],
skb,
WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
if (ret) {
ath12k_warn(ab,
"failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n",
ret);
dev_kfree_skb(skb);
}
return ret;
}
int ath12k_wmi_delba_send(struct ath12k *ar, u32 vdev_id, const u8 *mac,
u32 tid, u32 initiator, u32 reason)
{
@ -3324,7 +3467,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf
wmi_cfg->bpf_instruction_size = cpu_to_le32(tg_cfg->bpf_instruction_size);
wmi_cfg->max_bssid_rx_filters = cpu_to_le32(tg_cfg->max_bssid_rx_filters);
wmi_cfg->use_pdev_id = cpu_to_le32(tg_cfg->use_pdev_id);
wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config);
wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config |
WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64);
wmi_cfg->peer_map_unmap_version = cpu_to_le32(tg_cfg->peer_map_unmap_version);
wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params);
wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count);
@ -4041,6 +4185,7 @@ static void ath12k_wmi_free_dbring_caps(struct ath12k_base *ab)
{
kfree(ab->db_caps);
ab->db_caps = NULL;
ab->num_db_cap = 0;
}
static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab,
@ -5927,13 +6072,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
}
}
/* TODO: Pending handle beacon implementation
*if (ieee80211_is_beacon(hdr->frame_control))
* ath12k_mac_handle_beacon(ar, skb);
*/
if (ieee80211_is_beacon(hdr->frame_control))
ath12k_mac_handle_beacon(ar, skb);
ath12k_dbg(ab, ATH12K_DBG_MGMT,
"event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
"event mgmt rx skb %p len %d ftype %02x stype %02x\n",
skb, skb->len,
fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
@ -6137,42 +6280,44 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
{
struct wmi_roam_event roam_ev = {};
struct ath12k *ar;
u32 vdev_id;
u8 roam_reason;
if (ath12k_pull_roam_ev(ab, skb, &roam_ev) != 0) {
ath12k_warn(ab, "failed to extract roam event");
return;
}
vdev_id = le32_to_cpu(roam_ev.vdev_id);
roam_reason = u32_get_bits(le32_to_cpu(roam_ev.reason),
WMI_ROAM_REASON_MASK);
ath12k_dbg(ab, ATH12K_DBG_WMI,
"wmi roam event vdev %u reason 0x%08x rssi %d\n",
roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi);
"wmi roam event vdev %u reason %d rssi %d\n",
vdev_id, roam_reason, roam_ev.rssi);
rcu_read_lock();
ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(roam_ev.vdev_id));
ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
if (!ar) {
ath12k_warn(ab, "invalid vdev id in roam ev %d",
roam_ev.vdev_id);
ath12k_warn(ab, "invalid vdev id in roam ev %d", vdev_id);
rcu_read_unlock();
return;
}
if (le32_to_cpu(roam_ev.reason) >= WMI_ROAM_REASON_MAX)
if (roam_reason >= WMI_ROAM_REASON_MAX)
ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n",
roam_ev.reason, roam_ev.vdev_id);
roam_reason, vdev_id);
switch (le32_to_cpu(roam_ev.reason)) {
switch (roam_reason) {
case WMI_ROAM_REASON_BEACON_MISS:
/* TODO: Pending beacon miss and connection_loss_work
* implementation
* ath12k_mac_handle_beacon_miss(ar, vdev_id);
*/
ath12k_mac_handle_beacon_miss(ar, vdev_id);
break;
case WMI_ROAM_REASON_BETTER_AP:
case WMI_ROAM_REASON_LOW_RSSI:
case WMI_ROAM_REASON_SUITABLE_AP_FOUND:
case WMI_ROAM_REASON_HO_FAILED:
ath12k_warn(ab, "ignoring not implemented roam event reason %d on vdev %i\n",
roam_ev.reason, roam_ev.vdev_id);
roam_reason, vdev_id);
break;
}

View File

@ -353,6 +353,9 @@ enum wmi_tlv_cmd_id {
WMI_PDEV_DMA_RING_CFG_REQ_CMDID,
WMI_PDEV_HE_TB_ACTION_FRM_CMDID,
WMI_PDEV_PKTLOG_FILTER_CMDID,
WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID = 0x4044,
WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
WMI_VDEV_DELETE_CMDID,
WMI_VDEV_START_REQUEST_CMDID,
@ -1925,6 +1928,9 @@ enum wmi_tlv_tag {
WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
WMI_TAG_EHT_RATE_SET = 0x3C4,
WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD = 0x3D9,
WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD = 0x3FB,
WMI_TAG_MAX
};
@ -2195,8 +2201,11 @@ enum wmi_peer_param {
WMI_PEER_SET_MAX_TX_RATE = 17,
WMI_PEER_SET_MIN_TX_RATE = 18,
WMI_PEER_SET_DEFAULT_ROUTING = 19,
WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP = 39,
};
#define WMI_PEER_PUNCTURE_BITMAP GENMASK(23, 8)
enum wmi_slot_time {
WMI_VDEV_SLOT_TIME_LONG = 1,
WMI_VDEV_SLOT_TIME_SHORT = 2,
@ -2400,6 +2409,7 @@ struct wmi_init_cmd {
#define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4
#define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4)
#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
struct ath12k_wmi_resource_config_params {
__le32 tlv_header;
@ -2600,6 +2610,19 @@ struct ath12k_wmi_soc_hal_reg_caps_params {
__le32 num_phy;
} __packed;
enum wmi_channel_width {
WMI_CHAN_WIDTH_20 = 0,
WMI_CHAN_WIDTH_40 = 1,
WMI_CHAN_WIDTH_80 = 2,
WMI_CHAN_WIDTH_160 = 3,
WMI_CHAN_WIDTH_80P80 = 4,
WMI_CHAN_WIDTH_5 = 5,
WMI_CHAN_WIDTH_10 = 6,
WMI_CHAN_WIDTH_165 = 7,
WMI_CHAN_WIDTH_160P160 = 8,
WMI_CHAN_WIDTH_320 = 9,
};
#define WMI_MAX_EHTCAP_MAC_SIZE 2
#define WMI_MAX_EHTCAP_PHY_SIZE 3
#define WMI_MAX_EHTCAP_RATE_SET 3
@ -2724,9 +2747,9 @@ struct wmi_vdev_create_cmd {
struct ath12k_wmi_vdev_txrx_streams_params {
__le32 tlv_header;
u32 band;
u32 supported_tx_streams;
u32 supported_rx_streams;
__le32 band;
__le32 supported_tx_streams;
__le32 supported_rx_streams;
} __packed;
struct wmi_vdev_delete_cmd {
@ -4182,6 +4205,9 @@ struct wmi_peer_sta_kickout_event {
struct ath12k_wmi_mac_addr_params peer_macaddr;
} __packed;
#define WMI_ROAM_REASON_MASK GENMASK(3, 0)
#define WMI_ROAM_SUBNET_STATUS_MASK GENMASK(5, 4)
enum wmi_roam_reason {
WMI_ROAM_REASON_BETTER_AP = 1,
WMI_ROAM_REASON_BEACON_MISS = 2,
@ -4774,6 +4800,37 @@ struct ath12k_wmi_base {
struct ath12k_wmi_target_cap_arg *targ_cap;
};
struct wmi_pdev_set_bios_interface_cmd {
__le32 tlv_header;
__le32 pdev_id;
__le32 param_type_id;
__le32 length;
} __packed;
enum wmi_bios_param_type {
WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE = 0,
WMI_BIOS_PARAM_TAS_CONFIG_TYPE = 1,
WMI_BIOS_PARAM_TAS_DATA_TYPE = 2,
/* bandedge control power */
WMI_BIOS_PARAM_TYPE_BANDEDGE = 3,
WMI_BIOS_PARAM_TYPE_MAX,
};
struct wmi_pdev_set_bios_sar_table_cmd {
__le32 tlv_header;
__le32 pdev_id;
__le32 sar_len;
__le32 dbs_backoff_len;
} __packed;
struct wmi_pdev_set_bios_geo_table_cmd {
__le32 tlv_header;
__le32 pdev_id;
__le32 geo_len;
} __packed;
#define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
enum wmi_sys_cap_info_flags {
@ -4932,6 +4989,10 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
struct sk_buff *tmpl);
int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
enum wmi_host_hw_mode_config_type mode);
int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id,
const u8 *buf, size_t buf_len);
int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table);
int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table);
static inline u32
ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param)

View File

@ -1427,25 +1427,7 @@ static struct sdio_driver ath6kl_sdio_driver = {
.remove = ath6kl_sdio_remove,
.drv.pm = ATH6KL_SDIO_PM_OPS,
};
static int __init ath6kl_sdio_init(void)
{
int ret;
ret = sdio_register_driver(&ath6kl_sdio_driver);
if (ret)
ath6kl_err("sdio driver registration failed: %d\n", ret);
return ret;
}
static void __exit ath6kl_sdio_exit(void)
{
sdio_unregister_driver(&ath6kl_sdio_driver);
}
module_init(ath6kl_sdio_init);
module_exit(ath6kl_sdio_exit);
module_sdio_driver(ath6kl_sdio_driver);
MODULE_AUTHOR("Atheros Communications, Inc.");
MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");

View File

@ -135,8 +135,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
if (power_mode != ATH9K_PM_AWAKE) {
spin_lock(&common->cc_lock);
ath_hw_cycle_counters_update(common);
memset(&common->cc_survey, 0, sizeof(common->cc_survey));
memset(&common->cc_ani, 0, sizeof(common->cc_ani));
memset(&common->cc, 0, sizeof(common->cc));
spin_unlock(&common->cc_lock);
}

View File

@ -280,7 +280,8 @@ static void carl9170_tx_release(struct kref *ref)
* carl9170_tx_fill_rateinfo() has filled the rate information
* before we get to this point.
*/
memset_after(&txinfo->status, 0, rates);
memset(&txinfo->pad, 0, sizeof(txinfo->pad));
memset(&txinfo->rate_driver_data, 0, sizeof(txinfo->rate_driver_data));
if (atomic_read(&ar->tx_total_queued))
ar->tx_schedule = true;

View File

@ -1069,6 +1069,38 @@ static int carl9170_usb_probe(struct usb_interface *intf,
ar->usb_ep_cmd_is_bulk = true;
}
/* Verify that all expected endpoints are present */
if (ar->usb_ep_cmd_is_bulk) {
u8 bulk_ep_addr[] = {
AR9170_USB_EP_RX | USB_DIR_IN,
AR9170_USB_EP_TX | USB_DIR_OUT,
AR9170_USB_EP_CMD | USB_DIR_OUT,
0};
u8 int_ep_addr[] = {
AR9170_USB_EP_IRQ | USB_DIR_IN,
0};
if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
!usb_check_int_endpoints(intf, int_ep_addr))
err = -ENODEV;
} else {
u8 bulk_ep_addr[] = {
AR9170_USB_EP_RX | USB_DIR_IN,
AR9170_USB_EP_TX | USB_DIR_OUT,
0};
u8 int_ep_addr[] = {
AR9170_USB_EP_IRQ | USB_DIR_IN,
AR9170_USB_EP_CMD | USB_DIR_OUT,
0};
if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
!usb_check_int_endpoints(intf, int_ep_addr))
err = -ENODEV;
}
if (err) {
carl9170_free(ar);
return err;
}
usb_set_intfdata(intf, ar);
SET_IEEE80211_DEV(ar->hw, &intf->dev);

View File

@ -892,10 +892,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wireless_dev *wdev = request->wdev;
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
struct {
struct wmi_start_scan_cmd cmd;
u16 chnl[4];
} __packed cmd;
DEFINE_FLEX(struct wmi_start_scan_cmd, cmd,
channel_list, num_channels, 4);
uint i, n;
int rc;
@ -977,9 +975,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
vif->scan_request = request;
mod_timer(&vif->scan_timer, jiffies + WIL6210_SCAN_TO);
memset(&cmd, 0, sizeof(cmd));
cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
cmd.cmd.num_channels = 0;
cmd->scan_type = WMI_ACTIVE_SCAN;
cmd->num_channels = 0;
n = min(request->n_channels, 4U);
for (i = 0; i < n; i++) {
int ch = request->channels[i]->hw_value;
@ -991,7 +988,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
continue;
}
/* 0-based channel indexes */
cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
cmd->num_channels++;
cmd->channel_list[cmd->num_channels - 1].channel = ch - 1;
wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch,
request->channels[i]->center_freq);
}
@ -1007,16 +1005,15 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
if (rc)
goto out_restore;
if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
cmd.cmd.discovery_mode = 1;
if (wil->discovery_mode && cmd->scan_type == WMI_ACTIVE_SCAN) {
cmd->discovery_mode = 1;
wil_dbg_misc(wil, "active scan with discovery_mode=1\n");
}
if (vif->mid == 0)
wil->radio_wdev = wdev;
rc = wmi_send(wil, WMI_START_SCAN_CMDID, vif->mid,
&cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
cmd, struct_size(cmd, channel_list, cmd->num_channels));
out_restore:
if (rc) {

View File

@ -4014,28 +4014,23 @@ int wmi_set_cqm_rssi_config(struct wil6210_priv *wil,
struct net_device *ndev = wil->main_ndev;
struct wil6210_vif *vif = ndev_to_vif(ndev);
int rc;
struct {
struct wmi_set_link_monitor_cmd cmd;
s8 rssi_thold;
} __packed cmd = {
.cmd = {
.rssi_hyst = rssi_hyst,
.rssi_thresholds_list_size = 1,
},
.rssi_thold = rssi_thold,
};
struct {
struct wmi_cmd_hdr hdr;
struct wmi_set_link_monitor_event evt;
} __packed reply = {
.evt = {.status = WMI_FW_STATUS_FAILURE},
};
DEFINE_FLEX(struct wmi_set_link_monitor_cmd, cmd,
rssi_thresholds_list, rssi_thresholds_list_size, 1);
cmd->rssi_hyst = rssi_hyst;
cmd->rssi_thresholds_list[0] = rssi_thold;
if (rssi_thold > S8_MAX || rssi_thold < S8_MIN || rssi_hyst > U8_MAX)
return -EINVAL;
rc = wmi_call(wil, WMI_SET_LINK_MONITOR_CMDID, vif->mid, &cmd,
sizeof(cmd), WMI_SET_LINK_MONITOR_EVENTID,
rc = wmi_call(wil, WMI_SET_LINK_MONITOR_CMDID, vif->mid, cmd,
__struct_size(cmd), WMI_SET_LINK_MONITOR_EVENTID,
&reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
if (rc) {
wil_err(wil, "WMI_SET_LINK_MONITOR_CMDID failed, rc %d\n", rc);

View File

@ -474,7 +474,7 @@ struct wmi_start_scan_cmd {
struct {
u8 channel;
u8 reserved;
} channel_list[];
} channel_list[] __counted_by(num_channels);
} __packed;
#define WMI_MAX_PNO_SSID_NUM (16)
@ -3320,7 +3320,7 @@ struct wmi_set_link_monitor_cmd {
u8 rssi_hyst;
u8 reserved[12];
u8 rssi_thresholds_list_size;
s8 rssi_thresholds_list[];
s8 rssi_thresholds_list[] __counted_by(rssi_thresholds_list_size);
} __packed;
/* wmi_link_monitor_event_type */

View File

@ -630,12 +630,28 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl);
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl);
/**
* mhi_power_down - Start MHI power down sequence
* mhi_power_down - Power down the MHI device and also destroy the
* 'struct device' for the channels associated with it.
* See also mhi_power_down_keep_dev() which is a variant
* of this API that keeps the 'struct device' for channels
* (useful during suspend/hibernation).
* @mhi_cntrl: MHI controller
* @graceful: Link is still accessible, so do a graceful shutdown process
*/
void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful);
/**
* mhi_power_down_keep_dev - Power down the MHI device but keep the 'struct
* device' for the channels associated with it.
* This is a variant of 'mhi_power_down()' and
* useful in scenarios such as suspend/hibernation
* where destroying of the 'struct device' is not
* needed.
* @mhi_cntrl: MHI controller
* @graceful: Link is still accessible, so do a graceful shutdown process
*/
void mhi_power_down_keep_dev(struct mhi_controller *mhi_cntrl, bool graceful);
/**
* mhi_unprepare_after_power_down - Free any allocated memory after power down
* @mhi_cntrl: MHI controller

View File

@ -118,6 +118,51 @@ static const struct mhi_device_id qcom_mhi_qrtr_id_table[] = {
};
MODULE_DEVICE_TABLE(mhi, qcom_mhi_qrtr_id_table);
static int __maybe_unused qcom_mhi_qrtr_pm_suspend_late(struct device *dev)
{
struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev);
enum mhi_state state;
state = mhi_get_mhi_state(mhi_dev->mhi_cntrl);
/*
* If the device is in suspend state, then no need for the
* client driver to unprepare the channels.
*/
if (state == MHI_STATE_M3)
return 0;
mhi_unprepare_from_transfer(mhi_dev);
return 0;
}
static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev)
{
struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev);
enum mhi_state state;
int rc;
state = mhi_get_mhi_state(mhi_dev->mhi_cntrl);
/*
* If the device is in suspend state, we won't unprepare channels
* in suspend callback, therefore no need to prepare channels when
* resume.
*/
if (state == MHI_STATE_M3)
return 0;
rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
if (rc)
dev_err(dev, "failed to prepare for autoqueue transfer %d\n", rc);
return rc;
}
static const struct dev_pm_ops qcom_mhi_qrtr_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(qcom_mhi_qrtr_pm_suspend_late,
qcom_mhi_qrtr_pm_resume_early)
};
static struct mhi_driver qcom_mhi_qrtr_driver = {
.probe = qcom_mhi_qrtr_probe,
.remove = qcom_mhi_qrtr_remove,
@ -126,6 +171,7 @@ static struct mhi_driver qcom_mhi_qrtr_driver = {
.id_table = qcom_mhi_qrtr_id_table,
.driver = {
.name = "qcom_mhi_qrtr",
.pm = &qcom_mhi_qrtr_pm_ops,
},
};