Linux-libre 3.16.85-gnu
[librecmc/linux-libre.git] / drivers / net / wireless / ath / wil6210 / netdev.c
1 /*
2  * Copyright (c) 2012 Qualcomm Atheros, Inc.
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
17 #include <linux/etherdevice.h>
18
19 #include "wil6210.h"
20
21 static int wil_open(struct net_device *ndev)
22 {
23         struct wil6210_priv *wil = ndev_to_wil(ndev);
24
25         return wil_up(wil);
26 }
27
28 static int wil_stop(struct net_device *ndev)
29 {
30         struct wil6210_priv *wil = ndev_to_wil(ndev);
31
32         return wil_down(wil);
33 }
34
35 static int wil_change_mtu(struct net_device *ndev, int new_mtu)
36 {
37         struct wil6210_priv *wil = ndev_to_wil(ndev);
38
39         if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG)
40                 return -EINVAL;
41
42         wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
43         ndev->mtu = new_mtu;
44
45         return 0;
46 }
47
48 static const struct net_device_ops wil_netdev_ops = {
49         .ndo_open               = wil_open,
50         .ndo_stop               = wil_stop,
51         .ndo_start_xmit         = wil_start_xmit,
52         .ndo_set_mac_address    = eth_mac_addr,
53         .ndo_validate_addr      = eth_validate_addr,
54         .ndo_change_mtu         = wil_change_mtu,
55 };
56
57 static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
58 {
59         struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
60                                                 napi_rx);
61         int quota = budget;
62         int done;
63
64         wil_rx_handle(wil, &quota);
65         done = budget - quota;
66
67         if (done <= 1) { /* burst ends - only one packet processed */
68                 napi_complete(napi);
69                 wil6210_unmask_irq_rx(wil);
70                 wil_dbg_txrx(wil, "NAPI RX complete\n");
71         }
72
73         wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
74
75         return done;
76 }
77
78 static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
79 {
80         struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
81                                                 napi_tx);
82         int tx_done = 0;
83         uint i;
84
85         /* always process ALL Tx complete, regardless budget - it is fast */
86         for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
87                 struct vring *vring = &wil->vring_tx[i];
88
89                 if (!vring->va)
90                         continue;
91
92                 tx_done += wil_tx_complete(wil, i);
93         }
94
95         if (tx_done <= 1) { /* burst ends - only one packet processed */
96                 napi_complete(napi);
97                 wil6210_unmask_irq_tx(wil);
98                 wil_dbg_txrx(wil, "NAPI TX complete\n");
99         }
100
101         wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
102
103         return min(tx_done, budget);
104 }
105
106 void *wil_if_alloc(struct device *dev, void __iomem *csr)
107 {
108         struct net_device *ndev;
109         struct wireless_dev *wdev;
110         struct wil6210_priv *wil;
111         struct ieee80211_channel *ch;
112         int rc = 0;
113
114         wdev = wil_cfg80211_init(dev);
115         if (IS_ERR(wdev)) {
116                 dev_err(dev, "wil_cfg80211_init failed\n");
117                 return wdev;
118         }
119
120         wil = wdev_to_wil(wdev);
121         wil->csr = csr;
122         wil->wdev = wdev;
123
124         rc = wil_priv_init(wil);
125         if (rc) {
126                 dev_err(dev, "wil_priv_init failed\n");
127                 goto out_wdev;
128         }
129
130         wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
131         /* default monitor channel */
132         ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
133         cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
134
135         ndev = alloc_netdev(0, "wlan%d", ether_setup);
136         if (!ndev) {
137                 dev_err(dev, "alloc_netdev_mqs failed\n");
138                 rc = -ENOMEM;
139                 goto out_priv;
140         }
141
142         ndev->netdev_ops = &wil_netdev_ops;
143         ndev->ieee80211_ptr = wdev;
144         ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
145                             NETIF_F_SG | NETIF_F_GRO;
146         ndev->features |= ndev->hw_features;
147         SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
148         wdev->netdev = ndev;
149
150         netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
151                        WIL6210_NAPI_BUDGET);
152         netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
153                        WIL6210_NAPI_BUDGET);
154
155         wil_link_off(wil);
156
157         return wil;
158
159  out_priv:
160         wil_priv_deinit(wil);
161
162  out_wdev:
163         wil_wdev_free(wil);
164
165         return ERR_PTR(rc);
166 }
167
168 void wil_if_free(struct wil6210_priv *wil)
169 {
170         struct net_device *ndev = wil_to_ndev(wil);
171         if (!ndev)
172                 return;
173
174         free_netdev(ndev);
175         wil_priv_deinit(wil);
176         wil_wdev_free(wil);
177 }
178
179 int wil_if_add(struct wil6210_priv *wil)
180 {
181         struct net_device *ndev = wil_to_ndev(wil);
182         int rc;
183
184         rc = register_netdev(ndev);
185         if (rc < 0) {
186                 dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
187                 return rc;
188         }
189
190         wil_link_off(wil);
191
192         return 0;
193 }
194
195 void wil_if_remove(struct wil6210_priv *wil)
196 {
197         struct net_device *ndev = wil_to_ndev(wil);
198
199         unregister_netdev(ndev);
200 }