Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad45c888 authored by Marek Puzyniak's avatar Marek Puzyniak Committed by Kalle Valo
Browse files

ath10k: add wmi support for tdls



As a part of tdls implementation introduce
tdls related wmi data structures, constant
values and functions.

Signed-off-by: default avatarMarek Puzyniak <marek.puzyniak@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 7c354242
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -166,6 +166,13 @@ struct wmi_ops {
					       int pattern_offset);
	struct sk_buff *(*gen_wow_del_pattern)(struct ath10k *ar, u32 vdev_id,
					       u32 pattern_id);
	struct sk_buff *(*gen_update_fw_tdls_state)(struct ath10k *ar,
						    u32 vdev_id,
						    enum wmi_tdls_state state);
	struct sk_buff *(*gen_tdls_peer_update)(struct ath10k *ar,
						const struct wmi_tdls_peer_update_cmd_arg *arg,
						const struct wmi_tdls_peer_capab_arg *cap,
						const struct wmi_channel_arg *chan);
};

int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1189,4 +1196,40 @@ ath10k_wmi_wow_del_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id)
	cmd_id = ar->wmi.cmd->wow_del_wake_pattern_cmdid;
	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
}

static inline int
ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
				enum wmi_tdls_state state)
{
	struct sk_buff *skb;

	if (!ar->wmi.ops->gen_update_fw_tdls_state)
		return -EOPNOTSUPP;

	skb = ar->wmi.ops->gen_update_fw_tdls_state(ar, vdev_id, state);
	if (IS_ERR(skb))
		return PTR_ERR(skb);

	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->tdls_set_state_cmdid);
}

static inline int
ath10k_wmi_tdls_peer_update(struct ath10k *ar,
			    const struct wmi_tdls_peer_update_cmd_arg *arg,
			    const struct wmi_tdls_peer_capab_arg *cap,
			    const struct wmi_channel_arg *chan)
{
	struct sk_buff *skb;

	if (!ar->wmi.ops->gen_tdls_peer_update)
		return -EOPNOTSUPP;

	skb = ar->wmi.ops->gen_tdls_peer_update(ar, arg, cap, chan);
	if (IS_ERR(skb))
		return PTR_ERR(skb);

	return ath10k_wmi_cmd_send(ar, skb,
				   ar->wmi.cmd->tdls_peer_update_cmdid);
}

#endif
+153 −0
Original line number Diff line number Diff line
@@ -2596,6 +2596,155 @@ ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
	return skb;
}

static struct sk_buff *
ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
					   enum wmi_tdls_state state)
{
	struct wmi_tdls_set_state_cmd *cmd;
	struct wmi_tlv *tlv;
	struct sk_buff *skb;
	void *ptr;
	size_t len;
	/* Set to options from wmi_tlv_tdls_options,
	 * for now none of them are enabled.
	 */
	u32 options = 0;

	len = sizeof(*tlv) + sizeof(*cmd);
	skb = ath10k_wmi_alloc_skb(ar, len);
	if (!skb)
		return ERR_PTR(-ENOMEM);

	ptr = (void *)skb->data;
	tlv = ptr;
	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD);
	tlv->len = __cpu_to_le16(sizeof(*cmd));

	cmd = (void *)tlv->value;
	cmd->vdev_id = __cpu_to_le32(vdev_id);
	cmd->state = __cpu_to_le32(state);
	cmd->notification_interval_ms = __cpu_to_le32(5000);
	cmd->tx_discovery_threshold = __cpu_to_le32(100);
	cmd->tx_teardown_threshold = __cpu_to_le32(5);
	cmd->rssi_teardown_threshold = __cpu_to_le32(-75);
	cmd->rssi_delta = __cpu_to_le32(-20);
	cmd->tdls_options = __cpu_to_le32(options);
	cmd->tdls_peer_traffic_ind_window = __cpu_to_le32(2);
	cmd->tdls_peer_traffic_response_timeout_ms = __cpu_to_le32(5000);
	cmd->tdls_puapsd_mask = __cpu_to_le32(0xf);
	cmd->tdls_puapsd_inactivity_time_ms = __cpu_to_le32(0);
	cmd->tdls_puapsd_rx_frame_threshold = __cpu_to_le32(10);

	ptr += sizeof(*tlv);
	ptr += sizeof(*cmd);

	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv update fw tdls state %d for vdev %i\n",
		   state, vdev_id);
	return skb;
}

