aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2013-08-05 21:52:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-08-09 15:57:51 -0400
commit562fc5b30f228d4a8c1dad90c82897a5440d7a0b (patch)
tree663df0f0777f30e83ba56cbce05ee25be3c5c28a
parentafd84de47309cbdf96ea80d073233834f28393a5 (diff)
mwifiex: add packet coalesce support
Coalesce filters are configured in firmware based on settings received from cfg80211. Packet type which is required by firmware is determined based on provided patterns in a rule: Unicast: if pattern '01' with offset 0 is found Multicast: if pattern '33:33' or '01:00:5e' with offset 0 is found Broadcast: if pattern 'ff:ff:ff:ff' with offset 0 is found Some example coalesce configuration files: 1) Coalesce Rx data packets from 192.168.0.88 mac address of our device is 00:50:43:21:53:7A Source IP address offset comes out as 52 after following calculations: 32 bytes of HW 802.11 header + 8 bytes LLC + 12 bytes in IPV4 header till source IP address Destination mac is at offset 6 in HW header. delay=100 condition=1 patterns=01,6+00:50:43:22,10+53:7A,52+c0:a8:00:58 2) Coalesce all broadcast and multicast packets(Multiple packet types are not allowed in a single rule. Hence created separate rules) delay=400 condition=1 patterns=33:33 delay=400 condition=1 patterns=ff:ff:ff:ff Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c125
-rw-r--r--drivers/net/wireless/mwifiex/fw.h24
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h35
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c68
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c2
5 files changed, 254 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 62c3d9880607..07d23183898c 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -2455,6 +2455,119 @@ static void mwifiex_cfg80211_set_wakeup(struct wiphy *wiphy,
2455} 2455}
2456#endif 2456#endif
2457 2457
2458static int mwifiex_get_coalesce_pkt_type(u8 *byte_seq)
2459{
2460 const u8 ipv4_mc_mac[] = {0x33, 0x33};
2461 const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
2462 const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff};
2463
2464 if ((byte_seq[0] & 0x01) &&
2465 (byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 1))
2466 return PACKET_TYPE_UNICAST;
2467 else if (!memcmp(byte_seq, bc_mac, 4))
2468 return PACKET_TYPE_BROADCAST;
2469 else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
2470 byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 2) ||
2471 (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
2472 byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 3))
2473 return PACKET_TYPE_MULTICAST;
2474
2475 return 0;
2476}
2477
2478static int
2479mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
2480 struct cfg80211_coalesce_rules *crule,
2481 struct mwifiex_coalesce_rule *mrule)
2482{
2483 u8 byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ + 1];
2484 struct filt_field_param *param;
2485 int i;
2486
2487 mrule->max_coalescing_delay = crule->delay;
2488
2489 param = mrule->params;
2490
2491 for (i = 0; i < crule->n_patterns; i++) {
2492 memset(byte_seq, 0, sizeof(byte_seq));
2493 if (!mwifiex_is_pattern_supported(&crule->patterns[i],
2494 byte_seq,
2495 MWIFIEX_COALESCE_MAX_BYTESEQ)) {
2496 dev_err(priv->adapter->dev, "Pattern not supported\n");
2497 return -EOPNOTSUPP;
2498 }
2499
2500 if (!crule->patterns[i].pkt_offset) {
2501 u8 pkt_type;
2502
2503 pkt_type = mwifiex_get_coalesce_pkt_type(byte_seq);
2504 if (pkt_type && mrule->pkt_type) {
2505 dev_err(priv->adapter->dev,
2506 "Multiple packet types not allowed\n");
2507 return -EOPNOTSUPP;
2508 } else if (pkt_type) {
2509 mrule->pkt_type = pkt_type;
2510 continue;
2511 }
2512 }
2513
2514 if (crule->condition == NL80211_COALESCE_CONDITION_MATCH)
2515 param->operation = RECV_FILTER_MATCH_TYPE_EQ;
2516 else
2517 param->operation = RECV_FILTER_MATCH_TYPE_NE;
2518
2519 param->operand_len = byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ];
2520 memcpy(param->operand_byte_stream, byte_seq,
2521 param->operand_len);
2522 param->offset = crule->patterns[i].pkt_offset;
2523 param++;
2524
2525 mrule->num_of_fields++;
2526 }
2527
2528 if (!mrule->pkt_type) {
2529 dev_err(priv->adapter->dev,
2530 "Packet type can not be determined\n");
2531 return -EOPNOTSUPP;
2532 }
2533
2534 return 0;
2535}
2536
2537static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
2538 struct cfg80211_coalesce *coalesce)
2539{
2540 struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
2541 int i, ret;
2542 struct mwifiex_ds_coalesce_cfg coalesce_cfg;
2543 struct mwifiex_private *priv =
2544 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
2545
2546 memset(&coalesce_cfg, 0, sizeof(coalesce_cfg));
2547 if (!coalesce) {
2548 dev_dbg(adapter->dev,
2549 "Disable coalesce and reset all previous rules\n");
2550 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG,
2551 HostCmd_ACT_GEN_SET, 0,
2552 &coalesce_cfg);
2553 }
2554
2555 coalesce_cfg.num_of_rules = coalesce->n_rules;
2556 for (i = 0; i < coalesce->n_rules; i++) {
2557 ret = mwifiex_fill_coalesce_rule_info(priv, &coalesce->rules[i],
2558 &coalesce_cfg.rule[i]);
2559 if (ret) {
2560 dev_err(priv->adapter->dev,
2561 "Recheck the patterns provided for rule %d\n",
2562 i + 1);
2563 return ret;
2564 }
2565 }
2566
2567 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG,
2568 HostCmd_ACT_GEN_SET, 0, &coalesce_cfg);
2569}
2570
2458/* station cfg80211 operations */ 2571/* station cfg80211 operations */
2459static struct cfg80211_ops mwifiex_cfg80211_ops = { 2572static struct cfg80211_ops mwifiex_cfg80211_ops = {
2460 .add_virtual_intf = mwifiex_add_virtual_intf, 2573 .add_virtual_intf = mwifiex_add_virtual_intf,
@@ -2488,6 +2601,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
2488 .suspend = mwifiex_cfg80211_suspend, 2601 .suspend = mwifiex_cfg80211_suspend,
2489 .resume = mwifiex_cfg80211_resume, 2602 .resume = mwifiex_cfg80211_resume,
2490 .set_wakeup = mwifiex_cfg80211_set_wakeup, 2603 .set_wakeup = mwifiex_cfg80211_set_wakeup,
2604 .set_coalesce = mwifiex_cfg80211_set_coalesce,
2491#endif 2605#endif
2492}; 2606};
2493 2607
@@ -2512,6 +2626,15 @@ static bool mwifiex_is_valid_alpha2(const char *alpha2)
2512 return false; 2626 return false;
2513} 2627}
2514 2628
2629static const struct wiphy_coalesce_support mwifiex_coalesce_support = {
2630 .n_rules = MWIFIEX_COALESCE_MAX_RULES,
2631 .max_delay = MWIFIEX_MAX_COALESCING_DELAY,
2632 .n_patterns = MWIFIEX_COALESCE_MAX_FILTERS,
2633 .pattern_min_len = 1,
2634 .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
2635 .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
2636};
2637
2515/* 2638/*
2516 * This function registers the device with CFG802.11 subsystem. 2639 * This function registers the device with CFG802.11 subsystem.
2517 * 2640 *
@@ -2573,6 +2696,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
2573 wiphy->wowlan = &mwifiex_wowlan_support; 2696 wiphy->wowlan = &mwifiex_wowlan_support;
2574#endif 2697#endif
2575 2698
2699 wiphy->coalesce = &mwifiex_coalesce_support;
2700
2576 wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | 2701 wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
2577 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | 2702 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
2578 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; 2703 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 12c6223ebb8c..c9ad1c0d338d 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -153,6 +153,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
153#define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123) 153#define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123)
154#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) 154#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145)
155#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) 155#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146)
156#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154)
156 157
157#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 158#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
158 159
@@ -294,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
294#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed 295#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
295#define HostCmd_CMD_SET_BSS_MODE 0x00f7 296#define HostCmd_CMD_SET_BSS_MODE 0x00f7
296#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa 297#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
298#define HostCmd_CMD_COALESCE_CFG 0x010a
297#define HostCmd_CMD_MGMT_FRAME_REG 0x010c 299#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
298#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d 300#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
299#define HostCmd_CMD_11AC_CFG 0x0112 301#define HostCmd_CMD_11AC_CFG 0x0112
@@ -1596,6 +1598,27 @@ struct host_cmd_ds_802_11_cfg_data {
1596 __le16 data_len; 1598 __le16 data_len;
1597} __packed; 1599} __packed;
1598 1600
1601struct coalesce_filt_field_param {
1602 u8 operation;
1603 u8 operand_len;
1604 __le16 offset;
1605 u8 operand_byte_stream[4];
1606};
1607
1608struct coalesce_receive_filt_rule {
1609 struct mwifiex_ie_types_header header;
1610 u8 num_of_fields;
1611 u8 pkt_type;
1612 __le16 max_coalescing_delay;
1613 struct coalesce_filt_field_param params[0];
1614} __packed;
1615
1616struct host_cmd_ds_coalesce_cfg {
1617 __le16 action;
1618 __le16 num_of_rules;
1619 struct coalesce_receive_filt_rule rule[0];
1620} __packed;
1621
1599struct host_cmd_ds_command { 1622struct host_cmd_ds_command {
1600 __le16 command; 1623 __le16 command;
1601 __le16 size; 1624 __le16 size;
@@ -1656,6 +1679,7 @@ struct host_cmd_ds_command {
1656 struct host_cmd_ds_sta_deauth sta_deauth; 1679 struct host_cmd_ds_sta_deauth sta_deauth;
1657 struct host_cmd_11ac_vht_cfg vht_cfg; 1680 struct host_cmd_11ac_vht_cfg vht_cfg;
1658 struct host_cmd_ds_802_11_cfg_data cfg_data; 1681 struct host_cmd_ds_802_11_cfg_data cfg_data;
1682 struct host_cmd_ds_coalesce_cfg coalesce_cfg;
1659 } params; 1683 } params;
1660} __packed; 1684} __packed;
1661 1685
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 5ecda453f832..00a95f4c6a6c 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -397,4 +397,39 @@ enum {
397 MWIFIEX_FUNC_SHUTDOWN, 397 MWIFIEX_FUNC_SHUTDOWN,
398}; 398};
399 399
400enum COALESCE_OPERATION {
401 RECV_FILTER_MATCH_TYPE_EQ = 0x80,
402 RECV_FILTER_MATCH_TYPE_NE,
403};
404
405enum COALESCE_PACKET_TYPE {
406 PACKET_TYPE_UNICAST = 1,
407 PACKET_TYPE_MULTICAST = 2,
408 PACKET_TYPE_BROADCAST = 3
409};
410
411#define MWIFIEX_COALESCE_MAX_RULES 8
412#define MWIFIEX_COALESCE_MAX_BYTESEQ 4 /* non-adjustable */
413#define MWIFIEX_COALESCE_MAX_FILTERS 4
414#define MWIFIEX_MAX_COALESCING_DELAY 100 /* in msecs */
415
416struct filt_field_param {
417 u8 operation;
418 u8 operand_len;
419 u16 offset;
420 u8 operand_byte_stream[MWIFIEX_COALESCE_MAX_BYTESEQ];
421};
422
423struct mwifiex_coalesce_rule {
424 u16 max_coalescing_delay;
425 u8 num_of_fields;
426 u8 pkt_type;
427 struct filt_field_param params[MWIFIEX_COALESCE_MAX_FILTERS];
428};
429
430struct mwifiex_ds_coalesce_cfg {
431 u16 num_of_rules;
432 struct mwifiex_coalesce_rule rule[MWIFIEX_COALESCE_MAX_RULES];
433};
434
400#endif /* !_MWIFIEX_IOCTL_H_ */ 435#endif /* !_MWIFIEX_IOCTL_H_ */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 448baf191321..c0268b597748 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1184,6 +1184,70 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
1184 return 0; 1184 return 0;
1185} 1185}
1186 1186
1187static int
1188mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv,
1189 struct host_cmd_ds_command *cmd,
1190 u16 cmd_action, void *data_buf)
1191{
1192 struct host_cmd_ds_coalesce_cfg *coalesce_cfg =
1193 &cmd->params.coalesce_cfg;
1194 struct mwifiex_ds_coalesce_cfg *cfg = data_buf;
1195 struct coalesce_filt_field_param *param;
1196 u16 cnt, idx, length;
1197 struct coalesce_receive_filt_rule *rule;
1198
1199 cmd->command = cpu_to_le16(HostCmd_CMD_COALESCE_CFG);
1200 cmd->size = cpu_to_le16(S_DS_GEN);
1201
1202 coalesce_cfg->action = cpu_to_le16(cmd_action);
1203 coalesce_cfg->num_of_rules = cpu_to_le16(cfg->num_of_rules);
1204 rule = coalesce_cfg->rule;
1205
1206 for (cnt = 0; cnt < cfg->num_of_rules; cnt++) {
1207 rule->header.type = cpu_to_le16(TLV_TYPE_COALESCE_RULE);
1208 rule->max_coalescing_delay =
1209 cpu_to_le16(cfg->rule[cnt].max_coalescing_delay);
1210 rule->pkt_type = cfg->rule[cnt].pkt_type;
1211 rule->num_of_fields = cfg->rule[cnt].num_of_fields;
1212
1213 length = 0;
1214
1215 param = rule->params;
1216 for (idx = 0; idx < cfg->rule[cnt].num_of_fields; idx++) {
1217 param->operation = cfg->rule[cnt].params[idx].operation;
1218 param->operand_len =
1219 cfg->rule[cnt].params[idx].operand_len;
1220 param->offset =
1221 cpu_to_le16(cfg->rule[cnt].params[idx].offset);
1222 memcpy(param->operand_byte_stream,
1223 cfg->rule[cnt].params[idx].operand_byte_stream,
1224 param->operand_len);
1225
1226 length += sizeof(struct coalesce_filt_field_param);
1227
1228 param++;
1229 }
1230
1231 /* Total rule length is sizeof max_coalescing_delay(u16),
1232 * num_of_fields(u8), pkt_type(u8) and total length of the all
1233 * params
1234 */
1235 rule->header.len = cpu_to_le16(length + sizeof(u16) +
1236 sizeof(u8) + sizeof(u8));
1237
1238 /* Add the rule length to the command size*/
1239 le16_add_cpu(&cmd->size, le16_to_cpu(rule->header.len) +
1240 sizeof(struct mwifiex_ie_types_header));
1241
1242 rule = (void *)((u8 *)rule->params + length);
1243 }
1244
1245 /* Add sizeof action, num_of_rules to total command length */
1246 le16_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16));
1247
1248 return 0;
1249}
1250
1187/* 1251/*
1188 * This function prepares the commands before sending them to the firmware. 1252 * This function prepares the commands before sending them to the firmware.
1189 * 1253 *
@@ -1407,6 +1471,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
1407 case HostCmd_CMD_MEF_CFG: 1471 case HostCmd_CMD_MEF_CFG:
1408 ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf); 1472 ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf);
1409 break; 1473 break;
1474 case HostCmd_CMD_COALESCE_CFG:
1475 ret = mwifiex_cmd_coalesce_cfg(priv, cmd_ptr, cmd_action,
1476 data_buf);
1477 break;
1410 default: 1478 default:
1411 dev_err(priv->adapter->dev, 1479 dev_err(priv->adapter->dev,
1412 "PREP_CMD: unknown cmd- %#x\n", cmd_no); 1480 "PREP_CMD: unknown cmd- %#x\n", cmd_no);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index d85df158cc6c..6a814eb2671a 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -997,6 +997,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
997 break; 997 break;
998 case HostCmd_CMD_MEF_CFG: 998 case HostCmd_CMD_MEF_CFG:
999 break; 999 break;
1000 case HostCmd_CMD_COALESCE_CFG:
1001 break;
1000 default: 1002 default:
1001 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", 1003 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
1002 resp->command); 1004 resp->command);