ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/netback/interface.c @ 6412:37030498b978

Store correct rx ring handle in netback driver.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Aug 25 14:58:20 2005 +0000 (2005-08-25)
parents 522bc50588ed
children b54144915ae6 0610add7c3fe b4b3f6be5226
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 */
9 #include "common.h"
10 #include <linux/rtnetlink.h>
12 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
13 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
14 #endif
16 #define NETIF_HASHSZ 1024
17 #define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1))
19 static netif_t *netif_hash[NETIF_HASHSZ];
21 netif_t *netif_find_by_handle(domid_t domid, unsigned int handle)
22 {
23 netif_t *netif = netif_hash[NETIF_HASH(domid, handle)];
24 while ( (netif != NULL) &&
25 ((netif->domid != domid) || (netif->handle != handle)) )
26 netif = netif->hash_next;
27 return netif;
28 }
30 static void __netif_up(netif_t *netif)
31 {
32 struct net_device *dev = netif->dev;
33 spin_lock_bh(&dev->xmit_lock);
34 netif->active = 1;
35 spin_unlock_bh(&dev->xmit_lock);
36 (void)bind_evtchn_to_irqhandler(
37 netif->evtchn, netif_be_int, 0, dev->name, netif);
38 netif_schedule_work(netif);
39 }
41 static void __netif_down(netif_t *netif)
42 {
43 struct net_device *dev = netif->dev;
44 spin_lock_bh(&dev->xmit_lock);
45 netif->active = 0;
46 spin_unlock_bh(&dev->xmit_lock);
47 unbind_evtchn_from_irqhandler(netif->evtchn, netif);
48 netif_deschedule_work(netif);
49 }
51 static int net_open(struct net_device *dev)
52 {
53 netif_t *netif = netdev_priv(dev);
54 if ( netif->status == CONNECTED )
55 __netif_up(netif);
56 netif_start_queue(dev);
57 return 0;
58 }
60 static int net_close(struct net_device *dev)
61 {
62 netif_t *netif = netdev_priv(dev);
63 netif_stop_queue(dev);
64 if ( netif->status == CONNECTED )
65 __netif_down(netif);
66 return 0;
67 }
69 static void __netif_disconnect_complete(void *arg)
70 {
71 netif_t *netif = (netif_t *)arg;
72 ctrl_msg_t cmsg;
73 netif_be_disconnect_t disc;
74 #if defined(CONFIG_XEN_NETDEV_GRANT_RX) || defined(CONFIG_XEN_NETDEV_GRANT_TX)
75 struct gnttab_unmap_grant_ref op;
76 #endif
78 /*
79 * These can't be done in netif_disconnect() because at that point there
80 * may be outstanding requests in the network stack whose asynchronous
81 * responses must still be notified to the remote driver.
82 */
84 #ifdef CONFIG_XEN_NETDEV_GRANT_TX
85 op.host_addr = netif->tx_shmem_vaddr;
86 op.handle = netif->tx_shmem_handle;
87 op.dev_bus_addr = 0;
88 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
89 #endif
91 #ifdef CONFIG_XEN_NETDEV_GRANT_RX
92 op.host_addr = netif->rx_shmem_vaddr;
93 op.handle = netif->rx_shmem_handle;
94 op.dev_bus_addr = 0;
95 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
96 #endif
99 vfree(netif->tx); /* Frees netif->rx as well. */
101 /* Construct the deferred response message. */
102 cmsg.type = CMSG_NETIF_BE;
103 cmsg.subtype = CMSG_NETIF_BE_DISCONNECT;
104 cmsg.id = netif->disconnect_rspid;
105 cmsg.length = sizeof(netif_be_disconnect_t);
106 disc.domid = netif->domid;
107 disc.netif_handle = netif->handle;
108 disc.status = NETIF_BE_STATUS_OKAY;
109 memcpy(cmsg.msg, &disc, sizeof(disc));
111 /*
112 * Make sure message is constructed /before/ status change, because
113 * after the status change the 'netif' structure could be deallocated at
114 * any time. Also make sure we send the response /after/ status change,
115 * as otherwise a subsequent CONNECT request could spuriously fail if
116 * another CPU doesn't see the status change yet.
117 */
118 mb();
119 if ( netif->status != DISCONNECTING )
120 BUG();
121 netif->status = DISCONNECTED;
122 mb();
124 /* Send the successful response. */
125 ctrl_if_send_response(&cmsg);
126 }
128 void netif_disconnect_complete(netif_t *netif)
129 {
130 INIT_WORK(&netif->work, __netif_disconnect_complete, (void *)netif);
131 schedule_work(&netif->work);
132 }
134 void netif_create(netif_be_create_t *create)
135 {
136 int err = 0;
137 domid_t domid = create->domid;
138 unsigned int handle = create->netif_handle;
139 struct net_device *dev;
140 netif_t **pnetif, *netif;
141 char name[IFNAMSIZ] = {};
143 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
144 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
145 if ( dev == NULL )
146 {
147 DPRINTK("Could not create netif: out of memory\n");
148 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
149 return;
150 }
152 netif = netdev_priv(dev);
153 memset(netif, 0, sizeof(*netif));
154 netif->domid = domid;
155 netif->handle = handle;
156 netif->status = DISCONNECTED;
157 atomic_set(&netif->refcnt, 0);
158 netif->dev = dev;
160 netif->credit_bytes = netif->remaining_credit = ~0UL;
161 netif->credit_usec = 0UL;
162 init_timer(&netif->credit_timeout);
164 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
165 while ( *pnetif != NULL )
166 {
167 if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) )
168 {
169 DPRINTK("Could not create netif: already exists\n");
170 create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
171 free_netdev(dev);
172 return;
173 }
174 pnetif = &(*pnetif)->hash_next;
175 }
177 dev->hard_start_xmit = netif_be_start_xmit;
178 dev->get_stats = netif_be_get_stats;
179 dev->open = net_open;
180 dev->stop = net_close;
181 dev->features = NETIF_F_NO_CSUM;
183 /* Disable queuing. */
184 dev->tx_queue_len = 0;
186 if ( (create->be_mac[0] == 0) && (create->be_mac[1] == 0) &&
187 (create->be_mac[2] == 0) && (create->be_mac[3] == 0) &&
188 (create->be_mac[4] == 0) && (create->be_mac[5] == 0) )
189 {
190 /*
191 * Initialise a dummy MAC address. We choose the numerically largest
192 * non-broadcast address to prevent the address getting stolen by an
193 * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
194 */
195 memset(dev->dev_addr, 0xFF, ETH_ALEN);
196 dev->dev_addr[0] &= ~0x01;
197 }
198 else
199 {
200 memcpy(dev->dev_addr, create->be_mac, ETH_ALEN);
201 }
203 memcpy(netif->fe_dev_addr, create->mac, ETH_ALEN);
205 rtnl_lock();
206 err = register_netdevice(dev);
207 rtnl_unlock();
209 if ( err != 0 )
210 {
211 DPRINTK("Could not register new net device %s: err=%d\n",
212 dev->name, err);
213 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
214 free_netdev(dev);
215 return;
216 }
218 netif->hash_next = *pnetif;
219 *pnetif = netif;
221 DPRINTK("Successfully created netif\n");
222 create->status = NETIF_BE_STATUS_OKAY;
223 }
225 void netif_destroy(netif_be_destroy_t *destroy)
226 {
227 domid_t domid = destroy->domid;
228 unsigned int handle = destroy->netif_handle;
229 netif_t **pnetif, *netif;
231 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
232 while ( (netif = *pnetif) != NULL )
233 {
234 if ( (netif->domid == domid) && (netif->handle == handle) )
235 {
236 if ( netif->status != DISCONNECTED )
237 goto still_connected;
238 goto destroy;
239 }
240 pnetif = &netif->hash_next;
241 }
243 destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
244 return;
246 still_connected:
247 destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
248 return;
250 destroy:
251 *pnetif = netif->hash_next;
252 unregister_netdev(netif->dev);
253 free_netdev(netif->dev);
254 destroy->status = NETIF_BE_STATUS_OKAY;
255 }
257 void netif_creditlimit(netif_be_creditlimit_t *creditlimit)
258 {
259 domid_t domid = creditlimit->domid;
260 unsigned int handle = creditlimit->netif_handle;
261 netif_t *netif;
263 netif = netif_find_by_handle(domid, handle);
264 if ( unlikely(netif == NULL) )
265 {
266 DPRINTK("netif_creditlimit attempted for non-existent netif"
267 " (%u,%u)\n", creditlimit->domid, creditlimit->netif_handle);
268 creditlimit->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
269 return;
270 }
272 /* Set the credit limit (reset remaining credit to new limit). */
273 netif->credit_bytes = netif->remaining_credit = creditlimit->credit_bytes;
274 netif->credit_usec = creditlimit->period_usec;
276 if ( netif->status == CONNECTED )
277 {
278 /*
279 * Schedule work so that any packets waiting under previous credit
280 * limit are dealt with (acts like a replenishment point).
281 */
282 netif->credit_timeout.expires = jiffies;
283 netif_schedule_work(netif);
284 }
286 creditlimit->status = NETIF_BE_STATUS_OKAY;
287 }
289 void netif_connect(netif_be_connect_t *connect)
290 {
291 domid_t domid = connect->domid;
292 unsigned int handle = connect->netif_handle;
293 unsigned int evtchn = connect->evtchn;
294 unsigned long tx_shmem_frame = connect->tx_shmem_frame;
295 unsigned long rx_shmem_frame = connect->rx_shmem_frame;
296 struct vm_struct *vma;
297 #if !defined(CONFIG_XEN_NETDEV_GRANT_TX)||!defined(CONFIG_XEN_NETDEV_GRANT_RX)
298 pgprot_t prot = __pgprot(_KERNPG_TABLE);
299 int error;
300 #endif
301 netif_t *netif;
303 netif = netif_find_by_handle(domid, handle);
304 if ( unlikely(netif == NULL) ) {
305 DPRINTK("netif_connect attempted for non-existent netif (%u,%u)\n",
306 connect->domid, connect->netif_handle);
307 connect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
308 return;
309 }
311 if ( netif->status != DISCONNECTED ) {
312 connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
313 return;
314 }
316 if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL ) {
317 connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
318 return;
319 }
322 #if defined(CONFIG_XEN_NETDEV_GRANT_TX)
323 {
324 struct gnttab_map_grant_ref op;
325 int tx_ref = connect->tx_shmem_ref;
327 /* Map: Use the Grant table reference */
328 op.host_addr = VMALLOC_VMADDR(vma->addr);
329 op.flags = GNTMAP_host_map;
330 op.ref = tx_ref;
331 op.dom = domid;
333 if ((HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) < 0) ||
334 (op.handle < 0)) {
335 DPRINTK(" Grant table operation failure !\n");
336 connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
337 vfree(vma->addr);
338 return;
339 }
341 netif->tx_shmem_ref = tx_ref;
342 netif->tx_shmem_handle = op.handle;
343 netif->tx_shmem_vaddr = VMALLOC_VMADDR(vma->addr);
344 }
347 #else
348 error = direct_remap_area_pages(&init_mm,
349 VMALLOC_VMADDR(vma->addr),
350 tx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
351 prot, domid);
352 if ( error != 0 )
353 {
354 if ( error == -ENOMEM )
355 connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
356 else if ( error == -EFAULT )
357 connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
358 else
359 connect->status = NETIF_BE_STATUS_ERROR;
360 vfree(vma->addr);
361 return;
362 }
363 #endif
366 #if defined(CONFIG_XEN_NETDEV_GRANT_RX)
367 {
368 struct gnttab_map_grant_ref op;
369 int rx_ref = connect->rx_shmem_ref;
372 /* Map: Use the Grant table reference */
373 op.host_addr = VMALLOC_VMADDR(vma->addr) + PAGE_SIZE;
374 op.flags = GNTMAP_host_map;
375 op.ref = rx_ref;
376 op.dom = domid;
378 if ((HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) < 0) ||
379 (op.handle < 0)) {
380 DPRINTK(" Grant table operation failure !\n");
381 connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
382 vfree(vma->addr);
383 return;
384 }
386 netif->rx_shmem_ref = rx_ref;
387 netif->rx_shmem_handle = op.handle;
388 netif->rx_shmem_vaddr = VMALLOC_VMADDR(vma->addr) + PAGE_SIZE;
389 }
390 #else
391 error = direct_remap_area_pages(&init_mm,
392 VMALLOC_VMADDR(vma->addr) + PAGE_SIZE,
393 rx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
394 prot, domid);
395 if ( error != 0 )
396 {
397 if ( error == -ENOMEM )
398 connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
399 else if ( error == -EFAULT )
400 connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
401 else
402 connect->status = NETIF_BE_STATUS_ERROR;
403 vfree(vma->addr);
404 return;
405 }
407 #endif
409 netif->evtchn = evtchn;
410 netif->tx_shmem_frame = tx_shmem_frame;
411 netif->rx_shmem_frame = rx_shmem_frame;
412 netif->tx =
413 (netif_tx_interface_t *)vma->addr;
414 netif->rx =
415 (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
416 netif->tx->resp_prod = netif->rx->resp_prod = 0;
417 netif_get(netif);
418 wmb(); /* Other CPUs see new state before interface is started. */
420 rtnl_lock();
421 netif->status = CONNECTED;
422 wmb();
423 if ( netif_running(netif->dev) )
424 __netif_up(netif);
425 rtnl_unlock();
427 connect->status = NETIF_BE_STATUS_OKAY;
428 }
430 int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
431 {
432 domid_t domid = disconnect->domid;
433 unsigned int handle = disconnect->netif_handle;
434 netif_t *netif;
436 netif = netif_find_by_handle(domid, handle);
437 if ( unlikely(netif == NULL) )
438 {
439 DPRINTK("netif_disconnect attempted for non-existent netif"
440 " (%u,%u)\n", disconnect->domid, disconnect->netif_handle);
441 disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
442 return 1; /* Caller will send response error message. */
443 }
445 if ( netif->status == CONNECTED )
446 {
447 rtnl_lock();
448 netif->status = DISCONNECTING;
449 netif->disconnect_rspid = rsp_id;
450 wmb();
451 if ( netif_running(netif->dev) )
452 __netif_down(netif);
453 rtnl_unlock();
454 netif_put(netif);
455 return 0; /* Caller should not send response message. */
456 }
458 disconnect->status = NETIF_BE_STATUS_OKAY;
459 return 1;
460 }
462 void netif_interface_init(void)
463 {
464 memset(netif_hash, 0, sizeof(netif_hash));
465 }