ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/netback/interface.c @ 6422:e24fd7012ffb

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 10:09:39 2005 +0000 (2005-08-25)
parents 2f20c2fce2c5 522bc50588ed
children 4abd299ef2f6
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 #define NETIF_HASHSZ 1024
13 #define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1))
15 static netif_t *netif_hash[NETIF_HASHSZ];
17 netif_t *netif_find_by_handle(domid_t domid, unsigned int handle)
18 {
19 netif_t *netif = netif_hash[NETIF_HASH(domid, handle)];
20 while ( (netif != NULL) &&
21 ((netif->domid != domid) || (netif->handle != handle)) )
22 netif = netif->hash_next;
23 return netif;
24 }
26 static void __netif_up(netif_t *netif)
27 {
28 struct net_device *dev = netif->dev;
29 spin_lock_bh(&dev->xmit_lock);
30 netif->active = 1;
31 spin_unlock_bh(&dev->xmit_lock);
32 (void)bind_evtchn_to_irqhandler(
33 netif->evtchn, netif_be_int, 0, dev->name, netif);
34 netif_schedule_work(netif);
35 }
37 static void __netif_down(netif_t *netif)
38 {
39 struct net_device *dev = netif->dev;
40 spin_lock_bh(&dev->xmit_lock);
41 netif->active = 0;
42 spin_unlock_bh(&dev->xmit_lock);
43 unbind_evtchn_from_irqhandler(netif->evtchn, netif);
44 netif_deschedule_work(netif);
45 }
47 static int net_open(struct net_device *dev)
48 {
49 netif_t *netif = netdev_priv(dev);
50 if ( netif->status == CONNECTED )
51 __netif_up(netif);
52 netif_start_queue(dev);
53 return 0;
54 }
56 static int net_close(struct net_device *dev)
57 {
58 netif_t *netif = netdev_priv(dev);
59 netif_stop_queue(dev);
60 if ( netif->status == CONNECTED )
61 __netif_down(netif);
62 return 0;
63 }
65 netif_t *alloc_netif(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
66 {
67 int err = 0, i;
68 struct net_device *dev;
69 netif_t **pnetif, *netif;
70 char name[IFNAMSIZ] = {};
72 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
73 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
74 if ( dev == NULL )
75 {
76 DPRINTK("Could not create netif: out of memory\n");
77 // create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
78 return NULL;
79 }
81 netif = netdev_priv(dev);
82 memset(netif, 0, sizeof(*netif));
83 netif->domid = domid;
84 netif->handle = handle;
85 netif->status = DISCONNECTED;
86 atomic_set(&netif->refcnt, 0);
87 netif->dev = dev;
89 netif->credit_bytes = netif->remaining_credit = ~0UL;
90 netif->credit_usec = 0UL;
91 init_timer(&netif->credit_timeout);
93 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
94 while ( *pnetif != NULL )
95 {
96 if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) )
97 {
98 DPRINTK("Could not create netif: already exists\n");
99 // create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
100 free_netdev(dev);
101 return NULL;
102 }
103 pnetif = &(*pnetif)->hash_next;
104 }
106 dev->hard_start_xmit = netif_be_start_xmit;
107 dev->get_stats = netif_be_get_stats;
108 dev->open = net_open;
109 dev->stop = net_close;
110 dev->features = NETIF_F_NO_CSUM;
112 /* Disable queuing. */
113 dev->tx_queue_len = 0;
115 for (i = 0; i < ETH_ALEN; i++)
116 if (be_mac[i] != 0)
117 break;
118 if (i == ETH_ALEN)
119 {
120 /*
121 * Initialise a dummy MAC address. We choose the numerically largest
122 * non-broadcast address to prevent the address getting stolen by an
123 * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
124 */
125 memset(dev->dev_addr, 0xFF, ETH_ALEN);
126 dev->dev_addr[0] &= ~0x01;
127 }
128 else
129 {
130 memcpy(dev->dev_addr, be_mac, ETH_ALEN);
131 }
133 rtnl_lock();
134 err = register_netdevice(dev);
135 rtnl_unlock();
137 if ( err != 0 )
138 {
139 DPRINTK("Could not register new net device %s: err=%d\n",
140 dev->name, err);
141 // create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
142 free_netdev(dev);
143 return NULL;
144 }
146 netif->hash_next = *pnetif;
147 *pnetif = netif;
149 DPRINTK("Successfully created netif\n");
150 // create->status = NETIF_BE_STATUS_OKAY;
151 return netif;
152 }
154 static int map_frontend_page(netif_t *netif, unsigned long localaddr,
155 unsigned long tx_ring_ref, unsigned long rx_ring_ref)
156 {
157 #if !defined(CONFIG_XEN_NETDEV_GRANT_TX)||!defined(CONFIG_XEN_NETDEV_GRANT_RX)
158 pgprot_t prot = __pgprot(_KERNPG_TABLE);
159 int err;
160 #endif
161 #if defined(CONFIG_XEN_NETDEV_GRANT_TX)
162 {
163 struct gnttab_map_grant_ref op;
165 /* Map: Use the Grant table reference */
166 op.host_addr = localaddr;
167 op.flags = GNTMAP_host_map;
168 op.ref = tx_ring_ref;
169 op.dom = netif->domid;
171 BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
172 if (op.handle < 0) {
173 DPRINTK(" Grant table operation failure !\n");
174 return op.handle;
175 }
177 netif->tx_shmem_ref = tx_ring_ref;
178 netif->tx_shmem_handle = op.handle;
179 netif->tx_shmem_vaddr = localaddr;
180 }
181 #else
182 err = direct_remap_area_pages(&init_mm, localaddr,
183 tx_ring_ref<<PAGE_SHIFT, PAGE_SIZE,
184 prot, netif->domid);
185 if (err)
186 return err;
187 #endif
189 #if defined(CONFIG_XEN_NETDEV_GRANT_RX)
190 {
191 struct gnttab_map_grant_ref op;
193 /* Map: Use the Grant table reference */
194 op.host_addr = localaddr + PAGE_SIZE;
195 op.flags = GNTMAP_host_map;
196 op.ref = rx_ring_ref;
197 op.dom = netif->domid;
199 BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
200 if (op.handle < 0) {
201 DPRINTK(" Grant table operation failure !\n");
202 return op.handle;
203 }
205 netif->rx_shmem_ref = rx_ring_ref;
206 netif->rx_shmem_handle = op.handle;
207 netif->rx_shmem_vaddr = localaddr + PAGE_SIZE;
208 }
209 #else
210 err = direct_remap_area_pages(&init_mm, localaddr + PAGE_SIZE,
211 rx_ring_ref<<PAGE_SHIFT, PAGE_SIZE,
212 prot, netif->domid);
213 if (err)
214 return err;
215 #endif
217 return 0;
218 }
220 static void unmap_frontend_page(netif_t *netif)
221 {
222 #if defined(CONFIG_XEN_NETDEV_GRANT_RX) || defined(CONFIG_XEN_NETDEV_GRANT_TX)
223 struct gnttab_unmap_grant_ref op;
224 #endif
226 #ifdef CONFIG_XEN_NETDEV_GRANT_TX
227 op.host_addr = netif->tx_shmem_vaddr;
228 op.handle = netif->tx_shmem_handle;
229 op.dev_bus_addr = 0;
230 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
231 #endif
233 #ifdef CONFIG_XEN_NETDEV_GRANT_RX
234 op.host_addr = netif->rx_shmem_vaddr;
235 op.handle = netif->rx_shmem_handle;
236 op.dev_bus_addr = 0;
237 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
238 #endif
239 }
241 int netif_map(netif_t *netif, unsigned long tx_ring_ref,
242 unsigned long rx_ring_ref, unsigned int evtchn)
243 {
244 struct vm_struct *vma;
245 evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
246 int err;
248 #if 0
249 if ( netif->status != DISCONNECTED ) {
250 connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
251 return;
252 }
253 #endif
255 if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL ) {
256 // connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
257 return -ENOMEM;
258 }
260 err = map_frontend_page(netif, (unsigned long)vma->addr, tx_ring_ref,
261 rx_ring_ref);
262 if (err) {
263 vfree(vma->addr);
264 return err;
265 }
267 op.u.bind_interdomain.dom1 = DOMID_SELF;
268 op.u.bind_interdomain.dom2 = netif->domid;
269 op.u.bind_interdomain.port1 = 0;
270 op.u.bind_interdomain.port2 = evtchn;
271 err = HYPERVISOR_event_channel_op(&op);
272 if (err) {
273 unmap_frontend_page(netif);
274 vfree(vma->addr);
275 return err;
276 }
278 netif->evtchn = op.u.bind_interdomain.port1;
279 netif->remote_evtchn = evtchn;
281 netif->tx_shmem_frame = tx_ring_ref;
282 netif->rx_shmem_frame = rx_ring_ref;
283 netif->tx =
284 (netif_tx_interface_t *)vma->addr;
285 netif->rx =
286 (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
287 netif->tx->resp_prod = netif->rx->resp_prod = 0;
288 netif_get(netif);
289 wmb(); /* Other CPUs see new state before interface is started. */
291 rtnl_lock();
292 netif->status = CONNECTED;
293 wmb();
294 if ( netif_running(netif->dev) )
295 __netif_up(netif);
296 rtnl_unlock();
298 // connect->status = NETIF_BE_STATUS_OKAY;
299 return 0;
300 }
302 static void free_netif(void *arg)
303 {
304 netif_t *netif = (netif_t *)arg;
306 /*
307 * These can't be done in netif_disconnect() because at that point there
308 * may be outstanding requests in the network stack whose asynchronous
309 * responses must still be notified to the remote driver.
310 */
312 unmap_frontend_page(netif);
313 vfree(netif->tx); /* Frees netif->rx as well. */
315 netif->status = DISCONNECTED;
316 }
318 void free_netif_callback(netif_t *netif)
319 {
320 INIT_WORK(&netif->free_work, free_netif, (void *)netif);
321 schedule_work(&netif->free_work);
322 }
324 void netif_destroy(netif_be_destroy_t *destroy)
325 {
326 domid_t domid = destroy->domid;
327 unsigned int handle = destroy->netif_handle;
328 netif_t **pnetif, *netif;
330 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
331 while ( (netif = *pnetif) != NULL )
332 {
333 if ( (netif->domid == domid) && (netif->handle == handle) )
334 {
335 if ( netif->status != DISCONNECTED )
336 goto still_connected;
337 goto destroy;
338 }
339 pnetif = &netif->hash_next;
340 }
342 destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
343 return;
345 still_connected:
346 destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
347 return;
349 destroy:
350 *pnetif = netif->hash_next;
351 unregister_netdev(netif->dev);
352 free_netdev(netif->dev);
353 destroy->status = NETIF_BE_STATUS_OKAY;
354 }
356 void netif_creditlimit(netif_be_creditlimit_t *creditlimit)
357 {
358 domid_t domid = creditlimit->domid;
359 unsigned int handle = creditlimit->netif_handle;
360 netif_t *netif;
362 netif = netif_find_by_handle(domid, handle);
363 if ( unlikely(netif == NULL) )
364 {
365 DPRINTK("netif_creditlimit attempted for non-existent netif"
366 " (%u,%u)\n", creditlimit->domid, creditlimit->netif_handle);
367 creditlimit->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
368 return;
369 }
371 /* Set the credit limit (reset remaining credit to new limit). */
372 netif->credit_bytes = netif->remaining_credit = creditlimit->credit_bytes;
373 netif->credit_usec = creditlimit->period_usec;
375 if ( netif->status == CONNECTED )
376 {
377 /*
378 * Schedule work so that any packets waiting under previous credit
379 * limit are dealt with (acts like a replenishment point).
380 */
381 netif->credit_timeout.expires = jiffies;
382 netif_schedule_work(netif);
383 }
385 creditlimit->status = NETIF_BE_STATUS_OKAY;
386 }
388 int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
389 {
390 domid_t domid = disconnect->domid;
391 unsigned int handle = disconnect->netif_handle;
392 netif_t *netif;
394 netif = netif_find_by_handle(domid, handle);
395 if ( unlikely(netif == NULL) )
396 {
397 DPRINTK("netif_disconnect attempted for non-existent netif"
398 " (%u,%u)\n", disconnect->domid, disconnect->netif_handle);
399 disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
400 return 1; /* Caller will send response error message. */
401 }
403 if ( netif->status == CONNECTED )
404 {
405 rtnl_lock();
406 netif->status = DISCONNECTING;
407 netif->disconnect_rspid = rsp_id;
408 wmb();
409 if ( netif_running(netif->dev) )
410 __netif_down(netif);
411 rtnl_unlock();
412 netif_put(netif);
413 return 0; /* Caller should not send response message. */
414 }
416 disconnect->status = NETIF_BE_STATUS_OKAY;
417 return 1;
418 }
420 void netif_interface_init(void)
421 {
422 memset(netif_hash, 0, sizeof(netif_hash));
423 }