static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
{
	u32 peer_qos = 0;

	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;

	peer_qos |= SM(sp, WMI_TLV_TDLS_PEER_SP);

	return peer_qos;
}

static struct sk_buff *
ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
				       const struct wmi_tdls_peer_update_cmd_arg *arg,
				       const struct wmi_tdls_peer_capab_arg *cap,
				       const struct wmi_channel_arg *chan_arg)
{
	struct wmi_tdls_peer_update_cmd *cmd;
	struct wmi_tdls_peer_capab *peer_cap;
	struct wmi_channel *chan;
	struct wmi_tlv *tlv;
	struct sk_buff *skb;
	u32 peer_qos;
	void *ptr;
	int len;
	int i;

	len = sizeof(*tlv) + sizeof(*cmd) +
	      sizeof(*tlv) + sizeof(*peer_cap) +
	      sizeof(*tlv) + cap->peer_chan_len * sizeof(*chan);

	skb = ath10k_wmi_alloc_skb(ar, len);
	if (!skb)
		return ERR_PTR(-ENOMEM);

	ptr = (void *)skb->data;
	tlv = ptr;
	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD);
	tlv->len = __cpu_to_le16(sizeof(*cmd));

	cmd = (void *)tlv->value;
	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
	ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
	cmd->peer_state = __cpu_to_le32(arg->peer_state);

	ptr += sizeof(*tlv);
	ptr += sizeof(*cmd);

	tlv = ptr;
	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES);
	tlv->len = __cpu_to_le16(sizeof(*peer_cap));
	peer_cap = (void *)tlv->value;
	peer_qos = ath10k_wmi_tlv_prepare_peer_qos(cap->peer_uapsd_queues,
						   cap->peer_max_sp);
	peer_cap->peer_qos = __cpu_to_le32(peer_qos);
	peer_cap->buff_sta_support = __cpu_to_le32(cap->buff_sta_support);
	peer_cap->off_chan_support = __cpu_to_le32(cap->off_chan_support);
	peer_cap->peer_curr_operclass = __cpu_to_le32(cap->peer_curr_operclass);
	peer_cap->self_curr_operclass = __cpu_to_le32(cap->self_curr_operclass);
	peer_cap->peer_chan_len = __cpu_to_le32(cap->peer_chan_len);
	peer_cap->peer_operclass_len = __cpu_to_le32(cap->peer_operclass_len);

	for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++)
		peer_cap->peer_operclass[i] = cap->peer_operclass[i];

	peer_cap->is_peer_responder = __cpu_to_le32(cap->is_peer_responder);
	peer_cap->pref_offchan_num = __cpu_to_le32(cap->pref_offchan_num);
	peer_cap->pref_offchan_bw = __cpu_to_le32(cap->pref_offchan_bw);

	ptr += sizeof(*tlv);
	ptr += sizeof(*peer_cap);

	tlv = ptr;
	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
	tlv->len = __cpu_to_le16(cap->peer_chan_len * sizeof(*chan));

	ptr += sizeof(*tlv);

	for (i = 0; i < cap->peer_chan_len; i++) {
		tlv = ptr;
		tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
		tlv->len = __cpu_to_le16(sizeof(*chan));
		chan = (void *)tlv->value;
		ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);

		ptr += sizeof(*tlv);
		ptr += sizeof(*chan);
	}

	ath10k_dbg(ar, ATH10K_DBG_WMI,
		   "wmi tlv tdls peer update vdev %i state %d n_chans %u\n",
		   arg->vdev_id, arg->peer_state, cap->peer_chan_len);
	return skb;
}

static struct sk_buff *
ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar)
{
@@ -2924,6 +3073,8 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
	.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
	.pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
	.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
	.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
	.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
};

static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
@@ -3103,6 +3254,8 @@ static const struct wmi_ops wmi_tlv_ops = {
	.gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind,
	.gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern,
	.gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern,
	.gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
	.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
};

