f509a1b8ddbdb9c3fe7357a1eef8703573a09002
[linux-2.6.git] / drivers / xen / netback / interface.c
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
9 #include "common.h"
10 #include <linux/rtnetlink.h>
11
12 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
13 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
14 #endif
15
16 #define NETIF_HASHSZ 1024
17 #define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1))
18
19 static netif_t *netif_hash[NETIF_HASHSZ];
20
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 }
29
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)request_irq(netif->irq, netif_be_int, 0, dev->name, netif);
37     netif_schedule_work(netif);
38 }
39
40 static void __netif_down(netif_t *netif)
41 {
42     struct net_device *dev = netif->dev;
43     spin_lock_bh(&dev->xmit_lock);
44     netif->active = 0;
45     spin_unlock_bh(&dev->xmit_lock);
46     free_irq(netif->irq, netif);
47     netif_deschedule_work(netif);
48 }
49
50 static int net_open(struct net_device *dev)
51 {
52     netif_t *netif = netdev_priv(dev);
53     if ( netif->status == CONNECTED )
54         __netif_up(netif);
55     netif_start_queue(dev);
56     return 0;
57 }
58
59 static int net_close(struct net_device *dev)
60 {
61     netif_t *netif = netdev_priv(dev);
62     netif_stop_queue(dev);
63     if ( netif->status == CONNECTED )
64         __netif_down(netif);
65     return 0;
66 }
67
68 static void __netif_disconnect_complete(void *arg)
69 {
70     netif_t              *netif = (netif_t *)arg;
71     ctrl_msg_t            cmsg;
72     netif_be_disconnect_t disc;
73
74     /*
75      * These can't be done in netif_disconnect() because at that point there
76      * may be outstanding requests in the network stack whose asynchronous
77      * responses must still be notified to the remote driver.
78      */
79     unbind_evtchn_from_irq(netif->evtchn);
80     vfree(netif->tx); /* Frees netif->rx as well. */
81
82     /* Construct the deferred response message. */
83     cmsg.type         = CMSG_NETIF_BE;
84     cmsg.subtype      = CMSG_NETIF_BE_DISCONNECT;
85     cmsg.id           = netif->disconnect_rspid;
86     cmsg.length       = sizeof(netif_be_disconnect_t);
87     disc.domid        = netif->domid;
88     disc.netif_handle = netif->handle;
89     disc.status       = NETIF_BE_STATUS_OKAY;
90     memcpy(cmsg.msg, &disc, sizeof(disc));
91
92     /*
93      * Make sure message is constructed /before/ status change, because
94      * after the status change the 'netif' structure could be deallocated at
95      * any time. Also make sure we send the response /after/ status change,
96      * as otherwise a subsequent CONNECT request could spuriously fail if
97      * another CPU doesn't see the status change yet.
98      */
99     mb();
100     if ( netif->status != DISCONNECTING )
101         BUG();
102     netif->status = DISCONNECTED;
103     mb();
104
105     /* Send the successful response. */
106     ctrl_if_send_response(&cmsg);
107 }
108
109 void netif_disconnect_complete(netif_t *netif)
110 {
111     INIT_WORK(&netif->work, __netif_disconnect_complete, (void *)netif);
112     schedule_work(&netif->work);
113 }
114
115 void netif_create(netif_be_create_t *create)
116 {
117     int                err = 0;
118     domid_t            domid  = create->domid;
119     unsigned int       handle = create->netif_handle;
120     struct net_device *dev;
121     netif_t          **pnetif, *netif;
122     char               name[IFNAMSIZ] = {};
123
124     snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
125     dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
126     if ( dev == NULL )
127     {
128         DPRINTK("Could not create netif: out of memory\n");
129         create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
130         return;
131     }
132
133     netif = netdev_priv(dev);
134     memset(netif, 0, sizeof(*netif));
135     netif->domid  = domid;
136     netif->handle = handle;
137     netif->status = DISCONNECTED;
138     atomic_set(&netif->refcnt, 0);
139     netif->dev = dev;
140
141     netif->credit_bytes = netif->remaining_credit = ~0UL;
142     netif->credit_usec  = 0UL;
143     init_timer(&netif->credit_timeout);
144
145     pnetif = &netif_hash[NETIF_HASH(domid, handle)];
146     while ( *pnetif != NULL )
147     {
148         if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) )
149         {
150             DPRINTK("Could not create netif: already exists\n");
151             create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
152             free_netdev(dev);
153             return;
154         }
155         pnetif = &(*pnetif)->hash_next;
156     }
157
158     dev->hard_start_xmit = netif_be_start_xmit;
159     dev->get_stats       = netif_be_get_stats;
160     dev->open            = net_open;
161     dev->stop            = net_close;
162
163     /* Disable queuing. */
164     dev->tx_queue_len = 0;
165
166     if ( (create->be_mac[0] == 0) && (create->be_mac[1] == 0) &&
167          (create->be_mac[2] == 0) && (create->be_mac[3] == 0) &&
168          (create->be_mac[4] == 0) && (create->be_mac[5] == 0) )
169     {
170         /*
171          * Initialise a dummy MAC address. We choose the numerically largest
172          * non-broadcast address to prevent the address getting stolen by an
173          * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
174          */ 
175         memset(dev->dev_addr, 0xFF, ETH_ALEN);
176         dev->dev_addr[0] &= ~0x01;
177     }
178     else
179     {
180         memcpy(dev->dev_addr, create->be_mac, ETH_ALEN);
181     }
182
183     memcpy(netif->fe_dev_addr, create->mac, ETH_ALEN);
184
185     rtnl_lock();
186     err = register_netdevice(dev);
187     rtnl_unlock();
188
189     if ( err != 0 )
190     {
191         DPRINTK("Could not register new net device %s: err=%d\n",
192                 dev->name, err);
193         create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
194         free_netdev(dev);
195         return;
196     }
197
198     netif->hash_next = *pnetif;
199     *pnetif = netif;
200
201     DPRINTK("Successfully created netif\n");
202     create->status = NETIF_BE_STATUS_OKAY;
203 }
204
205 void netif_destroy(netif_be_destroy_t *destroy)
206 {
207     domid_t       domid  = destroy->domid;
208     unsigned int  handle = destroy->netif_handle;
209     netif_t     **pnetif, *netif;
210
211     pnetif = &netif_hash[NETIF_HASH(domid, handle)];
212     while ( (netif = *pnetif) != NULL )
213     {
214         if ( (netif->domid == domid) && (netif->handle == handle) )
215         {
216             if ( netif->status != DISCONNECTED )
217                 goto still_connected;
218             goto destroy;
219         }
220         pnetif = &netif->hash_next;
221     }
222
223     destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
224     return;
225
226  still_connected:
227     destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
228     return;
229
230  destroy:
231     *pnetif = netif->hash_next;
232     unregister_netdev(netif->dev);
233     free_netdev(netif->dev);
234     destroy->status = NETIF_BE_STATUS_OKAY;
235 }
236
237 void netif_creditlimit(netif_be_creditlimit_t *creditlimit)
238 {
239     domid_t       domid  = creditlimit->domid;
240     unsigned int  handle = creditlimit->netif_handle;
241     netif_t      *netif;
242
243     netif = netif_find_by_handle(domid, handle);
244     if ( unlikely(netif == NULL) )
245     {
246         DPRINTK("netif_creditlimit attempted for non-existent netif"
247                 " (%u,%u)\n", creditlimit->domid, creditlimit->netif_handle); 
248         creditlimit->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
249         return; 
250     }
251
252     /* Set the credit limit (reset remaining credit to new limit). */
253     netif->credit_bytes = netif->remaining_credit = creditlimit->credit_bytes;
254     netif->credit_usec = creditlimit->period_usec;
255
256     if ( netif->status == CONNECTED )
257     {
258         /*
259          * Schedule work so that any packets waiting under previous credit 
260          * limit are dealt with (acts like a replenishment point).
261          */
262         netif->credit_timeout.expires = jiffies;
263         netif_schedule_work(netif);
264     }
265     
266     creditlimit->status = NETIF_BE_STATUS_OKAY;
267 }
268
269 void netif_connect(netif_be_connect_t *connect)
270 {
271     domid_t       domid  = connect->domid;
272     unsigned int  handle = connect->netif_handle;
273     unsigned int  evtchn = connect->evtchn;
274     unsigned long tx_shmem_frame = connect->tx_shmem_frame;
275     unsigned long rx_shmem_frame = connect->rx_shmem_frame;
276     struct vm_struct *vma;
277     pgprot_t      prot;
278     int           error;
279     netif_t      *netif;
280
281     netif = netif_find_by_handle(domid, handle);
282     if ( unlikely(netif == NULL) )
283     {
284         DPRINTK("netif_connect attempted for non-existent netif (%u,%u)\n", 
285                 connect->domid, connect->netif_handle); 
286         connect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
287         return;
288     }
289
290     if ( netif->status != DISCONNECTED )
291     {
292         connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
293         return;
294     }
295
296     if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL )
297     {
298         connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
299         return;
300     }
301
302     prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
303     error  = direct_remap_area_pages(&init_mm, 
304                                      VMALLOC_VMADDR(vma->addr),
305                                      tx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
306                                      prot, domid);
307     error |= direct_remap_area_pages(&init_mm, 
308                                      VMALLOC_VMADDR(vma->addr) + PAGE_SIZE,
309                                      rx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
310                                      prot, domid);
311     if ( error != 0 )
312     {
313         if ( error == -ENOMEM )
314             connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
315         else if ( error == -EFAULT )
316             connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
317         else
318             connect->status = NETIF_BE_STATUS_ERROR;
319         vfree(vma->addr);
320         return;
321     }
322
323     netif->evtchn         = evtchn;
324     netif->irq            = bind_evtchn_to_irq(evtchn);
325     netif->tx_shmem_frame = tx_shmem_frame;
326     netif->rx_shmem_frame = rx_shmem_frame;
327     netif->tx             = 
328         (netif_tx_interface_t *)vma->addr;
329     netif->rx             = 
330         (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
331     netif->tx->resp_prod = netif->rx->resp_prod = 0;
332     netif_get(netif);
333     wmb(); /* Other CPUs see new state before interface is started. */
334
335     rtnl_lock();
336     netif->status = CONNECTED;
337     wmb();
338     if ( netif_running(netif->dev) )
339         __netif_up(netif);
340     rtnl_unlock();
341
342     connect->status = NETIF_BE_STATUS_OKAY;
343 }
344
345 int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
346 {
347     domid_t       domid  = disconnect->domid;
348     unsigned int  handle = disconnect->netif_handle;
349     netif_t      *netif;
350
351     netif = netif_find_by_handle(domid, handle);
352     if ( unlikely(netif == NULL) )
353     {
354         DPRINTK("netif_disconnect attempted for non-existent netif"
355                 " (%u,%u)\n", disconnect->domid, disconnect->netif_handle); 
356         disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
357         return 1; /* Caller will send response error message. */
358     }
359
360     if ( netif->status == CONNECTED )
361     {
362         rtnl_lock();
363         netif->status = DISCONNECTING;
364         netif->disconnect_rspid = rsp_id;
365         wmb();
366         if ( netif_running(netif->dev) )
367             __netif_down(netif);
368         rtnl_unlock();
369         netif_put(netif);
370         return 0; /* Caller should not send response message. */
371     }
372
373     disconnect->status = NETIF_BE_STATUS_OKAY;
374     return 1;
375 }
376
377 void netif_interface_init(void)
378 {
379     memset(netif_hash, 0, sizeof(netif_hash));
380 }