ia64/linux-2.6.18-xen.hg

view drivers/xen/netback/interface.c @ 820:8b86d11a6eb3

netback: parent sysfs device should be set before registering.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 17 14:21:51 2009 +0000 (2009-03-17)
parents 3aa9b8a7876b
children
line source
1 /******************************************************************************
2 * arch/xen/drivers/netif/backend/interface.c
3 *
4 * Network-device interface management.
5 *
6 * Copyright (c) 2004-2005, Keir Fraser
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 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
33 #include "common.h"
34 #include <linux/ethtool.h>
35 #include <linux/rtnetlink.h>
37 /*
38 * Module parameter 'queue_length':
39 *
40 * Enables queuing in the network stack when a client has run out of receive
41 * descriptors. Although this feature can improve receive bandwidth by avoiding
42 * packet loss, it can also result in packets sitting in the 'tx_queue' for
43 * unbounded time. This is bad if those packets hold onto foreign resources.
44 * For example, consider a packet that holds onto resources belonging to the
45 * guest for which it is queued (e.g., packet received on vif1.0, destined for
46 * vif1.1 which is not activated in the guest): in this situation the guest
47 * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
48 * run a timer (tx_queue_timeout) to drain the queue when the interface is
49 * blocked.
50 */
51 static unsigned long netbk_queue_length = 32;
52 module_param_named(queue_length, netbk_queue_length, ulong, 0644);
54 static void __netif_up(netif_t *netif)
55 {
56 enable_irq(netif->irq);
57 netif_schedule_work(netif);
58 }
60 static void __netif_down(netif_t *netif)
61 {
62 disable_irq(netif->irq);
63 netif_deschedule_work(netif);
64 }
66 static int net_open(struct net_device *dev)
67 {
68 netif_t *netif = netdev_priv(dev);
69 if (netback_carrier_ok(netif)) {
70 __netif_up(netif);
71 netif_start_queue(dev);
72 }
73 return 0;
74 }
76 static int net_close(struct net_device *dev)
77 {
78 netif_t *netif = netdev_priv(dev);
79 if (netback_carrier_ok(netif))
80 __netif_down(netif);
81 netif_stop_queue(dev);
82 return 0;
83 }
85 static int netbk_change_mtu(struct net_device *dev, int mtu)
86 {
87 int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
89 if (mtu > max)
90 return -EINVAL;
91 dev->mtu = mtu;
92 return 0;
93 }
95 static int netbk_set_sg(struct net_device *dev, u32 data)
96 {
97 if (data) {
98 netif_t *netif = netdev_priv(dev);
100 if (!(netif->features & NETIF_F_SG))
101 return -ENOSYS;
102 }
104 return ethtool_op_set_sg(dev, data);
105 }
107 static int netbk_set_tso(struct net_device *dev, u32 data)
108 {
109 if (data) {
110 netif_t *netif = netdev_priv(dev);
112 if (!(netif->features & NETIF_F_TSO))
113 return -ENOSYS;
114 }
116 return ethtool_op_set_tso(dev, data);
117 }
119 static void netbk_get_drvinfo(struct net_device *dev,
120 struct ethtool_drvinfo *info)
121 {
122 strcpy(info->driver, "netbk");
123 strcpy(info->bus_info, dev->class_dev.dev->bus_id);
124 }
126 static const struct netif_stat {
127 char name[ETH_GSTRING_LEN];
128 u16 offset;
129 } netbk_stats[] = {
130 { "copied_skbs", offsetof(netif_t, nr_copied_skbs) },
131 };
133 static int netbk_get_stats_count(struct net_device *dev)
134 {
135 return ARRAY_SIZE(netbk_stats);
136 }
138 static void netbk_get_ethtool_stats(struct net_device *dev,
139 struct ethtool_stats *stats, u64 * data)
140 {
141 void *netif = netdev_priv(dev);
142 int i;
144 for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
145 data[i] = *(int *)(netif + netbk_stats[i].offset);
146 }
148 static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
149 {
150 int i;
152 switch (stringset) {
153 case ETH_SS_STATS:
154 for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
155 memcpy(data + i * ETH_GSTRING_LEN,
156 netbk_stats[i].name, ETH_GSTRING_LEN);
157 break;
158 }
159 }
161 static struct ethtool_ops network_ethtool_ops =
162 {
163 .get_drvinfo = netbk_get_drvinfo,
165 .get_tx_csum = ethtool_op_get_tx_csum,
166 .set_tx_csum = ethtool_op_set_tx_csum,
167 .get_sg = ethtool_op_get_sg,
168 .set_sg = netbk_set_sg,
169 .get_tso = ethtool_op_get_tso,
170 .set_tso = netbk_set_tso,
171 .get_link = ethtool_op_get_link,
173 .get_stats_count = netbk_get_stats_count,
174 .get_ethtool_stats = netbk_get_ethtool_stats,
175 .get_strings = netbk_get_strings,
176 };
178 netif_t *netif_alloc(struct device *parent, domid_t domid, unsigned int handle)
179 {
180 int err = 0;
181 struct net_device *dev;
182 netif_t *netif;
183 char name[IFNAMSIZ] = {};
185 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
186 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
187 if (dev == NULL) {
188 DPRINTK("Could not create netif: out of memory\n");
189 return ERR_PTR(-ENOMEM);
190 }
192 SET_NETDEV_DEV(dev, parent);
194 netif = netdev_priv(dev);
195 memset(netif, 0, sizeof(*netif));
196 netif->domid = domid;
197 netif->handle = handle;
198 atomic_set(&netif->refcnt, 1);
199 init_waitqueue_head(&netif->waiting_to_free);
200 netif->dev = dev;
202 netback_carrier_off(netif);
204 netif->credit_bytes = netif->remaining_credit = ~0UL;
205 netif->credit_usec = 0UL;
206 init_timer(&netif->credit_timeout);
207 /* Initialize 'expires' now: it's used to track the credit window. */
208 netif->credit_timeout.expires = jiffies;
210 init_timer(&netif->tx_queue_timeout);
212 dev->hard_start_xmit = netif_be_start_xmit;
213 dev->get_stats = netif_be_get_stats;
214 dev->open = net_open;
215 dev->stop = net_close;
216 dev->change_mtu = netbk_change_mtu;
217 dev->features = NETIF_F_IP_CSUM;
219 SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
221 dev->tx_queue_len = netbk_queue_length;
223 /*
224 * Initialise a dummy MAC address. We choose the numerically
225 * largest non-broadcast address to prevent the address getting
226 * stolen by an Ethernet bridge for STP purposes.
227 * (FE:FF:FF:FF:FF:FF)
228 */
229 memset(dev->dev_addr, 0xFF, ETH_ALEN);
230 dev->dev_addr[0] &= ~0x01;
232 rtnl_lock();
233 err = register_netdevice(dev);
234 rtnl_unlock();
235 if (err) {
236 DPRINTK("Could not register new net device %s: err=%d\n",
237 dev->name, err);
238 free_netdev(dev);
239 return ERR_PTR(err);
240 }
242 DPRINTK("Successfully created netif\n");
243 return netif;
244 }
246 static int map_frontend_pages(
247 netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
248 {
249 struct gnttab_map_grant_ref op;
251 gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
252 GNTMAP_host_map, tx_ring_ref, netif->domid);
254 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
255 BUG();
257 if (op.status) {
258 DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
259 return op.status;
260 }
262 netif->tx_shmem_ref = tx_ring_ref;
263 netif->tx_shmem_handle = op.handle;
265 gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
266 GNTMAP_host_map, rx_ring_ref, netif->domid);
268 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
269 BUG();
271 if (op.status) {
272 struct gnttab_unmap_grant_ref unop;
274 gnttab_set_unmap_op(&unop,
275 (unsigned long)netif->tx_comms_area->addr,
276 GNTMAP_host_map, netif->tx_shmem_handle);
277 VOID(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
278 &unop, 1));
279 DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
280 return op.status;
281 }
283 netif->rx_shmem_ref = rx_ring_ref;
284 netif->rx_shmem_handle = op.handle;
286 return 0;
287 }
289 static void unmap_frontend_pages(netif_t *netif)
290 {
291 struct gnttab_unmap_grant_ref op;
293 gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
294 GNTMAP_host_map, netif->tx_shmem_handle);
296 if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
297 BUG();
299 gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
300 GNTMAP_host_map, netif->rx_shmem_handle);
302 if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
303 BUG();
304 }
306 int netif_map(netif_t *netif, unsigned long tx_ring_ref,
307 unsigned long rx_ring_ref, unsigned int evtchn)
308 {
309 int err = -ENOMEM;
310 netif_tx_sring_t *txs;
311 netif_rx_sring_t *rxs;
313 /* Already connected through? */
314 if (netif->irq)
315 return 0;
317 netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
318 if (netif->tx_comms_area == NULL)
319 return -ENOMEM;
320 netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
321 if (netif->rx_comms_area == NULL)
322 goto err_rx;
324 err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
325 if (err)
326 goto err_map;
328 err = bind_interdomain_evtchn_to_irqhandler(
329 netif->domid, evtchn, netif_be_int, 0,
330 netif->dev->name, netif);
331 if (err < 0)
332 goto err_hypervisor;
333 netif->irq = err;
334 disable_irq(netif->irq);
336 txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
337 BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
339 rxs = (netif_rx_sring_t *)
340 ((char *)netif->rx_comms_area->addr);
341 BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
343 netif->rx_req_cons_peek = 0;
345 netif_get(netif);
347 rtnl_lock();
348 netback_carrier_on(netif);
349 if (netif_running(netif->dev))
350 __netif_up(netif);
351 rtnl_unlock();
353 return 0;
354 err_hypervisor:
355 unmap_frontend_pages(netif);
356 err_map:
357 free_vm_area(netif->rx_comms_area);
358 err_rx:
359 free_vm_area(netif->tx_comms_area);
360 return err;
361 }
363 void netif_disconnect(netif_t *netif)
364 {
365 if (netback_carrier_ok(netif)) {
366 rtnl_lock();
367 netback_carrier_off(netif);
368 netif_carrier_off(netif->dev); /* discard queued packets */
369 if (netif_running(netif->dev))
370 __netif_down(netif);
371 rtnl_unlock();
372 netif_put(netif);
373 }
375 atomic_dec(&netif->refcnt);
376 wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
378 del_timer_sync(&netif->credit_timeout);
379 del_timer_sync(&netif->tx_queue_timeout);
381 if (netif->irq)
382 unbind_from_irqhandler(netif->irq, netif);
384 unregister_netdev(netif->dev);
386 if (netif->tx.sring) {
387 unmap_frontend_pages(netif);
388 free_vm_area(netif->tx_comms_area);
389 free_vm_area(netif->rx_comms_area);
390 }
392 free_netdev(netif->dev);
393 }