From 6e8b188ba782bd04f942b7d489b8b2b81606f690 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 28 Jan 2015 09:57:39 +0200 Subject: [PATCH] ath10k: implement sta keepalive command New wmi-tlv firmware for qca6174 has STA keepalive service available. The service can provide automatic idle connection polling via NullFunc frames to AP when acting as a client. Signed-off-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 20 ++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 45 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 7 ++++ drivers/net/wireless/ath/ath10k/wmi.h | 10 +++++ 4 files changed, 82 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 987414abc443..058f88b6ff53 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -143,6 +143,8 @@ struct wmi_ops { const u8 peer_addr[ETH_ALEN], const struct wmi_sta_uapsd_auto_trig_arg *args, u32 num_ac); + struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -1034,4 +1036,22 @@ ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie) return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie); } +static inline int +ath10k_wmi_sta_keepalive(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_sta_keepalive) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_sta_keepalive(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->sta_keepalive_cmd; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 00ca544bc94d..be32db96701f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1635,6 +1635,50 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct wmi_tlv_sta_keepalive_cmd *cmd; + struct wmi_sta_keepalive_arp_resp *arp; + struct sk_buff *skb; + struct wmi_tlv *tlv; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*arp); + 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_STA_KEEPALIVE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->enabled = __cpu_to_le32(arg->enabled); + cmd->method = __cpu_to_le32(arg->method); + cmd->interval = __cpu_to_le32(arg->interval); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE); + tlv->len = __cpu_to_le16(sizeof(*arp)); + arp = (void *)tlv->value; + + arp->src_ip4_addr = arg->src_ip4_addr; + arp->dest_ip4_addr = arg->dest_ip4_addr; + ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n", + arg->vdev_id, arg->enabled, arg->method, arg->interval); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, const u8 peer_addr[ETH_ALEN]) @@ -2634,6 +2678,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, + .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, }; /************/ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 3dc43b90469d..de68fe76eae6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1432,6 +1432,13 @@ struct wmi_tlv_diag_data_ev { __le32 num_items; } __packed; +struct wmi_tlv_sta_keepalive_cmd { + __le32 vdev_id; + __le32 enabled; + __le32 method; /* WMI_STA_KEEPALIVE_METHOD_ */ + __le32 interval; /* in seconds */ +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 3c48e0d21900..1a99a7dd0e95 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4680,6 +4680,16 @@ struct wmi_sta_keepalive_cmd { struct wmi_sta_keepalive_arp_resp arp_resp; } __packed; +struct wmi_sta_keepalive_arg { + u32 vdev_id; + u32 enabled; + u32 method; + u32 interval; + __be32 src_ip4_addr; + __be32 dest_ip4_addr; + const u8 dest_mac_addr[ETH_ALEN]; +}; + enum wmi_force_fw_hang_type { WMI_FORCE_FW_HANG_ASSERT = 1, WMI_FORCE_FW_HANG_NO_DETECT,