diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/cmdevt.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/cmdevt.c | 150 |
1 files changed, 103 insertions, 47 deletions
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 1ddc8b2e3722..b41155829220 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c | |||
@@ -37,13 +37,12 @@ | |||
37 | static void | 37 | static void |
38 | mwifiex_init_cmd_node(struct mwifiex_private *priv, | 38 | mwifiex_init_cmd_node(struct mwifiex_private *priv, |
39 | struct cmd_ctrl_node *cmd_node, | 39 | struct cmd_ctrl_node *cmd_node, |
40 | u32 cmd_oid, void *data_buf) | 40 | u32 cmd_oid, void *data_buf, bool sync) |
41 | { | 41 | { |
42 | cmd_node->priv = priv; | 42 | cmd_node->priv = priv; |
43 | cmd_node->cmd_oid = cmd_oid; | 43 | cmd_node->cmd_oid = cmd_oid; |
44 | if (priv->adapter->cmd_wait_q_required) { | 44 | if (sync) { |
45 | cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; | 45 | cmd_node->wait_q_enabled = true; |
46 | priv->adapter->cmd_wait_q_required = false; | ||
47 | cmd_node->cmd_wait_q_woken = false; | 46 | cmd_node->cmd_wait_q_woken = false; |
48 | cmd_node->condition = &cmd_node->cmd_wait_q_woken; | 47 | cmd_node->condition = &cmd_node->cmd_wait_q_woken; |
49 | } | 48 | } |
@@ -166,8 +165,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, | |||
166 | dev_err(adapter->dev, | 165 | dev_err(adapter->dev, |
167 | "DNLD_CMD: FW in reset state, ignore cmd %#x\n", | 166 | "DNLD_CMD: FW in reset state, ignore cmd %#x\n", |
168 | cmd_code); | 167 | cmd_code); |
169 | mwifiex_complete_cmd(adapter, cmd_node); | 168 | if (cmd_node->wait_q_enabled) |
169 | mwifiex_complete_cmd(adapter, cmd_node); | ||
170 | mwifiex_recycle_cmd_node(adapter, cmd_node); | 170 | mwifiex_recycle_cmd_node(adapter, cmd_node); |
171 | queue_work(adapter->workqueue, &adapter->main_work); | ||
171 | return -1; | 172 | return -1; |
172 | } | 173 | } |
173 | 174 | ||
@@ -480,28 +481,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) | |||
480 | } | 481 | } |
481 | 482 | ||
482 | /* | 483 | /* |
483 | * This function is used to send synchronous command to the firmware. | 484 | * This function prepares a command and send it to the firmware. |
484 | * | ||
485 | * it allocates a wait queue for the command and wait for the command | ||
486 | * response. | ||
487 | */ | ||
488 | int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, | ||
489 | u16 cmd_action, u32 cmd_oid, void *data_buf) | ||
490 | { | ||
491 | int ret = 0; | ||
492 | struct mwifiex_adapter *adapter = priv->adapter; | ||
493 | |||
494 | adapter->cmd_wait_q_required = true; | ||
495 | |||
496 | ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, | ||
497 | data_buf); | ||
498 | |||
499 | return ret; | ||
500 | } | ||
501 | |||
502 | |||
503 | /* | ||
504 | * This function prepares a command and asynchronously send it to the firmware. | ||
505 | * | 485 | * |
506 | * Preparation includes - | 486 | * Preparation includes - |
507 | * - Sanity tests to make sure the card is still present or the FW | 487 | * - Sanity tests to make sure the card is still present or the FW |
@@ -511,8 +491,8 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, | |||
511 | * - Fill up the non-default parameters and buffer pointers | 491 | * - Fill up the non-default parameters and buffer pointers |
512 | * - Add the command to pending queue | 492 | * - Add the command to pending queue |
513 | */ | 493 | */ |
514 | int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, | 494 | int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, |
515 | u16 cmd_action, u32 cmd_oid, void *data_buf) | 495 | u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync) |
516 | { | 496 | { |
517 | int ret; | 497 | int ret; |
518 | struct mwifiex_adapter *adapter = priv->adapter; | 498 | struct mwifiex_adapter *adapter = priv->adapter; |
@@ -534,6 +514,11 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, | |||
534 | return -1; | 514 | return -1; |
535 | } | 515 | } |
536 | 516 | ||
517 | if (adapter->is_cmd_timedout) { | ||
518 | dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n"); | ||
519 | return -1; | ||
520 | } | ||
521 | |||
537 | if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { | 522 | if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { |
538 | if (cmd_no != HostCmd_CMD_FUNC_INIT) { | 523 | if (cmd_no != HostCmd_CMD_FUNC_INIT) { |
539 | dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); | 524 | dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); |
@@ -550,7 +535,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, | |||
550 | } | 535 | } |
551 | 536 | ||
552 | /* Initialize the command node */ | 537 | /* Initialize the command node */ |
553 | mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf); | 538 | mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync); |
554 | 539 | ||
555 | if (!cmd_node->cmd_skb) { | 540 | if (!cmd_node->cmd_skb) { |
556 | dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); | 541 | dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); |
@@ -595,7 +580,8 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, | |||
595 | } | 580 | } |
596 | 581 | ||
597 | /* Send command */ | 582 | /* Send command */ |
598 | if (cmd_no == HostCmd_CMD_802_11_SCAN) { | 583 | if (cmd_no == HostCmd_CMD_802_11_SCAN || |
584 | cmd_no == HostCmd_CMD_802_11_SCAN_EXT) { | ||
599 | mwifiex_queue_scan_cmd(priv, cmd_node); | 585 | mwifiex_queue_scan_cmd(priv, cmd_node); |
600 | } else { | 586 | } else { |
601 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); | 587 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); |
@@ -785,7 +771,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) | |||
785 | unsigned long flags; | 771 | unsigned long flags; |
786 | 772 | ||
787 | /* Now we got response from FW, cancel the command timer */ | 773 | /* Now we got response from FW, cancel the command timer */ |
788 | del_timer(&adapter->cmd_timer); | 774 | del_timer_sync(&adapter->cmd_timer); |
789 | 775 | ||
790 | if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { | 776 | if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { |
791 | resp = (struct host_cmd_ds_command *) adapter->upld_buf; | 777 | resp = (struct host_cmd_ds_command *) adapter->upld_buf; |
@@ -794,7 +780,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) | |||
794 | return -1; | 780 | return -1; |
795 | } | 781 | } |
796 | 782 | ||
797 | adapter->num_cmd_timeout = 0; | 783 | adapter->is_cmd_timedout = 0; |
798 | 784 | ||
799 | resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; | 785 | resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; |
800 | if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { | 786 | if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { |
@@ -905,8 +891,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context) | |||
905 | struct cmd_ctrl_node *cmd_node; | 891 | struct cmd_ctrl_node *cmd_node; |
906 | struct timeval tstamp; | 892 | struct timeval tstamp; |
907 | 893 | ||
908 | adapter->num_cmd_timeout++; | 894 | adapter->is_cmd_timedout = 1; |
909 | adapter->dbg.num_cmd_timeout++; | ||
910 | if (!adapter->curr_cmd) { | 895 | if (!adapter->curr_cmd) { |
911 | dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); | 896 | dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); |
912 | return; | 897 | return; |
@@ -929,8 +914,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context) | |||
929 | dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", | 914 | dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", |
930 | adapter->dbg.num_cmd_host_to_card_failure); | 915 | adapter->dbg.num_cmd_host_to_card_failure); |
931 | 916 | ||
932 | dev_err(adapter->dev, "num_cmd_timeout = %d\n", | 917 | dev_err(adapter->dev, "is_cmd_timedout = %d\n", |
933 | adapter->dbg.num_cmd_timeout); | 918 | adapter->is_cmd_timedout); |
934 | dev_err(adapter->dev, "num_tx_timeout = %d\n", | 919 | dev_err(adapter->dev, "num_tx_timeout = %d\n", |
935 | adapter->dbg.num_tx_timeout); | 920 | adapter->dbg.num_tx_timeout); |
936 | 921 | ||
@@ -987,7 +972,9 @@ void | |||
987 | mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) | 972 | mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) |
988 | { | 973 | { |
989 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; | 974 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; |
990 | unsigned long flags; | 975 | unsigned long flags, cmd_flags; |
976 | struct mwifiex_private *priv; | ||
977 | int i; | ||
991 | 978 | ||
992 | /* Cancel current cmd */ | 979 | /* Cancel current cmd */ |
993 | if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { | 980 | if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { |
@@ -1027,9 +1014,21 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) | |||
1027 | } | 1014 | } |
1028 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); | 1015 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); |
1029 | 1016 | ||
1030 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | 1017 | if (adapter->scan_processing) { |
1031 | adapter->scan_processing = false; | 1018 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); |
1032 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | 1019 | adapter->scan_processing = false; |
1020 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | ||
1021 | for (i = 0; i < adapter->priv_num; i++) { | ||
1022 | priv = adapter->priv[i]; | ||
1023 | if (!priv) | ||
1024 | continue; | ||
1025 | if (priv->scan_request) { | ||
1026 | dev_dbg(adapter->dev, "info: aborting scan\n"); | ||
1027 | cfg80211_scan_done(priv->scan_request, 1); | ||
1028 | priv->scan_request = NULL; | ||
1029 | } | ||
1030 | } | ||
1031 | } | ||
1033 | } | 1032 | } |
1034 | 1033 | ||
1035 | /* | 1034 | /* |
@@ -1048,7 +1047,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) | |||
1048 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; | 1047 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; |
1049 | unsigned long cmd_flags; | 1048 | unsigned long cmd_flags; |
1050 | unsigned long scan_pending_q_flags; | 1049 | unsigned long scan_pending_q_flags; |
1051 | bool cancel_scan_cmd = false; | 1050 | struct mwifiex_private *priv; |
1051 | int i; | ||
1052 | 1052 | ||
1053 | if ((adapter->curr_cmd) && | 1053 | if ((adapter->curr_cmd) && |
1054 | (adapter->curr_cmd->wait_q_enabled)) { | 1054 | (adapter->curr_cmd->wait_q_enabled)) { |
@@ -1074,15 +1074,24 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) | |||
1074 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | 1074 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); |
1075 | spin_lock_irqsave(&adapter->scan_pending_q_lock, | 1075 | spin_lock_irqsave(&adapter->scan_pending_q_lock, |
1076 | scan_pending_q_flags); | 1076 | scan_pending_q_flags); |
1077 | cancel_scan_cmd = true; | ||
1078 | } | 1077 | } |
1079 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | 1078 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, |
1080 | scan_pending_q_flags); | 1079 | scan_pending_q_flags); |
1081 | 1080 | ||
1082 | if (cancel_scan_cmd) { | 1081 | if (adapter->scan_processing) { |
1083 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); | 1082 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); |
1084 | adapter->scan_processing = false; | 1083 | adapter->scan_processing = false; |
1085 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | 1084 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); |
1085 | for (i = 0; i < adapter->priv_num; i++) { | ||
1086 | priv = adapter->priv[i]; | ||
1087 | if (!priv) | ||
1088 | continue; | ||
1089 | if (priv->scan_request) { | ||
1090 | dev_dbg(adapter->dev, "info: aborting scan\n"); | ||
1091 | cfg80211_scan_done(priv->scan_request, 1); | ||
1092 | priv->scan_request = NULL; | ||
1093 | } | ||
1094 | } | ||
1086 | } | 1095 | } |
1087 | adapter->cmd_wait_q.status = -1; | 1096 | adapter->cmd_wait_q.status = -1; |
1088 | } | 1097 | } |
@@ -1454,7 +1463,10 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | |||
1454 | { | 1463 | { |
1455 | struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; | 1464 | struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; |
1456 | struct mwifiex_adapter *adapter = priv->adapter; | 1465 | struct mwifiex_adapter *adapter = priv->adapter; |
1457 | int i; | 1466 | struct mwifiex_ie_types_header *tlv; |
1467 | struct hw_spec_fw_api_rev *api_rev; | ||
1468 | u16 resp_size, api_id; | ||
1469 | int i, left_len, parsed_len = 0; | ||
1458 | 1470 | ||
1459 | adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); | 1471 | adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); |
1460 | 1472 | ||
@@ -1490,6 +1502,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | |||
1490 | } | 1502 | } |
1491 | 1503 | ||
1492 | adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); | 1504 | adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); |
1505 | adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff; | ||
1493 | adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); | 1506 | adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); |
1494 | 1507 | ||
1495 | if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { | 1508 | if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { |
@@ -1498,8 +1511,10 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | |||
1498 | /* Copy 11AC cap */ | 1511 | /* Copy 11AC cap */ |
1499 | adapter->hw_dot_11ac_dev_cap = | 1512 | adapter->hw_dot_11ac_dev_cap = |
1500 | le32_to_cpu(hw_spec->dot_11ac_dev_cap); | 1513 | le32_to_cpu(hw_spec->dot_11ac_dev_cap); |
1501 | adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap; | 1514 | adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap |
1502 | adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap; | 1515 | & ~MWIFIEX_DEF_11AC_CAP_BF_RESET_MASK; |
1516 | adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap | ||
1517 | & ~MWIFIEX_DEF_11AC_CAP_BF_RESET_MASK; | ||
1503 | 1518 | ||
1504 | /* Copy 11AC mcs */ | 1519 | /* Copy 11AC mcs */ |
1505 | adapter->hw_dot_11ac_mcs_support = | 1520 | adapter->hw_dot_11ac_mcs_support = |
@@ -1510,6 +1525,46 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | |||
1510 | adapter->is_hw_11ac_capable = false; | 1525 | adapter->is_hw_11ac_capable = false; |
1511 | } | 1526 | } |
1512 | 1527 | ||
1528 | resp_size = le16_to_cpu(resp->size) - S_DS_GEN; | ||
1529 | if (resp_size > sizeof(struct host_cmd_ds_get_hw_spec)) { | ||
1530 | /* we have variable HW SPEC information */ | ||
1531 | left_len = resp_size - sizeof(struct host_cmd_ds_get_hw_spec); | ||
1532 | while (left_len > sizeof(struct mwifiex_ie_types_header)) { | ||
1533 | tlv = (void *)&hw_spec->tlvs + parsed_len; | ||
1534 | switch (le16_to_cpu(tlv->type)) { | ||
1535 | case TLV_TYPE_FW_API_REV: | ||
1536 | api_rev = (struct hw_spec_fw_api_rev *)tlv; | ||
1537 | api_id = le16_to_cpu(api_rev->api_id); | ||
1538 | switch (api_id) { | ||
1539 | case KEY_API_VER_ID: | ||
1540 | adapter->fw_key_api_major_ver = | ||
1541 | api_rev->major_ver; | ||
1542 | adapter->fw_key_api_minor_ver = | ||
1543 | api_rev->minor_ver; | ||
1544 | dev_dbg(adapter->dev, | ||
1545 | "fw_key_api v%d.%d\n", | ||
1546 | adapter->fw_key_api_major_ver, | ||
1547 | adapter->fw_key_api_minor_ver); | ||
1548 | break; | ||
1549 | default: | ||
1550 | dev_warn(adapter->dev, | ||
1551 | "Unknown FW api_id: %d\n", | ||
1552 | api_id); | ||
1553 | break; | ||
1554 | } | ||
1555 | break; | ||
1556 | default: | ||
1557 | dev_warn(adapter->dev, | ||
1558 | "Unknown GET_HW_SPEC TLV type: %#x\n", | ||
1559 | le16_to_cpu(tlv->type)); | ||
1560 | break; | ||
1561 | } | ||
1562 | parsed_len += le16_to_cpu(tlv->len) + | ||
1563 | sizeof(struct mwifiex_ie_types_header); | ||
1564 | left_len -= parsed_len; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1513 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", | 1568 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", |
1514 | adapter->fw_release_number); | 1569 | adapter->fw_release_number); |
1515 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", | 1570 | dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", |
@@ -1538,6 +1593,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | |||
1538 | 1593 | ||
1539 | adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); | 1594 | adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); |
1540 | adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; | 1595 | adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; |
1596 | adapter->user_dev_mcs_support = adapter->hw_dev_mcs_support; | ||
1541 | 1597 | ||
1542 | if (adapter->if_ops.update_mp_end_port) | 1598 | if (adapter->if_ops.update_mp_end_port) |
1543 | adapter->if_ops.update_mp_end_port(adapter, | 1599 | adapter->if_ops.update_mp_end_port(adapter, |