diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/main.c')
| -rw-r--r-- | drivers/net/wireless/mwifiex/main.c | 562 |
1 files changed, 360 insertions, 202 deletions
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index b728f54451e..e91cd0fa5ca 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -25,6 +25,87 @@ #define VERSION "1.0" const char driver_version[] = "mwifiex " VERSION " (%s) "; +static char *cal_data_cfg; +module_param(cal_data_cfg, charp, 0); + +static void scan_delay_timer_fn(unsigned long data) +{ + struct mwifiex_private *priv = (struct mwifiex_private *)data; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node, *tmp_node; + unsigned long flags; + + if (adapter->surprise_removed) + return; + + if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT || + !adapter->scan_processing) { + /* + * Abort scan operation by cancelling all pending scan + * commands + */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + adapter->scan_delay_cnt = 0; + adapter->empty_tx_q_cnt = 0; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } else { + priv->scan_aborting = false; + dev_dbg(adapter->dev, "info: scan already aborted\n"); + } + goto done; + } + + if (!atomic_read(&priv->adapter->is_tx_received)) { + adapter->empty_tx_q_cnt++; + if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) { + /* + * No Tx traffic for 200msec. Get scan command from + * scan pending queue and put to cmd pending queue to + * resume scan operation + */ + adapter->scan_delay_cnt = 0; + adapter->empty_tx_q_cnt = 0; + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, + true); + queue_work(adapter->workqueue, &adapter->main_work); + goto done; + } + } else { + adapter->empty_tx_q_cnt = 0; + } + + /* Delay scan operation further by 20msec */ + mod_timer(&priv->scan_delay_timer, jiffies + + msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); + adapter->scan_delay_cnt++; + +done: + if (atomic_read(&priv->adapter->is_tx_received)) + atomic_set(&priv->adapter->is_tx_received, false); + + return; +} /* * This function registers the device and performs all the necessary @@ -58,23 +139,26 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); /* card specific initialization has been deferred until now .. */ - if (adapter->if_ops.init_if(adapter)) - goto error; + if (adapter->if_ops.init_if) + if (adapter->if_ops.init_if(adapter)) + goto error; adapter->priv_num = 0; - /* Allocate memory for private structure */ - adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), - GFP_KERNEL); - if (!adapter->priv[0]) { - dev_err(adapter->dev, "%s: failed to alloc priv[0]\n", - __func__); - goto error; - } + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + /* Allocate memory for private structure */ + adapter->priv[i] = + kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL); + if (!adapter->priv[i]) + goto error; - adapter->priv_num++; + adapter->priv[i]->adapter = adapter; + adapter->priv_num++; - adapter->priv[0]->adapter = adapter; + setup_timer(&adapter->priv[i]->scan_delay_timer, + scan_delay_timer_fn, + (unsigned long)adapter->priv[i]); + } mwifiex_init_lock_list(adapter); init_timer(&adapter->cmd_timer); @@ -108,12 +192,16 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) { s32 i; - del_timer(&adapter->cmd_timer); + if (adapter->if_ops.cleanup_if) + adapter->if_ops.cleanup_if(adapter); + + del_timer_sync(&adapter->cmd_timer); /* Free private structures */ for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { mwifiex_free_curr_bcn(adapter->priv[i]); + del_timer_sync(&adapter->priv[i]->scan_delay_timer); kfree(adapter->priv[i]); } } @@ -141,6 +229,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) { int ret = 0; unsigned long flags; + struct sk_buff *skb; spin_lock_irqsave(&adapter->main_proc_lock, flags); @@ -162,19 +251,21 @@ process_start: if (adapter->int_status) { if (adapter->hs_activated) mwifiex_process_hs_config(adapter); - adapter->if_ops.process_int_status(adapter); + if (adapter->if_ops.process_int_status) + adapter->if_ops.process_int_status(adapter); } /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && (adapter->pm_wakeup_card_req && !adapter->pm_wakeup_fw_try) && - (is_command_pending(adapter) - || !mwifiex_wmm_lists_empty(adapter))) { + (is_command_pending(adapter) || + !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; adapter->if_ops.wakeup(adapter); continue; } + if (IS_CARD_RX_RCVD(adapter)) { adapter->pm_wakeup_fw_try = false; if (adapter->ps_state == PS_STATE_SLEEP) @@ -187,14 +278,26 @@ process_start: adapter->tx_lock_flag) break; - if (adapter->scan_processing || adapter->data_sent - || mwifiex_wmm_lists_empty(adapter)) { - if (adapter->cmd_sent || adapter->curr_cmd - || (!is_command_pending(adapter))) + if ((adapter->scan_processing && + !adapter->scan_delay_cnt) || adapter->data_sent || + mwifiex_wmm_lists_empty(adapter)) { + if (adapter->cmd_sent || adapter->curr_cmd || + (!is_command_pending(adapter))) break; } } + /* Check Rx data for USB */ + if (adapter->iface_type == MWIFIEX_USB) + while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) + mwifiex_handle_rx_packet(adapter, skb); + + /* Check for event */ + if (adapter->event_received) { + adapter->event_received = false; + mwifiex_process_event(adapter); + } + /* Check for Cmd Resp */ if (adapter->cmd_resp_received) { adapter->cmd_resp_received = false; @@ -207,12 +310,6 @@ process_start: } } - /* Check for event */ - if (adapter->event_received) { - adapter->event_received = false; - mwifiex_process_event(adapter); - } - /* Check if we need to confirm Sleep Request received previously */ if (adapter->ps_state == PS_STATE_PRE_SLEEP) { @@ -223,10 +320,10 @@ process_start: /* * The ps_state may have been changed during processing of * Sleep Request event. */ - if ((adapter->ps_state == PS_STATE_SLEEP) - || (adapter->ps_state == PS_STATE_PRE_SLEEP) - || (adapter->ps_state == PS_STATE_SLEEP_CFM) - || adapter->tx_lock_flag) + if ((adapter->ps_state == PS_STATE_SLEEP) || + (adapter->ps_state == PS_STATE_PRE_SLEEP) || + (adapter->ps_state == PS_STATE_SLEEP_CFM) || + adapter->tx_lock_flag) continue; if (!adapter->cmd_sent && !adapter->curr_cmd) { @@ -236,8 +333,8 @@ process_start: } } - if (!adapter->scan_processing && !adapter->data_sent && - !mwifiex_wmm_lists_empty(adapter)) { + if ((!adapter->scan_processing || adapter->scan_delay_cnt) && + !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { adapter->is_hs_configured = false; @@ -249,8 +346,8 @@ process_start: } if (adapter->delay_null_pkt && !adapter->cmd_sent && - !adapter->curr_cmd && !is_command_pending(adapter) - && mwifiex_wmm_lists_empty(adapter)) { + !adapter->curr_cmd && !is_command_pending(adapter) && + mwifiex_wmm_lists_empty(adapter)) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | @@ -262,10 +359,12 @@ process_start: } } while (true); - if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) + spin_lock_irqsave(&adapter->main_proc_lock, flags); + if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); goto process_start; + } - spin_lock_irqsave(&adapter->main_proc_lock, flags); adapter->mwifiex_processing = false; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); @@ -274,6 +373,7 @@ exit_main_proc: mwifiex_shutdown_drv(adapter); return ret; } +EXPORT_SYMBOL_GPL(mwifiex_main_process); /* * This function frees the adapter structure. @@ -293,42 +393,71 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) } /* - * This function initializes the hardware and firmware. + * This function cancels all works in the queue and destroys + * the main workqueue. + */ +static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) +{ + flush_workqueue(adapter->workqueue); + destroy_workqueue(adapter->workqueue); + adapter->workqueue = NULL; +} + +/* + * This function gets firmware and initializes it. * * The main initialization steps followed are - * - Download the correct firmware to card - * - Allocate and initialize the adapter structure - * - Initialize the private structures * - Issue the init commands to firmware */ -static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) +static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) { - int ret, err; + int ret; + char fmt[64]; + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter = context; struct mwifiex_fw_image fw; + struct semaphore *sem = adapter->card_sem; + bool init_failed = false; + struct wireless_dev *wdev; + + if (!firmware) { + dev_err(adapter->dev, + "Failed to get firmware %s\n", adapter->fw_name); + goto err_dnld_fw; + } memset(&fw, 0, sizeof(struct mwifiex_fw_image)); - - err = request_firmware(&adapter->firmware, adapter->fw_name, - adapter->dev); - if (err < 0) { - dev_err(adapter->dev, "request_firmware() returned" - " error code %#x\n", err); - ret = -1; - goto done; - } + adapter->firmware = firmware; fw.fw_buf = (u8 *) adapter->firmware->data; fw.fw_len = adapter->firmware->size; - ret = mwifiex_dnld_fw(adapter, &fw); + if (adapter->if_ops.dnld_fw) + ret = adapter->if_ops.dnld_fw(adapter, &fw); + else + ret = mwifiex_dnld_fw(adapter, &fw); if (ret == -1) - goto done; + goto err_dnld_fw; dev_notice(adapter->dev, "WLAN FW is active\n"); + if (cal_data_cfg) { + if ((request_firmware(&adapter->cal_data, cal_data_cfg, + adapter->dev)) < 0) + dev_err(adapter->dev, + "Cal data request_firmware() failed\n"); + } + + /* enable host interrupt after fw dnld is successful */ + if (adapter->if_ops.enable_int) { + if (adapter->if_ops.enable_int(adapter)) + goto err_dnld_fw; + } + adapter->init_wait_q_woken = false; ret = mwifiex_init_fw(adapter); if (ret == -1) { - goto done; + goto err_init_fw; } else if (!ret) { adapter->hw_status = MWIFIEX_HW_STATUS_READY; goto done; @@ -336,61 +465,82 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) /* Wait for mwifiex_init to complete */ wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); - if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) { - ret = -1; - goto done; + if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) + goto err_init_fw; + + priv = adapter->priv[MWIFIEX_BSS_ROLE_STA]; + if (mwifiex_register_cfg80211(adapter)) { + dev_err(adapter->dev, "cannot register with cfg80211\n"); + goto err_init_fw; } - ret = 0; + rtnl_lock(); + /* Create station interface by default */ + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", + NL80211_IFTYPE_STATION, NULL, NULL); + if (IS_ERR(wdev)) { + dev_err(adapter->dev, "cannot create default STA interface\n"); + rtnl_unlock(); + goto err_add_intf; + } + rtnl_unlock(); + + mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); + dev_notice(adapter->dev, "driver_version = %s\n", fmt); + goto done; + +err_add_intf: + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); +err_init_fw: + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); +err_dnld_fw: + pr_debug("info: %s: unregister device\n", __func__); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); + + if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || + (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + pr_debug("info: %s: shutdown mwifiex\n", __func__); + adapter->init_wait_q_woken = false; + + if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + } + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); + init_failed = true; done: - if (adapter->firmware) + if (adapter->cal_data) { + release_firmware(adapter->cal_data); + adapter->cal_data = NULL; + } + if (adapter->firmware) { release_firmware(adapter->firmware); - if (ret) - ret = -1; - return ret; + adapter->firmware = NULL; + } + if (init_failed) + mwifiex_free_adapter(adapter); + up(sem); + return; } /* - * This function fills a driver buffer. - * - * The function associates a given SKB with the provided driver buffer - * and also updates some of the SKB parameters, including IP header, - * priority and timestamp. + * This function initializes the hardware and gets firmware. */ -static void -mwifiex_fill_buffer(struct sk_buff *skb) +static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) { - struct ethhdr *eth; - struct iphdr *iph; - struct timeval tv; - u8 tid = 0; - - eth = (struct ethhdr *) skb->data; - switch (eth->h_proto) { - case __constant_htons(ETH_P_IP): - iph = ip_hdr(skb); - tid = IPTOS_PREC(iph->tos); - pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", - eth->h_proto, tid, skb->priority); - break; - case __constant_htons(ETH_P_ARP): - pr_debug("data: ARP packet: %04x\n", eth->h_proto); - default: - break; - } -/* Offset for TOS field in the IP header */ -#define IPTOS_OFFSET 5 - tid = (tid >> IPTOS_OFFSET); - skb->priority = tid; - /* Record the current time the packet was queued; used to - determine the amount of time the packet was queued in - the driver before it was sent to the firmware. - The delay is then sent along with the packet to the - firmware for aggregate delay calculation for stats and - MSDU lifetime expiry. - */ - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + int ret; + + ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name, + adapter->dev, GFP_KERNEL, adapter, + mwifiex_fw_dpc); + if (ret < 0) + dev_err(adapter->dev, + "request_firmware_nowait() returned error %d\n", ret); + return ret; } /* @@ -411,6 +561,42 @@ mwifiex_open(struct net_device *dev) static int mwifiex_close(struct net_device *dev) { + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->scan_request) { + dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + priv->scan_aborting = true; + } + + return 0; +} + +/* + * Add buffer into wmm tx queue and queue work to transmit it. + */ +int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) +{ + struct netdev_queue *txq; + int index = mwifiex_1d_to_wmm_queue[skb->priority]; + + if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) { + txq = netdev_get_tx_queue(priv->netdev, index); + if (!netif_tx_queue_stopped(txq)) { + netif_tx_stop_queue(txq); + dev_dbg(priv->adapter->dev, "stop queue: %d\n", index); + } + } + + atomic_inc(&priv->adapter->tx_pending); + mwifiex_wmm_add_buf_txqueue(priv, skb); + + if (priv->adapter->scan_delay_cnt) + atomic_set(&priv->adapter->is_tx_received, true); + + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + return 0; } @@ -423,9 +609,10 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; + struct timeval tv; - dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", - jiffies, priv->bss_index); + dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", + jiffies, priv->bss_type, priv->bss_num); if (priv->adapter->surprise_removed) { kfree_skb(skb); @@ -441,7 +628,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { dev_dbg(priv->adapter->dev, "data: Tx: insufficient skb headroom %d\n", - skb_headroom(skb)); + skb_headroom(skb)); /* Insufficient skb headroom - allocate a new skb */ new_skb = skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); @@ -454,22 +641,26 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(skb); skb = new_skb; dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", - skb_headroom(skb)); + skb_headroom(skb)); } tx_info = MWIFIEX_SKB_TXCB(skb); - tx_info->bss_index = priv->bss_index; - mwifiex_fill_buffer(skb); - - mwifiex_wmm_add_buf_txqueue(priv->adapter, skb); - atomic_inc(&priv->adapter->tx_pending); + memset(tx_info, 0, sizeof(*tx_info)); + tx_info->bss_num = priv->bss_num; + tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = skb->len; - if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { - mwifiex_set_trans_start(dev); - mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); - } + /* Record the current time the packet was queued; used to + * determine the amount of time the packet was queued in + * the driver before it was sent to the firmware. + * The delay is then sent along with the packet to the + * firmware for aggregate delay calculation for stats and + * MSDU lifetime expiry. + */ + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + mwifiex_queue_tx_pkt(priv, skb); return 0; } @@ -487,14 +678,14 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr) memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS, - HostCmd_ACT_GEN_SET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + HostCmd_ACT_GEN_SET, 0, NULL, true); if (!ret) memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); else - dev_err(priv->adapter->dev, "set mac address failed: ret=%d" - "\n", ret); + dev_err(priv->adapter->dev, + "set mac address failed: ret=%d\n", ret); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); @@ -516,9 +707,8 @@ static void mwifiex_set_multicast_list(struct net_device *dev) mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; } else { mcast_list.mode = MWIFIEX_MULTICAST_MODE; - if (netdev_mc_count(dev)) - mcast_list.num_multicast_addr = - mwifiex_copy_mcast_addr(&mcast_list, dev); + mcast_list.num_multicast_addr = + mwifiex_copy_mcast_addr(&mcast_list, dev); } mwifiex_request_set_multicast_list(priv, &mcast_list); } @@ -531,10 +721,19 @@ mwifiex_tx_timeout(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", - jiffies, priv->bss_index); - mwifiex_set_trans_start(dev); priv->num_tx_timeout++; + priv->tx_timeout_cnt++; + dev_err(priv->adapter->dev, + "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n", + jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num); + mwifiex_set_trans_start(dev); + + if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD && + priv->adapter->if_ops.card_reset) { + dev_err(priv->adapter->dev, + "tx_timeout_cnt exceeds threshold. Triggering card reset!\n"); + priv->adapter->if_ops.card_reset(priv->adapter); + } } /* @@ -547,6 +746,14 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) return &priv->stats; } +static u16 +mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + skb->priority = cfg80211_classify8021d(skb, NULL); + return mwifiex_1d_to_wmm_queue[skb->priority]; +} + /* Network device handlers */ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_open = mwifiex_open, @@ -556,6 +763,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_tx_timeout = mwifiex_tx_timeout, .ndo_get_stats = mwifiex_get_stats, .ndo_set_rx_mode = mwifiex_set_multicast_list, + .ndo_select_queue = mwifiex_netdev_select_wmm_queue, }; /* @@ -581,10 +789,17 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) { dev->netdev_ops = &mwifiex_netdev_ops; + dev->destructor = free_netdev; /* Initialize private structure */ priv->current_key_index = 0; priv->media_connected = false; memset(&priv->nick_name, 0, sizeof(priv->nick_name)); + memset(priv->mgmt_ie, 0, + sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); + priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; + priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK; + priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; + priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); } @@ -605,18 +820,6 @@ int is_command_pending(struct mwifiex_adapter *adapter) } /* - * This function returns the correct private structure pointer based - * upon the BSS number. - */ -struct mwifiex_private * -mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index) -{ - if (!adapter || (bss_index >= adapter->priv_num)) - return NULL; - return adapter->priv[bss_index]; -} - -/* * This is the main work queue function. * * It handles the main process, which in turn handles the complete @@ -633,18 +836,6 @@ static void mwifiex_main_work_queue(struct work_struct *work) } /* - * This function cancels all works in the queue and destroys - * the main workqueue. - */ -static void -mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) -{ - flush_workqueue(adapter->workqueue); - destroy_workqueue(adapter->workqueue); - adapter->workqueue = NULL; -} - -/* * This function adds the card. * * This function follows the following major steps to set up the device - @@ -662,8 +853,6 @@ mwifiex_add_card(void *card, struct semaphore *sem, struct mwifiex_if_ops *if_ops, u8 iface_type) { struct mwifiex_adapter *adapter; - char fmt[64]; - struct mwifiex_private *priv; if (down_interruptible(sem)) goto exit_sem_err; @@ -674,6 +863,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, } adapter->iface_type = iface_type; + adapter->card_sem = sem; adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; adapter->surprise_removed = false; @@ -681,19 +871,20 @@ mwifiex_add_card(void *card, struct semaphore *sem, adapter->is_suspended = false; adapter->hs_activated = false; init_waitqueue_head(&adapter->hs_activate_wait_q); - adapter->cmd_wait_q_required = false; init_waitqueue_head(&adapter->cmd_wait_q.wait); adapter->cmd_wait_q.status = 0; adapter->scan_wait_q_woken = false; - adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); + adapter->workqueue = + alloc_workqueue("MWIFIEX_WORK_QUEUE", + WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1); if (!adapter->workqueue) goto err_kmalloc; INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); /* Register the device. Fill up the private data structure with relevant - information from the card and request for the required IRQ. */ + information from the card. */ if (adapter->if_ops.register_dev(adapter)) { pr_err("%s: failed to register mwifiex device\n", __func__); goto err_registerdev; @@ -704,44 +895,12 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_init_fw; } - priv = adapter->priv[0]; - - if (mwifiex_register_cfg80211(priv) != 0) { - dev_err(adapter->dev, "cannot register netdevice" - " with cfg80211\n"); - goto err_init_fw; - } - - rtnl_lock(); - /* Create station interface by default */ - if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", - NL80211_IFTYPE_STATION, NULL, NULL)) { - rtnl_unlock(); - dev_err(adapter->dev, "cannot create default station" - " interface\n"); - goto err_add_intf; - } - - rtnl_unlock(); - - up(sem); - - mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); - dev_notice(adapter->dev, "driver_version = %s\n", fmt); - return 0; -err_add_intf: - rtnl_lock(); - mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); - rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); - adapter->if_ops.unregister_dev(adapter); -err_registerdev: - adapter->surprise_removed = true; - mwifiex_terminate_workqueue(adapter); -err_kmalloc: + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { pr_debug("info: %s: shutdown mwifiex\n", __func__); @@ -751,7 +910,10 @@ err_kmalloc: wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); } - +err_registerdev: + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); +err_kmalloc: mwifiex_free_adapter(adapter); err_init_sw: @@ -784,15 +946,18 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) if (!adapter) goto exit_remove; + /* We can no longer handle interrupts once we start doing the teardown + * below. */ + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); + adapter->surprise_removed = true; /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; if (priv && priv->netdev) { - if (!netif_queue_stopped(priv->netdev)) - mwifiex_stop_net_dev_queue(priv->netdev, - adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); } @@ -823,26 +988,19 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) rtnl_lock(); if (priv->wdev && priv->netdev) - mwifiex_del_virtual_intf(priv->wdev->wiphy, - priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); } - priv = adapter->priv[0]; - if (!priv) - goto exit_remove; - - if (priv->wdev) { - wiphy_unregister(priv->wdev->wiphy); - wiphy_free(priv->wdev->wiphy); - kfree(priv->wdev); - } + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); mwifiex_terminate_workqueue(adapter); /* Unregister device */ dev_dbg(adapter->dev, "info: unregister device\n"); - adapter->if_ops.unregister_dev(adapter); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); /* Free adapter structure */ dev_dbg(adapter->dev, "info: free adapter\n"); mwifiex_free_adapter(adapter); |
