ath6kl: Add support for uAPSD
* A new APSD power save queue is added in the station structure.
* When a station has APSD capability and goes to power save, the frame
designated to the station will be buffered in APSD queue.
* When the host receives a frame which the firmware marked as trigger,
host delivers the buffered frame from the APSD power save queue.
Number of frames to deliver is decided by MAX SP length.
* When a station moves from sleep to awake state, all frames buffered
in APSD power save queue are sent to the firmware.
* When a station is disconnected, all frames bufferes in APSD power save
queue are dropped.
* When the host queues the first frame to the APSD queue or removes the
last frame from the APSD queue, it is indicated to the firmware using
WMI_AP_APSD_BUFFERED_TRAFFIC_CMD.
kvalo: fix buggy handling of sks queues, made it more obvious
the user priority when wmm is disabled, remove unneed else block and
combined some variable declarations
Signed-off-by: Thirumalai Pachamuthu <tpachamu@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 08fbd9a..c2420f8 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -180,7 +180,7 @@
}
int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
- u8 msg_type, bool more_data,
+ u8 msg_type, u32 flags,
enum wmi_data_hdr_data_type data_type,
u8 meta_ver, void *tx_meta_info, u8 if_idx)
{
@@ -204,17 +204,19 @@
data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
- if (more_data)
- data_hdr->info |=
- WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT;
+ if (flags & WMI_DATA_HDR_FLAGS_MORE)
+ data_hdr->info |= WMI_DATA_HDR_MORE;
- data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
- data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
+ if (flags & WMI_DATA_HDR_FLAGS_EOSP)
+ data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);
+
+ data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
+ data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
return 0;
}
-static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
+u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
{
struct iphdr *ip_hdr = (struct iphdr *) pkt;
u8 ip_pri;
@@ -236,6 +238,11 @@
return ip_pri;
}
+u8 ath6kl_wmi_get_traffic_class(u8 user_priority)
+{
+ return up_to_ac[user_priority & 0x7];
+}
+
int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
struct sk_buff *skb,
u32 layer2_priority, bool wmm_enabled,
@@ -786,12 +793,14 @@
ev->u.ap_sta.keymgmt,
le16_to_cpu(ev->u.ap_sta.cipher),
ev->u.ap_sta.apsd_info);
+
ath6kl_connect_ap_mode_sta(
vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
ev->u.ap_sta.keymgmt,
le16_to_cpu(ev->u.ap_sta.cipher),
ev->u.ap_sta.auth, ev->assoc_req_len,
- ev->assoc_info + ev->beacon_ie_len);
+ ev->assoc_info + ev->beacon_ie_len,
+ ev->u.ap_sta.apsd_info);
}
return 0;
}
@@ -2993,6 +3002,43 @@
NO_SYNC_WMIFLAG);
}
+/* This command will be used to enable/disable AP uAPSD feature */
+int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)
+{
+ struct wmi_ap_set_apsd_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_ap_set_apsd_cmd *)skb->data;
+ cmd->enable = enable;
+
+ return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx,
+ u16 aid, u16 bitmap, u32 flags)
+{
+ struct wmi_ap_apsd_buffered_traffic_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data;
+ cmd->aid = cpu_to_le16(aid);
+ cmd->bitmap = cpu_to_le16(bitmap);
+ cmd->flags = cpu_to_le32(flags);
+
+ return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+ WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len,
struct ath6kl_vif *vif)
{