1/* 2 * Intel Wireless Multicomm 3200 WiFi driver 3 * 4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> 5 * Samuel Ortiz <samuel.ortiz@intel.com> 6 * Zhu Yi <yi.zhu@intel.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License version 10 * 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 * 02110-1301, USA. 21 * 22 */ 23 24/* 25 * This is the netdev related hooks for iwm. 26 * 27 * Some interesting code paths: 28 * 29 * iwm_open() (Called at netdev interface bringup time) 30 * -> iwm_up() (main.c) 31 * -> iwm_bus_enable() 32 * -> if_sdio_enable() (In case of an SDIO bus) 33 * -> sdio_enable_func() 34 * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker) 35 * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker) 36 * -> iwm_load_fw() (fw.c) 37 * -> iwm_load_umac() 38 * -> iwm_load_lmac() (Calibration LMAC) 39 * -> iwm_load_lmac() (Operational LMAC) 40 * -> iwm_send_umac_config() 41 * 42 * iwm_stop() (Called at netdev interface bringdown time) 43 * -> iwm_down() 44 * -> iwm_bus_disable() 45 * -> if_sdio_disable() (In case of an SDIO bus) 46 * -> sdio_disable_func() 47 */ 48#include <linux/netdevice.h> 49#include <linux/slab.h> 50 51#include "iwm.h" 52#include "commands.h" 53#include "cfg80211.h" 54#include "debug.h" 55 56static int iwm_open(struct net_device *ndev) 57{ 58 struct iwm_priv *iwm = ndev_to_iwm(ndev); 59 60 return iwm_up(iwm); 61} 62 63static int iwm_stop(struct net_device *ndev) 64{ 65 struct iwm_priv *iwm = ndev_to_iwm(ndev); 66 67 return iwm_down(iwm); 68} 69 70/* 71 * iwm AC to queue mapping 72 * 73 * AC_VO -> queue 3 74 * AC_VI -> queue 2 75 * AC_BE -> queue 1 76 * AC_BK -> queue 0 77 */ 78static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; 79 80int iwm_tid_to_queue(u16 tid) 81{ 82 if (tid > IWM_UMAC_TID_NR - 2) 83 return -EINVAL; 84 85 return iwm_1d_to_queue[tid]; 86} 87 88static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) 89{ 90 skb->priority = cfg80211_classify8021d(skb); 91 92 return iwm_1d_to_queue[skb->priority]; 93} 94 95static const struct net_device_ops iwm_netdev_ops = { 96 .ndo_open = iwm_open, 97 .ndo_stop = iwm_stop, 98 .ndo_start_xmit = iwm_xmit_frame, 99 .ndo_select_queue = iwm_select_queue, 100}; 101 102void *iwm_if_alloc(int sizeof_bus, struct device *dev, 103 struct iwm_if_ops *if_ops) 104{ 105 struct net_device *ndev; 106 struct wireless_dev *wdev; 107 struct iwm_priv *iwm; 108 int ret = 0; 109 110 wdev = iwm_wdev_alloc(sizeof_bus, dev); 111 if (IS_ERR(wdev)) 112 return wdev; 113 114 iwm = wdev_to_iwm(wdev); 115 iwm->bus_ops = if_ops; 116 iwm->wdev = wdev; 117 118 ret = iwm_priv_init(iwm); 119 if (ret) { 120 dev_err(dev, "failed to init iwm_priv\n"); 121 goto out_wdev; 122 } 123 124 wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); 125 126 ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); 127 if (!ndev) { 128 dev_err(dev, "no memory for network device instance\n"); 129 ret = -ENOMEM; 130 goto out_priv; 131 } 132 133 ndev->netdev_ops = &iwm_netdev_ops; 134 ndev->ieee80211_ptr = wdev; 135 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); 136 wdev->netdev = ndev; 137 138 iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), 139 GFP_KERNEL); 140 if (!iwm->umac_profile) { 141 dev_err(dev, "Couldn't alloc memory for profile\n"); 142 ret = -ENOMEM; 143 goto out_profile; 144 } 145 146 iwm_init_default_profile(iwm, iwm->umac_profile); 147 148 return iwm; 149 150 out_profile: 151 free_netdev(ndev); 152 153 out_priv: 154 iwm_priv_deinit(iwm); 155 156 out_wdev: 157 iwm_wdev_free(iwm); 158 return ERR_PTR(ret); 159} 160 161void iwm_if_free(struct iwm_priv *iwm) 162{ 163 if (!iwm_to_ndev(iwm)) 164 return; 165 166 cancel_delayed_work_sync(&iwm->ct_kill_delay); 167 free_netdev(iwm_to_ndev(iwm)); 168 iwm_priv_deinit(iwm); 169 kfree(iwm->umac_profile); 170 iwm->umac_profile = NULL; 171 iwm_wdev_free(iwm); 172} 173 174int iwm_if_add(struct iwm_priv *iwm) 175{ 176 struct net_device *ndev = iwm_to_ndev(iwm); 177 int ret; 178 179 ret = register_netdev(ndev); 180 if (ret < 0) { 181 dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret); 182 return ret; 183 } 184 185 return 0; 186} 187 188void iwm_if_remove(struct iwm_priv *iwm) 189{ 190 unregister_netdev(iwm_to_ndev(iwm)); 191} 192