Commit ec038c61 authored by Wen Gong's avatar Wen Gong Committed by Kalle Valo
Browse files

ath11k: add support for hardware rfkill for QCA6390



When hardware rfkill is enabled in the firmware it will report the
capability via using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY
event to the host. ath11k will check the capability, and if it is enabled then
ath11k will set the GPIO information to firmware using WMI_PDEV_SET_PARAM. When
the firmware detects hardware rfkill is enabled by the user, it will report it
via WMI_RFKILL_STATE_CHANGE_EVENTID. Once ath11k receives the event it will
send wmi command WMI_PDEV_SET_PARAM to the firmware and also notifies cfg80211.

This only enable rfkill feature for QCA6390, rfkill_pin is all initialized to 0
for other chips in ath11k_hw_params.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

Signed-off-by: default avatarWen Gong <quic_wgong@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20211217102334.14907-1-quic_wgong@quicinc.com
parent 1b8bb94c
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -52,6 +52,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.target_ce_count = 11,
		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074,
		.svc_to_ce_map_len = 21,
		.rfkill_pin = 0,
		.rfkill_cfg = 0,
		.rfkill_on_level = 0,
		.single_pdev_only = false,
		.rxdma1_enable = true,
		.num_rxmda_per_pdev = 1,
@@ -114,6 +117,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.target_ce_count = 11,
		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018,
		.svc_to_ce_map_len = 19,
		.rfkill_pin = 0,
		.rfkill_cfg = 0,
		.rfkill_on_level = 0,
		.single_pdev_only = false,
		.rxdma1_enable = true,
		.num_rxmda_per_pdev = 1,
@@ -173,6 +179,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.target_ce_count = 9,
		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
		.svc_to_ce_map_len = 14,
		.rfkill_pin = 48,
		.rfkill_cfg = 0,
		.rfkill_on_level = 1,
		.single_pdev_only = true,
		.rxdma1_enable = false,
		.num_rxmda_per_pdev = 2,
@@ -231,6 +240,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.target_ce_count = 9,
		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qcn9074,
		.svc_to_ce_map_len = 18,
		.rfkill_pin = 0,
		.rfkill_cfg = 0,
		.rfkill_on_level = 0,
		.rxdma1_enable = true,
		.num_rxmda_per_pdev = 1,
		.rx_mac_buf_ring = false,
@@ -289,6 +301,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.target_ce_count = 9,
		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
		.svc_to_ce_map_len = 14,
		.rfkill_pin = 0,
		.rfkill_cfg = 0,
		.rfkill_on_level = 0,
		.single_pdev_only = true,
		.rxdma1_enable = false,
		.num_rxmda_per_pdev = 2,
@@ -347,6 +362,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.target_ce_count = 9,
		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
		.svc_to_ce_map_len = 14,
		.rfkill_pin = 0,
		.rfkill_cfg = 0,
		.rfkill_on_level = 0,
		.single_pdev_only = true,
		.rxdma1_enable = false,
		.num_rxmda_per_pdev = 2,
@@ -1015,6 +1033,27 @@ static int ath11k_core_start(struct ath11k_base *ab,
	return ret;
}

static int ath11k_core_rfkill_config(struct ath11k_base *ab)
{
	struct ath11k *ar;
	int ret = 0, i;

	if (!(ab->target_caps.sys_cap_info & WMI_SYS_CAP_INFO_RFKILL))
		return 0;

	for (i = 0; i < ab->num_radios; i++) {
		ar = ab->pdevs[i].ar;

		ret = ath11k_mac_rfkill_config(ar);
		if (ret && ret != -EOPNOTSUPP) {
			ath11k_warn(ab, "failed to configure rfkill: %d", ret);
			return ret;
		}
	}

	return ret;
}

int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
{
	int ret;
@@ -1061,6 +1100,13 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
		goto err_core_stop;
	}
	ath11k_hif_irq_enable(ab);

	ret = ath11k_core_rfkill_config(ab);
	if (ret && ret != -EOPNOTSUPP) {
		ath11k_err(ab, "failed to config rfkill: %d\n", ret);
		goto err_core_stop;
	}

	mutex_unlock(&ab->core_lock);

	return 0;
@@ -1126,6 +1172,7 @@ void ath11k_core_halt(struct ath11k *ar)
	cancel_delayed_work_sync(&ar->scan.timeout);
	cancel_work_sync(&ar->regd_update_work);
	cancel_work_sync(&ab->update_11d_work);
	cancel_work_sync(&ab->rfkill_work);

	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
	synchronize_rcu();
