| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. |
| * |
| * Based on the r8180 driver, which is: |
| * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al. |
| * |
| * Contact Information: wlanfae <wlanfae@realtek.com> |
| */ |
| #include <linux/uaccess.h> |
| #include <linux/pci.h> |
| #include <linux/vmalloc.h> |
| #include <linux/ieee80211.h> |
| #include "rtl_core.h" |
| #include "r8192E_phy.h" |
| #include "r8192E_phyreg.h" |
| #include "r8190P_rtl8256.h" |
| #include "r8192E_cmdpkt.h" |
| |
| #include "rtl_wx.h" |
| #include "rtl_dm.h" |
| |
| #include "rtl_pm.h" |
| |
| int hwwep = 1; |
| static char *ifname = "wlan%d"; |
| |
| static struct pci_device_id rtl8192_pci_id_tbl[] = { |
| {PCI_DEVICE(0x10ec, 0x8192)}, |
| {PCI_DEVICE(0x07aa, 0x0044)}, |
| {PCI_DEVICE(0x07aa, 0x0047)}, |
| {} |
| }; |
| |
| MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl); |
| |
| static int _rtl92e_pci_probe(struct pci_dev *pdev, |
| const struct pci_device_id *id); |
| static void _rtl92e_pci_disconnect(struct pci_dev *pdev); |
| static irqreturn_t _rtl92e_irq(int irq, void *netdev); |
| |
| static SIMPLE_DEV_PM_OPS(rtl92e_pm_ops, rtl92e_suspend, rtl92e_resume); |
| |
| static struct pci_driver rtl8192_pci_driver = { |
| .name = DRV_NAME, /* Driver name */ |
| .id_table = rtl8192_pci_id_tbl, /* PCI_ID table */ |
| .probe = _rtl92e_pci_probe, /* probe fn */ |
| .remove = _rtl92e_pci_disconnect, /* remove fn */ |
| .driver.pm = &rtl92e_pm_ops, |
| }; |
| |
| static short _rtl92e_is_tx_queue_empty(struct net_device *dev); |
| static void _rtl92e_watchdog_wq_cb(void *data); |
| static void _rtl92e_watchdog_timer_cb(struct timer_list *t); |
| static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, |
| int rate); |
| static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); |
| static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb); |
| static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb); |
| static short _rtl92e_pci_initdescring(struct net_device *dev); |
| static void _rtl92e_irq_tx_tasklet(struct tasklet_struct *t); |
| static void _rtl92e_irq_rx_tasklet(struct tasklet_struct *t); |
| static void _rtl92e_cancel_deferred_work(struct r8192_priv *priv); |
| static int _rtl92e_up(struct net_device *dev); |
| static int _rtl92e_try_up(struct net_device *dev); |
| static int _rtl92e_down(struct net_device *dev, bool shutdownrf); |
| static void _rtl92e_restart(void *data); |
| |
| /**************************************************************************** |
| * -----------------------------IO STUFF------------------------- |
| ****************************************************************************/ |
| |
| u8 rtl92e_readb(struct net_device *dev, int x) |
| { |
| return 0xff & readb((u8 __iomem *)dev->mem_start + x); |
| } |
| |
| u32 rtl92e_readl(struct net_device *dev, int x) |
| { |
| return readl((u8 __iomem *)dev->mem_start + x); |
| } |
| |
| u16 rtl92e_readw(struct net_device *dev, int x) |
| { |
| return readw((u8 __iomem *)dev->mem_start + x); |
| } |
| |
| void rtl92e_writeb(struct net_device *dev, int x, u8 y) |
| { |
| writeb(y, (u8 __iomem *)dev->mem_start + x); |
| |
| udelay(20); |
| } |
| |
| void rtl92e_writel(struct net_device *dev, int x, u32 y) |
| { |
| writel(y, (u8 __iomem *)dev->mem_start + x); |
| |
| udelay(20); |
| } |
| |
| void rtl92e_writew(struct net_device *dev, int x, u16 y) |
| { |
| writew(y, (u8 __iomem *)dev->mem_start + x); |
| |
| udelay(20); |
| } |
| |
| /**************************************************************************** |
| * -----------------------------GENERAL FUNCTION------------------------- |
| ****************************************************************************/ |
| bool rtl92e_set_rf_state(struct net_device *dev, |
| enum rt_rf_power_state state_to_set, |
| RT_RF_CHANGE_SOURCE change_source) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtllib_device *ieee = priv->rtllib; |
| bool action_allowed = false; |
| bool connect_by_ssid = false; |
| enum rt_rf_power_state rt_state; |
| u16 rf_wait_counter = 0; |
| unsigned long flag; |
| |
| while (true) { |
| spin_lock_irqsave(&priv->rf_ps_lock, flag); |
| if (priv->rf_change_in_progress) { |
| spin_unlock_irqrestore(&priv->rf_ps_lock, flag); |
| |
| while (priv->rf_change_in_progress) { |
| rf_wait_counter++; |
| mdelay(1); |
| |
| if (rf_wait_counter > 100) { |
| netdev_warn(dev, |
| "%s(): Timeout waiting for RF change.\n", |
| __func__); |
| return false; |
| } |
| } |
| } else { |
| priv->rf_change_in_progress = true; |
| spin_unlock_irqrestore(&priv->rf_ps_lock, flag); |
| break; |
| } |
| } |
| |
| rt_state = priv->rtllib->rf_power_state; |
| |
| switch (state_to_set) { |
| case rf_on: |
| priv->rtllib->rf_off_reason &= (~change_source); |
| |
| if ((change_source == RF_CHANGE_BY_HW) && priv->hw_radio_off) |
| priv->hw_radio_off = false; |
| |
| if (!priv->rtllib->rf_off_reason) { |
| priv->rtllib->rf_off_reason = 0; |
| action_allowed = true; |
| |
| if (rt_state == rf_off && |
| change_source >= RF_CHANGE_BY_HW) |
| connect_by_ssid = true; |
| } |
| break; |
| |
| case rf_off: |
| |
| if (priv->rtllib->iw_mode == IW_MODE_INFRA) { |
| if ((priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) || |
| (change_source > RF_CHANGE_BY_IPS)) { |
| if (ieee->link_state == MAC80211_LINKED) |
| priv->blinked_ingpio = true; |
| else |
| priv->blinked_ingpio = false; |
| rtllib_mgnt_disconnect(priv->rtllib, |
| WLAN_REASON_DISASSOC_STA_HAS_LEFT); |
| } |
| } |
| if ((change_source == RF_CHANGE_BY_HW) && !priv->hw_radio_off) |
| priv->hw_radio_off = true; |
| priv->rtllib->rf_off_reason |= change_source; |
| action_allowed = true; |
| break; |
| |
| case rf_sleep: |
| priv->rtllib->rf_off_reason |= change_source; |
| action_allowed = true; |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (action_allowed) { |
| rtl92e_set_rf_power_state(dev, state_to_set); |
| if (state_to_set == rf_on) { |
| if (connect_by_ssid && priv->blinked_ingpio) { |
| schedule_delayed_work( |
| &ieee->associate_procedure_wq, 0); |
| priv->blinked_ingpio = false; |
| } |
| } |
| } |
| |
| spin_lock_irqsave(&priv->rf_ps_lock, flag); |
| priv->rf_change_in_progress = false; |
| spin_unlock_irqrestore(&priv->rf_ps_lock, flag); |
| return action_allowed; |
| } |
| |
| static short _rtl92e_check_nic_enough_desc(struct net_device *dev, int prio) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; |
| |
| if (ring->entries - skb_queue_len(&ring->queue) >= 2) |
| return 1; |
| return 0; |
| } |
| |
| static void _rtl92e_tx_timeout(struct net_device *dev, unsigned int txqueue) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| schedule_work(&priv->reset_wq); |
| netdev_info(dev, "TXTIMEOUT"); |
| } |
| |
| static void _rtl92e_update_cap(struct net_device *dev, u16 cap) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtllib_network *net = &priv->rtllib->current_network; |
| bool ShortPreamble; |
| |
| if (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) { |
| if (priv->dot11_current_preamble_mode != PREAMBLE_SHORT) { |
| ShortPreamble = true; |
| priv->dot11_current_preamble_mode = PREAMBLE_SHORT; |
| priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE, |
| (unsigned char *)&ShortPreamble); |
| } |
| } else { |
| if (priv->dot11_current_preamble_mode != PREAMBLE_LONG) { |
| ShortPreamble = false; |
| priv->dot11_current_preamble_mode = PREAMBLE_LONG; |
| priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE, |
| (unsigned char *)&ShortPreamble); |
| } |
| } |
| |
| if (net->mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) { |
| u8 slot_time_val; |
| u8 cur_slot_time = priv->slot_time; |
| |
| if ((cap & WLAN_CAPABILITY_SHORT_SLOT_TIME) && |
| (!priv->rtllib->ht_info->current_rt2rt_long_slot_time)) { |
| if (cur_slot_time != SHORT_SLOT_TIME) { |
| slot_time_val = SHORT_SLOT_TIME; |
| priv->rtllib->set_hw_reg_handler(dev, |
| HW_VAR_SLOT_TIME, &slot_time_val); |
| } |
| } else { |
| if (cur_slot_time != NON_SHORT_SLOT_TIME) { |
| slot_time_val = NON_SHORT_SLOT_TIME; |
| priv->rtllib->set_hw_reg_handler(dev, |
| HW_VAR_SLOT_TIME, &slot_time_val); |
| } |
| } |
| } |
| } |
| |
| static const struct rtllib_qos_parameters def_qos_parameters = { |
| {cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3)}, |
| {cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7)}, |
| {2, 2, 2, 2}, |
| {0, 0, 0, 0}, |
| {0, 0, 0, 0} |
| }; |
| |
| static void _rtl92e_update_beacon(void *data) |
| { |
| struct r8192_priv *priv = container_of(data, struct r8192_priv, update_beacon_wq.work); |
| struct net_device *dev = priv->rtllib->dev; |
| struct rtllib_device *ieee = priv->rtllib; |
| struct rtllib_network *net = &ieee->current_network; |
| |
| if (ieee->ht_info->current_ht_support) |
| HT_update_self_and_peer_setting(ieee, net); |
| ieee->ht_info->current_rt2rt_long_slot_time = net->bssht.bd_rt2rt_long_slot_time; |
| _rtl92e_update_cap(dev, net->capability); |
| } |
| |
| static void _rtl92e_qos_activate(void *data) |
| { |
| struct r8192_priv *priv = container_of(data, struct r8192_priv, qos_activate); |
| struct net_device *dev = priv->rtllib->dev; |
| int i; |
| |
| mutex_lock(&priv->mutex); |
| if (priv->rtllib->link_state != MAC80211_LINKED) |
| goto success; |
| |
| for (i = 0; i < QOS_QUEUE_NUM; i++) |
| priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM, (u8 *)(&i)); |
| |
| success: |
| mutex_unlock(&priv->mutex); |
| } |
| |
| static int _rtl92e_qos_handle_probe_response(struct r8192_priv *priv, |
| int active_network, |
| struct rtllib_network *network) |
| { |
| int ret = 0; |
| u32 size = sizeof(struct rtllib_qos_parameters); |
| |
| if (priv->rtllib->link_state != MAC80211_LINKED) |
| return ret; |
| |
| if (priv->rtllib->iw_mode != IW_MODE_INFRA) |
| return ret; |
| |
| if (network->flags & NETWORK_HAS_QOS_MASK) { |
| if (active_network && |
| (network->flags & NETWORK_HAS_QOS_PARAMETERS)) |
| network->qos_data.active = network->qos_data.supported; |
| |
| if ((network->qos_data.active == 1) && (active_network == 1) && |
| (network->flags & NETWORK_HAS_QOS_PARAMETERS) && |
| (network->qos_data.old_param_count != |
| network->qos_data.param_count)) { |
| network->qos_data.old_param_count = |
| network->qos_data.param_count; |
| priv->rtllib->wmm_acm = network->qos_data.wmm_acm; |
| schedule_work(&priv->qos_activate); |
| } |
| } else { |
| memcpy(&priv->rtllib->current_network.qos_data.parameters, |
| &def_qos_parameters, size); |
| |
| if ((network->qos_data.active == 1) && (active_network == 1)) |
| schedule_work(&priv->qos_activate); |
| |
| network->qos_data.active = 0; |
| network->qos_data.supported = 0; |
| } |
| |
| return 0; |
| } |
| |
| static int _rtl92e_handle_beacon(struct net_device *dev, |
| struct rtllib_beacon *beacon, |
| struct rtllib_network *network) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| _rtl92e_qos_handle_probe_response(priv, 1, network); |
| |
| schedule_delayed_work(&priv->update_beacon_wq, 0); |
| return 0; |
| } |
| |
| static int _rtl92e_qos_assoc_resp(struct r8192_priv *priv, |
| struct rtllib_network *network) |
| { |
| unsigned long flags; |
| u32 size = sizeof(struct rtllib_qos_parameters); |
| int set_qos_param = 0; |
| |
| if (!priv || !network) |
| return 0; |
| |
| if (priv->rtllib->link_state != MAC80211_LINKED) |
| return 0; |
| |
| if (priv->rtllib->iw_mode != IW_MODE_INFRA) |
| return 0; |
| |
| spin_lock_irqsave(&priv->rtllib->lock, flags); |
| if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { |
| memcpy(&priv->rtllib->current_network.qos_data.parameters, |
| &network->qos_data.parameters, |
| sizeof(struct rtllib_qos_parameters)); |
| priv->rtllib->current_network.qos_data.active = 1; |
| priv->rtllib->wmm_acm = network->qos_data.wmm_acm; |
| set_qos_param = 1; |
| priv->rtllib->current_network.qos_data.old_param_count = |
| priv->rtllib->current_network.qos_data.param_count; |
| priv->rtllib->current_network.qos_data.param_count = |
| network->qos_data.param_count; |
| } else { |
| memcpy(&priv->rtllib->current_network.qos_data.parameters, |
| &def_qos_parameters, size); |
| priv->rtllib->current_network.qos_data.active = 0; |
| priv->rtllib->current_network.qos_data.supported = 0; |
| set_qos_param = 1; |
| } |
| |
| spin_unlock_irqrestore(&priv->rtllib->lock, flags); |
| |
| if (set_qos_param == 1) { |
| rtl92e_dm_init_edca_turbo(priv->rtllib->dev); |
| schedule_work(&priv->qos_activate); |
| } |
| return 0; |
| } |
| |
| static int _rtl92e_handle_assoc_response(struct net_device *dev, |
| struct rtllib_assoc_response_frame *resp, |
| struct rtllib_network *network) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| _rtl92e_qos_assoc_resp(priv, network); |
| return 0; |
| } |
| |
| void rtl92e_config_rate(struct net_device *dev, u16 *rate_config) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtllib_network *net; |
| u8 i = 0, basic_rate = 0; |
| |
| net = &priv->rtllib->current_network; |
| |
| for (i = 0; i < net->rates_len; i++) { |
| basic_rate = net->rates[i] & 0x7f; |
| switch (basic_rate) { |
| case MGN_1M: |
| *rate_config |= RRSR_1M; |
| break; |
| case MGN_2M: |
| *rate_config |= RRSR_2M; |
| break; |
| case MGN_5_5M: |
| *rate_config |= RRSR_5_5M; |
| break; |
| case MGN_11M: |
| *rate_config |= RRSR_11M; |
| break; |
| case MGN_6M: |
| *rate_config |= RRSR_6M; |
| break; |
| case MGN_9M: |
| *rate_config |= RRSR_9M; |
| break; |
| case MGN_12M: |
| *rate_config |= RRSR_12M; |
| break; |
| case MGN_18M: |
| *rate_config |= RRSR_18M; |
| break; |
| case MGN_24M: |
| *rate_config |= RRSR_24M; |
| break; |
| case MGN_36M: |
| *rate_config |= RRSR_36M; |
| break; |
| case MGN_48M: |
| *rate_config |= RRSR_48M; |
| break; |
| case MGN_54M: |
| *rate_config |= RRSR_54M; |
| break; |
| } |
| } |
| |
| for (i = 0; i < net->rates_ex_len; i++) { |
| basic_rate = net->rates_ex[i] & 0x7f; |
| switch (basic_rate) { |
| case MGN_1M: |
| *rate_config |= RRSR_1M; |
| break; |
| case MGN_2M: |
| *rate_config |= RRSR_2M; |
| break; |
| case MGN_5_5M: |
| *rate_config |= RRSR_5_5M; |
| break; |
| case MGN_11M: |
| *rate_config |= RRSR_11M; |
| break; |
| case MGN_6M: |
| *rate_config |= RRSR_6M; |
| break; |
| case MGN_9M: |
| *rate_config |= RRSR_9M; |
| break; |
| case MGN_12M: |
| *rate_config |= RRSR_12M; |
| break; |
| case MGN_18M: |
| *rate_config |= RRSR_18M; |
| break; |
| case MGN_24M: |
| *rate_config |= RRSR_24M; |
| break; |
| case MGN_36M: |
| *rate_config |= RRSR_36M; |
| break; |
| case MGN_48M: |
| *rate_config |= RRSR_48M; |
| break; |
| case MGN_54M: |
| *rate_config |= RRSR_54M; |
| break; |
| } |
| } |
| } |
| |
| static void _rtl92e_refresh_support_rate(struct r8192_priv *priv) |
| { |
| struct rtllib_device *ieee = priv->rtllib; |
| |
| if (ieee->mode == WIRELESS_MODE_N_24G) { |
| memcpy(ieee->reg_dot11ht_oper_rate_set, |
| ieee->reg_ht_supp_rate_set, 16); |
| memcpy(ieee->reg_dot11tx_ht_oper_rate_set, |
| ieee->reg_ht_supp_rate_set, 16); |
| |
| } else { |
| memset(ieee->reg_dot11ht_oper_rate_set, 0, 16); |
| } |
| } |
| |
| void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| u8 support_mode = (WIRELESS_MODE_N_24G | WIRELESS_MODE_G | WIRELESS_MODE_B); |
| |
| if ((wireless_mode == WIRELESS_MODE_AUTO) || ((wireless_mode & support_mode) == 0)) |
| wireless_mode = WIRELESS_MODE_N_24G; |
| |
| if ((wireless_mode & (WIRELESS_MODE_B | WIRELESS_MODE_G)) == |
| (WIRELESS_MODE_G | WIRELESS_MODE_B)) |
| wireless_mode = WIRELESS_MODE_G; |
| |
| priv->rtllib->mode = wireless_mode; |
| |
| if (wireless_mode == WIRELESS_MODE_N_24G) |
| priv->rtllib->ht_info->enable_ht = 1; |
| else |
| priv->rtllib->ht_info->enable_ht = 0; |
| |
| _rtl92e_refresh_support_rate(priv); |
| } |
| |
| static int _rtl92e_sta_up(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) |
| (&priv->rtllib->pwr_save_ctrl); |
| bool init_status; |
| |
| priv->up = 1; |
| priv->rtllib->ieee_up = 1; |
| |
| priv->up_first_time = 0; |
| init_status = rtl92e_start_adapter(dev); |
| if (!init_status) { |
| netdev_err(dev, "%s(): Initialization failed!\n", __func__); |
| return -1; |
| } |
| |
| RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC); |
| |
| if (priv->polling_timer_on == 0) |
| rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer); |
| |
| if (priv->rtllib->link_state != MAC80211_LINKED) |
| rtllib_softmac_start_protocol(priv->rtllib); |
| rtllib_reset_queue(priv->rtllib); |
| _rtl92e_watchdog_timer_cb(&priv->watch_dog_timer); |
| |
| if (!netif_queue_stopped(dev)) |
| netif_start_queue(dev); |
| else |
| netif_wake_queue(dev); |
| |
| priv->bfirst_after_down = false; |
| return 0; |
| } |
| |
| static int _rtl92e_sta_down(struct net_device *dev, bool shutdownrf) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| unsigned long flags = 0; |
| u8 rf_in_progress_timeout = 0; |
| |
| if (priv->up == 0) |
| return -1; |
| |
| priv->rtllib->rtllib_ips_leave(dev); |
| |
| if (priv->rtllib->link_state == MAC80211_LINKED) |
| rtl92e_leisure_ps_leave(dev); |
| |
| priv->up = 0; |
| priv->rtllib->ieee_up = 0; |
| priv->bfirst_after_down = true; |
| if (!netif_queue_stopped(dev)) |
| netif_stop_queue(dev); |
| |
| priv->rtllib->wpa_ie_len = 0; |
| kfree(priv->rtllib->wpa_ie); |
| priv->rtllib->wpa_ie = NULL; |
| rtl92e_cam_reset(dev); |
| memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); |
| rtl92e_irq_disable(dev); |
| |
| del_timer_sync(&priv->watch_dog_timer); |
| _rtl92e_cancel_deferred_work(priv); |
| cancel_delayed_work(&priv->rtllib->hw_wakeup_wq); |
| |
| rtllib_softmac_stop_protocol(priv->rtllib); |
| spin_lock_irqsave(&priv->rf_ps_lock, flags); |
| while (priv->rf_change_in_progress) { |
| spin_unlock_irqrestore(&priv->rf_ps_lock, flags); |
| if (rf_in_progress_timeout > 100) { |
| spin_lock_irqsave(&priv->rf_ps_lock, flags); |
| break; |
| } |
| mdelay(1); |
| rf_in_progress_timeout++; |
| spin_lock_irqsave(&priv->rf_ps_lock, flags); |
| } |
| priv->rf_change_in_progress = true; |
| spin_unlock_irqrestore(&priv->rf_ps_lock, flags); |
| rtl92e_stop_adapter(dev, false); |
| spin_lock_irqsave(&priv->rf_ps_lock, flags); |
| priv->rf_change_in_progress = false; |
| spin_unlock_irqrestore(&priv->rf_ps_lock, flags); |
| udelay(100); |
| memset(&priv->rtllib->current_network, 0, |
| offsetof(struct rtllib_network, list)); |
| |
| return 0; |
| } |
| |
| static void _rtl92e_init_priv_handler(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| priv->rtllib->softmac_hard_start_xmit = _rtl92e_hard_start_xmit; |
| priv->rtllib->set_chan = rtl92e_set_channel; |
| priv->rtllib->link_change = rtl92e_link_change; |
| priv->rtllib->softmac_data_hard_start_xmit = _rtl92e_hard_data_xmit; |
| priv->rtllib->check_nic_enough_desc = _rtl92e_check_nic_enough_desc; |
| priv->rtllib->handle_assoc_response = _rtl92e_handle_assoc_response; |
| priv->rtllib->handle_beacon = _rtl92e_handle_beacon; |
| priv->rtllib->set_wireless_mode = rtl92e_set_wireless_mode; |
| priv->rtllib->leisure_ps_leave = rtl92e_leisure_ps_leave; |
| priv->rtllib->set_bw_mode_handler = rtl92e_set_bw_mode; |
| |
| priv->rtllib->sta_wake_up = rtl92e_hw_wakeup; |
| priv->rtllib->enter_sleep_state = rtl92e_enter_sleep; |
| priv->rtllib->ps_is_queue_empty = _rtl92e_is_tx_queue_empty; |
| |
| priv->rtllib->get_nmode_support_by_sec_cfg = rtl92e_get_nmode_support_by_sec; |
| priv->rtllib->get_half_nmode_support_by_aps_handler = |
| rtl92e_is_halfn_supported_by_ap; |
| |
| priv->rtllib->set_hw_reg_handler = rtl92e_set_reg; |
| priv->rtllib->allow_all_dest_addr_handler = rtl92e_set_monitor_mode; |
| priv->rtllib->init_gain_handler = rtl92e_init_gain; |
| priv->rtllib->rtllib_ips_leave_wq = rtl92e_rtllib_ips_leave_wq; |
| priv->rtllib->rtllib_ips_leave = rtl92e_rtllib_ips_leave; |
| priv->rtllib->ScanOperationBackupHandler = rtl92e_scan_op_backup; |
| } |
| |
| static void _rtl92e_init_priv_variable(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| u8 i; |
| |
| priv->dot11_current_preamble_mode = PREAMBLE_AUTO; |
| priv->rtllib->status = 0; |
| priv->polling_timer_on = 0; |
| priv->up_first_time = 1; |
| priv->blinked_ingpio = false; |
| priv->being_init_adapter = false; |
| priv->txringcount = 64; |
| priv->rxbuffersize = 9100; |
| priv->rxringcount = MAX_RX_COUNT; |
| priv->irq_enabled = 0; |
| priv->chan = 1; |
| priv->rtllib->mode = WIRELESS_MODE_AUTO; |
| priv->rtllib->iw_mode = IW_MODE_INFRA; |
| priv->rtllib->ieee_up = 0; |
| priv->retry_rts = DEFAULT_RETRY_RTS; |
| priv->retry_data = DEFAULT_RETRY_DATA; |
| priv->rtllib->rts = DEFAULT_RTS_THRESHOLD; |
| priv->rtllib->rate = 110; |
| priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; |
| priv->bcck_in_ch14 = false; |
| priv->cck_present_attn = 0; |
| priv->rfa_txpowertrackingindex = 0; |
| priv->cck_pwr_enl = 6; |
| memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); |
| priv->rx_ctr = 0; |
| priv->rtllib->wx_set_enc = 0; |
| priv->hw_radio_off = false; |
| priv->rtllib->rf_off_reason = 0; |
| priv->rf_change_in_progress = false; |
| priv->hw_rf_off_action = 0; |
| priv->set_rf_pwr_state_in_progress = false; |
| priv->rtllib->pwr_save_ctrl.bLeisurePs = true; |
| priv->rtllib->lps_delay_cnt = 0; |
| priv->rtllib->sta_sleep = LPS_IS_WAKE; |
| priv->rtllib->rf_power_state = rf_on; |
| |
| priv->rtllib->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; |
| priv->rtllib->iw_mode = IW_MODE_INFRA; |
| priv->rtllib->be_scan_inprogress = false; |
| |
| priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD; |
| |
| priv->fw_info = vzalloc(sizeof(struct rt_firmware)); |
| if (!priv->fw_info) |
| netdev_err(dev, |
| "rtl8192e: Unable to allocate space for firmware\n"); |
| |
| skb_queue_head_init(&priv->skb_queue); |
| |
| for (i = 0; i < MAX_QUEUE_SIZE; i++) |
| skb_queue_head_init(&priv->rtllib->skb_waitq[i]); |
| } |
| |
| static void _rtl92e_init_priv_lock(struct r8192_priv *priv) |
| { |
| spin_lock_init(&priv->tx_lock); |
| spin_lock_init(&priv->irq_th_lock); |
| spin_lock_init(&priv->rf_ps_lock); |
| spin_lock_init(&priv->ps_lock); |
| mutex_init(&priv->wx_mutex); |
| mutex_init(&priv->rf_mutex); |
| mutex_init(&priv->mutex); |
| } |
| |
| static void _rtl92e_init_priv_task(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| INIT_WORK(&priv->reset_wq, (void *)_rtl92e_restart); |
| INIT_WORK(&priv->rtllib->ips_leave_wq, (void *)rtl92e_ips_leave_wq); |
| INIT_DELAYED_WORK(&priv->watch_dog_wq, (void *)_rtl92e_watchdog_wq_cb); |
| INIT_DELAYED_WORK(&priv->txpower_tracking_wq, (void *)rtl92e_dm_txpower_tracking_wq); |
| INIT_DELAYED_WORK(&priv->rfpath_check_wq, (void *)rtl92e_dm_rf_pathcheck_wq); |
| INIT_DELAYED_WORK(&priv->update_beacon_wq, (void *)_rtl92e_update_beacon); |
| INIT_WORK(&priv->qos_activate, (void *)_rtl92e_qos_activate); |
| INIT_DELAYED_WORK(&priv->rtllib->hw_wakeup_wq, (void *)rtl92e_hw_wakeup_wq); |
| INIT_DELAYED_WORK(&priv->rtllib->hw_sleep_wq, (void *)rtl92e_hw_sleep_wq); |
| tasklet_setup(&priv->irq_rx_tasklet, _rtl92e_irq_rx_tasklet); |
| tasklet_setup(&priv->irq_tx_tasklet, _rtl92e_irq_tx_tasklet); |
| } |
| |
| static short _rtl92e_get_channel_map(struct net_device *dev) |
| { |
| int i; |
| |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| for (i = 1; i <= 11; i++) |
| (priv->rtllib->active_channel_map)[i] = 1; |
| (priv->rtllib->active_channel_map)[12] = 2; |
| (priv->rtllib->active_channel_map)[13] = 2; |
| |
| return 0; |
| } |
| |
| static short _rtl92e_init(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| memset(&priv->stats, 0, sizeof(struct rt_stats)); |
| |
| _rtl92e_init_priv_handler(dev); |
| _rtl92e_init_priv_variable(dev); |
| _rtl92e_init_priv_lock(priv); |
| _rtl92e_init_priv_task(dev); |
| rtl92e_get_eeprom_size(dev); |
| rtl92e_init_variables(dev); |
| _rtl92e_get_channel_map(dev); |
| |
| rtl92e_dm_init(dev); |
| |
| timer_setup(&priv->watch_dog_timer, _rtl92e_watchdog_timer_cb, 0); |
| |
| timer_setup(&priv->gpio_polling_timer, rtl92e_check_rfctrl_gpio_timer, |
| 0); |
| |
| rtl92e_irq_disable(dev); |
| if (request_irq(dev->irq, _rtl92e_irq, IRQF_SHARED, dev->name, dev)) { |
| netdev_err(dev, "Error allocating IRQ %d", dev->irq); |
| return -1; |
| } |
| |
| priv->irq = dev->irq; |
| |
| if (_rtl92e_pci_initdescring(dev) != 0) { |
| netdev_err(dev, "Endopoints initialization failed"); |
| free_irq(dev->irq, dev); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /*************************************************************************** |
| * -------------------------------WATCHDOG STUFF--------------------------- |
| **************************************************************************/ |
| static short _rtl92e_is_tx_queue_empty(struct net_device *dev) |
| { |
| int i = 0; |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| for (i = 0; i <= MGNT_QUEUE; i++) { |
| if ((i == TXCMD_QUEUE) || (i == HCCA_QUEUE)) |
| continue; |
| if (skb_queue_len(&(&priv->tx_ring[i])->queue) > 0) { |
| netdev_info(dev, "===>tx queue is not empty:%d, %d\n", |
| i, skb_queue_len(&(&priv->tx_ring[i])->queue)); |
| return 0; |
| } |
| } |
| return 1; |
| } |
| |
| static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| u8 QueueID; |
| bool bCheckFwTxCnt = false; |
| struct rtl8192_tx_ring *ring = NULL; |
| struct sk_buff *skb = NULL; |
| struct cb_desc *tcb_desc = NULL; |
| unsigned long flags = 0; |
| |
| switch (priv->rtllib->ps) { |
| case RTLLIB_PS_DISABLED: |
| break; |
| case (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST): |
| break; |
| default: |
| break; |
| } |
| spin_lock_irqsave(&priv->irq_th_lock, flags); |
| for (QueueID = 0; QueueID < MAX_TX_QUEUE; QueueID++) { |
| if (QueueID == TXCMD_QUEUE) |
| continue; |
| |
| if (QueueID == BEACON_QUEUE) |
| continue; |
| |
| ring = &priv->tx_ring[QueueID]; |
| |
| if (skb_queue_len(&ring->queue) == 0) { |
| continue; |
| } else { |
| skb = __skb_peek(&ring->queue); |
| tcb_desc = (struct cb_desc *)(skb->cb + |
| MAX_DEV_ADDR_SIZE); |
| tcb_desc->nStuckCount++; |
| bCheckFwTxCnt = true; |
| if (tcb_desc->nStuckCount > 1) |
| netdev_info(dev, |
| "%s: QueueID=%d tcb_desc->nStuckCount=%d\n", |
| __func__, QueueID, |
| tcb_desc->nStuckCount); |
| } |
| } |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| |
| if (bCheckFwTxCnt) { |
| if (rtl92e_is_tx_stuck(dev)) |
| return RESET_TYPE_SILENT; |
| } |
| |
| return RESET_TYPE_NORESET; |
| } |
| |
| static enum reset_type _rtl92e_rx_check_stuck(struct net_device *dev) |
| { |
| if (rtl92e_is_rx_stuck(dev)) |
| return RESET_TYPE_SILENT; |
| |
| return RESET_TYPE_NORESET; |
| } |
| |
| static void _rtl92e_if_check_reset(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| enum reset_type TxResetType = RESET_TYPE_NORESET; |
| enum reset_type RxResetType = RESET_TYPE_NORESET; |
| enum rt_rf_power_state rfState; |
| |
| rfState = priv->rtllib->rf_power_state; |
| |
| if (rfState == rf_on) |
| TxResetType = _rtl92e_tx_check_stuck(dev); |
| |
| if (rfState == rf_on && |
| (priv->rtllib->iw_mode == IW_MODE_INFRA) && |
| (priv->rtllib->link_state == MAC80211_LINKED)) |
| RxResetType = _rtl92e_rx_check_stuck(dev); |
| |
| if (TxResetType == RESET_TYPE_SILENT || |
| RxResetType == RESET_TYPE_SILENT) { |
| netdev_info(dev, "%s(): TxResetType is %d, RxResetType is %d\n", |
| __func__, TxResetType, RxResetType); |
| } |
| } |
| |
| static void _rtl92e_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum, |
| u32 *TotalRxDataNum) |
| { |
| u16 slot_index; |
| u8 i; |
| |
| *TotalRxBcnNum = 0; |
| *TotalRxDataNum = 0; |
| |
| slot_index = (priv->rtllib->link_detect_info.slot_index++) % |
| (priv->rtllib->link_detect_info.slot_num); |
| priv->rtllib->link_detect_info.RxBcnNum[slot_index] = |
| priv->rtllib->link_detect_info.num_recv_bcn_in_period; |
| priv->rtllib->link_detect_info.RxDataNum[slot_index] = |
| priv->rtllib->link_detect_info.num_recv_data_in_period; |
| for (i = 0; i < priv->rtllib->link_detect_info.slot_num; i++) { |
| *TotalRxBcnNum += priv->rtllib->link_detect_info.RxBcnNum[i]; |
| *TotalRxDataNum += priv->rtllib->link_detect_info.RxDataNum[i]; |
| } |
| } |
| |
| static void _rtl92e_watchdog_wq_cb(void *data) |
| { |
| struct r8192_priv *priv = container_of_dwork_rsl(data, |
| struct r8192_priv, watch_dog_wq); |
| struct net_device *dev = priv->rtllib->dev; |
| struct rtllib_device *ieee = priv->rtllib; |
| static u8 check_reset_cnt; |
| unsigned long flags; |
| struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) |
| (&priv->rtllib->pwr_save_ctrl); |
| bool busy_traffic = false; |
| bool bHigherBusyTraffic = false; |
| bool bHigherBusyRxTraffic = false; |
| bool bEnterPS = false; |
| |
| if (!priv->up || priv->hw_radio_off) |
| return; |
| |
| if (priv->rtllib->link_state >= MAC80211_LINKED) { |
| if (priv->rtllib->CntAfterLink < 2) |
| priv->rtllib->CntAfterLink++; |
| } else { |
| priv->rtllib->CntAfterLink = 0; |
| } |
| |
| rtl92e_dm_watchdog(dev); |
| |
| if (!rtllib_act_scanning(priv->rtllib, false)) { |
| if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->link_state == |
| MAC80211_NOLINK) && |
| (ieee->rf_power_state == rf_on) && !ieee->is_set_key && |
| (!ieee->proto_stoppping) && !ieee->wx_set_enc) { |
| if (ieee->pwr_save_ctrl.ReturnPoint == IPS_CALLBACK_NONE) |
| rtl92e_ips_enter(dev); |
| } |
| } |
| if ((ieee->link_state == MAC80211_LINKED) && (ieee->iw_mode == IW_MODE_INFRA)) { |
| if (ieee->link_detect_info.num_rx_ok_in_period > 100 || |
| ieee->link_detect_info.num_tx_ok_in_period > 100) |
| busy_traffic = true; |
| |
| if (ieee->link_detect_info.num_rx_ok_in_period > 4000 || |
| ieee->link_detect_info.num_tx_ok_in_period > 4000) { |
| bHigherBusyTraffic = true; |
| if (ieee->link_detect_info.num_rx_ok_in_period > 5000) |
| bHigherBusyRxTraffic = true; |
| else |
| bHigherBusyRxTraffic = false; |
| } |
| |
| if (((ieee->link_detect_info.num_rx_unicast_ok_in_period + |
| ieee->link_detect_info.num_tx_ok_in_period) > 8) || |
| (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2)) |
| bEnterPS = false; |
| else |
| bEnterPS = true; |
| |
| if (ieee->current_network.beacon_interval < 95) |
| bEnterPS = false; |
| |
| if (bEnterPS) |
| rtl92e_leisure_ps_enter(dev); |
| else |
| rtl92e_leisure_ps_leave(dev); |
| |
| } else { |
| rtl92e_leisure_ps_leave(dev); |
| } |
| |
| ieee->link_detect_info.num_rx_ok_in_period = 0; |
| ieee->link_detect_info.num_tx_ok_in_period = 0; |
| ieee->link_detect_info.num_rx_unicast_ok_in_period = 0; |
| ieee->link_detect_info.busy_traffic = busy_traffic; |
| |
| ieee->link_detect_info.bHigherBusyTraffic = bHigherBusyTraffic; |
| ieee->link_detect_info.bHigherBusyRxTraffic = bHigherBusyRxTraffic; |
| |
| if (ieee->link_state == MAC80211_LINKED && ieee->iw_mode == IW_MODE_INFRA) { |
| u32 TotalRxBcnNum = 0; |
| u32 TotalRxDataNum = 0; |
| |
| _rtl92e_update_rxcounts(priv, &TotalRxBcnNum, &TotalRxDataNum); |
| |
| if ((TotalRxBcnNum + TotalRxDataNum) == 0) |
| priv->check_roaming_cnt++; |
| else |
| priv->check_roaming_cnt = 0; |
| |
| if (priv->check_roaming_cnt > 0) { |
| if (ieee->rf_power_state == rf_off) |
| netdev_info(dev, "%s(): RF is off\n", __func__); |
| |
| netdev_info(dev, |
| "===>%s(): AP is power off, chan:%d, connect another one\n", |
| __func__, priv->chan); |
| |
| ieee->link_state = RTLLIB_ASSOCIATING; |
| |
| remove_peer_ts(priv->rtllib, |
| priv->rtllib->current_network.bssid); |
| ieee->is_roaming = true; |
| ieee->is_set_key = false; |
| ieee->link_change(dev); |
| notify_wx_assoc_event(ieee); |
| |
| if (!(ieee->rtllib_ap_sec_type(ieee) & |
| (SEC_ALG_CCMP | SEC_ALG_TKIP))) |
| schedule_delayed_work( |
| &ieee->associate_procedure_wq, 0); |
| |
| priv->check_roaming_cnt = 0; |
| } |
| ieee->link_detect_info.num_recv_bcn_in_period = 0; |
| ieee->link_detect_info.num_recv_data_in_period = 0; |
| } |
| |
| spin_lock_irqsave(&priv->tx_lock, flags); |
| if ((check_reset_cnt++ >= 3) && (!ieee->is_roaming) && |
| (!priv->rf_change_in_progress) && (!psc->bSwRfProcessing)) { |
| _rtl92e_if_check_reset(dev); |
| check_reset_cnt = 3; |
| } |
| spin_unlock_irqrestore(&priv->tx_lock, flags); |
| } |
| |
| static void _rtl92e_watchdog_timer_cb(struct timer_list *t) |
| { |
| struct r8192_priv *priv = from_timer(priv, t, watch_dog_timer); |
| |
| schedule_delayed_work(&priv->watch_dog_wq, 0); |
| mod_timer(&priv->watch_dog_timer, jiffies + |
| msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME)); |
| } |
| |
| /**************************************************************************** |
| * ---------------------------- NIC TX/RX STUFF--------------------------- |
| ****************************************************************************/ |
| void rtl92e_rx_enable(struct net_device *dev) |
| { |
| rtl92e_enable_rx(dev); |
| } |
| |
| void rtl92e_tx_enable(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| rtl92e_enable_tx(dev); |
| |
| rtllib_reset_queue(priv->rtllib); |
| } |
| |
| static void _rtl92e_free_rx_ring(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| int i; |
| |
| for (i = 0; i < priv->rxringcount; i++) { |
| struct sk_buff *skb = priv->rx_buf[i]; |
| |
| if (!skb) |
| continue; |
| |
| dma_unmap_single(&priv->pdev->dev, |
| *((dma_addr_t *)skb->cb), |
| priv->rxbuffersize, DMA_FROM_DEVICE); |
| kfree_skb(skb); |
| } |
| |
| dma_free_coherent(&priv->pdev->dev, |
| sizeof(*priv->rx_ring) * priv->rxringcount, |
| priv->rx_ring, |
| priv->rx_ring_dma); |
| priv->rx_ring = NULL; |
| } |
| |
| static void _rtl92e_free_tx_ring(struct net_device *dev, unsigned int prio) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; |
| |
| while (skb_queue_len(&ring->queue)) { |
| struct tx_desc *entry = &ring->desc[ring->idx]; |
| struct sk_buff *skb = __skb_dequeue(&ring->queue); |
| |
| dma_unmap_single(&priv->pdev->dev, entry->TxBuffAddr, |
| skb->len, DMA_TO_DEVICE); |
| kfree_skb(skb); |
| ring->idx = (ring->idx + 1) % ring->entries; |
| } |
| |
| dma_free_coherent(&priv->pdev->dev, |
| sizeof(*ring->desc) * ring->entries, ring->desc, |
| ring->dma); |
| ring->desc = NULL; |
| } |
| |
| static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, |
| int rate) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| int ret; |
| struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + |
| MAX_DEV_ADDR_SIZE); |
| u8 queue_index = tcb_desc->queue_index; |
| |
| if ((priv->rtllib->rf_power_state == rf_off) || !priv->up) { |
| kfree_skb(skb); |
| return; |
| } |
| |
| if (queue_index == TXCMD_QUEUE) |
| netdev_warn(dev, "%s(): queue index == TXCMD_QUEUE\n", |
| __func__); |
| |
| memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); |
| skb_push(skb, priv->rtllib->tx_headroom); |
| ret = _rtl92e_tx(dev, skb); |
| |
| if (queue_index != MGNT_QUEUE) { |
| priv->rtllib->stats.tx_bytes += (skb->len - |
| priv->rtllib->tx_headroom); |
| priv->rtllib->stats.tx_packets++; |
| } |
| |
| if (ret != 0) |
| kfree_skb(skb); |
| } |
| |
| static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| int ret; |
| struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + |
| MAX_DEV_ADDR_SIZE); |
| u8 queue_index = tcb_desc->queue_index; |
| |
| if (queue_index != TXCMD_QUEUE) { |
| if ((priv->rtllib->rf_power_state == rf_off) || |
| !priv->up) { |
| kfree_skb(skb); |
| return 0; |
| } |
| } |
| |
| memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); |
| if (queue_index == TXCMD_QUEUE) { |
| _rtl92e_tx_cmd(dev, skb); |
| return 0; |
| } |
| |
| tcb_desc->ratr_index = 7; |
| tcb_desc->tx_dis_rate_fallback = 1; |
| tcb_desc->tx_use_drv_assinged_rate = 1; |
| tcb_desc->tx_enable_fw_calc_dur = 1; |
| skb_push(skb, priv->rtllib->tx_headroom); |
| ret = _rtl92e_tx(dev, skb); |
| if (ret != 0) |
| kfree_skb(skb); |
| return ret; |
| } |
| |
| static void _rtl92e_tx_isr(struct net_device *dev, int prio) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; |
| |
| while (skb_queue_len(&ring->queue)) { |
| struct tx_desc *entry = &ring->desc[ring->idx]; |
| struct sk_buff *skb; |
| |
| if (prio != BEACON_QUEUE) { |
| if (entry->OWN) |
| return; |
| ring->idx = (ring->idx + 1) % ring->entries; |
| } |
| |
| skb = __skb_dequeue(&ring->queue); |
| dma_unmap_single(&priv->pdev->dev, entry->TxBuffAddr, |
| skb->len, DMA_TO_DEVICE); |
| |
| kfree_skb(skb); |
| } |
| if (prio != BEACON_QUEUE) |
| tasklet_schedule(&priv->irq_tx_tasklet); |
| } |
| |
| static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtl8192_tx_ring *ring; |
| struct tx_desc_cmd *entry; |
| unsigned int idx; |
| struct cb_desc *tcb_desc; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&priv->irq_th_lock, flags); |
| ring = &priv->tx_ring[TXCMD_QUEUE]; |
| |
| idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; |
| entry = (struct tx_desc_cmd *)&ring->desc[idx]; |
| |
| tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); |
| |
| rtl92e_fill_tx_cmd_desc(dev, entry, tcb_desc, skb); |
| |
| __skb_queue_tail(&ring->queue, skb); |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| } |
| |
| static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtl8192_tx_ring *ring; |
| unsigned long flags; |
| struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + |
| MAX_DEV_ADDR_SIZE); |
| struct tx_desc *pdesc = NULL; |
| struct ieee80211_hdr *header = NULL; |
| u8 *pda_addr = NULL; |
| int idx; |
| u32 fwinfo_size = 0; |
| |
| priv->rtllib->awake_pkt_sent = true; |
| |
| fwinfo_size = sizeof(struct tx_fwinfo_8190pci); |
| |
| header = (struct ieee80211_hdr *)(((u8 *)skb->data) + fwinfo_size); |
| pda_addr = header->addr1; |
| |
| if (!is_broadcast_ether_addr(pda_addr) && !is_multicast_ether_addr(pda_addr)) |
| priv->stats.txbytesunicast += skb->len - fwinfo_size; |
| |
| spin_lock_irqsave(&priv->irq_th_lock, flags); |
| ring = &priv->tx_ring[tcb_desc->queue_index]; |
| if (tcb_desc->queue_index != BEACON_QUEUE) |
| idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; |
| else |
| idx = 0; |
| |
| pdesc = &ring->desc[idx]; |
| if ((pdesc->OWN == 1) && (tcb_desc->queue_index != BEACON_QUEUE)) { |
| netdev_warn(dev, |
| "No more TX desc@%d, ring->idx = %d, idx = %d, skblen = 0x%x queuelen=%d", |
| tcb_desc->queue_index, ring->idx, idx, skb->len, |
| skb_queue_len(&ring->queue)); |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| return skb->len; |
| } |
| rtl92e_fill_tx_desc(dev, pdesc, tcb_desc, skb); |
| __skb_queue_tail(&ring->queue, skb); |
| pdesc->OWN = 1; |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| netif_trans_update(dev); |
| |
| rtl92e_writew(dev, TP_POLL, 0x01 << tcb_desc->queue_index); |
| return 0; |
| } |
| |
| static short _rtl92e_alloc_rx_ring(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rx_desc *entry = NULL; |
| int i; |
| |
| priv->rx_ring = dma_alloc_coherent(&priv->pdev->dev, |
| sizeof(*priv->rx_ring) * priv->rxringcount, |
| &priv->rx_ring_dma, |
| GFP_ATOMIC); |
| if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { |
| netdev_warn(dev, "Cannot allocate RX ring\n"); |
| return -ENOMEM; |
| } |
| |
| priv->rx_idx = 0; |
| |
| for (i = 0; i < priv->rxringcount; i++) { |
| struct sk_buff *skb = dev_alloc_skb(priv->rxbuffersize); |
| dma_addr_t *mapping; |
| |
| entry = &priv->rx_ring[i]; |
| if (!skb) |
| return 0; |
| skb->dev = dev; |
| priv->rx_buf[i] = skb; |
| mapping = (dma_addr_t *)skb->cb; |
| *mapping = dma_map_single(&priv->pdev->dev, |
| skb_tail_pointer(skb), |
| priv->rxbuffersize, DMA_FROM_DEVICE); |
| if (dma_mapping_error(&priv->pdev->dev, *mapping)) { |
| dev_kfree_skb_any(skb); |
| return -1; |
| } |
| entry->BufferAddress = *mapping; |
| |
| entry->Length = priv->rxbuffersize; |
| entry->OWN = 1; |
| } |
| |
| if (entry) |
| entry->EOR = 1; |
| return 0; |
| } |
| |
| static int _rtl92e_alloc_tx_ring(struct net_device *dev, unsigned int prio, |
| unsigned int entries) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct tx_desc *ring; |
| dma_addr_t dma; |
| int i; |
| |
| ring = dma_alloc_coherent(&priv->pdev->dev, sizeof(*ring) * entries, |
| &dma, GFP_ATOMIC); |
| if (!ring || (unsigned long)ring & 0xFF) { |
| netdev_warn(dev, "Cannot allocate TX ring (prio = %d)\n", prio); |
| return -ENOMEM; |
| } |
| |
| priv->tx_ring[prio].desc = ring; |
| priv->tx_ring[prio].dma = dma; |
| priv->tx_ring[prio].idx = 0; |
| priv->tx_ring[prio].entries = entries; |
| skb_queue_head_init(&priv->tx_ring[prio].queue); |
| |
| for (i = 0; i < entries; i++) |
| ring[i].NextDescAddress = |
| (u32)dma + ((i + 1) % entries) * |
| sizeof(*ring); |
| |
| return 0; |
| } |
| |
| static short _rtl92e_pci_initdescring(struct net_device *dev) |
| { |
| u32 ret; |
| int i; |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| ret = _rtl92e_alloc_rx_ring(dev); |
| if (ret) |
| return ret; |
| |
| for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { |
| ret = _rtl92e_alloc_tx_ring(dev, i, priv->txringcount); |
| if (ret) |
| goto err_free_rings; |
| } |
| |
| return 0; |
| |
| err_free_rings: |
| _rtl92e_free_rx_ring(dev); |
| for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) |
| if (priv->tx_ring[i].desc) |
| _rtl92e_free_tx_ring(dev, i); |
| return 1; |
| } |
| |
| void rtl92e_reset_desc_ring(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| int i; |
| unsigned long flags = 0; |
| |
| if (priv->rx_ring) { |
| struct rx_desc *entry = NULL; |
| |
| for (i = 0; i < priv->rxringcount; i++) { |
| entry = &priv->rx_ring[i]; |
| entry->OWN = 1; |
| } |
| priv->rx_idx = 0; |
| } |
| |
| spin_lock_irqsave(&priv->irq_th_lock, flags); |
| for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { |
| if (priv->tx_ring[i].desc) { |
| struct rtl8192_tx_ring *ring = &priv->tx_ring[i]; |
| |
| while (skb_queue_len(&ring->queue)) { |
| struct tx_desc *entry = &ring->desc[ring->idx]; |
| struct sk_buff *skb = |
| __skb_dequeue(&ring->queue); |
| |
| dma_unmap_single(&priv->pdev->dev, |
| entry->TxBuffAddr, skb->len, |
| DMA_TO_DEVICE); |
| kfree_skb(skb); |
| ring->idx = (ring->idx + 1) % ring->entries; |
| } |
| ring->idx = 0; |
| } |
| } |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| } |
| |
| long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index) |
| { |
| long signal_power; |
| |
| signal_power = (long)((signal_strength_index + 1) >> 1); |
| signal_power -= 95; |
| |
| return signal_power; |
| } |
| |
| void rtl92e_update_rx_statistics(struct r8192_priv *priv, |
| struct rtllib_rx_stats *pprevious_stats) |
| { |
| int weighting = 0; |
| |
| if (priv->stats.recv_signal_power == 0) |
| priv->stats.recv_signal_power = |
| pprevious_stats->RecvSignalPower; |
| |
| if (pprevious_stats->RecvSignalPower > priv->stats.recv_signal_power) |
| weighting = 5; |
| else if (pprevious_stats->RecvSignalPower < |
| priv->stats.recv_signal_power) |
| weighting = (-5); |
| priv->stats.recv_signal_power = (priv->stats.recv_signal_power * 5 + |
| pprevious_stats->RecvSignalPower + |
| weighting) / 6; |
| } |
| |
| u8 rtl92e_rx_db_to_percent(s8 antpower) |
| { |
| if ((antpower <= -100) || (antpower >= 20)) |
| return 0; |
| else if (antpower >= 0) |
| return 100; |
| else |
| return 100 + antpower; |
| |
| } /* QueryRxPwrPercentage */ |
| |
| u8 rtl92e_evm_db_to_percent(s8 value) |
| { |
| s8 ret_val = clamp(-value, 0, 33) * 3; |
| |
| if (ret_val == 99) |
| ret_val = 100; |
| |
| return ret_val; |
| } |
| |
| void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, |
| struct rtllib_rx_stats *ptarget_stats) |
| { |
| ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; |
| ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; |
| } |
| |
| static void _rtl92e_rx_normal(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct ieee80211_hdr *rtllib_hdr = NULL; |
| bool unicast_packet = false; |
| u32 skb_len = 0; |
| |
| struct rtllib_rx_stats stats = { |
| .signal = 0, |
| .noise = (u8)-98, |
| .rate = 0, |
| }; |
| unsigned int count = priv->rxringcount; |
| |
| while (count--) { |
| struct rx_desc *pdesc = &priv->rx_ring |
| [priv->rx_idx]; |
| struct sk_buff *skb = priv->rx_buf |
| [priv->rx_idx]; |
| struct sk_buff *new_skb; |
| |
| if (pdesc->OWN) |
| return; |
| if (!rtl92e_get_rx_stats(dev, &stats, pdesc, skb)) |
| goto done; |
| new_skb = dev_alloc_skb(priv->rxbuffersize); |
| /* if allocation of new skb failed - drop current packet |
| * and reuse skb |
| */ |
| if (unlikely(!new_skb)) |
| goto done; |
| |
| dma_unmap_single(&priv->pdev->dev, *((dma_addr_t *)skb->cb), |
| priv->rxbuffersize, DMA_FROM_DEVICE); |
| |
| skb_put(skb, pdesc->Length); |
| skb_reserve(skb, stats.RxDrvInfoSize + |
| stats.RxBufShift); |
| skb_trim(skb, skb->len - S_CRC_LEN); |
| rtllib_hdr = (struct ieee80211_hdr *)skb->data; |
| if (!is_multicast_ether_addr(rtllib_hdr->addr1)) { |
| /* unicast packet */ |
| unicast_packet = true; |
| } |
| skb_len = skb->len; |
| |
| if (!rtllib_rx(priv->rtllib, skb, &stats)) { |
| dev_kfree_skb_any(skb); |
| } else { |
| if (unicast_packet) |
| priv->stats.rxbytesunicast += skb_len; |
| } |
| |
| skb = new_skb; |
| skb->dev = dev; |
| |
| priv->rx_buf[priv->rx_idx] = skb; |
| *((dma_addr_t *)skb->cb) = dma_map_single(&priv->pdev->dev, |
| skb_tail_pointer(skb), |
| priv->rxbuffersize, DMA_FROM_DEVICE); |
| if (dma_mapping_error(&priv->pdev->dev, *((dma_addr_t *)skb->cb))) { |
| dev_kfree_skb_any(skb); |
| return; |
| } |
| done: |
| pdesc->BufferAddress = *((dma_addr_t *)skb->cb); |
| pdesc->OWN = 1; |
| pdesc->Length = priv->rxbuffersize; |
| if (priv->rx_idx == priv->rxringcount - 1) |
| pdesc->EOR = 1; |
| priv->rx_idx = (priv->rx_idx + 1) % |
| priv->rxringcount; |
| } |
| } |
| |
| static void _rtl92e_tx_resume(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rtllib_device *ieee = priv->rtllib; |
| struct sk_buff *skb; |
| int queue_index; |
| |
| for (queue_index = BK_QUEUE; |
| queue_index < MAX_QUEUE_SIZE; queue_index++) { |
| while ((!skb_queue_empty(&ieee->skb_waitq[queue_index])) && |
| (priv->rtllib->check_nic_enough_desc(dev, queue_index) > 0)) { |
| skb = skb_dequeue(&ieee->skb_waitq[queue_index]); |
| ieee->softmac_data_hard_start_xmit(skb, dev, 0); |
| } |
| } |
| } |
| |
| static void _rtl92e_irq_tx_tasklet(struct tasklet_struct *t) |
| { |
| struct r8192_priv *priv = from_tasklet(priv, t, irq_tx_tasklet); |
| |
| _rtl92e_tx_resume(priv->rtllib->dev); |
| } |
| |
| static void _rtl92e_irq_rx_tasklet(struct tasklet_struct *t) |
| { |
| struct r8192_priv *priv = from_tasklet(priv, t, irq_rx_tasklet); |
| |
| _rtl92e_rx_normal(priv->rtllib->dev); |
| |
| rtl92e_writel(priv->rtllib->dev, INTA_MASK, |
| rtl92e_readl(priv->rtllib->dev, INTA_MASK) | IMR_RDU); |
| } |
| |
| /**************************************************************************** |
| * ---------------------------- NIC START/CLOSE STUFF--------------------------- |
| ****************************************************************************/ |
| static void _rtl92e_cancel_deferred_work(struct r8192_priv *priv) |
| { |
| cancel_delayed_work_sync(&priv->watch_dog_wq); |
| cancel_delayed_work_sync(&priv->update_beacon_wq); |
| cancel_delayed_work(&priv->rtllib->hw_sleep_wq); |
| cancel_work_sync(&priv->reset_wq); |
| cancel_work_sync(&priv->qos_activate); |
| } |
| |
| static int _rtl92e_up(struct net_device *dev) |
| { |
| if (_rtl92e_sta_up(dev) == -1) |
| return -1; |
| return 0; |
| } |
| |
| static int _rtl92e_open(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| int ret; |
| |
| mutex_lock(&priv->wx_mutex); |
| ret = _rtl92e_try_up(dev); |
| mutex_unlock(&priv->wx_mutex); |
| return ret; |
| } |
| |
| static int _rtl92e_try_up(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| if (priv->up == 1) |
| return -1; |
| return _rtl92e_up(dev); |
| } |
| |
| static int _rtl92e_close(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| int ret; |
| |
| if ((rtllib_act_scanning(priv->rtllib, false)) && |
| !(priv->rtllib->softmac_features & IEEE_SOFTMAC_SCAN)) { |
| rtllib_stop_scan(priv->rtllib); |
| } |
| |
| mutex_lock(&priv->wx_mutex); |
| |
| ret = _rtl92e_down(dev, true); |
| |
| mutex_unlock(&priv->wx_mutex); |
| |
| return ret; |
| } |
| |
| static int _rtl92e_down(struct net_device *dev, bool shutdownrf) |
| { |
| if (_rtl92e_sta_down(dev, shutdownrf) == -1) |
| return -1; |
| |
| return 0; |
| } |
| |
| void rtl92e_commit(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| |
| if (priv->up == 0) |
| return; |
| rtllib_softmac_stop_protocol(priv->rtllib); |
| rtl92e_irq_disable(dev); |
| rtl92e_stop_adapter(dev, true); |
| _rtl92e_up(dev); |
| } |
| |
| static void _rtl92e_restart(void *data) |
| { |
| struct r8192_priv *priv = container_of(data, struct r8192_priv, reset_wq); |
| struct net_device *dev = priv->rtllib->dev; |
| |
| mutex_lock(&priv->wx_mutex); |
| |
| rtl92e_commit(dev); |
| |
| mutex_unlock(&priv->wx_mutex); |
| } |
| |
| static void _rtl92e_set_multicast(struct net_device *dev) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| short promisc; |
| |
| promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; |
| priv->promisc = promisc; |
| } |
| |
| static int _rtl92e_set_mac_adr(struct net_device *dev, void *mac) |
| { |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct sockaddr *addr = mac; |
| |
| mutex_lock(&priv->wx_mutex); |
| |
| eth_hw_addr_set(dev, addr->sa_data); |
| |
| schedule_work(&priv->reset_wq); |
| mutex_unlock(&priv->wx_mutex); |
| |
| return 0; |
| } |
| |
| static irqreturn_t _rtl92e_irq(int irq, void *netdev) |
| { |
| struct net_device *dev = netdev; |
| struct r8192_priv *priv = rtllib_priv(dev); |
| unsigned long flags; |
| u32 inta; |
| |
| if (priv->irq_enabled == 0) |
| goto done; |
| |
| spin_lock_irqsave(&priv->irq_th_lock, flags); |
| |
| rtl92e_ack_irq(dev, &inta); |
| |
| if (!inta) { |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| goto done; |
| } |
| |
| if (inta == 0xffff) { |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| goto done; |
| } |
| |
| if (!netif_running(dev)) { |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| goto done; |
| } |
| |
| if (inta & IMR_MGNTDOK) { |
| _rtl92e_tx_isr(dev, MGNT_QUEUE); |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| if (priv->rtllib->ack_tx_to_ieee) { |
| if (_rtl92e_is_tx_queue_empty(dev)) { |
| priv->rtllib->ack_tx_to_ieee = 0; |
| rtllib_ps_tx_ack(priv->rtllib, 1); |
| } |
| } |
| spin_lock_irqsave(&priv->irq_th_lock, flags); |
| } |
| |
| if (inta & IMR_COMDOK) |
| _rtl92e_tx_isr(dev, TXCMD_QUEUE); |
| |
| if (inta & IMR_HIGHDOK) |
| _rtl92e_tx_isr(dev, HIGH_QUEUE); |
| |
| if (inta & IMR_ROK) |
| tasklet_schedule(&priv->irq_rx_tasklet); |
| |
| if (inta & IMR_RDU) { |
| rtl92e_writel(dev, INTA_MASK, |
| rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU); |
| tasklet_schedule(&priv->irq_rx_tasklet); |
| } |
| |
| if (inta & IMR_RXFOVW) |
| tasklet_schedule(&priv->irq_rx_tasklet); |
| |
| if (inta & IMR_BKDOK) { |
| priv->rtllib->link_detect_info.num_tx_ok_in_period++; |
| _rtl92e_tx_isr(dev, BK_QUEUE); |
| } |
| |
| if (inta & IMR_BEDOK) { |
| priv->rtllib->link_detect_info.num_tx_ok_in_period++; |
| _rtl92e_tx_isr(dev, BE_QUEUE); |
| } |
| |
| if (inta & IMR_VIDOK) { |
| priv->rtllib->link_detect_info.num_tx_ok_in_period++; |
| _rtl92e_tx_isr(dev, VI_QUEUE); |
| } |
| |
| if (inta & IMR_VODOK) { |
| priv->rtllib->link_detect_info.num_tx_ok_in_period++; |
| _rtl92e_tx_isr(dev, VO_QUEUE); |
| } |
| |
| spin_unlock_irqrestore(&priv->irq_th_lock, flags); |
| |
| done: |
| |
| return IRQ_HANDLED; |
| } |
| |
| /**************************************************************************** |
| * ---------------------------- PCI_STUFF--------------------------- |
| ****************************************************************************/ |
| static const struct net_device_ops rtl8192_netdev_ops = { |
| .ndo_open = _rtl92e_open, |
| .ndo_stop = _rtl92e_close, |
| .ndo_tx_timeout = _rtl92e_tx_timeout, |
| .ndo_set_rx_mode = _rtl92e_set_multicast, |
| .ndo_set_mac_address = _rtl92e_set_mac_adr, |
| .ndo_validate_addr = eth_validate_addr, |
| .ndo_start_xmit = rtllib_xmit, |
| }; |
| |
| static int _rtl92e_pci_probe(struct pci_dev *pdev, |
| const struct pci_device_id *id) |
| { |
| unsigned long ioaddr = 0; |
| struct net_device *dev = NULL; |
| struct r8192_priv *priv = NULL; |
| unsigned long pmem_start, pmem_len, pmem_flags; |
| int err = -ENOMEM; |
| |
| if (pci_enable_device(pdev)) { |
| dev_err(&pdev->dev, "Failed to enable PCI device"); |
| return -EIO; |
| } |
| |
| pci_set_master(pdev); |
| |
| if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { |
| if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { |
| dev_info(&pdev->dev, |
| "Unable to obtain 32bit DMA for consistent allocations\n"); |
| goto err_pci_disable; |
| } |
| } |
| dev = alloc_rtllib(sizeof(struct r8192_priv)); |
| if (!dev) |
| goto err_pci_disable; |
| |
| err = -ENODEV; |
| |
| pci_set_drvdata(pdev, dev); |
| SET_NETDEV_DEV(dev, &pdev->dev); |
| priv = rtllib_priv(dev); |
| priv->rtllib = (struct rtllib_device *)netdev_priv_rsl(dev); |
| priv->pdev = pdev; |
| priv->rtllib->pdev = pdev; |
| if ((pdev->subsystem_vendor == PCI_VENDOR_ID_DLINK) && |
| (pdev->subsystem_device == 0x3304)) |
| priv->rtllib->bSupportRemoteWakeUp = 1; |
| else |
| priv->rtllib->bSupportRemoteWakeUp = 0; |
| |
| pmem_start = pci_resource_start(pdev, 1); |
| pmem_len = pci_resource_len(pdev, 1); |
| pmem_flags = pci_resource_flags(pdev, 1); |
| |
| if (!(pmem_flags & IORESOURCE_MEM)) { |
| netdev_err(dev, "region #1 not a MMIO resource, aborting"); |
| goto err_rel_rtllib; |
| } |
| |
| dev_info(&pdev->dev, "Memory mapped space start: 0x%08lx\n", |
| pmem_start); |
| if (!request_mem_region(pmem_start, pmem_len, DRV_NAME)) { |
| netdev_err(dev, "request_mem_region failed!"); |
| goto err_rel_rtllib; |
| } |
| |
| ioaddr = (unsigned long)ioremap(pmem_start, pmem_len); |
| if (ioaddr == (unsigned long)NULL) { |
| netdev_err(dev, "ioremap failed!"); |
| goto err_rel_mem; |
| } |
| |
| dev->mem_start = ioaddr; |
| dev->mem_end = ioaddr + pci_resource_len(pdev, 0); |
| |
| if (!rtl92e_check_adapter(pdev, dev)) |
| goto err_unmap; |
| |
| dev->irq = pdev->irq; |
| priv->irq = 0; |
| |
| dev->netdev_ops = &rtl8192_netdev_ops; |
| |
| dev->wireless_handlers = &r8192_wx_handlers_def; |
| dev->ethtool_ops = &rtl819x_ethtool_ops; |
| |
| dev->type = ARPHRD_ETHER; |
| dev->watchdog_timeo = HZ * 3; |
| |
| if (dev_alloc_name(dev, ifname) < 0) |
| dev_alloc_name(dev, ifname); |
| |
| if (_rtl92e_init(dev) != 0) { |
| netdev_warn(dev, "Initialization failed"); |
| goto err_free_irq; |
| } |
| |
| netif_carrier_off(dev); |
| netif_stop_queue(dev); |
| |
| if (register_netdev(dev)) |
| goto err_free_irq; |
| |
| if (priv->polling_timer_on == 0) |
| rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer); |
| |
| return 0; |
| |
| err_free_irq: |
| free_irq(dev->irq, dev); |
| priv->irq = 0; |
| err_unmap: |
| iounmap((void __iomem *)ioaddr); |
| err_rel_mem: |
| release_mem_region(pmem_start, pmem_len); |
| err_rel_rtllib: |
| free_rtllib(dev); |
| err_pci_disable: |
| pci_disable_device(pdev); |
| return err; |
| } |
| |
| static void _rtl92e_pci_disconnect(struct pci_dev *pdev) |
| { |
| struct net_device *dev = pci_get_drvdata(pdev); |
| struct r8192_priv *priv; |
| u32 i; |
| |
| if (dev) { |
| unregister_netdev(dev); |
| |
| priv = rtllib_priv(dev); |
| |
| del_timer_sync(&priv->gpio_polling_timer); |
| cancel_delayed_work_sync(&priv->gpio_change_rf_wq); |
| priv->polling_timer_on = 0; |
| _rtl92e_down(dev, true); |
| rtl92e_dm_deinit(dev); |
| vfree(priv->fw_info); |
| priv->fw_info = NULL; |
| _rtl92e_free_rx_ring(dev); |
| for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) |
| _rtl92e_free_tx_ring(dev, i); |
| |
| if (priv->irq) { |
| dev_info(&pdev->dev, "Freeing irq %d\n", dev->irq); |
| free_irq(dev->irq, dev); |
| priv->irq = 0; |
| } |
| |
| if (dev->mem_start != 0) { |
| iounmap((void __iomem *)dev->mem_start); |
| release_mem_region(pci_resource_start(pdev, 1), |
| pci_resource_len(pdev, 1)); |
| } |
| |
| free_rtllib(dev); |
| } |
| |
| pci_disable_device(pdev); |
| } |
| |
| bool rtl92e_enable_nic(struct net_device *dev) |
| { |
| bool init_status = true; |
| struct r8192_priv *priv = rtllib_priv(dev); |
| struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) |
| (&priv->rtllib->pwr_save_ctrl); |
| |
| if (!priv->up) { |
| netdev_warn(dev, "%s(): Driver is already down!\n", __func__); |
| return false; |
| } |
| |
| init_status = rtl92e_start_adapter(dev); |
| if (!init_status) { |
| netdev_warn(dev, "%s(): Initialization failed!\n", __func__); |
| return false; |
| } |
| RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC); |
| |
| rtl92e_irq_enable(dev); |
| return init_status; |
| } |
| |
| module_pci_driver(rtl8192_pci_driver); |
| |
| void rtl92e_check_rfctrl_gpio_timer(struct timer_list *t) |
| { |
| struct r8192_priv *priv = from_timer(priv, t, gpio_polling_timer); |
| |
| priv->polling_timer_on = 1; |
| |
| schedule_delayed_work(&priv->gpio_change_rf_wq, 0); |
| |
| mod_timer(&priv->gpio_polling_timer, jiffies + |
| msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME)); |
| } |
| |
| /*************************************************************************** |
| * ------------------- module init / exit stubs ---------------- |
| ***************************************************************************/ |
| MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards"); |
| MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); |
| MODULE_VERSION(DRV_VERSION); |
| MODULE_LICENSE("GPL"); |
| MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW); |
| MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW); |
| MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW); |
| |
| module_param(ifname, charp, 0644); |
| module_param(hwwep, int, 0644); |
| |
| MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default"); |
| MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support(default use hw. set 0 to use software security)"); |