Commit | Line | Data |
---|---|---|
2be7d22f | 1 | /* |
640751ac | 2 | * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. |
2be7d22f VK |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
2be7d22f | 17 | #include <linux/etherdevice.h> |
2be7d22f | 18 | #include "wil6210.h" |
e0106ada | 19 | #include "txrx.h" |
2be7d22f VK |
20 | |
21 | static int wil_open(struct net_device *ndev) | |
22 | { | |
23 | struct wil6210_priv *wil = ndev_to_wil(ndev); | |
24 | ||
9cf10d62 VK |
25 | wil_dbg_misc(wil, "%s()\n", __func__); |
26 | ||
bfc2dc7a VK |
27 | if (debug_fw) { |
28 | wil_err(wil, "%s() while in debug_fw mode\n", __func__); | |
29 | return -EINVAL; | |
30 | } | |
31 | ||
2be7d22f VK |
32 | return wil_up(wil); |
33 | } | |
34 | ||
35 | static int wil_stop(struct net_device *ndev) | |
36 | { | |
37 | struct wil6210_priv *wil = ndev_to_wil(ndev); | |
38 | ||
9cf10d62 VK |
39 | wil_dbg_misc(wil, "%s()\n", __func__); |
40 | ||
2be7d22f VK |
41 | return wil_down(wil); |
42 | } | |
43 | ||
d87bac1b VK |
44 | static int wil_change_mtu(struct net_device *ndev, int new_mtu) |
45 | { | |
46 | struct wil6210_priv *wil = ndev_to_wil(ndev); | |
47 | ||
9a06bec9 | 48 | if (new_mtu < 68 || new_mtu > mtu_max) { |
e0106ada | 49 | wil_err(wil, "invalid MTU %d\n", new_mtu); |
d87bac1b | 50 | return -EINVAL; |
e0106ada | 51 | } |
d87bac1b VK |
52 | |
53 | wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu); | |
54 | ndev->mtu = new_mtu; | |
55 | ||
56 | return 0; | |
57 | } | |
58 | ||
dba4b74d VK |
59 | static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) |
60 | { | |
61 | struct wil6210_priv *wil = ndev_to_wil(ndev); | |
62 | ||
6777e71c | 63 | return wil_ioctl(wil, ifr->ifr_data, cmd); |
dba4b74d VK |
64 | } |
65 | ||
2be7d22f VK |
66 | static const struct net_device_ops wil_netdev_ops = { |
67 | .ndo_open = wil_open, | |
68 | .ndo_stop = wil_stop, | |
69 | .ndo_start_xmit = wil_start_xmit, | |
afda8bb5 VK |
70 | .ndo_set_mac_address = eth_mac_addr, |
71 | .ndo_validate_addr = eth_validate_addr, | |
d87bac1b | 72 | .ndo_change_mtu = wil_change_mtu, |
dba4b74d | 73 | .ndo_do_ioctl = wil_do_ioctl, |
2be7d22f VK |
74 | }; |
75 | ||
e0287c4a VK |
76 | static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) |
77 | { | |
78 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, | |
79 | napi_rx); | |
80 | int quota = budget; | |
81 | int done; | |
82 | ||
83 | wil_rx_handle(wil, "a); | |
84 | done = budget - quota; | |
85 | ||
7308a20e | 86 | if (done < budget) { |
e0287c4a VK |
87 | napi_complete(napi); |
88 | wil6210_unmask_irq_rx(wil); | |
89 | wil_dbg_txrx(wil, "NAPI RX complete\n"); | |
90 | } | |
91 | ||
92 | wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done); | |
93 | ||
94 | return done; | |
95 | } | |
96 | ||
97 | static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) | |
98 | { | |
99 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, | |
100 | napi_tx); | |
101 | int tx_done = 0; | |
102 | uint i; | |
103 | ||
104 | /* always process ALL Tx complete, regardless budget - it is fast */ | |
105 | for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { | |
106 | struct vring *vring = &wil->vring_tx[i]; | |
640751ac | 107 | struct vring_tx_data *txdata = &wil->vring_tx_data[i]; |
e0287c4a | 108 | |
640751ac | 109 | if (!vring->va || !txdata->enabled) |
e0287c4a VK |
110 | continue; |
111 | ||
112 | tx_done += wil_tx_complete(wil, i); | |
113 | } | |
114 | ||
7308a20e | 115 | if (tx_done < budget) { |
e0287c4a VK |
116 | napi_complete(napi); |
117 | wil6210_unmask_irq_tx(wil); | |
118 | wil_dbg_txrx(wil, "NAPI TX complete\n"); | |
119 | } | |
120 | ||
121 | wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done); | |
122 | ||
123 | return min(tx_done, budget); | |
124 | } | |
125 | ||
f1871cd9 VS |
126 | static void wil_dev_setup(struct net_device *dev) |
127 | { | |
128 | ether_setup(dev); | |
129 | dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; | |
130 | } | |
131 | ||
3e2d8e1b | 132 | void *wil_if_alloc(struct device *dev) |
2be7d22f VK |
133 | { |
134 | struct net_device *ndev; | |
135 | struct wireless_dev *wdev; | |
136 | struct wil6210_priv *wil; | |
137 | struct ieee80211_channel *ch; | |
138 | int rc = 0; | |
139 | ||
140 | wdev = wil_cfg80211_init(dev); | |
141 | if (IS_ERR(wdev)) { | |
142 | dev_err(dev, "wil_cfg80211_init failed\n"); | |
143 | return wdev; | |
144 | } | |
145 | ||
146 | wil = wdev_to_wil(wdev); | |
2be7d22f | 147 | wil->wdev = wdev; |
4332cac1 | 148 | wil->radio_wdev = wdev; |
2be7d22f | 149 | |
9cf10d62 VK |
150 | wil_dbg_misc(wil, "%s()\n", __func__); |
151 | ||
2be7d22f VK |
152 | rc = wil_priv_init(wil); |
153 | if (rc) { | |
154 | dev_err(dev, "wil_priv_init failed\n"); | |
155 | goto out_wdev; | |
156 | } | |
157 | ||
158 | wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */ | |
159 | /* default monitor channel */ | |
160 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; | |
161 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); | |
162 | ||
f1871cd9 | 163 | ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup); |
2be7d22f VK |
164 | if (!ndev) { |
165 | dev_err(dev, "alloc_netdev_mqs failed\n"); | |
166 | rc = -ENOMEM; | |
167 | goto out_priv; | |
168 | } | |
169 | ||
170 | ndev->netdev_ops = &wil_netdev_ops; | |
b6b1b0ec | 171 | wil_set_ethtoolops(ndev); |
2be7d22f | 172 | ndev->ieee80211_ptr = wdev; |
c236658f | 173 | ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | |
3d4bde15 | 174 | NETIF_F_SG | NETIF_F_GRO | |
0553640d VS |
175 | NETIF_F_TSO | NETIF_F_TSO6 | |
176 | NETIF_F_RXHASH; | |
3d4bde15 | 177 | |
c236658f | 178 | ndev->features |= ndev->hw_features; |
2be7d22f VK |
179 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); |
180 | wdev->netdev = ndev; | |
181 | ||
e0287c4a VK |
182 | netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx, |
183 | WIL6210_NAPI_BUDGET); | |
d64b5e85 | 184 | netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, |
e0287c4a VK |
185 | WIL6210_NAPI_BUDGET); |
186 | ||
c5e96c91 | 187 | netif_tx_stop_all_queues(ndev); |
2be7d22f VK |
188 | |
189 | return wil; | |
190 | ||
191 | out_priv: | |
192 | wil_priv_deinit(wil); | |
193 | ||
194 | out_wdev: | |
195 | wil_wdev_free(wil); | |
196 | ||
197 | return ERR_PTR(rc); | |
198 | } | |
199 | ||
200 | void wil_if_free(struct wil6210_priv *wil) | |
201 | { | |
202 | struct net_device *ndev = wil_to_ndev(wil); | |
8fcfdeac | 203 | |
9cf10d62 VK |
204 | wil_dbg_misc(wil, "%s()\n", __func__); |
205 | ||
2be7d22f VK |
206 | if (!ndev) |
207 | return; | |
208 | ||
2be7d22f | 209 | wil_priv_deinit(wil); |
8fcfdeac VK |
210 | |
211 | wil_to_ndev(wil) = NULL; | |
212 | free_netdev(ndev); | |
213 | ||
2be7d22f VK |
214 | wil_wdev_free(wil); |
215 | } | |
216 | ||
217 | int wil_if_add(struct wil6210_priv *wil) | |
218 | { | |
219 | struct net_device *ndev = wil_to_ndev(wil); | |
220 | int rc; | |
221 | ||
9cf10d62 VK |
222 | wil_dbg_misc(wil, "%s()\n", __func__); |
223 | ||
2be7d22f VK |
224 | rc = register_netdev(ndev); |
225 | if (rc < 0) { | |
226 | dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); | |
227 | return rc; | |
228 | } | |
229 | ||
2be7d22f VK |
230 | return 0; |
231 | } | |
232 | ||
233 | void wil_if_remove(struct wil6210_priv *wil) | |
234 | { | |
235 | struct net_device *ndev = wil_to_ndev(wil); | |
236 | ||
9cf10d62 VK |
237 | wil_dbg_misc(wil, "%s()\n", __func__); |
238 | ||
2be7d22f VK |
239 | unregister_netdev(ndev); |
240 | } |