/************/
+53 −0
Original line number Diff line number Diff line
@@ -1523,6 +1523,59 @@ struct wmi_tlv_wow_del_pattern_cmd {
	__le32 pattern_type;
} __packed;

/* TDLS Options */
enum wmi_tlv_tdls_options {
	WMI_TLV_TDLS_OFFCHAN_EN = BIT(0),
	WMI_TLV_TDLS_BUFFER_STA_EN = BIT(1),
	WMI_TLV_TDLS_SLEEP_STA_EN = BIT(2),
};

struct wmi_tdls_set_state_cmd {
	__le32 vdev_id;
	__le32 state;
	__le32 notification_interval_ms;
	__le32 tx_discovery_threshold;
	__le32 tx_teardown_threshold;
	__le32 rssi_teardown_threshold;
	__le32 rssi_delta;
	__le32 tdls_options;
	__le32 tdls_peer_traffic_ind_window;
	__le32 tdls_peer_traffic_response_timeout_ms;
	__le32 tdls_puapsd_mask;
	__le32 tdls_puapsd_inactivity_time_ms;
	__le32 tdls_puapsd_rx_frame_threshold;
} __packed;

struct wmi_tdls_peer_update_cmd {
	__le32 vdev_id;
	struct wmi_mac_addr peer_macaddr;
	__le32 peer_state;
} __packed;

enum {
	WMI_TLV_TDLS_PEER_QOS_AC_VO = BIT(0),
	WMI_TLV_TDLS_PEER_QOS_AC_VI = BIT(1),
	WMI_TLV_TDLS_PEER_QOS_AC_BK = BIT(2),
	WMI_TLV_TDLS_PEER_QOS_AC_BE = BIT(3),
};

#define WMI_TLV_TDLS_PEER_SP_MASK	0x60
#define WMI_TLV_TDLS_PEER_SP_LSB	5

struct wmi_tdls_peer_capab {
	__le32 peer_qos;
	__le32 buff_sta_support;
	__le32 off_chan_support;
	__le32 peer_curr_operclass;
	__le32 self_curr_operclass;
	__le32 peer_chan_len;
	__le32 peer_operclass_len;
	u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
	__le32 is_peer_responder;
	__le32 pref_offchan_num;
	__le32 pref_offchan_bw;
} __packed;

void ath10k_wmi_tlv_attach(struct ath10k *ar);

#endif
+37 −0
Original line number Diff line number Diff line
@@ -552,6 +552,8 @@ struct wmi_cmd_map {
	u32 gpio_output_cmdid;
	u32 pdev_get_temperature_cmdid;
	u32 vdev_set_wmm_params_cmdid;
	u32 tdls_set_state_cmdid;
	u32 tdls_peer_update_cmdid;
};

/*
@@ -5038,6 +5040,41 @@ struct wmi_wow_ev_arg {
#define WOW_MAX_PATTERN_SIZE	148
#define WOW_MAX_PKT_OFFSET	128

enum wmi_tdls_state {
	WMI_TDLS_DISABLE,
	WMI_TDLS_ENABLE_PASSIVE,
	WMI_TDLS_ENABLE_ACTIVE,
};

enum wmi_tdls_peer_state {
	WMI_TDLS_PEER_STATE_PEERING,
	WMI_TDLS_PEER_STATE_CONNECTED,
	WMI_TDLS_PEER_STATE_TEARDOWN,
};

struct wmi_tdls_peer_update_cmd_arg {
	u32 vdev_id;
	enum wmi_tdls_peer_state peer_state;
	u8 addr[ETH_ALEN];
};

#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32

struct wmi_tdls_peer_capab_arg {
	u8 peer_uapsd_queues;
	u8 peer_max_sp;
	u32 buff_sta_support;
	u32 off_chan_support;
	u32 peer_curr_operclass;
	u32 self_curr_operclass;
	u32 peer_chan_len;
	u32 peer_operclass_len;
	u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
	u32 is_peer_responder;
	u32 pref_offchan_num;
	u32 pref_offchan_bw;
};

struct ath10k;
struct ath10k_vif;
struct ath10k_fw_stats_pdev;