wlp: start/stop radio on network interface up/down
[safe/jmp/linux-2.6] / drivers / uwb / i1480 / i1480u-wlp / netdev.c
1 /*
2  * WUSB Wire Adapter: WLP interface
3  * Driver for the Linux Network stack.
4  *
5  * Copyright (C) 2005-2006 Intel Corporation
6  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@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  * FIXME: docs
24  *
25  * Implementation of the netdevice linkage (except tx and rx related stuff).
26  *
27  * ROADMAP:
28  *
29  *   ENTRY POINTS (Net device):
30  *
31  *     i1480u_open(): Called when we ifconfig up the interface;
32  *                    associates to a UWB host controller, reserves
33  *                    bandwidth (MAS), sets up RX USB URB and starts
34  *                    the queue.
35  *
36  *     i1480u_stop(): Called when we ifconfig down a interface;
37  *                    reverses _open().
38  *
39  *     i1480u_set_config():
40  */
41
42 #include <linux/if_arp.h>
43 #include <linux/etherdevice.h>
44 #include <linux/uwb/debug.h>
45 #include "i1480u-wlp.h"
46
47 struct i1480u_cmd_set_ip_mas {
48         struct uwb_rccb     rccb;
49         struct uwb_dev_addr addr;
50         u8                  stream;
51         u8                  owner;
52         u8                  type;       /* enum uwb_drp_type */
53         u8                  baMAS[32];
54 } __attribute__((packed));
55
56
57 static
58 int i1480u_set_ip_mas(
59         struct uwb_rc *rc,
60         const struct uwb_dev_addr *dstaddr,
61         u8 stream, u8 owner, u8 type, unsigned long *mas)
62 {
63
64         int result;
65         struct i1480u_cmd_set_ip_mas *cmd;
66         struct uwb_rc_evt_confirm reply;
67
68         result = -ENOMEM;
69         cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
70         if (cmd == NULL)
71                 goto error_kzalloc;
72         cmd->rccb.bCommandType = 0xfd;
73         cmd->rccb.wCommand = cpu_to_le16(0x000e);
74         cmd->addr = *dstaddr;
75         cmd->stream = stream;
76         cmd->owner = owner;
77         cmd->type = type;
78         if (mas == NULL)
79                 memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS));
80         else
81                 memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS));
82         reply.rceb.bEventType = 0xfd;
83         reply.rceb.wEvent = cpu_to_le16(0x000e);
84         result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd),
85                             &reply.rceb, sizeof(reply));
86         if (result < 0)
87                 goto error_cmd;
88         if (reply.bResultCode != UWB_RC_RES_FAIL) {
89                 dev_err(&rc->uwb_dev.dev,
90                         "SET-IP-MAS: command execution failed: %d\n",
91                         reply.bResultCode);
92                 result = -EIO;
93         }
94 error_cmd:
95         kfree(cmd);
96 error_kzalloc:
97         return result;
98 }
99
100 /*
101  * Inform a WLP interface of a MAS reservation
102  *
103  * @rc is assumed refcnted.
104  */
105 /* FIXME: detect if remote device is WLP capable? */
106 static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc,
107                               u8 stream, u8 owner, u8 type, unsigned long *mas)
108 {
109         int result = 0;
110         struct device *dev = &rc->uwb_dev.dev;
111
112         result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner,
113                                    type, mas);
114         if (result < 0) {
115                 char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE];
116                 uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf),
117                                    &rc->uwb_dev.dev_addr);
118                 uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf),
119                                    &uwb_dev->dev_addr);
120                 dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n",
121                         rcaddrbuf, devaddrbuf, result);
122         }
123         return result;
124 }
125
126 /**
127  * Called by bandwidth allocator when change occurs in reservation.
128  *
129  * @rsv:     The reservation that is being established, modified, or
130  *           terminated.
131  *
132  * When a reservation is established, modified, or terminated the upper layer
133  * (WLP here) needs set/update the currently available Media Access Slots
134  * that can be use for IP traffic.
135  *
136  * Our action taken during failure depends on how the reservation is being
137  * changed:
138  * - if reservation is being established we do nothing if we cannot set the
139  *   new MAS to be used
140  * - if reservation is being terminated we revert back to PCA whether the
141  *   SET IP MAS command succeeds or not.
142  */
143 void i1480u_bw_alloc_cb(struct uwb_rsv *rsv)
144 {
145         int result = 0;
146         struct i1480u *i1480u = rsv->pal_priv;
147         struct device *dev = &i1480u->usb_iface->dev;
148         struct uwb_dev *target_dev = rsv->target.dev;
149         struct uwb_rc *rc = i1480u->wlp.rc;
150         u8 stream = rsv->stream;
151         int type = rsv->type;
152         int is_owner = rsv->owner == &rc->uwb_dev;
153         unsigned long *bmp = rsv->mas.bm;
154
155         dev_err(dev, "WLP callback called - sending set ip mas\n");
156         /*user cannot change options while setting configuration*/
157         mutex_lock(&i1480u->options.mutex);
158         switch (rsv->state) {
159         case UWB_RSV_STATE_T_ACCEPTED:
160         case UWB_RSV_STATE_O_ESTABLISHED:
161                 result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
162                                         type, bmp);
163                 if (result < 0) {
164                         dev_err(dev, "MAS reservation failed: %d\n", result);
165                         goto out;
166                 }
167                 if (is_owner) {
168                         wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
169                                                         WLP_DRP | stream);
170                         wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0);
171                 }
172                 break;
173         case UWB_RSV_STATE_NONE:
174                 /* revert back to PCA */
175                 result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
176                                             type, bmp);
177                 if (result < 0)
178                         dev_err(dev, "MAS reservation failed: %d\n", result);
179                 /* Revert to PCA even though SET IP MAS failed. */
180                 wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
181                                                 i1480u->options.pca_base_priority);
182                 wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1);
183                 break;
184         default:
185                 dev_err(dev, "unexpected WLP reservation state: %s (%d).\n",
186                         uwb_rsv_state_str(rsv->state), rsv->state);
187                 break;
188         }
189 out:
190         mutex_unlock(&i1480u->options.mutex);
191         return;
192 }
193
194 /**
195  *
196  * Called on 'ifconfig up'
197  */
198 int i1480u_open(struct net_device *net_dev)
199 {
200         int result;
201         struct i1480u *i1480u = netdev_priv(net_dev);
202         struct wlp *wlp = &i1480u->wlp;
203         struct uwb_rc *rc;
204         struct device *dev = &i1480u->usb_iface->dev;
205
206         rc = wlp->rc;
207         result = i1480u_rx_setup(i1480u);               /* Alloc RX stuff */
208         if (result < 0)
209                 goto error_rx_setup;
210
211         result = uwb_radio_start(&wlp->pal);
212         if (result < 0)
213                 goto error_radio_start;
214
215         netif_wake_queue(net_dev);
216 #ifdef i1480u_FLOW_CONTROL
217         result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);;
218         if (result < 0) {
219                 dev_err(dev, "Can't submit notification URB: %d\n", result);
220                 goto error_notif_urb_submit;
221         }
222 #endif
223         /* Interface is up with an address, now we can create WSS */
224         result = wlp_wss_setup(net_dev, &wlp->wss);
225         if (result < 0) {
226                 dev_err(dev, "Can't create WSS: %d. \n", result);
227                 goto error_wss_setup;
228         }
229         return 0;
230 error_wss_setup:
231 #ifdef i1480u_FLOW_CONTROL
232         usb_kill_urb(i1480u->notif_urb);
233 error_notif_urb_submit:
234 #endif
235         uwb_radio_stop(&wlp->pal);
236 error_radio_start:
237         netif_stop_queue(net_dev);
238         i1480u_rx_release(i1480u);
239 error_rx_setup:
240         return result;
241 }
242
243
244 /**
245  * Called on 'ifconfig down'
246  */
247 int i1480u_stop(struct net_device *net_dev)
248 {
249         struct i1480u *i1480u = netdev_priv(net_dev);
250         struct wlp *wlp = &i1480u->wlp;
251
252         BUG_ON(wlp->rc == NULL);
253         wlp_wss_remove(&wlp->wss);
254         netif_carrier_off(net_dev);
255 #ifdef i1480u_FLOW_CONTROL
256         usb_kill_urb(i1480u->notif_urb);
257 #endif
258         netif_stop_queue(net_dev);
259         uwb_radio_stop(&wlp->pal);
260         i1480u_rx_release(i1480u);
261         i1480u_tx_release(i1480u);
262         return 0;
263 }
264
265
266 /** Report statistics */
267 struct net_device_stats *i1480u_get_stats(struct net_device *net_dev)
268 {
269         struct i1480u *i1480u = netdev_priv(net_dev);
270         return &i1480u->stats;
271 }
272
273
274 /**
275  *
276  * Change the interface config--we probably don't have to do anything.
277  */
278 int i1480u_set_config(struct net_device *net_dev, struct ifmap *map)
279 {
280         int result;
281         struct i1480u *i1480u = netdev_priv(net_dev);
282         BUG_ON(i1480u->wlp.rc == NULL);
283         result = 0;
284         return result;
285 }
286
287 /**
288  * Change the MTU of the interface
289  */
290 int i1480u_change_mtu(struct net_device *net_dev, int mtu)
291 {
292         static union {
293                 struct wlp_tx_hdr tx;
294                 struct wlp_rx_hdr rx;
295         } i1480u_all_hdrs;
296
297         if (mtu < ETH_HLEN)     /* We encap eth frames */
298                 return -ERANGE;
299         if (mtu > 4000 - sizeof(i1480u_all_hdrs))
300                 return -ERANGE;
301         net_dev->mtu = mtu;
302         return 0;
303 }
304
305 /**
306  * Stop the network queue
307  *
308  * Enable WLP substack to stop network queue. We also set the flow control
309  * threshold at this time to prevent the flow control from restarting the
310  * queue.
311  *
312  * we are loosing the current threshold value here ... FIXME?
313  */
314 void i1480u_stop_queue(struct wlp *wlp)
315 {
316         struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
317         struct net_device *net_dev = i1480u->net_dev;
318         i1480u->tx_inflight.threshold = 0;
319         netif_stop_queue(net_dev);
320 }
321
322 /**
323  * Start the network queue
324  *
325  * Enable WLP substack to start network queue. Also re-enable the flow
326  * control to manage the queue again.
327  *
328  * We re-enable the flow control by storing the default threshold in the
329  * flow control threshold. This means that if the user modified the
330  * threshold before the queue was stopped and restarted that information
331  * will be lost. FIXME?
332  */
333 void i1480u_start_queue(struct wlp *wlp)
334 {
335         struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
336         struct net_device *net_dev = i1480u->net_dev;
337         i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
338         netif_start_queue(net_dev);
339 }