1 /******************************************************************************
2 * arch/xen/drivers/netif/backend/interface.c
4 * Network-device interface management.
6 * Copyright (c) 2004-2005, Keir Fraser
10 #include <linux/rtnetlink.h>
12 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
13 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
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)
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;
30 static void __netif_up(netif_t *netif)
32 struct net_device *dev = netif->dev;
33 spin_lock_bh(&dev->xmit_lock);
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);
40 static void __netif_down(netif_t *netif)
42 struct net_device *dev = netif->dev;
43 spin_lock_bh(&dev->xmit_lock);
45 spin_unlock_bh(&dev->xmit_lock);
46 free_irq(netif->irq, netif);
47 netif_deschedule_work(netif);
50 static int net_open(struct net_device *dev)
52 netif_t *netif = netdev_priv(dev);
53 if ( netif->status == CONNECTED )
55 netif_start_queue(dev);
59 static int net_close(struct net_device *dev)
61 netif_t *netif = netdev_priv(dev);
62 netif_stop_queue(dev);
63 if ( netif->status == CONNECTED )
68 static void __netif_disconnect_complete(void *arg)
70 netif_t *netif = (netif_t *)arg;
72 netif_be_disconnect_t disc;
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.
79 unbind_evtchn_from_irq(netif->evtchn);
80 vfree(netif->tx); /* Frees netif->rx as well. */
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));
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.
100 if ( netif->status != DISCONNECTING )
102 netif->status = DISCONNECTED;
105 /* Send the successful response. */
106 ctrl_if_send_response(&cmsg);
109 void netif_disconnect_complete(netif_t *netif)
111 INIT_WORK(&netif->work, __netif_disconnect_complete, (void *)netif);
112 schedule_work(&netif->work);
115 void netif_create(netif_be_create_t *create)
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] = {};
124 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
125 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
128 DPRINTK("Could not create netif: out of memory\n");
129 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
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);
141 netif->credit_bytes = netif->remaining_credit = ~0UL;
142 netif->credit_usec = 0UL;
143 init_timer(&netif->credit_timeout);
145 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
146 while ( *pnetif != NULL )
148 if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) )
150 DPRINTK("Could not create netif: already exists\n");
151 create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
155 pnetif = &(*pnetif)->hash_next;
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;
163 /* Disable queuing. */
164 dev->tx_queue_len = 0;
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) )
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)
175 memset(dev->dev_addr, 0xFF, ETH_ALEN);
176 dev->dev_addr[0] &= ~0x01;
180 memcpy(dev->dev_addr, create->be_mac, ETH_ALEN);
183 memcpy(netif->fe_dev_addr, create->mac, ETH_ALEN);
186 err = register_netdevice(dev);
191 DPRINTK("Could not register new net device %s: err=%d\n",
193 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
198 netif->hash_next = *pnetif;
201 DPRINTK("Successfully created netif\n");
202 create->status = NETIF_BE_STATUS_OKAY;
205 void netif_destroy(netif_be_destroy_t *destroy)
207 domid_t domid = destroy->domid;
208 unsigned int handle = destroy->netif_handle;
209 netif_t **pnetif, *netif;
211 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
212 while ( (netif = *pnetif) != NULL )
214 if ( (netif->domid == domid) && (netif->handle == handle) )
216 if ( netif->status != DISCONNECTED )
217 goto still_connected;
220 pnetif = &netif->hash_next;
223 destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
227 destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
231 *pnetif = netif->hash_next;
232 unregister_netdev(netif->dev);
233 free_netdev(netif->dev);
234 destroy->status = NETIF_BE_STATUS_OKAY;
237 void netif_creditlimit(netif_be_creditlimit_t *creditlimit)
239 domid_t domid = creditlimit->domid;
240 unsigned int handle = creditlimit->netif_handle;
243 netif = netif_find_by_handle(domid, handle);
244 if ( unlikely(netif == NULL) )
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;
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;
256 if ( netif->status == CONNECTED )
259 * Schedule work so that any packets waiting under previous credit
260 * limit are dealt with (acts like a replenishment point).
262 netif->credit_timeout.expires = jiffies;
263 netif_schedule_work(netif);
266 creditlimit->status = NETIF_BE_STATUS_OKAY;
269 void netif_connect(netif_be_connect_t *connect)
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;
281 netif = netif_find_by_handle(domid, handle);
282 if ( unlikely(netif == NULL) )
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;
290 if ( netif->status != DISCONNECTED )
292 connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
296 if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL )
298 connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
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,
307 error |= direct_remap_area_pages(&init_mm,
308 VMALLOC_VMADDR(vma->addr) + PAGE_SIZE,
309 rx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
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;
318 connect->status = NETIF_BE_STATUS_ERROR;
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;
328 (netif_tx_interface_t *)vma->addr;
330 (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
331 netif->tx->resp_prod = netif->rx->resp_prod = 0;
333 wmb(); /* Other CPUs see new state before interface is started. */
336 netif->status = CONNECTED;
338 if ( netif_running(netif->dev) )
342 connect->status = NETIF_BE_STATUS_OKAY;
345 int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
347 domid_t domid = disconnect->domid;
348 unsigned int handle = disconnect->netif_handle;
351 netif = netif_find_by_handle(domid, handle);
352 if ( unlikely(netif == NULL) )
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. */
360 if ( netif->status == CONNECTED )
363 netif->status = DISCONNECTING;
364 netif->disconnect_rspid = rsp_id;
366 if ( netif_running(netif->dev) )
370 return 0; /* Caller should not send response message. */
373 disconnect->status = NETIF_BE_STATUS_OKAY;
377 void netif_interface_init(void)
379 memset(netif_hash, 0, sizeof(netif_hash));