@@ -1133,6 +1180,28 @@ void ath11k_core_halt(struct ath11k *ar)
	idr_init(&ar->txmgmt_idr);
}

static void ath11k_rfkill_work(struct work_struct *work)
{
	struct ath11k_base *ab = container_of(work, struct ath11k_base, rfkill_work);
	struct ath11k *ar;
	bool rfkill_radio_on;
	int i;

	spin_lock_bh(&ab->base_lock);
	rfkill_radio_on = ab->rfkill_radio_on;
	spin_unlock_bh(&ab->base_lock);

	for (i = 0; i < ab->num_radios; i++) {
		ar = ab->pdevs[i].ar;
		if (!ar)
			continue;

		/* notify cfg80211 radio state change */
		ath11k_mac_rfkill_enable_radio(ar, rfkill_radio_on);
		wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on);
	}
}

static void ath11k_update_11d(struct work_struct *work)
{
	struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work);
@@ -1339,6 +1408,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
	init_waitqueue_head(&ab->qmi.cold_boot_waitq);
	INIT_WORK(&ab->restart_work, ath11k_core_restart);
	INIT_WORK(&ab->update_11d_work, ath11k_update_11d);
	INIT_WORK(&ab->rfkill_work, ath11k_rfkill_work);
	timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
	init_completion(&ab->htc_suspend);
	init_completion(&ab->wow.wakeup_completed);
+4 −0
Original line number Diff line number Diff line
@@ -786,6 +786,10 @@ struct ath11k_base {

	struct ath11k_dbring_cap *db_caps;
	u32 num_db_cap;
	struct work_struct rfkill_work;

	/* true means radio is on */
	bool rfkill_radio_on;

	/* To synchronize 11d scan vdev id */
	struct mutex vdev_id_11d_lock;
+3 −0
Original line number Diff line number Diff line
@@ -151,6 +151,9 @@ struct ath11k_hw_params {
	u32 svc_to_ce_map_len;

	bool single_pdev_only;
	u32 rfkill_pin;
	u32 rfkill_cfg;
	u32 rfkill_on_level;

	bool rxdma1_enable;
	int num_rxmda_per_pdev;
+58 −0
Original line number Diff line number Diff line
@@ -5571,6 +5571,63 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb,
	return 0;
}

int ath11k_mac_rfkill_config(struct ath11k *ar)
{
	struct ath11k_base *ab = ar->ab;
	u32 param;
	int ret;

	if (ab->hw_params.rfkill_pin == 0)
		return -EOPNOTSUPP;

	ath11k_dbg(ab, ATH11K_DBG_MAC,
		   "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d",
		   ab->hw_params.rfkill_pin, ab->hw_params.rfkill_cfg,
		   ab->hw_params.rfkill_on_level);

	param = FIELD_PREP(WMI_RFKILL_CFG_RADIO_LEVEL,
			   ab->hw_params.rfkill_on_level) |
		FIELD_PREP(WMI_RFKILL_CFG_GPIO_PIN_NUM,
			   ab->hw_params.rfkill_pin) |
		FIELD_PREP(WMI_RFKILL_CFG_PIN_AS_GPIO,
			   ab->hw_params.rfkill_cfg);

	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG,
					param, ar->pdev->pdev_id);
	if (ret) {
		ath11k_warn(ab,
			    "failed to set rfkill config 0x%x: %d\n",
			    param, ret);
		return ret;
	}

	return 0;
}

int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable)
{
	enum wmi_rfkill_enable_radio param;
	int ret;

	if (enable)
		param = WMI_RFKILL_ENABLE_RADIO_ON;
	else
		param = WMI_RFKILL_ENABLE_RADIO_OFF;

	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac %d rfkill enable %d",
		   ar->pdev_idx, param);

	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE,
					param, ar->pdev->pdev_id);
	if (ret) {
		ath11k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n",
			    param, ret);
		return ret;
	}

	return 0;
}

static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
			     struct ieee80211_tx_control *control,
			     struct sk_buff *skb)
@@ -5803,6 +5860,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
	cancel_delayed_work_sync(&ar->scan.timeout);
	cancel_work_sync(&ar->regd_update_work);
	cancel_work_sync(&ar->ab->update_11d_work);
	cancel_work_sync(&ar->ab->rfkill_work);

	spin_lock_bh(&ar->data_lock);
	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
+2 −0
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@ u8 ath11k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,

void __ath11k_mac_scan_finish(struct ath11k *ar);
void ath11k_mac_scan_finish(struct ath11k *ar);
int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable);
int ath11k_mac_rfkill_config(struct ath11k *ar);

struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id);
struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab,
Loading